[Pkg-mozext-maintainers] Bug#1116040: trixie-pu: package eas4tbsync/4.17-1~deb13u1

Mechtilde Stehmann mechtilde at debian.org
Tue Sep 23 14:22:56 BST 2025


Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: eas4tbsync at packages.debian.org, mechtilde at debian.org
Control: affects -1 + src:eas4tbsync
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: eas4tbsync,
which is a dependency of 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 and there
dependency webext-eas4tbsync.

[ 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 eas4tbsync-4.11 eas4tbsync-4.17

 .github/issue_template.md                     |   16 
 CONTRIBUTORS.md                               |   39 
 LICENSE                                       |  746 +++---
 Makebeta                                      |   34 
 Makefile                                      |   25 
 Makefile.bat                                  |    9 
 README.md                                     |   46 
 _locales/Readme.txt                           |   16 
 _locales/bg/messages.json                     | 1132 ++++-----
 _locales/cs/messages.json                     | 1132 ++++-----
 _locales/de/messages.json                     | 1132 ++++-----
 _locales/en-US/messages.json                  | 1132 ++++-----
 _locales/es/messages.json                     | 1132 ++++-----
 _locales/fr/messages.json                     | 1132 ++++-----
 _locales/gl/messages.json                     | 1132 ++++-----
 _locales/hu/messages.json                     | 1132 ++++-----
 _locales/it/messages.json                     | 1132 ++++-----
 _locales/ja/messages.json                     | 1132 ++++-----
 _locales/pl/messages.json                     | 1132 ++++-----
 _locales/pt_BR/messages.json                  | 1132 ++++-----
 _locales/ro/messages.json                     | 1132 ++++-----
 _locales/ru/messages.json                     | 1132 ++++-----
 api/EAS4TbSync/implementation.js              |   74 
 api/EAS4TbSync/schema.json                    |   13 
 api/LegacyHelper/README.md                    |   50 
 api/LegacyHelper/implementation.js            |  118 
 api/LegacyHelper/schema.json                  |   42 
 background.js                                 |   11 
 beta-release-channel-update.json              |   13 
 content/api/BootstrapLoader/CHANGELOG.md      |   75 
 content/api/BootstrapLoader/README.md         |    1 
 content/api/BootstrapLoader/implementation.js |  187 -
 content/api/BootstrapLoader/schema.json       |   61 
 content/bootstrap.js                          |   53 
 content/includes/calendarsync.js              |  852 +++----
 content/includes/contactsync.js               | 1109 ++++-----
 content/includes/network.js                   | 3150 +++++++++++++-------------
 content/includes/sync.js                      | 3015 ++++++++++++------------
 content/includes/tasksync.js                  |  429 +--
 content/includes/tools.js                     | 1083 ++++----
 content/includes/wbxmltools.js                | 1766 +++++++-------
 content/includes/xmltools.js                  |  322 +-
 content/locales.js                            |   15 
 content/manager/createAccount.js              |  517 ++--
 content/manager/createAccount.xhtml           |  194 -
 content/manager/editAccountOverlay.js         |  112 
 content/manager/editAccountOverlay.xhtml      |  308 +-
 content/provider.js                           | 1477 ++++++------
 content/skin/365.svg                          |   22 
 content/skin/fieldset.css                     |   12 
 content/timezonedata/Aliases.csv              |  230 -
 content/timezonedata/README                   |    8 
 content/timezonedata/WindowsTimezone.csv      | 1028 ++++----
 crowdin.yml                                   |    5 
 debian/changelog                              |   28 
 debian/control                                |    8 
 debian/copyright                              |    4 
 debian/dpb.conf                               |   18 
 debian/gbp.conf                               |    7 
 debian/watch                                  |    6 
 manifest.json                                 |   79 
 61 files changed, 16654 insertions(+), 16627 deletions(-)

diff -Nru eas4tbsync-4.11/api/EAS4TbSync/implementation.js eas4tbsync-4.17/api/EAS4TbSync/implementation.js
--- eas4tbsync-4.11/api/EAS4TbSync/implementation.js	1970-01-01 01:00:00.000000000 +0100
+++ eas4tbsync-4.17/api/EAS4TbSync/implementation.js	2025-05-15 13:21:20.000000000 +0200
@@ -0,0 +1,74 @@
+/*
+ * 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 { ExtensionParent } = ChromeUtils.importESModule(
+    "resource://gre/modules/ExtensionParent.sys.mjs"
+  );
+
+  async function observeTbSyncInitialized(aSubject, aTopic, aData) {
+    try {
+      const tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+        "tbsync at jobisoft.de"
+      );
+      const { TbSync } = ChromeUtils.importESModule(
+        `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+      );
+      // Load this provider add-on into TbSync
+      if (TbSync.enabled) {
+        const easExtension = ExtensionParent.GlobalManager.getExtension(
+          "eas4tbsync at jobisoft.de"
+        );
+        console.log(`Registering EAS provider v${easExtension.manifest.version} with TbSync v${tbsyncExtension.manifest.version}`);
+        await TbSync.providers.loadProvider(easExtension, "eas", "chrome://eas4tbsync/content/provider.js");
+      }
+    } catch (e) {
+      // If this fails, TbSync is not loaded yet and we will get the notification later again.
+    }
+
+  }
+
+  var EAS4TbSync = class extends ExtensionCommon.ExtensionAPI {
+
+    getAPI(context) {
+      return {
+        EAS4TbSync: {
+          async load() {
+            Services.obs.addObserver(observeTbSyncInitialized, "tbsync.observer.initialized", false);
+
+            // Did we miss the observer?
+            observeTbSyncInitialized();
+          }
+        },
+      };
+    }
+
+    onShutdown(isAppShutdown) {
+      if (isAppShutdown) {
+        return; // the application gets unloaded anyway
+      }
+
+      Services.obs.removeObserver(observeTbSyncInitialized, "tbsync.observer.initialized");
+      //unload this provider add-on from TbSync
+      try {
+        const tbsyncExtension = ExtensionParent.GlobalManager.getExtension(
+          "tbsync at jobisoft.de"
+        );
+        const { TbSync } = ChromeUtils.importESModule(
+          `chrome://tbsync/content/tbsync.sys.mjs?${tbsyncExtension.manifest.version}`
+        );
+        TbSync.providers.unloadProvider("eas");
+      } catch (e) {
+        //if this fails, TbSync has been unloaded already and has unloaded this addon as well
+      }
+    }
+  };
+  exports.EAS4TbSync = EAS4TbSync;
+})(this);
\ Kein Zeilenumbruch am Dateiende.
diff -Nru eas4tbsync-4.11/api/EAS4TbSync/schema.json eas4tbsync-4.17/api/EAS4TbSync/schema.json
--- eas4tbsync-4.11/api/EAS4TbSync/schema.json	1970-01-01 01:00:00.000000000 +0100
+++ eas4tbsync-4.17/api/EAS4TbSync/schema.json	2025-05-15 13:21:20.000000000 +0200
@@ -0,0 +1,13 @@
+[
+  {
+    "namespace": "EAS4TbSync",
+    "functions": [
+      {
+        "name": "load",
+        "type": "function",
+        "async": true,
+        "parameters": []
+      }
+    ]
+  }
+]
\ Kein Zeilenumbruch am Dateiende.
diff -Nru eas4tbsync-4.11/api/LegacyHelper/implementation.js eas4tbsync-4.17/api/LegacyHelper/implementation.js
--- eas4tbsync-4.11/api/LegacyHelper/implementation.js	1970-01-01 01:00:00.000000000 +0100
+++ eas4tbsync-4.17/api/LegacyHelper/implementation.js	2025-05-15 13:21:20.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 eas4tbsync-4.11/api/LegacyHelper/README.md eas4tbsync-4.17/api/LegacyHelper/README.md
--- eas4tbsync-4.11/api/LegacyHelper/README.md	1970-01-01 01:00:00.000000000 +0100
+++ eas4tbsync-4.17/api/LegacyHelper/README.md	2025-05-15 13:21:20.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 eas4tbsync-4.11/api/LegacyHelper/schema.json eas4tbsync-4.17/api/LegacyHelper/schema.json
--- eas4tbsync-4.11/api/LegacyHelper/schema.json	1970-01-01 01:00:00.000000000 +0100
+++ eas4tbsync-4.17/api/LegacyHelper/schema.json	2025-05-15 13:21:20.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 eas4tbsync-4.11/background.js eas4tbsync-4.17/background.js
--- eas4tbsync-4.11/background.js	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/background.js	2025-05-15 13:21:20.000000000 +0200
@@ -1,6 +1,5 @@
-async function main() {
-  await messenger.BootstrapLoader.registerChromeUrl([ ["content", "eas4tbsync", "content/"] ]);
-  await messenger.BootstrapLoader.registerBootstrapScript("chrome://eas4tbsync/content/bootstrap.js");  
-}
-
-main();
+await browser.LegacyHelper.registerGlobalUrls([
+  ["content", "eas4tbsync", "content/"],
+]);
+
+await browser.EAS4TbSync.load();
diff -Nru eas4tbsync-4.11/beta-release-channel-update.json eas4tbsync-4.17/beta-release-channel-update.json
--- eas4tbsync-4.11/beta-release-channel-update.json	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/beta-release-channel-update.json	1970-01-01 01:00:00.000000000 +0100
@@ -1,13 +0,0 @@
-{
-  "addons": {
-    "eas4tbsync at jobisoft.de": {
-      "updates": [
-        { "version": "%VERSION%",
-          "update_info_url": "https://github.com/jobisoft/EAS-4-TbSync/releases",
-          "update_link": "%LINK%",
-          "applications": {
-            "gecko": { "strict_min_version": "78.0" } } }
-      ]
-    }
-  }
-}
\ Kein Zeilenumbruch am Dateiende.
diff -Nru eas4tbsync-4.11/content/api/BootstrapLoader/CHANGELOG.md eas4tbsync-4.17/content/api/BootstrapLoader/CHANGELOG.md
--- eas4tbsync-4.11/content/api/BootstrapLoader/CHANGELOG.md	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/api/BootstrapLoader/CHANGELOG.md	1970-01-01 01:00:00.000000000 +0100
@@ -1,75 +0,0 @@
-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 eas4tbsync-4.11/content/api/BootstrapLoader/implementation.js eas4tbsync-4.17/content/api/BootstrapLoader/implementation.js
--- eas4tbsync-4.11/content/api/BootstrapLoader/implementation.js	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/api/BootstrapLoader/implementation.js	1970-01-01 01:00:00.000000000 +0100
@@ -1,187 +0,0 @@
-/*
- * This file is provided by the addon-developer-support repository at
- * https://github.com/thundernest/addon-developer-support
- *
- * Version: 1.21
- *
- * 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 { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");
-var { ExtensionSupport } = ChromeUtils.import("resource:///modules/ExtensionSupport.jsm");
-var { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
-
-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;
-}
-
-// Removed all extra code for backward compatibility for better maintainability.
-var BootstrapLoader = class extends ExtensionCommon.ExtensionAPI {
-  getAPI(context) {
-    this.uniqueRandomID = "AddOnNS" + context.extension.instanceId;
-    this.menu_addonPrefs_id = "addonPrefs";
-
-
-    this.pathToBootstrapScript = null;
-    this.chromeHandle = null;
-    this.chromeData = 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: {
-        registerChromeUrl(data) {
-          let chromeData = [];
-          for (let entry of data) {
-            chromeData.push(entry)
-          }
-
-          if (chromeData.length > 0) {
-            const manifestURI = Services.io.newURI(
-              "manifest.json",
-              null,
-              context.extension.rootURI
-            );
-            self.chromeHandle = aomStartup.registerChrome(manifestURI, chromeData);
-          }
-
-          self.chromeData = chromeData;
-        },
-
-        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);
-          console.log(addon.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)
-          }
-
-        }
-      }
-    };
-  }
-
-  onShutdown(isAppShutdown) {
-    if (isAppShutdown) {
-      return; // the application gets unloaded anyway
-    }
-
-
-    // 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.chromeHandle) {
-      this.chromeHandle.destruct();
-      this.chromeHandle = null;
-    }
-    // Flush all caches
-    Services.obs.notifyObservers(null, "startupcache-invalidate");
-    console.log("BootstrapLoader for " + this.extension.id + " unloaded!");
-  }
-};
\ Kein Zeilenumbruch am Dateiende.
diff -Nru eas4tbsync-4.11/content/api/BootstrapLoader/README.md eas4tbsync-4.17/content/api/BootstrapLoader/README.md
--- eas4tbsync-4.11/content/api/BootstrapLoader/README.md	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/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 eas4tbsync-4.11/content/api/BootstrapLoader/schema.json eas4tbsync-4.17/content/api/BootstrapLoader/schema.json
--- eas4tbsync-4.11/content/api/BootstrapLoader/schema.json	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/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 eas4tbsync-4.11/content/bootstrap.js eas4tbsync-4.17/content/bootstrap.js
--- eas4tbsync-4.11/content/bootstrap.js	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/bootstrap.js	1970-01-01 01:00:00.000000000 +0100
@@ -1,53 +0,0 @@
-/*
- * This file is part of EAS-4-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/. 
- */
-
-// no need to create namespace, we are in a sandbox
-
-let onInitDoneObserver = {
-    observe: async function (aSubject, aTopic, aData) {        
-        let valid = false;
-        try {
-            var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
-            valid = TbSync.enabled;
-        } catch (e) {
-            // If this fails, TbSync is not loaded yet and we will get the notification later again.
-        }
-        
-        //load this provider add-on into TbSync
-        if (valid) {
-            await TbSync.providers.loadProvider(extension, "eas", "chrome://eas4tbsync/content/provider.js");
-        }
-    }
-}
-
-function startup(data, reason) {
-    // Possible reasons: APP_STARTUP, ADDON_ENABLE, ADDON_INSTALL, ADDON_UPGRADE, or ADDON_DOWNGRADE.
-
-    Services.obs.addObserver(onInitDoneObserver, "tbsync.observer.initialized", false);
-
-    // Did we miss the observer?
-    onInitDoneObserver.observe();
-}
-
-function shutdown(data, reason) {
-    // Possible reasons: APP_STARTUP, ADDON_ENABLE, ADDON_INSTALL, ADDON_UPGRADE, or ADDON_DOWNGRADE.
-
-    // When the application is shutting down we normally don't have to clean up.
-    if (reason == APP_SHUTDOWN) {
-        return;
-    }
-
-    Services.obs.removeObserver(onInitDoneObserver, "tbsync.observer.initialized");
-    //unload this provider add-on from TbSync
-    try {
-        var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
-        TbSync.providers.unloadProvider("eas");
-    } catch (e) {
-        //if this fails, TbSync has been unloaded already and has unloaded this addon as well
-    }
-}
diff -Nru eas4tbsync-4.11/content/includes/calendarsync.js eas4tbsync-4.17/content/includes/calendarsync.js
--- eas4tbsync-4.11/content/includes/calendarsync.js	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/includes/calendarsync.js	2025-05-15 13:21:20.000000000 +0200
@@ -1,422 +1,430 @@
-/*
- * This file is part of EAS-4-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 { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
-const cal = TbSync.lightning.cal;
-const ICAL = TbSync.lightning.ICAL;
-
-var Calendar = {
-
-    // --------------------------------------------------------------------------- //
-    // Read WBXML and set Thunderbird item
-    // --------------------------------------------------------------------------- //
-    setThunderbirdItemFromWbxml: function (tbItem, data, id, syncdata, mode = "standard") {
-        
-        let item = tbItem instanceof TbSync.lightning.TbItem ? tbItem.nativeItem : tbItem;
-        
-        let asversion = syncdata.accountData.getAccountProperty("asversion");
-        item.id = id;
-        eas.sync.setItemSubject(item, syncdata, data);
-        if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Processing " + mode + " calendar item", item.title + " (" + id + ")");
-
-        eas.sync.setItemLocation(item, syncdata, data);
-        eas.sync.setItemCategories(item, syncdata, data);
-        eas.sync.setItemBody(item, syncdata, data);
-
-        //timezone
-        let stdOffset = eas.defaultTimezoneInfo.std.offset;
-        let dstOffset = eas.defaultTimezoneInfo.dst.offset;
-        let easTZ = new eas.tools.TimeZoneDataStructure();
-        if (data.TimeZone) {
-            if (data.TimeZone == "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") {
-                TbSync.dump("Recieve TZ", "No timezone data received, using local default timezone.");
-            } else {
-                //load timezone struct into EAS TimeZone object
-                easTZ.easTimeZone64 = data.TimeZone;
-                if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Recieve TZ", item.title + easTZ.toString());
-                stdOffset = easTZ.utcOffset;
-                dstOffset = easTZ.daylightBias + easTZ.utcOffset;
-            }
-        }
-        let timezone = eas.tools.guessTimezoneByStdDstOffset(stdOffset, dstOffset, easTZ.standardName);
-        
-        if (data.StartTime) {
-            let utc = cal.createDateTime(data.StartTime); //format "19800101T000000Z" - UTC
-            item.startDate = utc.getInTimezone(timezone);
-            if (data.AllDayEvent && data.AllDayEvent == "1") {
-                item.startDate.timezone = (cal.dtz && cal.dtz.floating) ? cal.dtz.floating : cal.floating();
-                item.startDate.isDate = true;
-            }
-        }
-
-        if (data.EndTime) {
-            let utc = cal.createDateTime(data.EndTime);
-            item.endDate = utc.getInTimezone(timezone);
-            if (data.AllDayEvent && data.AllDayEvent == "1") {
-                item.endDate.timezone = (cal.dtz && cal.dtz.floating) ? cal.dtz.floating : cal.floating();
-                item.endDate.isDate = true;
-            }
-        }
-
-        //stamp time cannot be set and it is not needed, an updated version is only send to the server, if there was a change, so stamp will be updated
-
-
-        //EAS Reminder
-        item.clearAlarms();
-        if (data.Reminder && data.StartTime) {
-            let alarm = new CalAlarm();
-            alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_START;
-            alarm.offset = cal.createDuration();
-            alarm.offset.inSeconds = (0-parseInt(data.Reminder)*60);
-            alarm.action ="DISPLAY";
-            item.addAlarm(alarm);
-            
-            let alarmData = cal.alarms.calculateAlarmDate(item, alarm);
-            let startDate = cal.createDateTime(data.StartTime);
-            let nowDate = eas.tools.getNowUTC();
-            if (startDate.compare(nowDate) < 0) {
-                // Mark alarm as ACK if in the past.
-                item.alarmLastAck = nowDate;
-            }
-        }
-
-        eas.sync.mapEasPropertyToThunderbird ("BusyStatus", "TRANSP", data, item);
-        eas.sync.mapEasPropertyToThunderbird ("Sensitivity", "CLASS", data, item);
-
-        if (data.ResponseType) {
-            //store original EAS value 
-            item.setProperty("X-EAS-ResponseType", eas.xmltools.checkString(data.ResponseType, "0")); //some server send empty ResponseType ???
-        }
-
-        //Attendees - remove all Attendees and re-add the ones from XML
-        item.removeAllAttendees();
-        if (data.Attendees && data.Attendees.Attendee) {
-            let att = [];
-            if (Array.isArray(data.Attendees.Attendee)) att = data.Attendees.Attendee;
-            else att.push(data.Attendees.Attendee);
-            for (let i = 0; i < att.length; i++) {
-                if (att[i].Email && eas.tools.isString(att[i].Email) && att[i].Name) { //req.
-
-                    let attendee = new CalAttendee();
-
-                    //is this attendee the local EAS user?
-                    let isSelf = (att[i].Email == syncdata.accountData.getAccountProperty("user"));
-                    
-                    attendee["id"] = cal.email.prependMailTo(att[i].Email);
-                    attendee["commonName"] = att[i].Name;
-                    //default is "FALSE", only if THIS attendee isSelf, use ResponseRequested (we cannot respond for other attendee) - ResponseType is not send back to the server, it is just a local information
-                    attendee["rsvp"] = (isSelf && data.ResponseRequested) ? "TRUE" : "FALSE";		
-
-                    //not supported in 2.5
-                    switch (att[i].AttendeeType) {
-                        case "1": //required
-                            attendee["role"] = "REQ-PARTICIPANT";
-                            attendee["userType"] = "INDIVIDUAL";
-                            break;
-                        case "2": //optional
-                            attendee["role"] = "OPT-PARTICIPANT";
-                            attendee["userType"] = "INDIVIDUAL";
-                            break;
-                        default : //resource or unknown
-                            attendee["role"] = "NON-PARTICIPANT";
-                            attendee["userType"] = "RESOURCE";
-                            break;
-                    }
-
-                    //not supported in 2.5 - if attendeeStatus is missing, check if this isSelf and there is a ResponseType
-                    if (att[i].AttendeeStatus)
-                        attendee["participationStatus"] = eas.sync.MAP_EAS2TB.ATTENDEESTATUS[att[i].AttendeeStatus];
-                    else if (isSelf && data.ResponseType) 
-                        attendee["participationStatus"] = eas.sync.MAP_EAS2TB.ATTENDEESTATUS[data.ResponseType];
-                    else 
-                        attendee["participationStatus"] = "NEEDS-ACTION";
-
-                    // status  : [NEEDS-ACTION, ACCEPTED, DECLINED, TENTATIVE, DELEGATED, COMPLETED, IN-PROCESS]
-                    // rolemap : [REQ-PARTICIPANT, OPT-PARTICIPANT, NON-PARTICIPANT, CHAIR]
-                    // typemap : [INDIVIDUAL, GROUP, RESOURCE, ROOM]
-
-                    // Add attendee to event
-                    item.addAttendee(attendee);
-                } else {
-                    TbSync.eventlog.add("info", syncdata, "Attendee without required name and/or email found. Skipped.");
-                }
-            }
-        }
-        
-        if (data.OrganizerName && data.OrganizerEmail && eas.tools.isString(data.OrganizerEmail)) {
-            //Organizer
-            let organizer = new CalAttendee();
-            organizer.id = cal.email.prependMailTo(data.OrganizerEmail);
-            organizer.commonName = data.OrganizerName;
-            organizer.rsvp = "FALSE";
-            organizer.role = "CHAIR";
-            organizer.userType = null;
-            organizer.participationStatus = "ACCEPTED";
-            organizer.isOrganizer = true;
-            item.organizer = organizer;
-        }
-
-        eas.sync.setItemRecurrence(item, syncdata, data, timezone);
-        
-        // BusyStatus is always representing the status of the current user in terms of availability.
-        // It has nothing to do with the status of a meeting. The user could be just the organizer, but does not need to attend, so he would be free.
-        // The correct map is between BusyStatus and TRANSP (show time as avail, busy, unset)
-        // A new event always sets TRANSP to busy, so unset is indeed a good way to store Tentiative
-        // However:
-        //  - EAS Meetingstatus only knows ACTIVE or CANCELLED, but not CONFIRMED or TENTATIVE
-        //  - TB STATUS has UNSET, CONFIRMED, TENTATIVE, CANCELLED
-        //  -> Special case: User sets BusyStatus to TENTIATIVE -> TRANSP is unset and also set STATUS to TENTATIVE
-        // The TB STATUS is the correct map for EAS Meetingstatus and should be unset, if it is not a meeting EXCEPT if set to TENTATIVE
-        let tbStatus = (data.BusyStatus && data.BusyStatus == "1" ?  "TENTATIVE" : null);
-        
-        if (data.MeetingStatus) {
-            //store original EAS value 
-            item.setProperty("X-EAS-MeetingStatus", data.MeetingStatus);
-            //bitwise representation for Meeting, Received, Cancelled:
-            let M = data.MeetingStatus & 0x1;
-            let R = data.MeetingStatus & 0x2;
-            let C = data.MeetingStatus & 0x4;
-
-            // We can map M+C to TB STATUS (TENTATIVE, CONFIRMED, CANCELLED, unset).
-            if (M) {
-                if (C) tbStatus = "CANCELLED";
-                else if (!tbStatus) tbStatus = "CONFIRMED"; // do not override "TENTIATIVE"
-            }
-            
-            //we can also use the R information, to update our fallbackOrganizerName
-            if (!R && data.OrganizerName) syncdata.target.calendar.setProperty("fallbackOrganizerName", data.OrganizerName);            
-        }
-
-        if (tbStatus) item.setProperty("STATUS", tbStatus)
-        else item.deleteProperty("STATUS");
-
-        //TODO: attachements (needs EAS 16.0!)
-    },
-
-
-
-
-
-
-
-
-
-    // --------------------------------------------------------------------------- //
-    //read TB event and return its data as WBXML
-    // --------------------------------------------------------------------------- //
-    getWbxmlFromThunderbirdItem: async function (tbItem, syncdata, isException = false) {
-        let item = tbItem instanceof TbSync.lightning.TbItem ? tbItem.nativeItem : tbItem;
-
-        let asversion = syncdata.accountData.getAccountProperty("asversion");
-        let wbxml = eas.wbxmltools.createWBXML("", syncdata.type); //init wbxml with "" and not with precodes, and set initial codepage
-        let nowDate = new Date();
-
-        /*
-         *  We do not use ghosting, that means, if we do not include a value in CHANGE, it is removed from the server. 
-         *  However, this does not seem to work on all fields. Furthermore, we need to include any (empty) container to blank its childs.
-         */
-
-        //Order of tags taken from https://msdn.microsoft.com/en-us/library/dn338917(v=exchg.80).aspx
-        
-        //timezone
-        if (!isException) {
-            let easTZ = new eas.tools.TimeZoneDataStructure();
-
-            //if there is no end and no start (or both are floating) use default timezone info
-            let tzInfo = null;
-            if (item.startDate && item.startDate.timezone.tzid != "floating") tzInfo = eas.tools.getTimezoneInfo(item.startDate.timezone);
-            else if (item.endDate && item.endDate.timezone.tzid != "floating") tzInfo = eas.tools.getTimezoneInfo(item.endDate.timezone);
-            if (!tzInfo) tzInfo = eas.defaultTimezoneInfo;
-            
-            easTZ.utcOffset =   tzInfo.std.offset;
-            easTZ.standardBias = 0;
-            easTZ.daylightBias =  tzInfo.dst.offset -  tzInfo.std.offset;
-
-            easTZ.standardName = eas.ianaToWindowsTimezoneMap.hasOwnProperty(tzInfo.std.displayname) ? eas.ianaToWindowsTimezoneMap[tzInfo.std.displayname] : tzInfo.std.displayname;
-            easTZ.daylightName = eas.ianaToWindowsTimezoneMap.hasOwnProperty(tzInfo.dst.displayname) ? eas.ianaToWindowsTimezoneMap[tzInfo.dst.displayname] : tzInfo.dst.displayname;
-
-            if (tzInfo.std.switchdate && tzInfo.dst.switchdate) {
-                easTZ.standardDate.wMonth = tzInfo.std.switchdate.month;
-                easTZ.standardDate.wDay = tzInfo.std.switchdate.weekOfMonth;
-                easTZ.standardDate.wDayOfWeek = tzInfo.std.switchdate.dayOfWeek;
-                easTZ.standardDate.wHour = tzInfo.std.switchdate.hour;
-                easTZ.standardDate.wMinute = tzInfo.std.switchdate.minute;
-                easTZ.standardDate.wSecond = tzInfo.std.switchdate.second;
-                
-                easTZ.daylightDate.wMonth = tzInfo.dst.switchdate.month;
-                easTZ.daylightDate.wDay = tzInfo.dst.switchdate.weekOfMonth;
-                easTZ.daylightDate.wDayOfWeek = tzInfo.dst.switchdate.dayOfWeek;
-                easTZ.daylightDate.wHour = tzInfo.dst.switchdate.hour;
-                easTZ.daylightDate.wMinute = tzInfo.dst.switchdate.minute;
-                easTZ.daylightDate.wSecond = tzInfo.dst.switchdate.second;
-            }
-            
-            wbxml.atag("TimeZone", easTZ.easTimeZone64);
-             if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Send TZ", item.title + easTZ.toString());
-        }
-        
-        //AllDayEvent (for simplicity, we always send a value)
-        wbxml.atag("AllDayEvent", (item.startDate && item.startDate.isDate && item.endDate && item.endDate.isDate) ? "1" : "0");
-
-        //Body
-        wbxml.append(eas.sync.getItemBody(item, syncdata));
-
-        //BusyStatus (Free, Tentative, Busy) is taken from TRANSP (busy, free, unset=tentative)
-        //However if STATUS is set to TENTATIVE, overide TRANSP and set BusyStatus to TENTATIVE
-        if (item.hasProperty("STATUS") && item.getProperty("STATUS") == "TENTATIVE") {
-            wbxml.atag("BusyStatus","1");
-        } else {
-            wbxml.atag("BusyStatus", eas.sync.mapThunderbirdPropertyToEas("TRANSP", "BusyStatus", item));
-        }
-        
-        //Organizer
-        if (!isException) {
-            if (item.organizer && item.organizer.commonName) wbxml.atag("OrganizerName", item.organizer.commonName);
-            if (item.organizer && item.organizer.id) wbxml.atag("OrganizerEmail",  cal.email.removeMailTo(item.organizer.id));
-        }
-
-        //DtStamp in UTC
-        wbxml.atag("DtStamp", item.stampTime ? eas.tools.getIsoUtcString(item.stampTime) : eas.tools.dateToBasicISOString(nowDate));
-
-        //EndTime in UTC
-        wbxml.atag("EndTime", item.endDate ? eas.tools.getIsoUtcString(item.endDate) : eas.tools.dateToBasicISOString(nowDate));
-        
-        //Location
-        wbxml.atag("Location", (item.hasProperty("location")) ? item.getProperty("location") : "");
-
-        //EAS Reminder (TB getAlarms) - at least with zpush blanking by omitting works, horde does not work
-        let alarms = item.getAlarms({});
-        if (alarms.length>0) {
-
-            let reminder = -1;
-            if (alarms[0].offset !== null) {
-                reminder = 0 - alarms[0].offset.inSeconds/60;
-            } else if (item.startDate) {
-                let timeDiff =item.startDate.getInTimezone(eas.utcTimezone).subtractDate(alarms[0].alarmDate.getInTimezone(eas.utcTimezone));     
-                reminder = timeDiff.inSeconds/60;
-                TbSync.eventlog.add("info", syncdata, "Converting absolute alarm to relative alarm (not supported).", item.icalString);
-            }
-            if (reminder >= 0) wbxml.atag("Reminder", reminder.toString());
-            else TbSync.eventlog.add("info", syncdata, "Droping alarm after start date (not supported).", item.icalString);
-
-        }
-
-        //Sensitivity (CLASS)
-        wbxml.atag("Sensitivity", eas.sync.mapThunderbirdPropertyToEas("CLASS", "Sensitivity", item));
-
-        //Subject (obmitting these, should remove them from the server - that does not work reliably, so we send blanks)
-        wbxml.atag("Subject", (item.title) ? item.title : "");
-
-        //StartTime in UTC
-        wbxml.atag("StartTime", item.startDate ? eas.tools.getIsoUtcString(item.startDate) : eas.tools.dateToBasicISOString(nowDate));
-
-        //UID (limit to 300)
-        //each TB event has an ID, which is used as EAS serverId - however there is a second UID in the ApplicationData
-        //since we do not have two different IDs to use, we use the same ID
-        if (!isException) { //docs say it would be allowed in exception in 2.5, but it does not work, if present
-            wbxml.atag("UID", item.id);
-        }
-        //IMPORTANT in EAS v16 it is no longer allowed to send a UID
-        //Only allowed in exceptions in v2.5
-
-
-        //EAS MeetingStatus
-        // 0 (000) The event is an appointment, which has no attendees.
-        // 1 (001) The event is a meeting and the user is the meeting organizer.
-        // 3 (011) This event is a meeting, and the user is not the meeting organizer; the meeting was received from someone else.
-        // 5 (101) The meeting has been canceled and the user was the meeting organizer.
-        // 7 (111) The meeting has been canceled. The user was not the meeting organizer; the meeting was received from someone else
-
-        //there are 3 fields; Meeting, Owner, Cancelled
-        //M can be reconstructed from #of attendees (looking at the old value is not wise, since it could have been changed)
-        //C can be reconstucted from TB STATUS
-        //O can be reconstructed by looking at the original value, or (if not present) by comparing EAS ownerID with TB ownerID
-
-        let attendees = item.getAttendees();
-        //if (!(isException && asversion == "2.5")) { //MeetingStatus is not supported in exceptions in EAS 2.5
-        if (!isException) { //Exchange 2010 does not seem to support MeetingStatus at all in exceptions
-            if (attendees.length == 0) wbxml.atag("MeetingStatus", "0");
-            else {
-                //get owner information
-                let isReceived = false;
-                if (item.hasProperty("X-EAS-MEETINGSTATUS")) isReceived = item.getProperty("X-EAS-MEETINGSTATUS") & 0x2;
-                else isReceived = (item.organizer && item.organizer.id && cal.email.removeMailTo(item.organizer.id) != syncdata.accountData.getAccountProperty("user"));
-
-                //either 1,3,5 or 7
-                if (item.hasProperty("STATUS") && item.getProperty("STATUS") == "CANCELLED") {
-                    //either 5 or 7
-                    wbxml.atag("MeetingStatus", (isReceived ? "7" : "5"));
-                } else {
-                    //either 1 or 3
-                    wbxml.atag("MeetingStatus", (isReceived ? "3" : "1"));
-                }
-            }
-        }
-
-        //Attendees
-        let TB_responseType = null;
-        if (!(isException && asversion == "2.5")) { //attendees are not supported in exceptions in EAS 2.5
-            if (attendees.length > 0) { //We should use it instead of countAttendees.value
-                wbxml.otag("Attendees");
-                    for (let attendee of attendees) {
-                        wbxml.otag("Attendee");
-                            wbxml.atag("Email", cal.email.removeMailTo(attendee.id));
-                            wbxml.atag("Name", (attendee.commonName ? attendee.commonName : cal.email.removeMailTo(attendee.id).split("@")[0]));
-                            if (asversion != "2.5") {
-                                //it's pointless to send AttendeeStatus, 
-                                // - if we are the owner of a meeting, TB does not have an option to actually set the attendee status (on behalf of an attendee) in the UI
-                                // - if we are an attendee (of an invite) we cannot and should not set status of other attendees and or own status must be send through a MeetingResponse
-                                // -> all changes of attendee status are send from the server to us, either via ResponseType or via AttendeeStatus
-                                //wbxml.atag("AttendeeStatus", eas.sync.MAP_TB2EAS.ATTENDEESTATUS[attendee.participationStatus]);
-
-                                if (attendee.userType == "RESOURCE" || attendee.userType == "ROOM" || attendee.role == "NON-PARTICIPANT") wbxml.atag("AttendeeType","3");
-                                else if (attendee.role == "REQ-PARTICIPANT" || attendee.role == "CHAIR") wbxml.atag("AttendeeType","1");
-                                else wbxml.atag("AttendeeType","2"); //leftovers are optional
-                            }
-                        wbxml.ctag();
-                    }
-                wbxml.ctag();
-            } else {
-                wbxml.atag("Attendees");
-            }
-        }
-
-        //Categories (see https://github.com/jobisoft/TbSync/pull/35#issuecomment-359286374)
-        if (!isException) {
-            wbxml.append(eas.sync.getItemCategories(item, syncdata));
-        }
-
-        //recurrent events (implemented by Chris Allan)
-        if (!isException) {
-            wbxml.append(await eas.sync.getItemRecurrence(item, syncdata));
-        }
-
-
-        //---------------------------
-        
-        //TP PRIORITY (9=LOW, 5=NORMAL, 1=HIGH) not mapable to EAS Event
-        //TODO: attachements (needs EAS 16.0!)
-        
-        //https://dxr.mozilla.org/comm-central/source/calendar/base/public/calIAlarm.idl
-        //TbSync.dump("ALARM ("+i+")", [, alarms[i].related, alarms[i].repeat, alarms[i].repeatOffset, alarms[i].repeatDate, alarms[i].action].join("|"));
-
-        return wbxml.getBytes();
-    }    
-}
+/*
+ * This file is part of EAS-4-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, {
+    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 { 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}`
+);
+
+const cal = TbSync.lightning.cal;
+const ICAL = TbSync.lightning.ICAL;
+
+var Calendar = {
+
+    // --------------------------------------------------------------------------- //
+    // Read WBXML and set Thunderbird item
+    // --------------------------------------------------------------------------- //
+    setThunderbirdItemFromWbxml: function (tbItem, data, id, syncdata, mode = "standard") {
+
+        let item = tbItem instanceof TbSync.lightning.TbItem ? tbItem.nativeItem : tbItem;
+
+        let asversion = syncdata.accountData.getAccountProperty("asversion");
+        item.id = id;
+        eas.sync.setItemSubject(item, syncdata, data);
+        if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Processing " + mode + " calendar item", item.title + " (" + id + ")");
+
+        eas.sync.setItemLocation(item, syncdata, data);
+        eas.sync.setItemCategories(item, syncdata, data);
+        eas.sync.setItemBody(item, syncdata, data);
+
+        //timezone
+        let stdOffset = eas.defaultTimezoneInfo.std.offset;
+        let dstOffset = eas.defaultTimezoneInfo.dst.offset;
+        let easTZ = new eas.tools.TimeZoneDataStructure();
+        if (data.TimeZone) {
+            if (data.TimeZone == "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") {
+                TbSync.dump("Recieve TZ", "No timezone data received, using local default timezone.");
+            } else {
+                //load timezone struct into EAS TimeZone object
+                easTZ.easTimeZone64 = data.TimeZone;
+                if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Recieve TZ", item.title + easTZ.toString());
+                stdOffset = easTZ.utcOffset;
+                dstOffset = easTZ.daylightBias + easTZ.utcOffset;
+            }
+        }
+        let timezone = eas.tools.guessTimezoneByStdDstOffset(stdOffset, dstOffset, easTZ.standardName);
+
+        if (data.StartTime) {
+            let utc = cal.createDateTime(data.StartTime); //format "19800101T000000Z" - UTC
+            item.startDate = utc.getInTimezone(timezone);
+            if (data.AllDayEvent && data.AllDayEvent == "1") {
+                item.startDate.timezone = (cal.dtz && cal.dtz.floating) ? cal.dtz.floating : cal.floating();
+                item.startDate.isDate = true;
+            }
+        }
+
+        if (data.EndTime) {
+            let utc = cal.createDateTime(data.EndTime);
+            item.endDate = utc.getInTimezone(timezone);
+            if (data.AllDayEvent && data.AllDayEvent == "1") {
+                item.endDate.timezone = (cal.dtz && cal.dtz.floating) ? cal.dtz.floating : cal.floating();
+                item.endDate.isDate = true;
+            }
+        }
+
+        //stamp time cannot be set and it is not needed, an updated version is only send to the server, if there was a change, so stamp will be updated
+
+
+        //EAS Reminder
+        item.clearAlarms();
+        if (data.Reminder && data.StartTime) {
+            let alarm = new CalAlarm();
+            alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_START;
+            alarm.offset = cal.createDuration();
+            alarm.offset.inSeconds = (0 - parseInt(data.Reminder) * 60);
+            alarm.action = "DISPLAY";
+            item.addAlarm(alarm);
+
+            let alarmData = cal.alarms.calculateAlarmDate(item, alarm);
+            let startDate = cal.createDateTime(data.StartTime);
+            let nowDate = eas.tools.getNowUTC();
+            if (startDate.compare(nowDate) < 0) {
+                // Mark alarm as ACK if in the past.
+                item.alarmLastAck = nowDate;
+            }
+        }
+
+        eas.sync.mapEasPropertyToThunderbird("BusyStatus", "TRANSP", data, item);
+        eas.sync.mapEasPropertyToThunderbird("Sensitivity", "CLASS", data, item);
+
+        if (data.ResponseType) {
+            //store original EAS value 
+            item.setProperty("X-EAS-ResponseType", eas.xmltools.checkString(data.ResponseType, "0")); //some server send empty ResponseType ???
+        }
+
+        //Attendees - remove all Attendees and re-add the ones from XML
+        item.removeAllAttendees();
+        if (data.Attendees && data.Attendees.Attendee) {
+            let att = [];
+            if (Array.isArray(data.Attendees.Attendee)) att = data.Attendees.Attendee;
+            else att.push(data.Attendees.Attendee);
+            for (let i = 0; i < att.length; i++) {
+                if (att[i].Email && eas.tools.isString(att[i].Email) && att[i].Name) { //req.
+
+                    let attendee = new CalAttendee();
+
+                    //is this attendee the local EAS user?
+                    let isSelf = (att[i].Email == syncdata.accountData.getAccountProperty("user"));
+
+                    attendee["id"] = cal.email.prependMailTo(att[i].Email);
+                    attendee["commonName"] = att[i].Name;
+                    //default is "FALSE", only if THIS attendee isSelf, use ResponseRequested (we cannot respond for other attendee) - ResponseType is not send back to the server, it is just a local information
+                    attendee["rsvp"] = (isSelf && data.ResponseRequested) ? "TRUE" : "FALSE";
+
+                    //not supported in 2.5
+                    switch (att[i].AttendeeType) {
+                        case "1": //required
+                            attendee["role"] = "REQ-PARTICIPANT";
+                            attendee["userType"] = "INDIVIDUAL";
+                            break;
+                        case "2": //optional
+                            attendee["role"] = "OPT-PARTICIPANT";
+                            attendee["userType"] = "INDIVIDUAL";
+                            break;
+                        default: //resource or unknown
+                            attendee["role"] = "NON-PARTICIPANT";
+                            attendee["userType"] = "RESOURCE";
+                            break;
+                    }
+
+                    //not supported in 2.5 - if attendeeStatus is missing, check if this isSelf and there is a ResponseType
+                    if (att[i].AttendeeStatus)
+                        attendee["participationStatus"] = eas.sync.MAP_EAS2TB.ATTENDEESTATUS[att[i].AttendeeStatus];
+                    else if (isSelf && data.ResponseType)
+                        attendee["participationStatus"] = eas.sync.MAP_EAS2TB.ATTENDEESTATUS[data.ResponseType];
+                    else
+                        attendee["participationStatus"] = "NEEDS-ACTION";
+
+                    // status  : [NEEDS-ACTION, ACCEPTED, DECLINED, TENTATIVE, DELEGATED, COMPLETED, IN-PROCESS]
+                    // rolemap : [REQ-PARTICIPANT, OPT-PARTICIPANT, NON-PARTICIPANT, CHAIR]
+                    // typemap : [INDIVIDUAL, GROUP, RESOURCE, ROOM]
+
+                    // Add attendee to event
+                    item.addAttendee(attendee);
+                } else {
+                    TbSync.eventlog.add("info", syncdata, "Attendee without required name and/or email found. Skipped.");
+                }
+            }
+        }
+
+        if (data.OrganizerName && data.OrganizerEmail && eas.tools.isString(data.OrganizerEmail)) {
+            //Organizer
+            let organizer = new CalAttendee();
+            organizer.id = cal.email.prependMailTo(data.OrganizerEmail);
+            organizer.commonName = data.OrganizerName;
+            organizer.rsvp = "FALSE";
+            organizer.role = "CHAIR";
+            organizer.userType = null;
+            organizer.participationStatus = "ACCEPTED";
+            organizer.isOrganizer = true;
+            item.organizer = organizer;
+        }
+
+        eas.sync.setItemRecurrence(item, syncdata, data, timezone);
+
+        // BusyStatus is always representing the status of the current user in terms of availability.
+        // It has nothing to do with the status of a meeting. The user could be just the organizer, but does not need to attend, so he would be free.
+        // The correct map is between BusyStatus and TRANSP (show time as avail, busy, unset)
+        // A new event always sets TRANSP to busy, so unset is indeed a good way to store Tentiative
+        // However:
+        //  - EAS Meetingstatus only knows ACTIVE or CANCELLED, but not CONFIRMED or TENTATIVE
+        //  - TB STATUS has UNSET, CONFIRMED, TENTATIVE, CANCELLED
+        //  -> Special case: User sets BusyStatus to TENTIATIVE -> TRANSP is unset and also set STATUS to TENTATIVE
+        // The TB STATUS is the correct map for EAS Meetingstatus and should be unset, if it is not a meeting EXCEPT if set to TENTATIVE
+        let tbStatus = (data.BusyStatus && data.BusyStatus == "1" ? "TENTATIVE" : null);
+
+        if (data.MeetingStatus) {
+            //store original EAS value 
+            item.setProperty("X-EAS-MeetingStatus", data.MeetingStatus);
+            //bitwise representation for Meeting, Received, Cancelled:
+            let M = data.MeetingStatus & 0x1;
+            let R = data.MeetingStatus & 0x2;
+            let C = data.MeetingStatus & 0x4;
+
+            // We can map M+C to TB STATUS (TENTATIVE, CONFIRMED, CANCELLED, unset).
+            if (M) {
+                if (C) tbStatus = "CANCELLED";
+                else if (!tbStatus) tbStatus = "CONFIRMED"; // do not override "TENTIATIVE"
+            }
+
+            //we can also use the R information, to update our fallbackOrganizerName
+            if (!R && data.OrganizerName) syncdata.target.calendar.setProperty("fallbackOrganizerName", data.OrganizerName);
+        }
+
+        if (tbStatus) item.setProperty("STATUS", tbStatus)
+        else item.deleteProperty("STATUS");
+
+        //TODO: attachements (needs EAS 16.0!)
+    },
+
+
+
+
+
+
+
+
+
+    // --------------------------------------------------------------------------- //
+    //read TB event and return its data as WBXML
+    // --------------------------------------------------------------------------- //
+    getWbxmlFromThunderbirdItem: async function (tbItem, syncdata, isException = false) {
+        let item = tbItem instanceof TbSync.lightning.TbItem ? tbItem.nativeItem : tbItem;
+
+        let asversion = syncdata.accountData.getAccountProperty("asversion");
+        let wbxml = eas.wbxmltools.createWBXML("", syncdata.type); //init wbxml with "" and not with precodes, and set initial codepage
+        let nowDate = new Date();
+
+        /*
+         *  We do not use ghosting, that means, if we do not include a value in CHANGE, it is removed from the server. 
+         *  However, this does not seem to work on all fields. Furthermore, we need to include any (empty) container to blank its childs.
+         */
+
+        //Order of tags taken from https://msdn.microsoft.com/en-us/library/dn338917(v=exchg.80).aspx
+
+        //timezone
+        if (!isException) {
+            let easTZ = new eas.tools.TimeZoneDataStructure();
+
+            //if there is no end and no start (or both are floating) use default timezone info
+            let tzInfo = null;
+            if (item.startDate && item.startDate.timezone.tzid != "floating") tzInfo = eas.tools.getTimezoneInfo(item.startDate.timezone);
+            else if (item.endDate && item.endDate.timezone.tzid != "floating") tzInfo = eas.tools.getTimezoneInfo(item.endDate.timezone);
+            if (!tzInfo) tzInfo = eas.defaultTimezoneInfo;
+
+            easTZ.utcOffset = tzInfo.std.offset;
+            easTZ.standardBias = 0;
+            easTZ.daylightBias = tzInfo.dst.offset - tzInfo.std.offset;
+
+            easTZ.standardName = eas.ianaToWindowsTimezoneMap.hasOwnProperty(tzInfo.std.displayname) ? eas.ianaToWindowsTimezoneMap[tzInfo.std.displayname] : tzInfo.std.displayname;
+            easTZ.daylightName = eas.ianaToWindowsTimezoneMap.hasOwnProperty(tzInfo.dst.displayname) ? eas.ianaToWindowsTimezoneMap[tzInfo.dst.displayname] : tzInfo.dst.displayname;
+
+            if (tzInfo.std.switchdate && tzInfo.dst.switchdate) {
+                easTZ.standardDate.wMonth = tzInfo.std.switchdate.month;
+                easTZ.standardDate.wDay = tzInfo.std.switchdate.weekOfMonth;
+                easTZ.standardDate.wDayOfWeek = tzInfo.std.switchdate.dayOfWeek;
+                easTZ.standardDate.wHour = tzInfo.std.switchdate.hour;
+                easTZ.standardDate.wMinute = tzInfo.std.switchdate.minute;
+                easTZ.standardDate.wSecond = tzInfo.std.switchdate.second;
+
+                easTZ.daylightDate.wMonth = tzInfo.dst.switchdate.month;
+                easTZ.daylightDate.wDay = tzInfo.dst.switchdate.weekOfMonth;
+                easTZ.daylightDate.wDayOfWeek = tzInfo.dst.switchdate.dayOfWeek;
+                easTZ.daylightDate.wHour = tzInfo.dst.switchdate.hour;
+                easTZ.daylightDate.wMinute = tzInfo.dst.switchdate.minute;
+                easTZ.daylightDate.wSecond = tzInfo.dst.switchdate.second;
+            }
+
+            wbxml.atag("TimeZone", easTZ.easTimeZone64);
+            if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Send TZ", item.title + easTZ.toString());
+        }
+
+        //AllDayEvent (for simplicity, we always send a value)
+        wbxml.atag("AllDayEvent", (item.startDate && item.startDate.isDate && item.endDate && item.endDate.isDate) ? "1" : "0");
+
+        //Body
+        wbxml.append(eas.sync.getItemBody(item, syncdata));
+
+        //BusyStatus (Free, Tentative, Busy) is taken from TRANSP (busy, free, unset=tentative)
+        //However if STATUS is set to TENTATIVE, overide TRANSP and set BusyStatus to TENTATIVE
+        if (item.hasProperty("STATUS") && item.getProperty("STATUS") == "TENTATIVE") {
+            wbxml.atag("BusyStatus", "1");
+        } else {
+            wbxml.atag("BusyStatus", eas.sync.mapThunderbirdPropertyToEas("TRANSP", "BusyStatus", item));
+        }
+
+        //Organizer
+        if (!isException) {
+            if (item.organizer && item.organizer.commonName) wbxml.atag("OrganizerName", item.organizer.commonName);
+            if (item.organizer && item.organizer.id) wbxml.atag("OrganizerEmail", cal.email.removeMailTo(item.organizer.id));
+        }
+
+        //DtStamp in UTC
+        wbxml.atag("DtStamp", item.stampTime ? eas.tools.getIsoUtcString(item.stampTime) : eas.tools.dateToBasicISOString(nowDate));
+
+        //EndTime in UTC
+        wbxml.atag("EndTime", item.endDate ? eas.tools.getIsoUtcString(item.endDate) : eas.tools.dateToBasicISOString(nowDate));
+
+        //Location
+        wbxml.atag("Location", (item.hasProperty("location")) ? item.getProperty("location") : "");
+
+        //EAS Reminder (TB getAlarms) - at least with zpush blanking by omitting works, horde does not work
+        let alarms = item.getAlarms({});
+        if (alarms.length > 0) {
+
+            let reminder = -1;
+            if (alarms[0].offset !== null) {
+                reminder = 0 - alarms[0].offset.inSeconds / 60;
+            } else if (item.startDate) {
+                let timeDiff = item.startDate.getInTimezone(eas.utcTimezone).subtractDate(alarms[0].alarmDate.getInTimezone(eas.utcTimezone));
+                reminder = timeDiff.inSeconds / 60;
+                TbSync.eventlog.add("info", syncdata, "Converting absolute alarm to relative alarm (not supported).", item.icalString);
+            }
+            if (reminder >= 0) wbxml.atag("Reminder", reminder.toString());
+            else TbSync.eventlog.add("info", syncdata, "Droping alarm after start date (not supported).", item.icalString);
+
+        }
+
+        //Sensitivity (CLASS)
+        wbxml.atag("Sensitivity", eas.sync.mapThunderbirdPropertyToEas("CLASS", "Sensitivity", item));
+
+        //Subject (obmitting these, should remove them from the server - that does not work reliably, so we send blanks)
+        wbxml.atag("Subject", (item.title) ? item.title : "");
+
+        //StartTime in UTC
+        wbxml.atag("StartTime", item.startDate ? eas.tools.getIsoUtcString(item.startDate) : eas.tools.dateToBasicISOString(nowDate));
+
+        //UID (limit to 300)
+        //each TB event has an ID, which is used as EAS serverId - however there is a second UID in the ApplicationData
+        //since we do not have two different IDs to use, we use the same ID
+        if (!isException) { //docs say it would be allowed in exception in 2.5, but it does not work, if present
+            wbxml.atag("UID", item.id);
+        }
+        //IMPORTANT in EAS v16 it is no longer allowed to send a UID
+        //Only allowed in exceptions in v2.5
+
+
+        //EAS MeetingStatus
+        // 0 (000) The event is an appointment, which has no attendees.
+        // 1 (001) The event is a meeting and the user is the meeting organizer.
+        // 3 (011) This event is a meeting, and the user is not the meeting organizer; the meeting was received from someone else.
+        // 5 (101) The meeting has been canceled and the user was the meeting organizer.
+        // 7 (111) The meeting has been canceled. The user was not the meeting organizer; the meeting was received from someone else
+
+        //there are 3 fields; Meeting, Owner, Cancelled
+        //M can be reconstructed from #of attendees (looking at the old value is not wise, since it could have been changed)
+        //C can be reconstucted from TB STATUS
+        //O can be reconstructed by looking at the original value, or (if not present) by comparing EAS ownerID with TB ownerID
+
+        let attendees = item.getAttendees();
+        //if (!(isException && asversion == "2.5")) { //MeetingStatus is not supported in exceptions in EAS 2.5
+        if (!isException) { //Exchange 2010 does not seem to support MeetingStatus at all in exceptions
+            if (attendees.length == 0) wbxml.atag("MeetingStatus", "0");
+            else {
+                //get owner information
+                let isReceived = false;
+                if (item.hasProperty("X-EAS-MEETINGSTATUS")) isReceived = item.getProperty("X-EAS-MEETINGSTATUS") & 0x2;
+                else isReceived = (item.organizer && item.organizer.id && cal.email.removeMailTo(item.organizer.id) != syncdata.accountData.getAccountProperty("user"));
+
+                //either 1,3,5 or 7
+                if (item.hasProperty("STATUS") && item.getProperty("STATUS") == "CANCELLED") {
+                    //either 5 or 7
+                    wbxml.atag("MeetingStatus", (isReceived ? "7" : "5"));
+                } else {
+                    //either 1 or 3
+                    wbxml.atag("MeetingStatus", (isReceived ? "3" : "1"));
+                }
+            }
+        }
+
+        //Attendees
+        let TB_responseType = null;
+        if (!(isException && asversion == "2.5")) { //attendees are not supported in exceptions in EAS 2.5
+            if (attendees.length > 0) { //We should use it instead of countAttendees.value
+                wbxml.otag("Attendees");
+                for (let attendee of attendees) {
+                    wbxml.otag("Attendee");
+                    wbxml.atag("Email", cal.email.removeMailTo(attendee.id));
+                    wbxml.atag("Name", (attendee.commonName ? attendee.commonName : cal.email.removeMailTo(attendee.id).split("@")[0]));
+                    if (asversion != "2.5") {
+                        //it's pointless to send AttendeeStatus, 
+                        // - if we are the owner of a meeting, TB does not have an option to actually set the attendee status (on behalf of an attendee) in the UI
+                        // - if we are an attendee (of an invite) we cannot and should not set status of other attendees and or own status must be send through a MeetingResponse
+                        // -> all changes of attendee status are send from the server to us, either via ResponseType or via AttendeeStatus
+                        //wbxml.atag("AttendeeStatus", eas.sync.MAP_TB2EAS.ATTENDEESTATUS[attendee.participationStatus]);
+
+                        if (attendee.userType == "RESOURCE" || attendee.userType == "ROOM" || attendee.role == "NON-PARTICIPANT") wbxml.atag("AttendeeType", "3");
+                        else if (attendee.role == "REQ-PARTICIPANT" || attendee.role == "CHAIR") wbxml.atag("AttendeeType", "1");
+                        else wbxml.atag("AttendeeType", "2"); //leftovers are optional
+                    }
+                    wbxml.ctag();
+                }
+                wbxml.ctag();
+            } else {
+                wbxml.atag("Attendees");
+            }
+        }
+
+        //Categories (see https://github.com/jobisoft/TbSync/pull/35#issuecomment-359286374)
+        if (!isException) {
+            wbxml.append(eas.sync.getItemCategories(item, syncdata));
+        }
+
+        //recurrent events (implemented by Chris Allan)
+        if (!isException) {
+            wbxml.append(await eas.sync.getItemRecurrence(item, syncdata));
+        }
+
+
+        //---------------------------
+
+        //TP PRIORITY (9=LOW, 5=NORMAL, 1=HIGH) not mapable to EAS Event
+        //TODO: attachements (needs EAS 16.0!)
+
+        //https://dxr.mozilla.org/comm-central/source/calendar/base/public/calIAlarm.idl
+        //TbSync.dump("ALARM ("+i+")", [, alarms[i].related, alarms[i].repeat, alarms[i].repeatOffset, alarms[i].repeatDate, alarms[i].action].join("|"));
+
+        return wbxml.getBytes();
+    }
+}
diff -Nru eas4tbsync-4.11/content/includes/contactsync.js eas4tbsync-4.17/content/includes/contactsync.js
--- eas4tbsync-4.11/content/includes/contactsync.js	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/includes/contactsync.js	2025-05-15 13:21:20.000000000 +0200
@@ -1,551 +1,558 @@
-/*
- * This file is part of EAS-4-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, {
-    newUID: "resource:///modules/AddrBookUtils.jsm",
-    AddrBookCard: "resource:///modules/AddrBookCard.jsm",
-    BANISHED_PROPERTIES: "resource:///modules/VCardUtils.jsm",
-    VCardProperties: "resource:///modules/VCardUtils.jsm",
-    VCardPropertyEntry: "resource:///modules/VCardUtils.jsm",
-    VCardUtils: "resource:///modules/VCardUtils.jsm",
-});
-
-var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
-var { MailServices } = ChromeUtils.import("resource:///modules/MailServices.jsm");
-
-const eas = TbSync.providers.eas;
-
-var Contacts = {
-
-    // Remove if migration code is removed.
-    arrayFromString: function (stringValue) {
-        let arrayValue = [];
-        if (stringValue.trim().length>0) arrayValue = stringValue.trim().split("\u001A").filter(String);
-        return arrayValue;
-    },
-
-    /* The following TB properties are not synced to the server:
-       - only one WebPage
-       - more than 3 emails
-       - more than one fax, pager, mobile, work, home
-       - position (in org)
-    */
-
-    vcard_array_fields : {
-        n : 5,
-        adr : 7,
-        org : 2 
-    },
-
-    map_EAS_properties_to_vCard: revision => ({
-        FileAs: {item: "fn", type: "text", params: {}}, /* DisplayName */ 
-
-        Birthday: {item: "bday", type: "date", params: {}},
-        Anniversary: {item: "anniversary", type: "date", params: {}},
-        
-        LastName: {item: "n", type: "text", params: {}, index: 0},
-        FirstName: {item: "n", type: "text", params: {}, index: 1},
-        MiddleName: {item: "n", type: "text", params: {}, index: 2},
-        Title: {item: "n", type: "text", params: {}, index: 3},
-        Suffix: {item: "n", type: "text", params: {}, index: 4},
-
-        Notes: {item: "note", type: "text", params: {}},
-
-        // What should we do with Email 4+?
-        // EAS does not have the concept of home/work for emails. Define matchAll
-        // to not use params for finding the correct entry. They will come back as
-        // "other".
-        Email1Address: {item: "email", type: "text", entry: 0, matchAll: true, params: {}},
-        Email2Address: {item: "email", type: "text", entry: 1, matchAll: true, params: {}},
-        Email3Address: {item: "email", type: "text", entry: 2, matchAll: true, params: {}},
-
-        // EAS does not have the concept of home/work for WebPage. Define matchAll
-        // to not use params for finding the correct entry. It will come back as
-        // "other".
-        WebPage: {item: "url", type: "text", matchAll: true, params: {}},
-        
-        CompanyName: {item: "org", type: "text", params: {}, index: revision < 2 ? 1 : 0}, /* Company */
-        Department: {item: "org", type: "text", params: {}, index: revision < 2 ? 0 : 1}, /* Department */
-        JobTitle: { item: "title", type: "text", params: {} }, /* JobTitle */ 
-
-        MobilePhoneNumber: { item: "tel", type: "text", params: {type: "cell" }},
-        PagerNumber: { item: "tel", type: "text", params: {type: "pager" }},
-        HomeFaxNumber: { item: "tel", type: "text", params: {type: "fax" }},
-        // If home phone is defined, use that, otherwise use unspecified phone
-        // Note: This must be exclusive (no other field may use home/unspecified)
-        // except if entry is specified.
-        HomePhoneNumber: { item: "tel", type: "text", params: {type: "home"}, fallbackParams: [{}]},
-        BusinessPhoneNumber: { item: "tel", type: "text", params: {type: "work"}},
-        Home2PhoneNumber: { item: "tel", type: "text", params: {type: "home"}, entry: 1 },
-        Business2PhoneNumber: { item: "tel", type: "text", params: {type: "work"}, entry: 1 },
-
-        HomeAddressStreet: {item: "adr", type: "text", params: {type: "home"}, index: 2},  // needs special handling
-        HomeAddressCity: {item: "adr", type: "text", params: {type: "home"}, index: 3},
-        HomeAddressState: {item: "adr", type: "text", params: {type: "home"}, index: 4},
-        HomeAddressPostalCode: {item: "adr", type: "text", params: {type: "home"}, index: 5},
-        HomeAddressCountry: {item: "adr", type: "text", params: {type: "home"}, index: 6},
-
-        BusinessAddressStreet: {item: "adr", type: "text", params: {type: "work"}, index: 2},  // needs special handling
-        BusinessAddressCity: {item: "adr", type: "text", params: {type: "work"}, index: 3},
-        BusinessAddressState: {item: "adr", type: "text", params: {type: "work"}, index: 4},
-        BusinessAddressPostalCode: {item: "adr", type: "text", params: {type: "work"}, index: 5},
-        BusinessAddressCountry: {item: "adr", type: "text", params: {type: "work"}, index: 6},
-
-        OtherAddressStreet: {item: "adr", type: "text", params: {}, index: 2},  // needs special handling
-        OtherAddressCity: {item: "adr", type: "text", params: {}, index: 3},
-        OtherAddressState: {item: "adr", type: "text", params: {}, index: 4},
-        OtherAddressPostalCode: {item: "adr", type: "text", params: {}, index: 5},
-        OtherAddressCountry: {item: "adr", type: "text", params: {}, index: 6},
-
-        // Misusing this EAS field, so that "Custom1" is saved to the server.
-        OfficeLocation: {item: "x-custom1", type: "text", params: {}},
-
-        Picture: {item: "photo", params: {}, type: "uri"},
-
-        // TB shows them as undefined, but showing them might be better, than not. Use a prefix.
-        AssistantPhoneNumber: { item: "tel", type: "text", params: {type: "Assistant"}, prefix: true},
-        CarPhoneNumber: { item: "tel", type: "text", params: {type: "Car"}, prefix: true},
-        RadioPhoneNumber: { item: "tel", type: "text", params: {type: "Radio"}, prefix: true},
-        BusinessFaxNumber: { item: "tel", type: "text", params: {type: "WorkFax"}, prefix: true},
-    }),
-   
-    map_EAS_properties_to_vCard_set2 : {
-        NickName: {item: "nickname", type: "text", params: {} },
-        // Misusing these EAS fields, so that "Custom2,3,4" is saved to the server.
-        CustomerId: {item: "x-custom2", type: "text", params: {}},
-        GovernmentId: {item: "x-custom3", type: "text", params: {}},
-        AccountName:  {item: "x-custom4", type: "text", params: {}},
-
-        IMAddress: {item: "impp", type: "text", params: {} },
-        IMAddress2: {item: "impp", type: "text", params: {}, entry: 1 },
-        IMAddress3: {item: "impp", type: "text", params: {}, entry: 2 },
-
-        CompanyMainPhone: { item: "tel", type: "text", params: {type: "Company"}, prefix: true},
-    },
-
-    // There are currently no TB fields for these values, TbSync will store (and
-    // resend) them, but will not allow to view/edit.
-    unused_EAS_properties: [
-        "Alias", //pseudo field
-        "WeightedRank", //pseudo field
-        "YomiCompanyName", //japanese phonetic equivalent
-        "YomiFirstName", //japanese phonetic equivalent
-        "YomiLastName", //japanese phonetic equivalent
-        "CompressedRTF",
-        "MMS",
-        // Former custom EAS fields, no longer added to UI after 102.
-        "ManagerName",
-        "AssistantName",
-        "Spouse",
-    ],
-
-    // Normalize a parameters entry, to be able to find matching existing
-    // entries. If we want to be less restrictive, we need to check if all
-    // the requested values exist. But we should be the only one who sets
-    // the vCard props, so it should be safe. Except someone moves a contact.
-    // Should we prevent that via a vendor id in the vcard?
-    normalizeParameters: function (unordered) {
-        return JSON.stringify(
-            Object.keys(unordered).map(e => `${e}`.toLowerCase()).sort().reduce(
-                (obj, key) => { 
-                    obj[key] = `${unordered[key]}`.toLowerCase(); 
-                return obj;
-                }, 
-                {}
-            )
-        );
-    },
-
-    getValue: function (vCardProperties, vCard_property) {
-        let parameters = [vCard_property.params];
-        if (vCard_property.fallbackParams) {
-            parameters.push(...vCard_property.fallbackParams);
-        }
-        let entries;
-        for (let normalizedParams of parameters.map(this.normalizeParameters)) {
-            // If no params set, do not filter, otherwise filter for exact match.
-            entries = vCardProperties.getAllEntries(vCard_property.item)
-                .filter(e => vCard_property.matchAll || normalizedParams == this.normalizeParameters(e.params));
-            if (entries.length > 0) {
-                break;
-            }
-        }
-
-        // Which entry should we take?
-        let entryNr = vCard_property.entry || 0;
-        if (entries[entryNr]) {
-            let value;
-            if (vCard_property.item == "org" && !Array.isArray(entries[entryNr].value)) {
-                // The org field sometimes comes back as a string (then it is Company),
-                // even though it should be an array [Department,Company]
-                value =  vCard_property.index == 1 ? entries[entryNr].value : "";
-            } else if (this.vcard_array_fields[vCard_property.item]) {
-                if (!Array.isArray(entries[entryNr].value)) {
-                    // If the returned value is a single string, return it only
-                    // when index 0 is requested, otherwise return nothing.
-                    value =  vCard_property.index == 0 ? entries[entryNr].value : "";
-                } else {
-                    value = entries[entryNr].value[vCard_property.index];
-                }
-            } else {
-                value = entries[entryNr].value;
-            }
-
-            if (value) {
-                if (vCard_property.prefix && value.startsWith(`${vCard_property.params.type}: `)) {
-                    return value.substring(`${vCard_property.params.type}: `.length);
-                }
-                return value;
-            }
-        }
-        return "";
-    },
-
-    /**
-     * Reads a DOM File and returns a Promise for its dataUrl.
-     *
-     * @param {File} file
-     * @returns {string}
-     */
-    getDataUrl(file) {
-        return new Promise((resolve, reject) => {
-            var reader = new FileReader();
-            reader.readAsDataURL(file);
-            reader.onload = function() {
-                resolve(reader.result);
-            };
-            reader.onerror = function(error) {
-                resolve("");
-            };
-        });
-    },
-
-
-
-    // --------------------------------------------------------------------------- //
-    // Read WBXML and set Thunderbird item
-    // --------------------------------------------------------------------------- //
-    setThunderbirdItemFromWbxml: function (abItem, data, id, syncdata, mode = "standard") {
-        let asversion = syncdata.accountData.getAccountProperty("asversion");
-        let revision = parseInt(syncdata.target._directory.getStringValue("tbSyncRevision","1"), 10);
-        let map_EAS_properties_to_vCard = this.map_EAS_properties_to_vCard(revision);
-
-        if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Processing " + mode + " contact item", id);
-
-        // Make sure we are dealing with a vCard, so we can update the card just
-        // by updating its vCardProperties.
-        if (!abItem._card.supportsVCard) {
-            // This is an older card??
-            throw new Error("It looks like you are trying to sync a TB91 sync state. Does not work.");
-        }
-        let vCardProperties = abItem._card.vCardProperties
-        abItem.primaryKey = id;
-
-        // Loop over all known EAS properties (two EAS sets Contacts and Contacts2).
-        for (let set=0; set < 2; set++) {
-            let properties = (set == 0) ? this.EAS_properties : this.EAS_properties2;
-
-            for (let EAS_property of properties) {
-                let vCard_property = (set == 0) ? map_EAS_properties_to_vCard[EAS_property] : this.map_EAS_properties_to_vCard_set2[EAS_property];
-                let value;
-                switch (EAS_property) {
-                    case "Notes":
-                        if (asversion == "2.5") {
-                            value = eas.xmltools.checkString(data.Body);
-                        } else if (data.Body && data.Body.Data) {
-                            value = eas.xmltools.checkString(data.Body.Data);
-                        }
-                    break;
-
-                    default:
-                        value = eas.xmltools.checkString(data[EAS_property]);
-                }
-                
-                let normalizedParams = this.normalizeParameters(vCard_property.params)
-                let entries = vCardProperties.getAllEntries(vCard_property.item)
-                    .filter(e => vCard_property.matchAll || normalizedParams == this.normalizeParameters(e.params));
-                // Which entry should we update? Add empty entries, if the requested entry number
-                // does not yet exist.
-                let entryNr = vCard_property.entry || 0;
-                while (entries.length <= entryNr) {
-                    let newEntry = new VCardPropertyEntry(
-                        vCard_property.item, 
-                        vCard_property.params, 
-                        vCard_property.type, 
-                        this.vcard_array_fields[vCard_property.item] 
-                            ? new Array(this.vcard_array_fields[vCard_property.item]).fill("") 
-                            : ""
-                    );
-                    vCardProperties.addEntry(newEntry);
-                    entries = vCardProperties.getAllEntries(vCard_property.item);
-                    entryNr = entries.length - 1;
-                }
-
-                // Is this property part of the send data?
-                if (value) {
-                    // Do we need to manipulate the value?
-                    switch (EAS_property) {
-                        case "Picture":
-                            value = `data:image/jpeg;base64,${eas.xmltools.nodeAsArray(data.Picture)[0]}`; //Kerio sends Picture as container
-                            break;
-                        
-                        case "Birthday":
-                        case "Anniversary":
-                            let dateObj = new Date(value);
-                            value = dateObj.toISOString().substr(0, 10);
-                            break;
-
-                        case "Email1Address":
-                        case "Email2Address":
-                        case "Email3Address":
-                            let parsedInput = MailServices.headerParser.makeFromDisplayAddress(value);
-                            let fixedValue =  (parsedInput && parsedInput[0] && parsedInput[0].email) ? parsedInput[0].email : value;
-                            if (fixedValue != value) {
-                                if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Parsing email display string via RFC 2231 and RFC 2047 ("+EAS_property+")", value + " -> " + fixedValue);
-                                value = fixedValue;
-                            }
-                            break;
-                        
-                        case "HomeAddressStreet":
-                        case "BusinessAddressStreet":
-                        case "OtherAddressStreet":
-                            // Thunderbird accepts an array in the vCardProperty of the 2nd index of the adr field.
-                            let seperator = String.fromCharCode(syncdata.accountData.getAccountProperty("seperator")); // options are 44 (,) or 10 (\n)
-                            value = value.split(seperator);
-                        break;
-                    }
-
-                    // Add a typePrefix for fields unknown to TB (better: TB should use the type itself).
-                    if (vCard_property.prefix && !value.startsWith(`${vCard_property.params.type}: `)) {
-                        value = `${vCard_property.params.type}: ${value}`;
-                    }
-
-                    // Is this an array value?
-                    if (this.vcard_array_fields[vCard_property.item]) {
-                        // Make sure this is an array.
-                        if (!Array.isArray(entries[entryNr].value)) {
-                            let arr = new Array(this.vcard_array_fields[vCard_property.item]).fill("");
-                            arr[0] = entries[entryNr].value;
-                            entries[entryNr].value = arr;
-                        }
-                        entries[entryNr].value[vCard_property.index] = value;
-                    } else {
-                        entries[entryNr].value = value;
-                    }
-                } else {
-                    if (this.vcard_array_fields[vCard_property.item]) {
-                        // Make sure this is an array.
-                        if (!Array.isArray(entries[entryNr].value)) {
-                            let arr = new Array(this.vcard_array_fields[vCard_property.item]).fill("");
-                            arr[0] = entries[entryNr].value;
-                            entries[entryNr].value = arr;
-                        }
-                        entries[entryNr].value[vCard_property.index] = "";
-                    } else {
-                        entries[entryNr].value = "";
-                    }
-                }
-            }
-        }
-
-        // Take care of categories.
-        if (data["Categories"] && data["Categories"]["Category"]) {
-            let categories = Array.isArray(data["Categories"]["Category"])
-                ? data["Categories"]["Category"]
-                : [data["Categories"]["Category"]];
-            vCardProperties.clearValues("categories");
-            vCardProperties.addValue("categories", categories);
-            // Migration code, remove once no longer needed.
-            abItem.setProperty("Categories", "");
-        }
-
-        // Take care of children, stored in contacts property bag.
-        if (data["Children"] && data["Children"]["Child"]) {
-            let children = Array.isArray(data["Children"]["Child"])
-                ? data["Children"]["Child"]
-                : [data["Children"]["Child"]];
-            abItem.setProperty("Children", JSON.stringify(children));
-        }
-
-        // Take care of un-mappable EAS options, which are stored in the contacts
-        // property bag.
-        for (let i=0; i < this.unused_EAS_properties.length; i++) {
-            if (data[this.unused_EAS_properties[i]]) abItem.setProperty("EAS-" + this.unused_EAS_properties[i], data[this.unused_EAS_properties[i]]);
-        }
-
-        // Remove all entries, which are marked for deletion.
-        vCardProperties.entries = vCardProperties.entries.filter(e => Array.isArray(e.value) ? e.value.some(a => a != "") : e.value != "");
-
-        // Further manipulations (a few getters are still usable \o/).
-        if (syncdata.accountData.getAccountProperty("displayoverride")) {
-            abItem._card.displayName = abItem._card.firstName + " " + abItem._card.lastName;
-            if (abItem._card.displayName == " " ) {
-                let company = (vCardProperties.getFirstValue("org") || [""])[0];
-                abItem._card.displayName = company || abItem._card.primaryEmail
-            }
-        }
-    },
-
-
-
-
-    // --------------------------------------------------------------------------- //
-    //read TB event and return its data as WBXML
-    // --------------------------------------------------------------------------- //
-    getWbxmlFromThunderbirdItem: async function (abItem, syncdata, isException = false) {
-        let asversion = syncdata.accountData.getAccountProperty("asversion");
-        let revision = parseInt(syncdata.target._directory.getStringValue("tbSyncRevision","1"), 10);
-        let map_EAS_properties_to_vCard = this.map_EAS_properties_to_vCard(revision);
-
-        let wbxml = eas.wbxmltools.createWBXML("", syncdata.type); //init wbxml with "" and not with precodes, and set initial codepage
-        let nowDate = new Date();
-
-        // Make sure we are dealing with a vCard, so we can access its vCardProperties.
-        if (!abItem._card.supportsVCard) {
-            throw new Error("It looks like you are trying to sync a TB91 sync state. Does not work.");
-        }
-        let vCardProperties = abItem._card.vCardProperties
-
-        // Loop over all known EAS properties (send empty value if not set).
-        for (let EAS_property of this.EAS_properties) {
-            // Some props need special handling.
-            let vCard_property = map_EAS_properties_to_vCard[EAS_property];
-            let value;
-            switch (EAS_property) {
-                case "Notes":
-                    // Needs to be done later, because we have to switch the code page.
-                    continue;
-
-                case "Picture": {
-                    let photoUrl = abItem._card.photoURL;
-                    if (!photoUrl) {
-                        continue;
-                    }
-                    if (photoUrl.startsWith("file://")) {
-                        let realPhotoFile = Services.io.newURI(photoUrl).QueryInterface(Ci.nsIFileURL).file;
-                        let photoFile = await File.createFromNsIFile(realPhotoFile);
-                        photoUrl = await this.getDataUrl(photoFile);
-                    }
-                    if (photoUrl.startsWith("data:image/")) {
-                        let parts = photoUrl.split(",");
-                        parts.shift();
-                        value = parts.join(",");
-                    }
-                }
-                break;
-
-                case "Birthday":
-                case "Anniversary": {
-                    let raw = this.getValue(vCardProperties, vCard_property);
-                    if (raw) {
-                        let dateObj = new Date(raw);
-                        value = dateObj.toISOString();
-                    }
-                }
-                break;
-                    
-                case "HomeAddressStreet":
-                case "BusinessAddressStreet":
-                case "OtherAddressStreet": {
-                    let raw = this.getValue(vCardProperties, vCard_property);
-                    try {
-                        if (raw) {
-                            // We either get a single string or an array for the
-                            // street adr field from Thunderbird.
-                            if (!Array.isArray(raw)) {
-                                raw = [raw];
-                            }
-                            let seperator = String.fromCharCode(syncdata.accountData.getAccountProperty("seperator")); // options are 44 (,) or 10 (\n)
-                            value = raw.join(seperator);
-                        }
-                    } catch (ex) {
-                        throw new Error(`Failed to eval value: <${JSON.stringify(raw)}> @ ${JSON.stringify(vCard_property)}`);
-                    }
-                }
-                break;
-
-                default: {
-                    value = this.getValue(vCardProperties, vCard_property);
-                }
-            }
-            
-            if (value) {
-                wbxml.atag(EAS_property, value);
-            }
-        }
-
-        // Take care of un-mappable EAS option.
-        for (let i=0; i < this.unused_EAS_properties.length; i++) {
-            let value = abItem.getProperty("EAS-" + this.unused_EAS_properties[i], "");
-            if (value) wbxml.atag(this.unused_EAS_properties[i], value);
-        }
-
-        // Take care of categories.
-        let categories = vCardProperties.getFirstValue("categories");
-        let categoriesProperty = abItem.getProperty("Categories", "");
-        if (categoriesProperty) {
-            // Migration code, remove once no longer needed.
-            abItem.setProperty("Categories", "");
-            categories = this.arrayFromString(categoriesProperty);
-        }
-        if (categories) {
-            wbxml.otag("Categories");
-            for (let category of categories) wbxml.atag("Category", category);
-            wbxml.ctag();
-        }
-
-        // Take care of children, stored in contacts property bag.
-        let childrenProperty = abItem.getProperty("Children", "");
-        if (childrenProperty) {
-            let children = [];
-            try {
-                children = JSON.parse(childrenProperty);
-            } catch(ex) {
-                // Migration code, remove once no longer needed.
-                children = this.arrayFromString(childrenProperty);
-            }
-            wbxml.otag("Children");
-            for (let child of children) wbxml.atag("Child", child);
-            wbxml.ctag();
-        }
-
-        // Take care of notes - SWITCHING TO AirSyncBase (if 2.5, we still need Contact group here!)
-        let description = this.getValue(vCardProperties, map_EAS_properties_to_vCard["Notes"]);
-        if (asversion == "2.5") {
-            wbxml.atag("Body", description);
-        } else {
-            wbxml.switchpage("AirSyncBase");
-            wbxml.otag("Body");
-                wbxml.atag("Type", "1");
-                wbxml.atag("EstimatedDataSize", "" + description.length);
-                wbxml.atag("Data", description);
-            wbxml.ctag();
-        }
-
-        // Take care of Contacts2 group - SWITCHING TO CONTACTS2
-        wbxml.switchpage("Contacts2");
-
-        // Loop over all known TB properties of EAS group Contacts2 (send empty value if not set).
-        for (let EAS_property of this.EAS_properties2) {
-            let vCard_property = this.map_EAS_properties_to_vCard_set2[EAS_property];
-            let value = this.getValue(vCardProperties, vCard_property);
-            if (value) wbxml.atag(EAS_property, value);
-        }
-
-        return wbxml.getBytes();
-    }
-}
-
-Contacts.EAS_properties = Object.keys(Contacts.map_EAS_properties_to_vCard());
-Contacts.EAS_properties2 = Object.keys(Contacts.map_EAS_properties_to_vCard_set2);
+/*
+ * This file is part of EAS-4-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, {
+    newUID: "resource:///modules/AddrBookUtils.sys.mjs",
+    AddrBookCard: "resource:///modules/AddrBookCard.sys.mjs",
+    BANISHED_PROPERTIES: "resource:///modules/VCardUtils.sys.mjs",
+    VCardProperties: "resource:///modules/VCardUtils.sys.mjs",
+    VCardPropertyEntry: "resource:///modules/VCardUtils.sys.mjs",
+    VCardUtils: "resource:///modules/VCardUtils.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}`
+);
+
+const eas = TbSync.providers.eas;
+
+var Contacts = {
+
+    // Remove if migration code is removed.
+    arrayFromString: function (stringValue) {
+        let arrayValue = [];
+        if (stringValue.trim().length > 0) arrayValue = stringValue.trim().split("\u001A").filter(String);
+        return arrayValue;
+    },
+
+    /* The following TB properties are not synced to the server:
+       - only one WebPage
+       - more than 3 emails
+       - more than one fax, pager, mobile, work, home
+       - position (in org)
+    */
+
+    vcard_array_fields: {
+        n: 5,
+        adr: 7,
+        org: 2
+    },
+
+    map_EAS_properties_to_vCard: revision => ({
+        FileAs: { item: "fn", type: "text", params: {} }, /* DisplayName */
+
+        Birthday: { item: "bday", type: "date", params: {} },
+        Anniversary: { item: "anniversary", type: "date", params: {} },
+
+        LastName: { item: "n", type: "text", params: {}, index: 0 },
+        FirstName: { item: "n", type: "text", params: {}, index: 1 },
+        MiddleName: { item: "n", type: "text", params: {}, index: 2 },
+        Title: { item: "n", type: "text", params: {}, index: 3 },
+        Suffix: { item: "n", type: "text", params: {}, index: 4 },
+
+        Notes: { item: "note", type: "text", params: {} },
+
+        // What should we do with Email 4+?
+        // EAS does not have the concept of home/work for emails. Define matchAll
+        // to not use params for finding the correct entry. They will come back as
+        // "other".
+        Email1Address: { item: "email", type: "text", entry: 0, matchAll: true, params: {} },
+        Email2Address: { item: "email", type: "text", entry: 1, matchAll: true, params: {} },
+        Email3Address: { item: "email", type: "text", entry: 2, matchAll: true, params: {} },
+
+        // EAS does not have the concept of home/work for WebPage. Define matchAll
+        // to not use params for finding the correct entry. It will come back as
+        // "other".
+        WebPage: { item: "url", type: "text", matchAll: true, params: {} },
+
+        CompanyName: { item: "org", type: "text", params: {}, index: revision < 2 ? 1 : 0 }, /* Company */
+        Department: { item: "org", type: "text", params: {}, index: revision < 2 ? 0 : 1 }, /* Department */
+        JobTitle: { item: "title", type: "text", params: {} }, /* JobTitle */
+
+        MobilePhoneNumber: { item: "tel", type: "text", params: { type: "cell" } },
+        PagerNumber: { item: "tel", type: "text", params: { type: "pager" } },
+        HomeFaxNumber: { item: "tel", type: "text", params: { type: "fax" } },
+        // If home phone is defined, use that, otherwise use unspecified phone
+        // Note: This must be exclusive (no other field may use home/unspecified)
+        // except if entry is specified.
+        HomePhoneNumber: { item: "tel", type: "text", params: { type: "home" }, fallbackParams: [{}] },
+        BusinessPhoneNumber: { item: "tel", type: "text", params: { type: "work" } },
+        Home2PhoneNumber: { item: "tel", type: "text", params: { type: "home" }, entry: 1 },
+        Business2PhoneNumber: { item: "tel", type: "text", params: { type: "work" }, entry: 1 },
+
+        HomeAddressStreet: { item: "adr", type: "text", params: { type: "home" }, index: 2 },  // needs special handling
+        HomeAddressCity: { item: "adr", type: "text", params: { type: "home" }, index: 3 },
+        HomeAddressState: { item: "adr", type: "text", params: { type: "home" }, index: 4 },
+        HomeAddressPostalCode: { item: "adr", type: "text", params: { type: "home" }, index: 5 },
+        HomeAddressCountry: { item: "adr", type: "text", params: { type: "home" }, index: 6 },
+
+        BusinessAddressStreet: { item: "adr", type: "text", params: { type: "work" }, index: 2 },  // needs special handling
+        BusinessAddressCity: { item: "adr", type: "text", params: { type: "work" }, index: 3 },
+        BusinessAddressState: { item: "adr", type: "text", params: { type: "work" }, index: 4 },
+        BusinessAddressPostalCode: { item: "adr", type: "text", params: { type: "work" }, index: 5 },
+        BusinessAddressCountry: { item: "adr", type: "text", params: { type: "work" }, index: 6 },
+
+        OtherAddressStreet: { item: "adr", type: "text", params: {}, index: 2 },  // needs special handling
+        OtherAddressCity: { item: "adr", type: "text", params: {}, index: 3 },
+        OtherAddressState: { item: "adr", type: "text", params: {}, index: 4 },
+        OtherAddressPostalCode: { item: "adr", type: "text", params: {}, index: 5 },
+        OtherAddressCountry: { item: "adr", type: "text", params: {}, index: 6 },
+
+        // Misusing this EAS field, so that "Custom1" is saved to the server.
+        OfficeLocation: { item: "x-custom1", type: "text", params: {} },
+
+        Picture: { item: "photo", params: {}, type: "uri" },
+
+        // TB shows them as undefined, but showing them might be better, than not. Use a prefix.
+        AssistantPhoneNumber: { item: "tel", type: "text", params: { type: "Assistant" }, prefix: true },
+        CarPhoneNumber: { item: "tel", type: "text", params: { type: "Car" }, prefix: true },
+        RadioPhoneNumber: { item: "tel", type: "text", params: { type: "Radio" }, prefix: true },
+        BusinessFaxNumber: { item: "tel", type: "text", params: { type: "WorkFax" }, prefix: true },
+    }),
+
+    map_EAS_properties_to_vCard_set2: {
+        NickName: { item: "nickname", type: "text", params: {} },
+        // Misusing these EAS fields, so that "Custom2,3,4" is saved to the server.
+        CustomerId: { item: "x-custom2", type: "text", params: {} },
+        GovernmentId: { item: "x-custom3", type: "text", params: {} },
+        AccountName: { item: "x-custom4", type: "text", params: {} },
+
+        IMAddress: { item: "impp", type: "text", params: {} },
+        IMAddress2: { item: "impp", type: "text", params: {}, entry: 1 },
+        IMAddress3: { item: "impp", type: "text", params: {}, entry: 2 },
+
+        CompanyMainPhone: { item: "tel", type: "text", params: { type: "Company" }, prefix: true },
+    },
+
+    // There are currently no TB fields for these values, TbSync will store (and
+    // resend) them, but will not allow to view/edit.
+    unused_EAS_properties: [
+        "Alias", //pseudo field
+        "WeightedRank", //pseudo field
+        "YomiCompanyName", //japanese phonetic equivalent
+        "YomiFirstName", //japanese phonetic equivalent
+        "YomiLastName", //japanese phonetic equivalent
+        "CompressedRTF",
+        "MMS",
+        // Former custom EAS fields, no longer added to UI after 102.
+        "ManagerName",
+        "AssistantName",
+        "Spouse",
+    ],
+
+    // Normalize a parameters entry, to be able to find matching existing
+    // entries. If we want to be less restrictive, we need to check if all
+    // the requested values exist. But we should be the only one who sets
+    // the vCard props, so it should be safe. Except someone moves a contact.
+    // Should we prevent that via a vendor id in the vcard?
+    normalizeParameters: function (unordered) {
+        return JSON.stringify(
+            Object.keys(unordered).map(e => `${e}`.toLowerCase()).sort().reduce(
+                (obj, key) => {
+                    obj[key] = `${unordered[key]}`.toLowerCase();
+                    return obj;
+                },
+                {}
+            )
+        );
+    },
+
+    getValue: function (vCardProperties, vCard_property) {
+        let parameters = [vCard_property.params];
+        if (vCard_property.fallbackParams) {
+            parameters.push(...vCard_property.fallbackParams);
+        }
+        let entries;
+        for (let normalizedParams of parameters.map(this.normalizeParameters)) {
+            // If no params set, do not filter, otherwise filter for exact match.
+            entries = vCardProperties.getAllEntries(vCard_property.item)
+                .filter(e => vCard_property.matchAll || normalizedParams == this.normalizeParameters(e.params));
+            if (entries.length > 0) {
+                break;
+            }
+        }
+
+        // Which entry should we take?
+        let entryNr = vCard_property.entry || 0;
+        if (entries[entryNr]) {
+            let value;
+            if (vCard_property.item == "org" && !Array.isArray(entries[entryNr].value)) {
+                // The org field sometimes comes back as a string (then it is Company),
+                // even though it should be an array [Department,Company]
+                value = vCard_property.index == 1 ? entries[entryNr].value : "";
+            } else if (this.vcard_array_fields[vCard_property.item]) {
+                if (!Array.isArray(entries[entryNr].value)) {
+                    // If the returned value is a single string, return it only
+                    // when index 0 is requested, otherwise return nothing.
+                    value = vCard_property.index == 0 ? entries[entryNr].value : "";
+                } else {
+                    value = entries[entryNr].value[vCard_property.index];
+                }
+            } else {
+                value = entries[entryNr].value;
+            }
+
+            if (value) {
+                if (vCard_property.prefix && value.startsWith(`${vCard_property.params.type}: `)) {
+                    return value.substring(`${vCard_property.params.type}: `.length);
+                }
+                return value;
+            }
+        }
+        return "";
+    },
+
+    /**
+     * Reads a DOM File and returns a Promise for its dataUrl.
+     *
+     * @param {File} file
+     * @returns {string}
+     */
+    getDataUrl(file) {
+        return new Promise((resolve, reject) => {
+            var reader = new FileReader();
+            reader.readAsDataURL(file);
+            reader.onload = function () {
+                resolve(reader.result);
+            };
+            reader.onerror = function (error) {
+                resolve("");
+            };
+        });
+    },
+
+
+
+    // --------------------------------------------------------------------------- //
+    // Read WBXML and set Thunderbird item
+    // --------------------------------------------------------------------------- //
+    setThunderbirdItemFromWbxml: function (abItem, data, id, syncdata, mode = "standard") {
+        let asversion = syncdata.accountData.getAccountProperty("asversion");
+        let revision = parseInt(syncdata.target._directory.getStringValue("tbSyncRevision", "1"), 10);
+        let map_EAS_properties_to_vCard = this.map_EAS_properties_to_vCard(revision);
+
+        if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Processing " + mode + " contact item", id);
+
+        // Make sure we are dealing with a vCard, so we can update the card just
+        // by updating its vCardProperties.
+        if (!abItem._card.supportsVCard) {
+            // This is an older card??
+            throw new Error("It looks like you are trying to sync a TB91 sync state. Does not work.");
+        }
+        let vCardProperties = abItem._card.vCardProperties
+        abItem.primaryKey = id;
+
+        // Loop over all known EAS properties (two EAS sets Contacts and Contacts2).
+        for (let set = 0; set < 2; set++) {
+            let properties = (set == 0) ? this.EAS_properties : this.EAS_properties2;
+
+            for (let EAS_property of properties) {
+                let vCard_property = (set == 0) ? map_EAS_properties_to_vCard[EAS_property] : this.map_EAS_properties_to_vCard_set2[EAS_property];
+                let value;
+                switch (EAS_property) {
+                    case "Notes":
+                        if (asversion == "2.5") {
+                            value = eas.xmltools.checkString(data.Body);
+                        } else if (data.Body && data.Body.Data) {
+                            value = eas.xmltools.checkString(data.Body.Data);
+                        }
+                        break;
+
+                    default:
+                        value = eas.xmltools.checkString(data[EAS_property]);
+                }
+
+                let normalizedParams = this.normalizeParameters(vCard_property.params)
+                let entries = vCardProperties.getAllEntries(vCard_property.item)
+                    .filter(e => vCard_property.matchAll || normalizedParams == this.normalizeParameters(e.params));
+                // Which entry should we update? Add empty entries, if the requested entry number
+                // does not yet exist.
+                let entryNr = vCard_property.entry || 0;
+                while (entries.length <= entryNr) {
+                    let newEntry = new VCardPropertyEntry(
+                        vCard_property.item,
+                        vCard_property.params,
+                        vCard_property.type,
+                        this.vcard_array_fields[vCard_property.item]
+                            ? new Array(this.vcard_array_fields[vCard_property.item]).fill("")
+                            : ""
+                    );
+                    vCardProperties.addEntry(newEntry);
+                    entries = vCardProperties.getAllEntries(vCard_property.item);
+                    entryNr = entries.length - 1;
+                }
+
+                // Is this property part of the send data?
+                if (value) {
+                    // Do we need to manipulate the value?
+                    switch (EAS_property) {
+                        case "Picture":
+                            value = `data:image/jpeg;base64,${eas.xmltools.nodeAsArray(data.Picture)[0]}`; //Kerio sends Picture as container
+                            break;
+
+                        case "Birthday":
+                        case "Anniversary":
+                            let dateObj = new Date(value);
+                            value = dateObj.toISOString().substr(0, 10);
+                            break;
+
+                        case "Email1Address":
+                        case "Email2Address":
+                        case "Email3Address":
+                            let parsedInput = MailServices.headerParser.makeFromDisplayAddress(value);
+                            let fixedValue = (parsedInput && parsedInput[0] && parsedInput[0].email) ? parsedInput[0].email : value;
+                            if (fixedValue != value) {
+                                if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Parsing email display string via RFC 2231 and RFC 2047 (" + EAS_property + ")", value + " -> " + fixedValue);
+                                value = fixedValue;
+                            }
+                            break;
+
+                        case "HomeAddressStreet":
+                        case "BusinessAddressStreet":
+                        case "OtherAddressStreet":
+                            // Thunderbird accepts an array in the vCardProperty of the 2nd index of the adr field.
+                            let seperator = String.fromCharCode(syncdata.accountData.getAccountProperty("seperator")); // options are 44 (,) or 10 (\n)
+                            value = value.split(seperator);
+                            break;
+                    }
+
+                    // Add a typePrefix for fields unknown to TB (better: TB should use the type itself).
+                    if (vCard_property.prefix && !value.startsWith(`${vCard_property.params.type}: `)) {
+                        value = `${vCard_property.params.type}: ${value}`;
+                    }
+
+                    // Is this an array value?
+                    if (this.vcard_array_fields[vCard_property.item]) {
+                        // Make sure this is an array.
+                        if (!Array.isArray(entries[entryNr].value)) {
+                            let arr = new Array(this.vcard_array_fields[vCard_property.item]).fill("");
+                            arr[0] = entries[entryNr].value;
+                            entries[entryNr].value = arr;
+                        }
+                        entries[entryNr].value[vCard_property.index] = value;
+                    } else {
+                        entries[entryNr].value = value;
+                    }
+                } else {
+                    if (this.vcard_array_fields[vCard_property.item]) {
+                        // Make sure this is an array.
+                        if (!Array.isArray(entries[entryNr].value)) {
+                            let arr = new Array(this.vcard_array_fields[vCard_property.item]).fill("");
+                            arr[0] = entries[entryNr].value;
+                            entries[entryNr].value = arr;
+                        }
+                        entries[entryNr].value[vCard_property.index] = "";
+                    } else {
+                        entries[entryNr].value = "";
+                    }
+                }
+            }
+        }
+
+        // Take care of categories.
+        if (data["Categories"] && data["Categories"]["Category"]) {
+            let categories = Array.isArray(data["Categories"]["Category"])
+                ? data["Categories"]["Category"]
+                : [data["Categories"]["Category"]];
+            vCardProperties.clearValues("categories");
+            vCardProperties.addValue("categories", categories);
+            // Migration code, remove once no longer needed.
+            abItem.setProperty("Categories", "");
+        }
+
+        // Take care of children, stored in contacts property bag.
+        if (data["Children"] && data["Children"]["Child"]) {
+            let children = Array.isArray(data["Children"]["Child"])
+                ? data["Children"]["Child"]
+                : [data["Children"]["Child"]];
+            abItem.setProperty("Children", JSON.stringify(children));
+        }
+
+        // Take care of un-mappable EAS options, which are stored in the contacts
+        // property bag.
+        for (let i = 0; i < this.unused_EAS_properties.length; i++) {
+            if (data[this.unused_EAS_properties[i]]) abItem.setProperty("EAS-" + this.unused_EAS_properties[i], data[this.unused_EAS_properties[i]]);
+        }
+
+        // Remove all entries, which are marked for deletion.
+        vCardProperties.entries = vCardProperties.entries.filter(e => Array.isArray(e.value) ? e.value.some(a => a != "") : e.value != "");
+
+        // Further manipulations (a few getters are still usable \o/).
+        if (syncdata.accountData.getAccountProperty("displayoverride")) {
+            abItem._card.displayName = abItem._card.firstName + " " + abItem._card.lastName;
+            if (abItem._card.displayName == " ") {
+                let company = (vCardProperties.getFirstValue("org") || [""])[0];
+                abItem._card.displayName = company || abItem._card.primaryEmail
+            }
+        }
+    },
+
+
+
+
+    // --------------------------------------------------------------------------- //
+    //read TB event and return its data as WBXML
+    // --------------------------------------------------------------------------- //
+    getWbxmlFromThunderbirdItem: async function (abItem, syncdata, isException = false) {
+        let asversion = syncdata.accountData.getAccountProperty("asversion");
+        let revision = parseInt(syncdata.target._directory.getStringValue("tbSyncRevision", "1"), 10);
+        let map_EAS_properties_to_vCard = this.map_EAS_properties_to_vCard(revision);
+
+        let wbxml = eas.wbxmltools.createWBXML("", syncdata.type); //init wbxml with "" and not with precodes, and set initial codepage
+        let nowDate = new Date();
+
+        // Make sure we are dealing with a vCard, so we can access its vCardProperties.
+        if (!abItem._card.supportsVCard) {
+            throw new Error("It looks like you are trying to sync a TB91 sync state. Does not work.");
+        }
+        let vCardProperties = abItem._card.vCardProperties
+
+        // Loop over all known EAS properties (send empty value if not set).
+        for (let EAS_property of this.EAS_properties) {
+            // Some props need special handling.
+            let vCard_property = map_EAS_properties_to_vCard[EAS_property];
+            let value;
+            switch (EAS_property) {
+                case "Notes":
+                    // Needs to be done later, because we have to switch the code page.
+                    continue;
+
+                case "Picture": {
+                    let photoUrl = abItem._card.photoURL;
+                    if (!photoUrl) {
+                        continue;
+                    }
+                    if (photoUrl.startsWith("file://")) {
+                        let realPhotoFile = Services.io.newURI(photoUrl).QueryInterface(Ci.nsIFileURL).file;
+                        let photoFile = await File.createFromNsIFile(realPhotoFile);
+                        photoUrl = await this.getDataUrl(photoFile);
+                    }
+                    if (photoUrl.startsWith("data:image/")) {
+                        let parts = photoUrl.split(",");
+                        parts.shift();
+                        value = parts.join(",");
+                    }
+                }
+                    break;
+
+                case "Birthday":
+                case "Anniversary": {
+                    let raw = this.getValue(vCardProperties, vCard_property);
+                    if (raw) {
+                        let dateObj = new Date(raw);
+                        value = dateObj.toISOString();
+                    }
+                }
+                    break;
+
+                case "HomeAddressStreet":
+                case "BusinessAddressStreet":
+                case "OtherAddressStreet": {
+                    let raw = this.getValue(vCardProperties, vCard_property);
+                    try {
+                        if (raw) {
+                            // We either get a single string or an array for the
+                            // street adr field from Thunderbird.
+                            if (!Array.isArray(raw)) {
+                                raw = [raw];
+                            }
+                            let seperator = String.fromCharCode(syncdata.accountData.getAccountProperty("seperator")); // options are 44 (,) or 10 (\n)
+                            value = raw.join(seperator);
+                        }
+                    } catch (ex) {
+                        throw new Error(`Failed to eval value: <${JSON.stringify(raw)}> @ ${JSON.stringify(vCard_property)}`);
+                    }
+                }
+                    break;
+
+                default: {
+                    value = this.getValue(vCardProperties, vCard_property);
+                }
+            }
+
+            if (value) {
+                wbxml.atag(EAS_property, value);
+            }
+        }
+
+        // Take care of un-mappable EAS option.
+        for (let i = 0; i < this.unused_EAS_properties.length; i++) {
+            let value = abItem.getProperty("EAS-" + this.unused_EAS_properties[i], "");
+            if (value) wbxml.atag(this.unused_EAS_properties[i], value);
+        }
+
+        // Take care of categories.
+        let categories = vCardProperties.getFirstValue("categories");
+        let categoriesProperty = abItem.getProperty("Categories", "");
+        if (categoriesProperty) {
+            // Migration code, remove once no longer needed.
+            abItem.setProperty("Categories", "");
+            categories = this.arrayFromString(categoriesProperty);
+        }
+        if (categories) {
+            wbxml.otag("Categories");
+            for (let category of categories) wbxml.atag("Category", category);
+            wbxml.ctag();
+        }
+
+        // Take care of children, stored in contacts property bag.
+        let childrenProperty = abItem.getProperty("Children", "");
+        if (childrenProperty) {
+            let children = [];
+            try {
+                children = JSON.parse(childrenProperty);
+            } catch (ex) {
+                // Migration code, remove once no longer needed.
+                children = this.arrayFromString(childrenProperty);
+            }
+            wbxml.otag("Children");
+            for (let child of children) wbxml.atag("Child", child);
+            wbxml.ctag();
+        }
+
+        // Take care of notes - SWITCHING TO AirSyncBase (if 2.5, we still need Contact group here!)
+        let description = this.getValue(vCardProperties, map_EAS_properties_to_vCard["Notes"]);
+        if (asversion == "2.5") {
+            wbxml.atag("Body", description);
+        } else {
+            wbxml.switchpage("AirSyncBase");
+            wbxml.otag("Body");
+            wbxml.atag("Type", "1");
+            wbxml.atag("EstimatedDataSize", "" + description.length);
+            wbxml.atag("Data", description);
+            wbxml.ctag();
+        }
+
+        // Take care of Contacts2 group - SWITCHING TO CONTACTS2
+        wbxml.switchpage("Contacts2");
+
+        // Loop over all known TB properties of EAS group Contacts2 (send empty value if not set).
+        for (let EAS_property of this.EAS_properties2) {
+            let vCard_property = this.map_EAS_properties_to_vCard_set2[EAS_property];
+            let value = this.getValue(vCardProperties, vCard_property);
+            if (value) wbxml.atag(EAS_property, value);
+        }
+
+        return wbxml.getBytes();
+    }
+}
+
+Contacts.EAS_properties = Object.keys(Contacts.map_EAS_properties_to_vCard());
+Contacts.EAS_properties2 = Object.keys(Contacts.map_EAS_properties_to_vCard_set2);
diff -Nru eas4tbsync-4.11/content/includes/network.js eas4tbsync-4.17/content/includes/network.js
--- eas4tbsync-4.11/content/includes/network.js	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/includes/network.js	2025-05-15 13:21:20.000000000 +0200
@@ -1,1544 +1,1606 @@
-/*
- * This file is part of EAS-4-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 { OAuth2 } = ChromeUtils.import("resource:///modules/OAuth2.jsm");
-var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
-
-var containers = [];
-var sandboxes = {};
-
-function resetContainerWithId(id) {
-    Services.clearData.deleteDataFromOriginAttributesPattern({ userContextId: id });
-}
-
-function getContainerIdForContainerName(containerName) {
-    // Define the allowed range of container ids to be used
-    // TbSync is using 10000 - 19999
-    // Lightning is using 20000 - 29999
-    // Cardbook is using 30000 - 39999
-    let min = 10000;
-    let max = 19999;
-
-    //reset if adding an entry will exceed allowed range
-    if (containers.length > (max - min) && containers.indexOf(containerName) == -1) {
-        for (let i = 0; i < containers.length; i++) {
-            resetContainerWithId(i + min);
-        }
-        containers = [];
-    }
-
-    let idx = containers.indexOf(containerName);
-    return (idx == -1) ? containers.push(containerName) - 1 + min : (idx + min);
-}
-
-function getSandBoxedXHR({ user, accountname }, uri, containerReset = false) {
-    // The content principal used for the sandbox honours CORS. A server redirect
-    // to a different server may cause CORS violations. We implemented code to
-    // catch such redirects and re-run the request with the correct sandbox. If
-    // that becomes an issue, we need to make sandboxing optional.
-    // return new XMLHttpRequest({ mozAnon: false });
-
-    let containerName = `${accountname}::${user}@${uri.scheme}://${uri.hostPort}`;
-
-    let userContextId = getContainerIdForContainerName(containerName);
-    if (containerReset) {
-        resetContainerWithId(userContextId);
-    }
-    if (!sandboxes.hasOwnProperty(containerName)) {
-        console.log("Creating sandbox for <" + containerName + ">");
-        let principal = Services.scriptSecurityManager.createContentPrincipal(uri, { userContextId });
-        sandboxes[containerName] = Components.utils.Sandbox(principal, {
-            wantXrays: true,
-            wantGlobalProperties: ["XMLHttpRequest"],
-        });
-    }
-    return new sandboxes[containerName].XMLHttpRequest({ mozAnon: false });
-}
-
-var network = {
-
-    getEasURL: function (accountData) {
-        let protocol = (accountData.getAccountProperty("https")) ? "https://" : "http://";
-        let h = protocol + accountData.getAccountProperty("host");
-        while (h.endsWith("/")) { h = h.slice(0, -1); }
-
-        if (h.endsWith("Microsoft-Server-ActiveSync")) return h;
-        return h + "/Microsoft-Server-ActiveSync";
-    },
-
-    getAuthData: function (accountData) {
-        let authData = {
-            // This is the host for the password manager, which could be different from
-            // the actual host property of the account. For EAS we want to couple the password
-            // with the ACCOUNT and not any sort of url, which could change via autodiscover
-            // at any time.
-            get host() {
-                return "TbSync#" + accountData.accountID;
-            },
-
-            get user() {
-                return accountData.getAccountProperty("user");
-            },
-
-            get password() {
-                return TbSync.passwordManager.getLoginInfo(this.host, "TbSync/EAS", this.user);
-            },
-
-            get accountname() {
-                return accountData.getAccountProperty("accountname");
-            },
-
-            updateLoginData: async function (newUsername, newPassword) {
-                let oldUsername = this.user;
-                await TbSync.passwordManager.updateLoginInfo(this.host, "TbSync/EAS", oldUsername, newUsername, newPassword);
-                // Also update the username of this account. Add dedicated username setter?
-                accountData.setAccountProperty("user", newUsername);
-            },
-
-            removeLoginData: function () {
-                TbSync.passwordManager.removeLoginInfos(this.host, "TbSync/EAS");
-            }
-        };
-        return authData;
-    },
-
-    getContextData: function (configObject = null) {
-        let contextData = {}
-        contextData.accountData = (configObject && configObject.hasOwnProperty("accountData")) ? configObject.accountData : null;
-
-        if (contextData.accountData) {
-            contextData.accountname = contextData.accountData.getAccountProperty("accountname");
-            contextData.user = contextData.accountData.getAccountProperty("user");
-            contextData.host = contextData.accountData.getAccountProperty("host");
-            contextData.servertype = contextData.accountData.getAccountProperty("servertype");
-            contextData.accountID = contextData.accountData.accountID;
-        } else {
-            contextData.accountname = (configObject && configObject.hasOwnProperty("accountname")) ? configObject.accountname : "";
-            contextData.user = (configObject && configObject.hasOwnProperty("user")) ? configObject.user : "";
-            contextData.host = (configObject && configObject.hasOwnProperty("host")) ? configObject.host : "";
-            contextData.servertype = (configObject && configObject.hasOwnProperty("servertype")) ? configObject.servertype : "";
-            contextData.accountID = "";
-        }
-
-        return contextData;
-    },
-
-    // prepare and patch OAuth2 object
-    getOAuthObj: function (configObject = null) {
-        let {
-            accountData,
-            accountname,
-            user,
-            host,
-            accountID,
-            servertype
-        } = this.getContextData(configObject);
-
-        if (!["office365"].includes(servertype))
-            return null;
-
-        let config = {};
-        let customID = eas.Base.getCustomeOauthClientID();
-        switch (host) {
-            case "outlook.office365.com":
-            case "eas.outlook.com":
-                config = {
-                    auth_uri: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
-                    token_uri: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
-                    redirect_uri: "https://login.microsoftonline.com/common/oauth2/nativeclient",
-                    client_id: customID != "" ? customID : "2980deeb-7460-4723-864a-f9b0f10cd992",
-                }
-                break;
-
-            default:
-                return null;
-        }
-
-        switch (host) {
-            case "outlook.office365.com":
-                config.scope = "offline_access https://outlook.office.com/.default";
-                break;
-            case "eas.outlook.com":
-                config.scope = "offline_access https://outlook.office.com/EAS.AccessAsUser.All";
-                break;
-        }
-
-        let oauth = new OAuth2(config.scope, {
-            authorizationEndpoint: config.auth_uri,
-            tokenEndpoint: config.token_uri,
-            clientId: config.client_id,
-            clientSecret: config.client_secret
-        });
-        oauth.requestWindowFeatures = "chrome,private,centerscreen,width=500,height=750";
-
-        // The v2 redirection endpoint differs from the default and needs manual override
-        oauth.redirectionEndpoint = config.redirect_uri;
-
-        oauth.extraAuthParams = [
-            // removed in beta 1.14.1, according to
-            // https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#default-and-consent
-            // prompt = consent will always ask for admin consent, even if it was granted
-            //["prompt", "consent"],
-            ["login_hint", user],
-        ];
-
-        if (accountname) {
-            oauth.requestWindowTitle = "TbSync account <" + accountname + "> requests authorization.";
-        } else {
-            oauth.requestWindowTitle = "A TbSync account requests authorization.";
-        }
-
-
-
-
-        /* Adding custom methods to the oauth object */
-
-        oauth.asyncConnect = async function (rv) {
-            rv.error = "";
-
-            // If multiple resources need to authenticate they will all end here, even though they
-            // might share the same token. Due to the async nature, each process will refresh
-            // "its own" token again, which is not needed. We force clear the token here and each
-            // final connect process will actually check the acccessToken and abort the refresh, 
-            // if it is already there, generated by some other process. 
-            if (oauth.getToken("accessToken")) {
-                await oauth.setToken("accessToken", "");
-            }
-
-
-            try {
-                // refresh = false will do nothing and resolve immediately, if an accessToken
-                // exists already, which must have been generated by another process, as
-                // we cleared it beforehand.
-                await oauth.connect(/* with UI */ true, /* refresh */ false);
-                await oauth.setToken("accessToken", oauth.accessToken);
-                await oauth.setToken("refreshToken", oauth.refreshToken);
-                await oauth.setToken("tokenExpires", oauth.tokenExpires);
-                rv.tokens = oauth.tokens;
-                return true;
-            } catch (e) {
-                await oauth.setToken("accessToken", oauth.accessToken);
-                await oauth.setToken("refreshToken", oauth.refreshToken);
-                await oauth.setToken("tokenExpires", oauth.tokenExpires);
-                rv.error = eas.tools.isString(e) ? e : JSON.stringify(e);
-            }
-
-            try {
-                switch (JSON.parse(rv.error).error) {
-                    case "invalid_grant":
-                        await oauth.setToken("accessToken", "");
-                        await oauth.setToken("refreshToken", "");
-                        rv.tokens = oauth.tokens;
-                        return true;
-
-                    case "cancelled":
-                        rv.error = "OAuthAbortError";
-                        break;
-
-                    default:
-                        rv.error = "OAuthServerError::" + rv.error;
-                        break;
-                }
-            } catch (e) {
-                rv.error = "OAuthServerError::" + rv.error;
-                Components.utils.reportError(e);
-            }
-            rv.tokens = oauth.tokens;
-            return false;
-        };
-
-        oauth.isExpired = function () {
-            const OAUTH_GRACE_TIME = 30 * 1000;
-            return (oauth.getToken("tokenExpires") - OAUTH_GRACE_TIME < new Date().getTime());
-        };
-
-        const OAUTHVALUES = [
-            ["access", "", "accessToken"],
-            ["refresh", "", "refreshToken"],
-            ["expires", Number.MAX_VALUE, "tokenExpires"],
-        ];
-
-        // returns a JSON string containing all the oauth values
-        Object.defineProperty(oauth, "tokens", {
-            get: function () {
-                let tokensObj = {};
-                for (let oauthValue of OAUTHVALUES) {
-                    // use the system value or if not defined the default
-                    tokensObj[oauthValue[0]] = this[oauthValue[2]] || oauthValue[1];
-                }
-                return JSON.stringify(tokensObj);
-            },
-            enumerable: true,
-        });
-
-        if (accountData) {
-            // authData allows us to access the password manager values belonging to this account/calendar
-            // simply by authdata.username and authdata.password
-            oauth.authData = TbSync.providers.eas.network.getAuthData(accountData);
-
-            oauth.parseAndSanitizeTokenString = function (tokenString) {
-                let _tokensObj = {};
-                try {
-                    _tokensObj = JSON.parse(tokenString);
-                } catch (e) { }
-
-                let tokensObj = {};
-                for (let oauthValue of OAUTHVALUES) {
-                    // use the provided value or if not defined the default
-                    tokensObj[oauthValue[0]] = (_tokensObj && _tokensObj.hasOwnProperty(oauthValue[0]))
-                        ? _tokensObj[oauthValue[0]]
-                        : oauthValue[1];
-                }
-                return tokensObj;
-            };
-
-            oauth.getToken = function (tokenName) {
-                let oauthValue = OAUTHVALUES.find(e => e[2] == tokenName);
-                return oauth.parseAndSanitizeTokenString(oauth.authData.password)[oauthValue[0]];
-            };
-
-            oauth.setToken = async function (tokenName, val) {
-                oauth[tokenName] = val;
-
-                let oauthValue = OAUTHVALUES.find(e => e[2] == tokenName);
-                let tokens = oauth.parseAndSanitizeTokenString(oauth.authData.password);
-                let valueChanged = (val != tokens[oauthValue[0]])
-                if (valueChanged) {
-                    tokens[oauthValue[0]] = val;
-                    await oauth.authData.updateLoginData(oauth.authData.user, JSON.stringify(tokens));
-                }
-            };
-        } else {
-            oauth.getToken = function (tokenName) {
-                return oauth[tokenName];
-            };
-
-            oauth.setToken = async function (tokenName, val) {
-                oauth[tokenName] = val;
-            };
-        }
-
-        return oauth;
-    },
-
-    getOAuthValue: function (currentTokenString, type = "access") {
-        try {
-            let tokens = JSON.parse(currentTokenString);
-            if (tokens.hasOwnProperty(type))
-                return tokens[type];
-        } catch (e) {
-            //NOOP
-        }
-        return "";
-    },
-
-    sendRequest: async function (wbxml, command, syncData, allowSoftFail = false) {
-        let ALLOWED_RETRIES = {
-            PasswordPrompt: 3,
-            NetworkError: 1,
-        }
-
-        let rv = {};
-        let oauthData = eas.network.getOAuthObj({ accountData: syncData.accountData });
-        let syncState = syncData.getSyncState().state;
-
-        for (; ;) {
-
-            if (rv.errorType) {
-                let retry = false;
-
-                if (ALLOWED_RETRIES[rv.errorType] > 0) {
-                    ALLOWED_RETRIES[rv.errorType]--;
-
-
-                    switch (rv.errorType) {
-
-                        case "PasswordPrompt":
-                            {
-
-                                if (oauthData) {
-                                    await oauthData.setToken("accessToken", "");
-                                    retry = true;
-                                } else {
-                                    let authData = eas.network.getAuthData(syncData.accountData);
-                                    syncData.setSyncState("passwordprompt");
-                                    let promptData = {
-                                        windowID: "auth:" + syncData.accountData.accountID,
-                                        accountname: syncData.accountData.getAccountProperty("accountname"),
-                                        usernameLocked: syncData.accountData.isConnected(),
-                                        username: authData.user
-                                    }
-                                    let credentials = await TbSync.passwordManager.asyncPasswordPrompt(promptData, eas.openWindows);
-                                    if (credentials) {
-                                        retry = true;
-                                        await authData.updateLoginData(credentials.username, credentials.password);
-                                    }
-                                }
-                            }
-                            break;
-
-                        case "NetworkError":
-                            {
-                                // Could not connect to server. Can we rerun autodiscover?
-                                // Note: Autodiscover is currently not supported by OAuth
-                                if (syncData.accountData.getAccountProperty("servertype") == "auto" && !oauthData) {
-                                    let errorcode = await eas.network.updateServerConnectionViaAutodiscover(syncData);
-                                    console.log("ERR: " + errorcode);
-                                    if (errorcode == 200) {
-                                        // autodiscover succeeded, retry with new data
-                                        retry = true;
-                                    } else if (errorcode == 401) {
-                                        // manipulate rv to run password prompt
-                                        ALLOWED_RETRIES[rv.errorType]++;
-                                        rv.errorType = "PasswordPrompt";
-                                        rv.errorObj = eas.sync.finish("error", "401");
-                                        continue; // with the next loop, skip connection to the server
-                                    }
-                                }
-                            }
-                            break;
-
-                    }
-                }
-
-                if (!retry) throw rv.errorObj;
-            }
-
-            // check OAuth situation before connecting
-            if (oauthData && (!oauthData.getToken("accessToken") || oauthData.isExpired())) {
-                syncData.setSyncState("oauthprompt");
-                let _rv = {}
-                if (!(await oauthData.asyncConnect(_rv))) {
-                    throw eas.sync.finish("error", _rv.error);
-                }
-            }
-
-            // Return to original syncstate
-            if (syncState != syncData.getSyncState().state) {
-                syncData.setSyncState(syncState);
-            }
-            rv = await this.sendRequestPromise(wbxml, command, syncData, allowSoftFail);
-
-            if (rv.errorType) {
-                // make sure, there is a valid ALLOWED_RETRIES setting for the returned error
-                if (rv.errorType && !ALLOWED_RETRIES.hasOwnProperty(rv.errorType)) {
-                    ALLOWED_RETRIES[rv.errorType] = 1;
-                }
-            } else {
-                return rv;
-            }
-        }
-    },
-
-    sendRequestPromise: function (wbxml, command, syncData, allowSoftFail = false) {
-        let msg = "Sending data <" + syncData.getSyncState().state + "> for " + syncData.accountData.getAccountProperty("accountname");
-        if (syncData.currentFolderData) msg += " (" + syncData.currentFolderData.getFolderProperty("foldername") + ")";
-        syncData.request = eas.network.logXML(wbxml, msg);
-        syncData.response = "";
-
-        let connection = eas.network.getAuthData(syncData.accountData);
-        let userAgent = syncData.accountData.getAccountProperty("useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2
-        let deviceType = syncData.accountData.getAccountProperty("devicetype");
-        let deviceId = syncData.accountData.getAccountProperty("deviceId");
-
-        TbSync.dump("Sending (EAS v" + syncData.accountData.getAccountProperty("asversion") + ")", "POST " + eas.network.getEasURL(syncData.accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(connection.user) + '&DeviceType=' + deviceType + '&DeviceId=' + deviceId, true);
-
-        const textEncoder = new TextEncoder();
-        let encoded = textEncoder.encode(wbxml);
-        // console.log("wbxml: " + wbxml);
-        // console.log("byte array: " + encoded);
-        // console.log("length :" + wbxml.length + " vs " + encoded.byteLength + " vs " + encoded.length);
-
-        let contextData = eas.network.getContextData({ accountData: syncData.accountData });
-        let uri = Services.io.newURI(eas.network.getEasURL(syncData.accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(connection.user) + '&DeviceType=' + encodeURIComponent(deviceType) + '&DeviceId=' + deviceId);
-        return new Promise(function (resolve, reject) {
-            syncData.req = getSandBoxedXHR(contextData, uri);
-            syncData.req.mozBackgroundRequest = true;
-            syncData.req.open("POST", uri.spec, true);
-            syncData.req.overrideMimeType("text/plain");
-            syncData.req.setRequestHeader("User-Agent", userAgent);
-            syncData.req.setRequestHeader("Content-Type", "application/vnd.ms-sync.wbxml");
-            if (connection.password) {
-                if (eas.network.getOAuthObj({ accountData: syncData.accountData })) {
-                    syncData.req.setRequestHeader("Authorization", 'Bearer ' + eas.network.getOAuthValue(connection.password, "access"));
-                } else {
-                    syncData.req.setRequestHeader("Authorization", 'Basic ' + TbSync.tools.b64encode(connection.user + ':' + connection.password));
-                }
-            }
-
-            if (syncData.accountData.getAccountProperty("asversion") == "2.5") {
-                syncData.req.setRequestHeader("MS-ASProtocolVersion", "2.5");
-            } else {
-                syncData.req.setRequestHeader("MS-ASProtocolVersion", "14.0");
-            }
-            syncData.req.setRequestHeader("Content-Length", encoded.length);
-            if (syncData.accountData.getAccountProperty("provision")) {
-                syncData.req.setRequestHeader("X-MS-PolicyKey", syncData.accountData.getAccountProperty("policykey"));
-                TbSync.dump("PolicyKey used", syncData.accountData.getAccountProperty("policykey"));
-            }
-
-            syncData.req.timeout = eas.Base.getConnectionTimeout();
-
-            syncData.req.ontimeout = function () {
-                if (allowSoftFail) {
-                    resolve("");
-                } else {
-                    reject(eas.sync.finish("error", "timeout"));
-                }
-            };
-
-            syncData.req.onerror = function () {
-                if (allowSoftFail) {
-                    resolve("");
-                } else {
-                    let error = TbSync.network.createTCPErrorFromFailedXHR(syncData.req) || "networkerror";
-                    let rv = {};
-                    rv.errorObj = eas.sync.finish("error", error);
-                    rv.errorType = "NetworkError";
-                    resolve(rv);
-                }
-            };
-
-            syncData.req.onload = function () {
-                let response = syncData.req.responseText;
-                switch (syncData.req.status) {
-
-                    case 200: //OK
-                        let msg = "Receiving data <" + syncData.getSyncState().state + "> for " + syncData.accountData.getAccountProperty("accountname");
-                        if (syncData.currentFolderData) msg += " (" + syncData.currentFolderData.getFolderProperty("foldername") + ")";
-                        syncData.response = eas.network.logXML(response, msg);
-
-                        //What to do on error? IS this an error? Yes!
-                        if (!allowSoftFail && response.length !== 0 && response.substr(0, 4) !== String.fromCharCode(0x03, 0x01, 0x6A, 0x00)) {
-                            TbSync.dump("Recieved Data", "Expecting WBXML but got junk (request status = " + syncData.req.status + ", ready state = " + syncData.req.readyState + "\n>>>>>>>>>>\n" + response + "\n<<<<<<<<<<\n");
-                            reject(eas.sync.finish("warning", "invalid"));
-                        } else {
-                            resolve(response);
-                        }
-                        break;
-
-                    case 401: // AuthError
-                    case 403: // Forbiddden (some servers send forbidden on AuthError, like Freenet)
-                        let rv = {};
-                        rv.errorObj = eas.sync.finish("error", "401");
-                        rv.errorType = "PasswordPrompt";
-                        resolve(rv);
-                        break;
-
-                    case 449: // Request for new provision (enable it if needed)
-                        //enable provision
-                        syncData.accountData.setAccountProperty("provision", true);
-                        syncData.accountData.resetAccountProperty("policykey");
-                        reject(eas.sync.finish("resyncAccount", syncData.req.status));
-                        break;
-
-                    case 451: // Redirect - update host and login manager 
-                        let header = syncData.req.getResponseHeader("X-MS-Location");
-                        let newHost = header.slice(header.indexOf("://") + 3, header.indexOf("/M"));
-
-                        TbSync.dump("redirect (451)", "header: " + header + ", oldHost: " + syncData.accountData.getAccountProperty("host") + ", newHost: " + newHost);
-
-                        syncData.accountData.setAccountProperty("host", newHost);
-                        reject(eas.sync.finish("resyncAccount", syncData.req.status));
-                        break;
-
-                    default:
-                        if (allowSoftFail) {
-                            resolve("");
-                        } else {
-                            reject(eas.sync.finish("error", "httperror::" + syncData.req.status));
-                        }
-                }
-            };
-
-            syncData.req.send(encoded);
-
-        });
-    },
-
-
-
-
-
-
-
-
-
-
-    // RESPONSE EVALUATION
-
-    logXML: function (wbxml, what) {
-        let rawxml = eas.wbxmltools.convert2xml(wbxml);
-        let xml = null;
-        if (rawxml) {
-            xml = rawxml.split('><').join('>\n<');
-        }
-
-        //include xml in log, if userdatalevel 2 or greater
-        if (TbSync.prefs.getIntPref("log.userdatalevel") > 1) {
-
-            //log raw wbxml if userdatalevel is 3 or greater
-            if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) {
-                let charcodes = [];
-                for (let i = 0; i < wbxml.length; i++) charcodes.push(wbxml.charCodeAt(i).toString(16));
-                let bytestring = charcodes.join(" ");
-                TbSync.dump("WBXML: " + what, "\n" + bytestring);
-            }
-
-            if (xml) {
-                //raw xml is save xml with all special chars in user data encoded by encodeURIComponent - KEEP that in order to be able to analyze logged XML 
-                //let xml = decodeURIComponent(rawxml.split('><').join('>\n<'));
-                TbSync.dump("XML: " + what, "\n" + xml);
-            } else {
-                TbSync.dump("XML: " + what, "\nFailed to convert WBXML to XML!\n");
-            }
-        }
-
-        return xml;
-    },
-
-    //returns false on parse error and null on empty response (if allowed)
-    getDataFromResponse: function (wbxml, allowEmptyResponse = !eas.flags.allowEmptyResponse) {
-        //check for empty wbxml
-        if (wbxml.length === 0) {
-            if (allowEmptyResponse) return null;
-            else throw eas.sync.finish("warning", "empty-response");
-        }
-
-        //convert to save xml (all special chars in user data encoded by encodeURIComponent) and check for parse errors
-        let xml = eas.wbxmltools.convert2xml(wbxml);
-        if (xml === false) {
-            throw eas.sync.finish("warning", "wbxml-parse-error");
-        }
-
-        //retrieve data and check for empty data (all returned data fields are already decoded by decodeURIComponent)
-        let wbxmlData = eas.xmltools.getDataFromXMLString(xml);
-        if (wbxmlData === null) {
-            if (allowEmptyResponse) return null;
-            else throw eas.sync.finish("warning", "response-contains-no-data");
-        }
-
-        //debug
-        eas.xmltools.printXmlData(wbxmlData, false); //do not include ApplicationData in log
-        return wbxmlData;
-    },
-
-    updateSynckey: function (syncData, wbxmlData) {
-        let synckey = eas.xmltools.getWbxmlDataField(wbxmlData, "Sync.Collections.Collection.SyncKey");
-
-        if (synckey) {
-            // This COULD be a cause of problems... 
-            syncData.synckey = synckey;
-            syncData.currentFolderData.setFolderProperty("synckey", synckey);
-        } else {
-            throw eas.sync.finish("error", "wbxmlmissingfield::Sync.Collections.Collection.SyncKey");
-        }
-    },
-
-    checkStatus: function (syncData, wbxmlData, path, rootpath = "", allowSoftFail = false) {
-        //path is relative to wbxmlData
-        //rootpath is the absolute path and must be specified, if wbxml is not the root node and thus path is not the rootpath	    
-        let status = eas.xmltools.getWbxmlDataField(wbxmlData, path);
-        let fullpath = (rootpath == "") ? path : rootpath;
-        let elements = fullpath.split(".");
-        let type = elements[0];
-
-        //check if fallback to main class status: the answer could just be a "Sync.Status" instead of a "Sync.Collections.Collections.Status"
-        if (status === false) {
-            let mainStatus = eas.xmltools.getWbxmlDataField(wbxmlData, type + "." + elements[elements.length - 1]);
-            if (mainStatus === false) {
-                //both possible status fields are missing, abort
-                throw eas.sync.finish("warning", "wbxmlmissingfield::" + fullpath, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
-            } else {
-                //the alternative status could be extracted
-                status = mainStatus;
-                fullpath = type + "." + elements[elements.length - 1];
-            }
-        }
-
-        //check if all is fine (not bad)
-        if (status == "1") {
-            return "";
-        }
-
-        TbSync.dump("wbxml status check", type + ": " + fullpath + " = " + status);
-
-        //handle errrors based on type
-        let statusType = type + "." + status;
-        switch (statusType) {
-            case "Sync.3": /*
-                        MUST return to SyncKey element value of 0 for the collection. The client SHOULD either delete any items that were added 
-                        since the last successful Sync or the client MUST add those items back to the server after completing the full resynchronization
-                        */
-                TbSync.eventlog.add("warning", syncData.eventLogInfo, "Forced Folder Resync", "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
-                syncData.currentFolderData.remove();
-                throw eas.sync.finish("resyncFolder", statusType);
-
-            case "Sync.4": //Malformed request
-            case "Sync.5": //Temporary server issues or invalid item
-            case "Sync.6": //Invalid item
-            case "Sync.8": //Object not found
-                if (allowSoftFail) return statusType;
-                throw eas.sync.finish("warning", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
-
-            case "Sync.7": //The client has changed an item for which the conflict policy indicates that the server's changes take precedence.
-            case "Sync.9": //User account could be out of disk space, also send if no write permission (TODO)
-                return "";
-
-            case "FolderDelete.3": // special system folder - fatal error
-            case "FolderDelete.6": // error on server
-                throw eas.sync.finish("warning", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
-
-            case "FolderDelete.4": // folder does not exist - resync ( we allow delete only if folder is not subscribed )
-            case "FolderDelete.9": // invalid synchronization key - resync
-            case "FolderSync.9": // invalid synchronization key - resync
-            case "Sync.12": // folder hierarchy changed
-                {
-                    let folders = syncData.accountData.getAllFoldersIncludingCache();
-                    for (let folder of folders) {
-                        folder.remove();
-                    }
-                    // reset account
-                    eas.Base.onEnableAccount(syncData.accountData);
-                    throw eas.sync.finish("resyncAccount", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
-                }
-        }
-
-        //handle global error (https://msdn.microsoft.com/en-us/library/ee218647(v=exchg.80).aspx)
-        let descriptions = {};
-        switch (status) {
-            case "101": //invalid content
-            case "102": //invalid wbxml
-            case "103": //invalid xml
-                throw eas.sync.finish("error", "global." + status, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
-
-            case "109": descriptions["109"] = "DeviceTypeMissingOrInvalid";
-            case "112": descriptions["112"] = "ActiveDirectoryAccessDenied";
-            case "126": descriptions["126"] = "UserDisabledForSync";
-            case "127": descriptions["127"] = "UserOnNewMailboxCannotSync";
-            case "128": descriptions["128"] = "UserOnLegacyMailboxCannotSync";
-            case "129": descriptions["129"] = "DeviceIsBlockedForThisUser";
-            case "130": descriptions["120"] = "AccessDenied";
-            case "131": descriptions["131"] = "AccountDisabled";
-                throw eas.sync.finish("error", "global.clientdenied" + "::" + status + "::" + descriptions[status]);
-
-            case "110": //server error - abort and disable autoSync for 30 minutes
-                {
-                    let noAutosyncUntil = 30 * 60000 + Date.now();
-                    let humanDate = new Date(noAutosyncUntil).toUTCString();
-                    syncData.accountData.setAccountProperty("noAutosyncUntil", noAutosyncUntil);
-                    throw eas.sync.finish("error", "global." + status, "AutoSync disabled until: " + humanDate + " \n\nRequest:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
-
-                    /*                     // reset account
-                     *                     let folders = syncData.accountData.getAllFoldersIncludingCache();
-                     *                     for (let folder of folders) {
-                     *                         folder.remove();
-                     *                     }		    
-                     *                     // reset account
-                     *                     eas.Base.onEnableAccount(syncData.accountData);
-                     *                     throw eas.sync.finish("resyncAccount", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
-                     */
-                }
-
-            case "141": // The device is not provisionable
-            case "142": // DeviceNotProvisioned
-            case "143": // PolicyRefresh
-            case "144": // InvalidPolicyKey
-                //enable provision
-                syncData.accountData.setAccountProperty("provision", true);
-                syncData.accountData.resetAccountProperty("policykey");
-                throw eas.sync.finish("resyncAccount", statusType);
-
-            default:
-                if (allowSoftFail) return statusType;
-                throw eas.sync.finish("error", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
-
-        }
-    },
-
-
-
-
-
-
-
-
-
-
-    // WBXML COMM STUFF
-
-    setDeviceInformation: async function (syncData) {
-        if (syncData.accountData.getAccountProperty("asversion") == "2.5" || !syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("Settings")) {
-            return;
-        }
-
-        syncData.setSyncState("prepare.request.setdeviceinfo");
-
-        let wbxml = wbxmltools.createWBXML();
-        wbxml.switchpage("Settings");
-        wbxml.otag("Settings");
-        wbxml.otag("DeviceInformation");
-        wbxml.otag("Set");
-        wbxml.atag("Model", "Computer");
-        wbxml.atag("FriendlyName", "TbSync on Device " + syncData.accountData.getAccountProperty("deviceId").substring(4));
-        wbxml.atag("OS", Services.appinfo.OS);
-        wbxml.atag("UserAgent", syncData.accountData.getAccountProperty("useragent"));
-        wbxml.ctag();
-        wbxml.ctag();
-        wbxml.ctag();
-
-        syncData.setSyncState("send.request.setdeviceinfo");
-        let response = await eas.network.sendRequest(wbxml.getBytes(), "Settings", syncData);
-
-        syncData.setSyncState("eval.response.setdeviceinfo");
-        let wbxmlData = eas.network.getDataFromResponse(response);
-
-        eas.network.checkStatus(syncData, wbxmlData, "Settings.Status");
-    },
-
-    getPolicykey: async function (syncData) {
-        //build WBXML to request provision
-        syncData.setSyncState("prepare.request.provision");
-        let wbxml = eas.wbxmltools.createWBXML();
-        wbxml.switchpage("Provision");
-        wbxml.otag("Provision");
-        wbxml.otag("Policies");
-        wbxml.otag("Policy");
-        wbxml.atag("PolicyType", (syncData.accountData.getAccountProperty("asversion") == "2.5") ? "MS-WAP-Provisioning-XML" : "MS-EAS-Provisioning-WBXML");
-        wbxml.ctag();
-        wbxml.ctag();
-        wbxml.ctag();
-
-        for (let loop = 0; loop < 2; loop++) {
-            syncData.setSyncState("send.request.provision");
-            let response = await eas.network.sendRequest(wbxml.getBytes(), "Provision", syncData);
-
-            syncData.setSyncState("eval.response.provision");
-            let wbxmlData = eas.network.getDataFromResponse(response);
-            let policyStatus = eas.xmltools.getWbxmlDataField(wbxmlData, "Provision.Policies.Policy.Status");
-            let provisionStatus = eas.xmltools.getWbxmlDataField(wbxmlData, "Provision.Status");
-            if (provisionStatus === false) {
-                throw eas.sync.finish("error", "wbxmlmissingfield::Provision.Status");
-            } else if (provisionStatus != "1") {
-                //dump policy status as well
-                if (policyStatus) TbSync.dump("PolicyKey", "Received policy status: " + policyStatus);
-                throw eas.sync.finish("error", "provision::" + provisionStatus);
-            }
-
-            //reaching this point: provision status was ok
-            let policykey = eas.xmltools.getWbxmlDataField(wbxmlData, "Provision.Policies.Policy.PolicyKey");
-            switch (policyStatus) {
-                case false:
-                    throw eas.sync.finish("error", "wbxmlmissingfield::Provision.Policies.Policy.Status");
-
-                case "2":
-                    //server does not have a policy for this device: disable provisioning
-                    syncData.accountData.setAccountProperty("provision", false)
-                    syncData.accountData.resetAccountProperty("policykey");
-                    throw eas.sync.finish("resyncAccount", "NoPolicyForThisDevice");
-
-                case "1":
-                    if (policykey === false) {
-                        throw eas.sync.finish("error", "wbxmlmissingfield::Provision.Policies.Policy.PolicyKey");
-                    }
-                    TbSync.dump("PolicyKey", "Received policykey (" + loop + "): " + policykey);
-                    syncData.accountData.setAccountProperty("policykey", policykey);
-                    break;
-
-                default:
-                    throw eas.sync.finish("error", "policy." + policyStatus);
-            }
-
-            //build WBXML to acknowledge provision
-            syncData.setSyncState("prepare.request.provision");
-            wbxml = eas.wbxmltools.createWBXML();
-            wbxml.switchpage("Provision");
-            wbxml.otag("Provision");
-            wbxml.otag("Policies");
-            wbxml.otag("Policy");
-            wbxml.atag("PolicyType", (syncData.accountData.getAccountProperty("asversion") == "2.5") ? "MS-WAP-Provisioning-XML" : "MS-EAS-Provisioning-WBXML");
-            wbxml.atag("PolicyKey", policykey);
-            wbxml.atag("Status", "1");
-            wbxml.ctag();
-            wbxml.ctag();
-            wbxml.ctag();
-
-            //this wbxml will be used by Send at the top of this loop
-        }
-    },
-
-    getSynckey: async function (syncData) {
-        syncData.setSyncState("prepare.request.synckey");
-        //build WBXML to request a new syncKey
-        let wbxml = eas.wbxmltools.createWBXML();
-        wbxml.otag("Sync");
-        wbxml.otag("Collections");
-        wbxml.otag("Collection");
-        if (syncData.accountData.getAccountProperty("asversion") == "2.5") wbxml.atag("Class", syncData.type);
-        wbxml.atag("SyncKey", "0");
-        wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID"));
-        wbxml.ctag();
-        wbxml.ctag();
-        wbxml.ctag();
-
-        syncData.setSyncState("send.request.synckey");
-        let response = await eas.network.sendRequest(wbxml.getBytes(), "Sync", syncData);
-
-        syncData.setSyncState("eval.response.synckey");
-        // get data from wbxml response
-        let wbxmlData = eas.network.getDataFromResponse(response);
-        //check status
-        eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status");
-        //update synckey
-        eas.network.updateSynckey(syncData, wbxmlData);
-    },
-
-    getItemEstimate: async function (syncData) {
-        syncData.progressData.reset();
-
-        if (!syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("GetItemEstimate")) {
-            return; //do not throw, this is optional
-        }
-
-        syncData.setSyncState("prepare.request.estimate");
-
-        // BUILD WBXML
-        let wbxml = eas.wbxmltools.createWBXML();
-        wbxml.switchpage("GetItemEstimate");
-        wbxml.otag("GetItemEstimate");
-        wbxml.otag("Collections");
-        wbxml.otag("Collection");
-        if (syncData.accountData.getAccountProperty("asversion") == "2.5") { //got this order for 2.5 directly from Microsoft support
-            wbxml.atag("Class", syncData.type); //only 2.5
-            wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID"));
-            wbxml.switchpage("AirSync");
-            // required !
-            // https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-ascmd/ffbefa62-e315-40b9-9cc6-f8d74b5f65d4
-            if (syncData.type == "Calendar") wbxml.atag("FilterType", syncData.currentFolderData.accountData.getAccountProperty("synclimit"));
-            else wbxml.atag("FilterType", "0"); // we may filter incomplete tasks
-
-            wbxml.atag("SyncKey", syncData.synckey);
-            wbxml.switchpage("GetItemEstimate");
-        } else { //14.0
-            wbxml.switchpage("AirSync");
-            wbxml.atag("SyncKey", syncData.synckey);
-            wbxml.switchpage("GetItemEstimate");
-            wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID"));
-            wbxml.switchpage("AirSync");
-            wbxml.otag("Options");
-            // optional
-            if (syncData.type == "Calendar") wbxml.atag("FilterType", syncData.currentFolderData.accountData.getAccountProperty("synclimit"));
-            wbxml.atag("Class", syncData.type);
-            wbxml.ctag();
-            wbxml.switchpage("GetItemEstimate");
-        }
-        wbxml.ctag();
-        wbxml.ctag();
-        wbxml.ctag();
-
-        //SEND REQUEST
-        syncData.setSyncState("send.request.estimate");
-        let response = await eas.network.sendRequest(wbxml.getBytes(), "GetItemEstimate", syncData, /* allowSoftFail */ true);
-
-        //VALIDATE RESPONSE
-        syncData.setSyncState("eval.response.estimate");
-
-        // get data from wbxml response, some servers send empty response if there are no changes, which is not an error
-        let wbxmlData = eas.network.getDataFromResponse(response, eas.flags.allowEmptyResponse);
-        if (wbxmlData === null) return;
-
-        let status = eas.xmltools.getWbxmlDataField(wbxmlData, "GetItemEstimate.Response.Status");
-        let estimate = eas.xmltools.getWbxmlDataField(wbxmlData, "GetItemEstimate.Response.Collection.Estimate");
-
-        if (status && status == "1") { //do not throw on error, with EAS v2.5 I get error 2 for tasks and calendars ???
-            syncData.progressData.reset(0, estimate);
-        }
-    },
-
-    getUserInfo: async function (syncData) {
-        if (!syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("Settings")) {
-            return;
-        }
-
-        syncData.setSyncState("prepare.request.getuserinfo");
-
-        let wbxml = eas.wbxmltools.createWBXML();
-        wbxml.switchpage("Settings");
-        wbxml.otag("Settings");
-        wbxml.otag("UserInformation");
-        wbxml.atag("Get");
-        wbxml.ctag();
-        wbxml.ctag();
-
-        syncData.setSyncState("send.request.getuserinfo");
-        let response = await eas.network.sendRequest(wbxml.getBytes(), "Settings", syncData);
-
-
-        syncData.setSyncState("eval.response.getuserinfo");
-        let wbxmlData = eas.network.getDataFromResponse(response);
-
-        eas.network.checkStatus(syncData, wbxmlData, "Settings.Status");
-    },
-
-
-
-
-
-
-
-
-
-
-    // SEARCH
-
-    getSearchResults: async function (accountData, currentQuery) {
-
-        let _wbxml = eas.wbxmltools.createWBXML();
-        _wbxml.switchpage("Search");
-        _wbxml.otag("Search");
-        _wbxml.otag("Store");
-        _wbxml.atag("Name", "GAL");
-        _wbxml.atag("Query", currentQuery);
-        _wbxml.otag("Options");
-        _wbxml.atag("Range", "0-99"); //Z-Push needs a Range
-        //Not valid for GAL: https://msdn.microsoft.com/en-us/library/gg675461(v=exchg.80).aspx
-        //_wbxml.atag("DeepTraversal");
-        //_wbxml.atag("RebuildResults");
-        _wbxml.ctag();
-        _wbxml.ctag();
-        _wbxml.ctag();
-
-        let wbxml = _wbxml.getBytes();
-
-        eas.network.logXML(wbxml, "Send (GAL Search)");
-        let command = "Search";
-
-        let authData = eas.network.getAuthData(accountData);
-        let oauthData = eas.network.getOAuthObj({ accountData });
-        let userAgent = accountData.getAccountProperty("useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2
-        let deviceType = accountData.getAccountProperty("devicetype");
-        let deviceId = accountData.getAccountProperty("deviceId");
-
-        TbSync.dump("Sending (EAS v" + accountData.getAccountProperty("asversion") + ")", "POST " + eas.network.getEasURL(accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(authData.user) + '&DeviceType=' + deviceType + '&DeviceId=' + deviceId, true);
-
-        for (let i = 0; i < 2; i++) {
-            // check OAuth situation before connecting
-            if (oauthData && (!oauthData.getToken("accessToken") || oauthData.isExpired())) {
-                let _rv = {}
-                if (!(await oauthData.asyncConnect(_rv))) {
-                    throw eas.sync.finish("error", _rv.error);
-                }
-            }
-
-            try {
-                let contextData = eas.network.getContextData({ accountData });
-                let uri = Services.io.newURI(eas.network.getEasURL(accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(authData.user) + '&DeviceType=' + encodeURIComponent(deviceType) + '&DeviceId=' + deviceId);
-                let response = await new Promise(function (resolve, reject) {
-                    let req = getSandBoxedXHR(contextData, uri);
-                    req.mozBackgroundRequest = true;
-                    req.open("POST", uri.spec, true);
-                    req.overrideMimeType("text/plain");
-                    req.setRequestHeader("User-Agent", userAgent);
-                    req.setRequestHeader("Content-Type", "application/vnd.ms-sync.wbxml");
-
-                    if (authData.password) {
-                        if (eas.network.getOAuthObj({ accountData })) {
-                            req.setRequestHeader("Authorization", 'Bearer ' + eas.network.getOAuthValue(authData.password, "access"));
-                        } else {
-                            req.setRequestHeader("Authorization", 'Basic ' + TbSync.tools.b64encode(authData.user + ':' + authData.password));
-                        }
-                    }
-
-                    if (accountData.getAccountProperty("asversion") == "2.5") {
-                        req.setRequestHeader("MS-ASProtocolVersion", "2.5");
-                    } else {
-                        req.setRequestHeader("MS-ASProtocolVersion", "14.0");
-                    }
-                    req.setRequestHeader("Content-Length", wbxml.length);
-                    if (accountData.getAccountProperty("provision")) {
-                        req.setRequestHeader("X-MS-PolicyKey", accountData.getAccountProperty("policykey"));
-                        TbSync.dump("PolicyKey used", accountData.getAccountProperty("policykey"));
-                    }
-
-                    req.timeout = eas.Base.getConnectionTimeout();
-
-                    req.ontimeout = function () {
-                        reject("GAL Search timeout");
-                    };
-
-                    req.onerror = function () {
-                        reject("GAL Search Error");
-                    };
-
-                    req.onload = function () {
-                        let response = req.responseText;
-
-                        switch (req.status) {
-
-                            case 200: //OK
-                                eas.network.logXML(response, "Received (GAL Search");
-
-                                //What to do on error? IS this an error? Yes!
-                                if (response.length !== 0 && response.substr(0, 4) !== String.fromCharCode(0x03, 0x01, 0x6A, 0x00)) {
-                                    TbSync.dump("Recieved Data", "Expecting WBXML but got junk (request status = " + req.status + ", ready state = " + req.readyState + "\n>>>>>>>>>>\n" + response + "\n<<<<<<<<<<\n");
-                                    reject("GAL Search Response Invalid");
-                                } else {
-                                    resolve(response);
-                                }
-                                break;
-
-                            case 401: // bad auth
-                                resolve("401");
-                                break;
-
-                            default:
-                                reject("GAL Search Failed: " + req.status);
-                        }
-                    };
-
-                    req.send(wbxml);
-
-                });
-
-                if (response === "401") {
-                    // try to recover from bad auth via token refresh
-                    if (oauthData) {
-                        await oauthData.setToken("accessToken", "");
-                        continue;
-                    }
-                }
-
-                return response;
-            } catch (e) {
-                Components.utils.reportError(e);
-                return;
-            }
-        }
-    },
-
-
-
-
-
-
-
-
-
-
-    // OPTIONS
-
-    getServerOptions: async function (syncData) {
-        syncData.setSyncState("prepare.request.options");
-        let authData = eas.network.getAuthData(syncData.accountData);
-
-        let userAgent = syncData.accountData.getAccountProperty("useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2
-        TbSync.dump("Sending", "OPTIONS " + eas.network.getEasURL(syncData.accountData));
-
-        let allowedRetries = 5;
-        let retry;
-        let oauthData = eas.network.getOAuthObj({ accountData: syncData.accountData });
-
-        do {
-            retry = false;
-
-            // Check OAuth situation before connecting
-            if (oauthData && (!oauthData.getToken("accessToken") || oauthData.isExpired())) {
-                let _rv = {};
-                syncData.setSyncState("oauthprompt");
-                if (!(await oauthData.asyncConnect(_rv))) {
-                    throw eas.sync.finish("error", _rv.error);
-                }
-            }
-
-            let contextData = eas.network.getContextData({ accountData: syncData.accountData });
-            let uri = Services.io.newURI(eas.network.getEasURL(syncData.accountData));
-            let result = await new Promise(function (resolve, reject) {
-                syncData.req = getSandBoxedXHR(contextData, uri);
-                syncData.req.mozBackgroundRequest = true;
-                syncData.req.open("OPTIONS", uri.spec, true);
-                syncData.req.overrideMimeType("text/plain");
-                syncData.req.setRequestHeader("User-Agent", userAgent);
-                if (authData.password) {
-                    if (eas.network.getOAuthObj({ accountData: syncData.accountData })) {
-                        syncData.req.setRequestHeader("Authorization", 'Bearer ' + eas.network.getOAuthValue(authData.password, "access"));
-                    } else {
-                        syncData.req.setRequestHeader("Authorization", 'Basic ' + TbSync.tools.b64encode(authData.user + ':' + authData.password));
-                    }
-                }
-                syncData.req.timeout = eas.Base.getConnectionTimeout();
-
-                syncData.req.ontimeout = function () {
-                    resolve();
-                };
-
-                syncData.req.onerror = function () {
-                    let responseData = {};
-                    responseData["MS-ASProtocolVersions"] = syncData.req.getResponseHeader("MS-ASProtocolVersions");
-                    responseData["MS-ASProtocolCommands"] = syncData.req.getResponseHeader("MS-ASProtocolCommands");
-
-                    TbSync.dump("EAS OPTIONS with response (status: " + syncData.req.status + ")", "\n" +
-                        "responseText: " + syncData.req.responseText + "\n" +
-                        "responseHeader(MS-ASProtocolVersions): " + responseData["MS-ASProtocolVersions"] + "\n" +
-                        "responseHeader(MS-ASProtocolCommands): " + responseData["MS-ASProtocolCommands"]);
-                    resolve();
-                };
-
-                syncData.req.onload = function () {
-                    syncData.setSyncState("eval.request.options");
-                    let responseData = {};
-
-                    switch (syncData.req.status) {
-                        case 401: // AuthError
-                            let rv = {};
-                            rv.errorObj = eas.sync.finish("error", "401");
-                            rv.errorType = "PasswordPrompt";
-                            resolve(rv);
-                            break;
-
-                        case 200:
-                            responseData["MS-ASProtocolVersions"] = syncData.req.getResponseHeader("MS-ASProtocolVersions");
-                            responseData["MS-ASProtocolCommands"] = syncData.req.getResponseHeader("MS-ASProtocolCommands");
-
-                            TbSync.dump("EAS OPTIONS with response (status: 200)", "\n" +
-                                "responseText: " + syncData.req.responseText + "\n" +
-                                "responseHeader(MS-ASProtocolVersions): " + responseData["MS-ASProtocolVersions"] + "\n" +
-                                "responseHeader(MS-ASProtocolCommands): " + responseData["MS-ASProtocolCommands"]);
-
-                            if (responseData && responseData["MS-ASProtocolCommands"] && responseData["MS-ASProtocolVersions"]) {
-                                syncData.accountData.setAccountProperty("allowedEasCommands", responseData["MS-ASProtocolCommands"]);
-                                syncData.accountData.setAccountProperty("allowedEasVersions", responseData["MS-ASProtocolVersions"]);
-                                syncData.accountData.setAccountProperty("lastEasOptionsUpdate", Date.now());
-                            }
-                            resolve();
-                            break;
-
-                        default:
-                            resolve();
-                            break;
-
-                    }
-                };
-
-                syncData.setSyncState("send.request.options");
-                syncData.req.send();
-
-            });
-
-            if (result && result.hasOwnProperty("errorType") && result.errorType == "PasswordPrompt") {
-                if (allowedRetries > 0) {
-                    if (oauthData) {
-                        await oauthData.setToken("accessToken", "");
-                        retry = true;
-                    } else {
-                        syncData.setSyncState("passwordprompt");
-                        let authData = eas.network.getAuthData(syncData.accountData);
-                        let promptData = {
-                            windowID: "auth:" + syncData.accountData.accountID,
-                            accountname: syncData.accountData.getAccountProperty("accountname"),
-                            usernameLocked: syncData.accountData.isConnected(),
-                            username: authData.user
-                        }
-                        let credentials = await TbSync.passwordManager.asyncPasswordPrompt(promptData, eas.openWindows);
-                        if (credentials) {
-                            await authData.updateLoginData(credentials.username, credentials.password);
-                            retry = true;
-                        }
-                    }
-                }
-
-                if (!retry) {
-                    throw result.errorObj;
-                }
-            }
-
-            allowedRetries--;
-        } while (retry);
-    },
-
-
-
-
-
-
-
-
-
-
-    // AUTODISCOVER
-
-    updateServerConnectionViaAutodiscover: async function (syncData) {
-        syncData.setSyncState("prepare.request.autodiscover");
-        let authData = eas.network.getAuthData(syncData.accountData);
-
-        syncData.setSyncState("send.request.autodiscover");
-        let result = await eas.network.getServerConnectionViaAutodiscover(authData.accountname, authData.user, authData.password, 30 * 1000);
-
-        syncData.setSyncState("eval.response.autodiscover");
-        if (result.errorcode == 200) {
-            //update account
-            syncData.accountData.setAccountProperty("host", eas.network.stripAutodiscoverUrl(result.server));
-            syncData.accountData.setAccountProperty("user", result.user);
-            syncData.accountData.setAccountProperty("https", (result.server.substring(0, 5) == "https"));
-        }
-
-        return result.errorcode;
-    },
-
-    stripAutodiscoverUrl: function (url) {
-        let u = url;
-        while (u.endsWith("/")) { u = u.slice(0, -1); }
-        if (u.endsWith("/Microsoft-Server-ActiveSync")) u = u.slice(0, -28);
-        else TbSync.dump("Received non-standard EAS url via autodiscover:", url);
-
-        return u.split("//")[1]; //cut off protocol
-    },
-
-    getServerConnectionViaAutodiscover: async function (accountname, user, password, maxtimeout) {
-        let urls = [];
-        let parts = user.split("@");
-
-        urls.push({ "url": "https://autodiscover." + parts[1] + "/autodiscover/autodiscover.xml", "user": user });
-        urls.push({ "url": "https://" + parts[1] + "/autodiscover/autodiscover.xml", "user": user });
-        urls.push({ "url": "https://autodiscover." + parts[1] + "/Autodiscover/Autodiscover.xml", "user": user });
-        urls.push({ "url": "https://" + parts[1] + "/Autodiscover/Autodiscover.xml", "user": user });
-
-        urls.push({ "url": "http://autodiscover." + parts[1] + "/autodiscover/autodiscover.xml", "user": user });
-        urls.push({ "url": "http://" + parts[1] + "/autodiscover/autodiscover.xml", "user": user });
-        urls.push({ "url": "http://autodiscover." + parts[1] + "/Autodiscover/Autodiscover.xml", "user": user });
-        urls.push({ "url": "http://" + parts[1] + "/Autodiscover/Autodiscover.xml", "user": user });
-
-        let requests = [];
-        let responses = []; //array of objects {url, error, server}
-
-        for (let i = 0; i < urls.length; i++) {
-            await TbSync.tools.sleep(200);
-            requests.push(eas.network.getServerConnectionViaAutodiscoverRedirectWrapper(
-                accountname,
-                urls[i].url,
-                urls[i].user,
-                password,
-                maxtimeout
-            ));
-        }
-
-        try {
-            responses = await Promise.all(requests);
-        } catch (e) {
-            responses.push(e.result); //this is actually a success, see return value of getServerConnectionViaAutodiscoverRedirectWrapper()
-        }
-
-        let result;
-        let log = [];
-        for (let r = 0; r < responses.length; r++) {
-            log.push("*  " + responses[r].url + " @ " + responses[r].user + " : " + (responses[r].server ? responses[r].server : responses[r].error));
-
-            if (responses[r].server) {
-                result = { "server": responses[r].server, "user": responses[r].user, "error": "", "errorcode": 200 };
-                break;
-            }
-
-            if (responses[r].error == 403 || responses[r].error == 401) {
-                //we could still find a valid server, so just store this state
-                result = { "server": "", "user": responses[r].user, "errorcode": responses[r].error, "error": TbSync.getString("status." + responses[r].error, "eas") };
-            }
-        }
-
-        //this is only reached on fail, if no result defined yet, use general error
-        if (!result) {
-            result = { "server": "", "user": user, "error": TbSync.getString("autodiscover.Failed", "eas").replace("##user##", user), "errorcode": 503 };
-        }
-
-        TbSync.eventlog.add("error", new TbSync.EventLogInfo("eas"), result.error, log.join("\n"));
-        return result;
-    },
-
-    getServerConnectionViaAutodiscoverRedirectWrapper: async function (accountname, url, user, password, maxtimeout) {
-        let result = {};
-        let method = "POST";
-        let connection = { accountname, url, user };
-
-        do {
-            await TbSync.tools.sleep(200);
-            result = await eas.network.getServerConnectionViaAutodiscoverRequest(method, connection, password, maxtimeout);
-            method = "";
-
-            if (result.error == "redirect found") {
-                TbSync.dump("EAS autodiscover URL redirect", "\n" + connection.url + " @ " + connection.user + " => \n" + result.url + " @ " + result.user);
-                connection.url = result.url;
-                connection.user = result.user;
-                method = "POST";
-            }
-
-        } while (method);
-
-        //invert reject and resolve, so we exit the promise group on success right away
-        if (result.server) {
-            let e = new Error("Not an error (early exit from promise group)");
-            e.result = result;
-            throw e;
-        } else {
-            return result;
-        }
-    },
-
-    getServerConnectionViaAutodiscoverRequest: function (method, connection, password, maxtimeout) {
-        TbSync.dump("Querry EAS autodiscover URL", connection.url + " @ " + connection.user);
-
-        return new Promise(function (resolve, reject) {
-
-            let xml = '<?xml version="1.0" encoding="utf-8"?>\r\n';
-            xml += '<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/requestschema/2006">\r\n';
-            xml += '<Request>\r\n';
-            xml += '<EMailAddress>' + connection.user + '</EMailAddress>\r\n';
-            xml += '<AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006</AcceptableResponseSchema>\r\n';
-            xml += '</Request>\r\n';
-            xml += '</Autodiscover>\r\n';
-
-            let userAgent = eas.prefs.getCharPref("clientID.useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2
-            let uri = Services.io.newURI(connection.url);
-            let req = getSandBoxedXHR(connection, uri);
-            req.mozBackgroundRequest = true;
-            req.open(method, uri.spec, true);
-            req.timeout = maxtimeout;
-            req.setRequestHeader("User-Agent", userAgent);
-
-            let secure = (connection.url.substring(0, 8).toLowerCase() == "https://");
-
-            if (method == "POST") {
-                req.setRequestHeader("Content-Length", xml.length);
-                req.setRequestHeader("Content-Type", "text/xml");
-                if (secure && password) {
-                    // OAUTH accounts cannot authenticate against the standard discovery services
-                    // updateServerConnectionViaAutodiscover() is not passing them on
-                    req.setRequestHeader("Authorization", "Basic " + TbSync.tools.b64encode(connection.user + ":" + password));
-                }
-            }
-
-            req.ontimeout = function () {
-                TbSync.dump("EAS autodiscover with timeout", "\n" + connection.url + " => \n" + req.responseURL);
-                resolve({ "url": req.responseURL, "error": "timeout", "server": "", "user": connection.user });
-            };
-
-            req.onerror = function () {
-                let error = TbSync.network.createTCPErrorFromFailedXHR(req);
-                if (!error) error = req.responseText;
-
-                // CORS violations can happen on redirects. They come back as NS_ERROR_DOM_BAD_URI.
-                if (error == "network::NS_ERROR_DOM_BAD_URI" && req.channel.URI.spec != uri.spec) {
-                    resolve({ "url": req.channel.URI.spec, "error": "redirect found", "server": "", "user": connection.user });
-                    return;
-                }
-
-                TbSync.dump("EAS autodiscover with error (" + error + ")", "\n" + connection.url + " => \n" + req.responseURL);
-                resolve({ "url": req.responseURL, "error": error, "server": "", "user": connection.user });
-            };
-
-            req.onload = function () {
-                //initiate rerun on redirects
-                if (req.responseURL != connection.url) {
-                    resolve({ "url": req.responseURL, "error": "redirect found", "server": "", "user": connection.user });
-                    return;
-                }
-
-                //ignore POST without autherization (we just do them to get redirect information)
-                if (!secure) {
-                    resolve({ "url": req.responseURL, "error": "unsecure POST", "server": "", "user": connection.user });
-                    return;
-                }
-
-                //evaluate secure POST requests which have not been redirected
-                TbSync.dump("EAS autodiscover POST with status (" + req.status + ")", "\n" + connection.url + " => \n" + req.responseURL + "\n[" + req.responseText + "]");
-
-                if (req.status === 200) {
-                    let data = null;
-                    // getDataFromXMLString may throw an error which cannot be catched outside onload,
-                    // because we are in an async callback of the surrounding Promise
-                    // Alternatively we could just return the responseText and do any data analysis outside of the Promise
-                    try {
-                        data = eas.xmltools.getDataFromXMLString(req.responseText);
-                    } catch (e) {
-                        resolve({ "url": req.responseURL, "error": "bad response", "server": "", "user": connection.user });
-                        return;
-                    }
-
-                    if (!(data === null) && data.Autodiscover && data.Autodiscover.Response && data.Autodiscover.Response.Action) {
-                        // "Redirect" or "Settings" are possible
-                        if (data.Autodiscover.Response.Action.Redirect) {
-                            // redirect, start again with new user
-                            let newuser = action.Redirect;
-                            resolve({ "url": req.responseURL, "error": "redirect found", "server": "", "user": newuser });
-
-                        } else if (data.Autodiscover.Response.Action.Settings) {
-                            // get server settings
-                            let server = eas.xmltools.nodeAsArray(data.Autodiscover.Response.Action.Settings.Server);
-
-                            for (let count = 0; count < server.length; count++) {
-                                if (server[count].Type == "MobileSync" && server[count].Url) {
-                                    resolve({ "url": req.responseURL, "error": "", "server": server[count].Url, "user": connection.user });
-                                    return;
-                                }
-                            }
-                        }
-                    } else {
-                        resolve({ "url": req.responseURL, "error": "invalid", "server": "", "user": connection.user });
-                    }
-                } else {
-                    resolve({ "url": req.responseURL, "error": req.status, "server": "", "user": connection.user });
-                }
-            };
-
-            req.send(xml);
-        });
-    },
-
-    getServerConnectionViaAutodiscoverV2JsonRequest: function (accountname, user, url, maxtimeout) {
-        TbSync.dump("Querry EAS autodiscover V2 URL", url);
-
-        return new Promise(function (resolve, reject) {
-
-            let userAgent = eas.prefs.getCharPref("clientID.useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2
-            let uri = Services.io.newURI(url);
-            let req = getSandBoxedXHR({ accountname, user }, uri);
-            req.mozBackgroundRequest = true;
-            req.open("GET", uri.spec, true);
-            req.timeout = maxtimeout;
-            req.setRequestHeader("User-Agent", userAgent);
-
-            req.ontimeout = function () {
-                TbSync.dump("EAS autodiscover V2 with timeout", "\n" + url + " => \n" + req.responseURL);
-                resolve({ "url": req.responseURL, "error": "timeout", "server": "" });
-            };
-
-            req.onerror = function () {
-                let error = TbSync.network.createTCPErrorFromFailedXHR(req);
-                if (!error) error = req.responseText;
-                TbSync.dump("EAS autodiscover V2 with error (" + error + ")", "\n" + url + " => \n" + req.responseURL);
-                resolve({ "url": req.responseURL, "error": error, "server": "" });
-            };
-
-            req.onload = function () {
-                if (req.status === 200) {
-                    let data = JSON.parse(req.responseText);
-
-                    if (data && data.Url) {
-                        resolve({ "url": req.responseURL, "error": "", "server": eas.network.stripAutodiscoverUrl(data.Url) });
-                    } else {
-                        resolve({ "url": req.responseURL, "error": "invalid", "server": "" });
-                    }
-                    return;
-                }
-
-                resolve({ "url": req.responseURL, "error": req.status, "server": "" });
-            };
-
-            req.send();
-        });
-    }
-}
+/*
+ * This file is part of EAS-4-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 { OAuth2 } = ChromeUtils.importESModule(
+    "resource:///modules/OAuth2.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 containers = [];
+var sandboxes = {};
+
+function resetContainerWithId(id) {
+    Services.clearData.deleteDataFromOriginAttributesPattern({ userContextId: id });
+}
+
+function getContainerIdForContainerName(containerName) {
+    // Define the allowed range of container ids to be used
+    // TbSync is using 10000 - 19999
+    // Lightning is using 20000 - 29999
+    // Cardbook is using 30000 - 39999
+    let min = 10000;
+    let max = 19999;
+
+    //reset if adding an entry will exceed allowed range
+    if (containers.length > (max - min) && containers.indexOf(containerName) == -1) {
+        for (let i = 0; i < containers.length; i++) {
+            resetContainerWithId(i + min);
+        }
+        containers = [];
+    }
+
+    let idx = containers.indexOf(containerName);
+    return (idx == -1) ? containers.push(containerName) - 1 + min : (idx + min);
+}
+
+function getSandBoxedXHR({ user, accountname }, uri, containerReset = false) {
+    // The content principal used for the sandbox honours CORS. A server redirect
+    // to a different server may cause CORS violations. We implemented code to
+    // catch such redirects and re-run the request with the correct sandbox. If
+    // that becomes an issue, we need to make sandboxing optional.
+    // return new XMLHttpRequest({ mozAnon: false });
+
+    let containerName = `${accountname}::${user}@${uri.scheme}://${uri.hostPort}`;
+
+    let userContextId = getContainerIdForContainerName(containerName);
+    if (containerReset) {
+        resetContainerWithId(userContextId);
+    }
+    
+    // Pre-set cookie needed by eas.outlook.com. The cookie is returned with each
+    // server response, but is is SameSite=None without the secure flag being set
+    // and ignored.
+    if (uri.host == "eas.outlook.com") {
+        Services.cookies.add(
+            "eas.outlook.com",
+            "/",
+            "DefaultAnchorMailbox",
+            user,
+            /* isSecure */ true,
+            /* isHttponly */ false,
+            /* isSession = */ false,
+            /* expiry */ Number.MAX_SAFE_INTEGER,
+            { userContextId },
+            Ci.nsICookie.SAMESITE_NONE,
+            Ci.nsICookie.SCHEME_HTTPS,
+            /* partitioned */ false
+        );
+    }
+    if (!sandboxes.hasOwnProperty(containerName)) {
+        console.log("Creating sandbox for <" + containerName + ">");
+        let principal = Services.scriptSecurityManager.createContentPrincipal(uri, { userContextId });
+        sandboxes[containerName] = Components.utils.Sandbox(principal, {
+            wantXrays: true,
+            wantGlobalProperties: ["XMLHttpRequest"],
+        });
+    }
+    return new sandboxes[containerName].XMLHttpRequest({ mozAnon: false });
+}
+
+var network = {
+
+    getEasURL: function (accountData) {
+        let protocol = (accountData.getAccountProperty("https")) ? "https://" : "http://";
+        let h = protocol + accountData.getAccountProperty("host");
+        while (h.endsWith("/")) { h = h.slice(0, -1); }
+
+        if (h.endsWith("Microsoft-Server-ActiveSync")) return h;
+        return h + "/Microsoft-Server-ActiveSync";
+    },
+
+    getAuthData: function (accountData) {
+        let authData = {
+            // This is the host for the password manager, which could be different from
+            // the actual host property of the account. For EAS we want to couple the password
+            // with the ACCOUNT and not any sort of url, which could change via autodiscover
+            // at any time.
+            get host() {
+                return "TbSync#" + accountData.accountID;
+            },
+
+            get user() {
+                return accountData.getAccountProperty("user");
+            },
+
+            get password() {
+                return TbSync.passwordManager.getLoginInfo(this.host, "TbSync/EAS", this.user);
+            },
+
+            get accountname() {
+                return accountData.getAccountProperty("accountname");
+            },
+
+            updateLoginData: async function (newUsername, newPassword) {
+                let oldUsername = this.user;
+                await TbSync.passwordManager.updateLoginInfo(this.host, "TbSync/EAS", oldUsername, newUsername, newPassword);
+                // Also update the username of this account. Add dedicated username setter?
+                accountData.setAccountProperty("user", newUsername);
+            },
+
+            removeLoginData: function () {
+                TbSync.passwordManager.removeLoginInfos(this.host, "TbSync/EAS");
+            }
+        };
+        return authData;
+    },
+
+    getContextData: function (configObject = null) {
+        let contextData = {}
+        contextData.accountData = (configObject && configObject.hasOwnProperty("accountData")) ? configObject.accountData : null;
+
+        if (contextData.accountData) {
+            contextData.accountname = contextData.accountData.getAccountProperty("accountname");
+            contextData.user = contextData.accountData.getAccountProperty("user");
+            contextData.host = contextData.accountData.getAccountProperty("host");
+            contextData.servertype = contextData.accountData.getAccountProperty("servertype");
+            contextData.accountID = contextData.accountData.accountID;
+        } else {
+            contextData.accountname = (configObject && configObject.hasOwnProperty("accountname")) ? configObject.accountname : "";
+            contextData.user = (configObject && configObject.hasOwnProperty("user")) ? configObject.user : "";
+            contextData.host = (configObject && configObject.hasOwnProperty("host")) ? configObject.host : "";
+            contextData.servertype = (configObject && configObject.hasOwnProperty("servertype")) ? configObject.servertype : "";
+            contextData.accountID = "";
+        }
+
+        return contextData;
+    },
+
+    // prepare and patch OAuth2 object
+    getOAuthObj: function (configObject = null) {
+        let {
+            accountData,
+            accountname,
+            user,
+            host,
+            accountID,
+            servertype
+        } = this.getContextData(configObject);
+
+        if (!["office365"].includes(servertype))
+            return null;
+
+        let config = {};
+        let customID = eas.Base.getCustomeOauthClientID();
+        switch (host) {
+            case "outlook.office365.com":
+            case "eas.outlook.com":
+                config = {
+                    auth_uri: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
+                    token_uri: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
+                    redirect_uri: "https://login.microsoftonline.com/common/oauth2/nativeclient",
+                    client_id: customID != "" ? customID : "2980deeb-7460-4723-864a-f9b0f10cd992",
+                }
+                break;
+
+            default:
+                return null;
+        }
+
+        switch (host) {
+            case "outlook.office365.com":
+                config.scope = "offline_access https://outlook.office.com/.default";
+                break;
+            case "eas.outlook.com":
+                config.scope = "offline_access https://outlook.office.com/EAS.AccessAsUser.All";
+                break;
+        }
+
+        let oauth = new OAuth2(config.scope, {
+            authorizationEndpoint: config.auth_uri,
+            tokenEndpoint: config.token_uri,
+            clientId: config.client_id,
+            clientSecret: config.client_secret
+        });
+        oauth.requestWindowFeatures = "chrome,private,centerscreen,width=500,height=750";
+
+        // The v2 redirection endpoint differs from the default and needs manual override
+        oauth.redirectionEndpoint = config.redirect_uri;
+
+        oauth.extraAuthParams = [
+            // removed in beta 1.14.1, according to
+            // https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#default-and-consent
+            // prompt = consent will always ask for admin consent, even if it was granted
+            //["prompt", "consent"],
+            ["login_hint", user],
+        ];
+
+        if (accountname) {
+            oauth.requestWindowTitle = "TbSync account <" + accountname + "> requests authorization.";
+        } else {
+            oauth.requestWindowTitle = "A TbSync account requests authorization.";
+        }
+
+
+
+
+        /* Adding custom methods to the oauth object */
+
+        oauth.asyncConnect = async function (rv) {
+            rv.error = "";
+            // This function gets called if we have no accessToken, or the token
+            // is expired. Load current data from password manager into the
+            // properties used by the OAuth module.
+            oauth.accessToken = oauth.getToken("accessToken");
+            oauth.refreshToken = oauth.getToken("refreshToken");
+            oauth.tokenExpires = oauth.getToken("tokenExpires");
+
+            try {
+                // refresh = false will do nothing and resolve immediately, if
+                // a valid accessToken exists.
+                await oauth.connect(/* with UI */ true, /* refresh */ false);
+            } catch (e) {
+                rv.error = eas.tools.isString(e) ? e : JSON.stringify(e);
+            }
+
+            await oauth.setToken("accessToken", oauth.accessToken);
+            await oauth.setToken("refreshToken", oauth.refreshToken);
+            await oauth.setToken("tokenExpires", oauth.tokenExpires);
+            rv.tokens = oauth.tokens;
+
+            if (!rv.error) {
+                return true;
+            }
+
+            try {
+                switch (JSON.parse(rv.error).error) {
+                    case "invalid_grant":
+                        await oauth.setToken("accessToken", "");
+                        await oauth.setToken("refreshToken", "");
+                        await oauth.setToken("tokenExpires", 0);
+                        rv.tokens = oauth.tokens;
+                        return true;
+
+                    case "cancelled":
+                        rv.error = "OAuthAbortError";
+                        break;
+
+                    default:
+                        rv.error = "OAuthServerError::" + rv.error;
+                        break;
+                }
+            } catch (e) {
+                rv.error = "OAuthServerError::" + rv.error;
+                Components.utils.reportError(e);
+            }
+            rv.tokens = oauth.tokens;
+            return false;
+        };
+
+        oauth.isExpired = function () {
+            const OAUTH_GRACE_TIME = 30 * 1000;
+            return (oauth.getToken("tokenExpires") - OAUTH_GRACE_TIME < new Date().getTime());
+        };
+
+        const OAUTHVALUES = [
+            ["access", "", "accessToken"],
+            ["refresh", "", "refreshToken"],
+            ["expires", Number.MAX_VALUE, "tokenExpires"],
+        ];
+
+        // returns a JSON string containing all the oauth values
+        Object.defineProperty(oauth, "tokens", {
+            get: function () {
+                let tokensObj = {};
+                for (let oauthValue of OAUTHVALUES) {
+                    // use the system value or if not defined the default
+                    tokensObj[oauthValue[0]] = this[oauthValue[2]] || oauthValue[1];
+                }
+                return JSON.stringify(tokensObj);
+            },
+            enumerable: true,
+        });
+
+        if (accountData) {
+            // authData allows us to access the password manager values belonging to this account/calendar
+            // simply by authdata.username and authdata.password
+            oauth.authData = TbSync.providers.eas.network.getAuthData(accountData);
+
+            oauth.parseAndSanitizeTokenString = function (tokenString) {
+                let _tokensObj = {};
+                try {
+                    _tokensObj = JSON.parse(tokenString);
+                } catch (e) { }
+
+                let tokensObj = {};
+                for (let oauthValue of OAUTHVALUES) {
+                    // use the provided value or if not defined the default
+                    tokensObj[oauthValue[0]] = (_tokensObj && _tokensObj.hasOwnProperty(oauthValue[0]))
+                        ? _tokensObj[oauthValue[0]]
+                        : oauthValue[1];
+                }
+                return tokensObj;
+            };
+
+            oauth.getToken = function (tokenName) {
+                let oauthValue = OAUTHVALUES.find(e => e[2] == tokenName);
+                return oauth.parseAndSanitizeTokenString(oauth.authData.password)[oauthValue[0]];
+            };
+
+            oauth.setToken = async function (tokenName, val) {
+                oauth[tokenName] = val;
+
+                let oauthValue = OAUTHVALUES.find(e => e[2] == tokenName);
+                let tokens = oauth.parseAndSanitizeTokenString(oauth.authData.password);
+                let valueChanged = (val != tokens[oauthValue[0]])
+                if (valueChanged) {
+                    tokens[oauthValue[0]] = val;
+                    await oauth.authData.updateLoginData(oauth.authData.user, JSON.stringify(tokens));
+                }
+            };
+        } else {
+            oauth.getToken = function (tokenName) {
+                return oauth[tokenName];
+            };
+
+            oauth.setToken = async function (tokenName, val) {
+                oauth[tokenName] = val;
+            };
+        }
+
+        return oauth;
+    },
+
+    getOAuthValue: function (currentTokenString, type = "access") {
+        try {
+            let tokens = JSON.parse(currentTokenString);
+            if (tokens.hasOwnProperty(type))
+                return tokens[type];
+        } catch (e) {
+            //NOOP
+        }
+        return "";
+    },
+
+    sendRequest: async function (wbxml, command, syncData, allowSoftFail = false) {
+        let ALLOWED_RETRIES = {
+            PasswordPrompt: 3,
+            NetworkError: 1,
+        }
+
+        let rv = {};
+        let oauthData = eas.network.getOAuthObj({ accountData: syncData.accountData });
+        let syncState = syncData.getSyncState().state;
+
+        for (; ;) {
+
+            if (rv.errorType) {
+                let retry = false;
+
+                if (ALLOWED_RETRIES[rv.errorType] > 0) {
+                    ALLOWED_RETRIES[rv.errorType]--;
+
+
+                    switch (rv.errorType) {
+
+                        case "PasswordPrompt":
+                            {
+
+                                if (oauthData) {
+                                    await oauthData.setToken("accessToken", "");
+                                    retry = true;
+                                } else {
+                                    let authData = eas.network.getAuthData(syncData.accountData);
+                                    syncData.setSyncState("passwordprompt");
+                                    let promptData = {
+                                        windowID: "auth:" + syncData.accountData.accountID,
+                                        accountname: syncData.accountData.getAccountProperty("accountname"),
+                                        usernameLocked: syncData.accountData.isConnected(),
+                                        username: authData.user
+                                    }
+                                    let credentials = await TbSync.passwordManager.asyncPasswordPrompt(promptData, eas.openWindows);
+                                    if (credentials) {
+                                        retry = true;
+                                        await authData.updateLoginData(credentials.username, credentials.password);
+                                    }
+                                }
+                            }
+                            break;
+
+                        case "NetworkError":
+                            {
+                                // Could not connect to server. Can we rerun autodiscover?
+                                // Note: Autodiscover is currently not supported by OAuth
+                                if (syncData.accountData.getAccountProperty("servertype") == "auto" && !oauthData) {
+                                    let errorcode = await eas.network.updateServerConnectionViaAutodiscover(syncData);
+                                    console.log("ERR: " + errorcode);
+                                    if (errorcode == 200) {
+                                        // autodiscover succeeded, retry with new data
+                                        retry = true;
+                                    } else if (errorcode == 401) {
+                                        // manipulate rv to run password prompt
+                                        ALLOWED_RETRIES[rv.errorType]++;
+                                        rv.errorType = "PasswordPrompt";
+                                        rv.errorObj = eas.sync.finish("error", "401");
+                                        continue; // with the next loop, skip connection to the server
+                                    }
+                                }
+                            }
+                            break;
+
+                    }
+                }
+
+                if (!retry) throw rv.errorObj;
+            }
+
+            // check OAuth situation before connecting
+            if (oauthData && (!oauthData.getToken("accessToken") || oauthData.isExpired())) {
+                syncData.setSyncState("oauthprompt");
+                let _rv = {}
+                if (!(await oauthData.asyncConnect(_rv))) {
+                    throw eas.sync.finish("error", _rv.error);
+                }
+            }
+
+            // Return to original syncstate
+            if (syncState != syncData.getSyncState().state) {
+                syncData.setSyncState(syncState);
+            }
+            rv = await this.sendRequestPromise(wbxml, command, syncData, allowSoftFail);
+
+            if (rv.errorType) {
+                // make sure, there is a valid ALLOWED_RETRIES setting for the returned error
+                if (rv.errorType && !ALLOWED_RETRIES.hasOwnProperty(rv.errorType)) {
+                    ALLOWED_RETRIES[rv.errorType] = 1;
+                }
+            } else {
+                return rv;
+            }
+        }
+    },
+
+    sendRequestPromise: function (wbxml, command, syncData, allowSoftFail = false) {
+        let msg = "Sending data <" + syncData.getSyncState().state + "> for " + syncData.accountData.getAccountProperty("accountname");
+        if (syncData.currentFolderData) msg += " (" + syncData.currentFolderData.getFolderProperty("foldername") + ")";
+        syncData.request = eas.network.logXML(wbxml, msg);
+        syncData.response = "";
+
+        let connection = eas.network.getAuthData(syncData.accountData);
+        let userAgent = syncData.accountData.getAccountProperty("useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2
+        let deviceType = syncData.accountData.getAccountProperty("devicetype");
+        let deviceId = syncData.accountData.getAccountProperty("deviceId");
+
+        TbSync.dump("Sending (EAS v" + syncData.accountData.getAccountProperty("asversion") + ")", "POST " + eas.network.getEasURL(syncData.accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(connection.user) + '&DeviceType=' + deviceType + '&DeviceId=' + deviceId, true);
+
+        const textEncoder = new TextEncoder();
+        let encoded = textEncoder.encode(wbxml);
+        // console.log("wbxml: " + wbxml);
+        // console.log("byte array: " + encoded);
+        // console.log("length :" + wbxml.length + " vs " + encoded.byteLength + " vs " + encoded.length);
+
+        let contextData = eas.network.getContextData({ accountData: syncData.accountData });
+        let uri = Services.io.newURI(eas.network.getEasURL(syncData.accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(connection.user) + '&DeviceType=' + encodeURIComponent(deviceType) + '&DeviceId=' + deviceId);
+        return new Promise(function (resolve, reject) {
+            syncData.req = getSandBoxedXHR(contextData, uri);
+            syncData.req.mozBackgroundRequest = true;
+            syncData.req.open("POST", uri.spec, true);
+            syncData.req.overrideMimeType("text/plain");
+            syncData.req.setRequestHeader("User-Agent", userAgent);
+            syncData.req.setRequestHeader("Content-Type", "application/vnd.ms-sync.wbxml");
+            if (connection.password) {
+                if (eas.network.getOAuthObj({ accountData: syncData.accountData })) {
+                    syncData.req.setRequestHeader("Authorization", 'Bearer ' + eas.network.getOAuthValue(connection.password, "access"));
+                } else {
+                    syncData.req.setRequestHeader("Authorization", 'Basic ' + TbSync.tools.b64encode(connection.user + ':' + connection.password));
+                }
+            }
+
+            if (syncData.accountData.getAccountProperty("asversion") == "2.5") {
+                syncData.req.setRequestHeader("MS-ASProtocolVersion", "2.5");
+            } else {
+                syncData.req.setRequestHeader("MS-ASProtocolVersion", "14.0");
+            }
+            syncData.req.setRequestHeader("Content-Length", encoded.length);
+            if (syncData.accountData.getAccountProperty("provision")) {
+                syncData.req.setRequestHeader("X-MS-PolicyKey", syncData.accountData.getAccountProperty("policykey"));
+                TbSync.dump("PolicyKey used", syncData.accountData.getAccountProperty("policykey"));
+            }
+
+            syncData.req.timeout = eas.Base.getConnectionTimeout();
+
+            syncData.req.ontimeout = function () {
+                if (allowSoftFail) {
+                    resolve("");
+                } else {
+                    reject(eas.sync.finish("error", "timeout"));
+                }
+            };
+
+            syncData.req.onerror = function () {
+                if (allowSoftFail) {
+                    resolve("");
+                } else {
+                    let error = TbSync.network.createTCPErrorFromFailedXHR(syncData.req) || "networkerror";
+                    let rv = {};
+                    rv.errorObj = eas.sync.finish("error", error);
+                    rv.errorType = "NetworkError";
+                    resolve(rv);
+                }
+            };
+
+            syncData.req.onload = function () {
+                let response = syncData.req.responseText;
+
+                // Debug: Log received cookies.
+                const channel = syncData.req.channel.QueryInterface(Ci.nsIHttpChannel);
+                const SET_COOKIE_REGEXP = /set-cookie/i;
+                channel.visitOriginalResponseHeaders({
+                    visitHeader(name, value) {
+                        if (SET_COOKIE_REGEXP.test(name)) {
+                            console.log("Received cookie", value);
+                        }
+                    },
+                });
+
+                switch (syncData.req.status) {
+
+                    case 200: //OK
+                        let msg = "Receiving data <" + syncData.getSyncState().state + "> for " + syncData.accountData.getAccountProperty("accountname");
+                        if (syncData.currentFolderData) msg += " (" + syncData.currentFolderData.getFolderProperty("foldername") + ")";
+                        syncData.response = eas.network.logXML(response, msg);
+
+                        //What to do on error? IS this an error? Yes!
+                        if (!allowSoftFail && response.length !== 0 && response.substr(0, 4) !== String.fromCharCode(0x03, 0x01, 0x6A, 0x00)) {
+                            TbSync.dump("Recieved Data", "Expecting WBXML but got junk (request status = " + syncData.req.status + ", ready state = " + syncData.req.readyState + "\n>>>>>>>>>>\n" + response + "\n<<<<<<<<<<\n");
+                            reject(eas.sync.finish("warning", "invalid"));
+                        } else {
+                            resolve(response);
+                        }
+                        break;
+
+                    case 401: // AuthError
+                    case 403: // Forbiddden (some servers send forbidden on AuthError, like Freenet)
+                        let rv = {};
+                        rv.errorObj = eas.sync.finish("error", "401");
+                        rv.errorType = "PasswordPrompt";
+                        resolve(rv);
+                        break;
+
+                    case 449: // Request for new provision (enable it if needed)
+                        //enable provision
+                        syncData.accountData.setAccountProperty("provision", true);
+                        syncData.accountData.resetAccountProperty("policykey");
+                        reject(eas.sync.finish("resyncAccount", syncData.req.status));
+                        break;
+
+                    case 451: // Redirect - update host and login manager 
+                        let header = syncData.req.getResponseHeader("X-MS-Location");
+                        let newHost = header.slice(header.indexOf("://") + 3, header.indexOf("/M"));
+
+                        TbSync.dump("redirect (451)", "header: " + header + ", oldHost: " + syncData.accountData.getAccountProperty("host") + ", newHost: " + newHost);
+
+                        syncData.accountData.setAccountProperty("host", newHost);
+                        reject(eas.sync.finish("resyncAccount", syncData.req.status));
+                        break;
+
+                    default:
+                        if (allowSoftFail) {
+                            resolve("");
+                        } else {
+                            reject(eas.sync.finish("error", "httperror::" + syncData.req.status));
+                        }
+                }
+            };
+
+            syncData.req.send(encoded);
+
+        });
+    },
+
+
+
+
+
+
+
+
+
+
+    // RESPONSE EVALUATION
+
+    logXML: function (wbxml, what) {
+        let rawxml = eas.wbxmltools.convert2xml(wbxml);
+        let xml = null;
+        if (rawxml) {
+            xml = rawxml.split('><').join('>\n<');
+        }
+
+        //include xml in log, if userdatalevel 2 or greater
+        if (TbSync.prefs.getIntPref("log.userdatalevel") > 1) {
+
+            //log raw wbxml if userdatalevel is 3 or greater
+            if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) {
+                let charcodes = [];
+                for (let i = 0; i < wbxml.length; i++) charcodes.push(wbxml.charCodeAt(i).toString(16));
+                let bytestring = charcodes.join(" ");
+                TbSync.dump("WBXML: " + what, "\n" + bytestring);
+            }
+
+            if (xml) {
+                //raw xml is save xml with all special chars in user data encoded by encodeURIComponent - KEEP that in order to be able to analyze logged XML 
+                //let xml = decodeURIComponent(rawxml.split('><').join('>\n<'));
+                TbSync.dump("XML: " + what, "\n" + xml);
+            } else {
+                TbSync.dump("XML: " + what, "\nFailed to convert WBXML to XML!\n");
+            }
+        }
+
+        return xml;
+    },
+
+    //returns false on parse error and null on empty response (if allowed)
+    getDataFromResponse: function (wbxml, allowEmptyResponse = !eas.flags.allowEmptyResponse) {
+        //check for empty wbxml
+        if (wbxml.length === 0) {
+            if (allowEmptyResponse) return null;
+            else throw eas.sync.finish("warning", "empty-response");
+        }
+
+        //convert to save xml (all special chars in user data encoded by encodeURIComponent) and check for parse errors
+        let xml = eas.wbxmltools.convert2xml(wbxml);
+        if (xml === false) {
+            throw eas.sync.finish("warning", "wbxml-parse-error");
+        }
+
+        //retrieve data and check for empty data (all returned data fields are already decoded by decodeURIComponent)
+        let wbxmlData = eas.xmltools.getDataFromXMLString(xml);
+        if (wbxmlData === null) {
+            if (allowEmptyResponse) return null;
+            else throw eas.sync.finish("warning", "response-contains-no-data");
+        }
+
+        //debug
+        eas.xmltools.printXmlData(wbxmlData, false); //do not include ApplicationData in log
+        return wbxmlData;
+    },
+
+    updateSynckey: function (syncData, wbxmlData) {
+        let synckey = eas.xmltools.getWbxmlDataField(wbxmlData, "Sync.Collections.Collection.SyncKey");
+
+        if (synckey) {
+            // This COULD be a cause of problems... 
+            syncData.synckey = synckey;
+            syncData.currentFolderData.setFolderProperty("synckey", synckey);
+        } else {
+            throw eas.sync.finish("error", "wbxmlmissingfield::Sync.Collections.Collection.SyncKey");
+        }
+    },
+
+    checkStatus: function (syncData, wbxmlData, path, rootpath = "", allowSoftFail = false) {
+        //path is relative to wbxmlData
+        //rootpath is the absolute path and must be specified, if wbxml is not the root node and thus path is not the rootpath	    
+        let status = eas.xmltools.getWbxmlDataField(wbxmlData, path);
+        let fullpath = (rootpath == "") ? path : rootpath;
+        let elements = fullpath.split(".");
+        let type = elements[0];
+
+        //check if fallback to main class status: the answer could just be a "Sync.Status" instead of a "Sync.Collections.Collections.Status"
+        if (status === false) {
+            let mainStatus = eas.xmltools.getWbxmlDataField(wbxmlData, type + "." + elements[elements.length - 1]);
+            if (mainStatus === false) {
+                //both possible status fields are missing, abort
+                throw eas.sync.finish("warning", "wbxmlmissingfield::" + fullpath, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
+            } else {
+                //the alternative status could be extracted
+                status = mainStatus;
+                fullpath = type + "." + elements[elements.length - 1];
+            }
+        }
+
+        //check if all is fine (not bad)
+        if (status == "1") {
+            return "";
+        }
+
+        TbSync.dump("wbxml status check", type + ": " + fullpath + " = " + status);
+
+        //handle errrors based on type
+        let statusType = type + "." + status;
+        switch (statusType) {
+            case "Sync.3": /*
+                        MUST return to SyncKey element value of 0 for the collection. The client SHOULD either delete any items that were added 
+                        since the last successful Sync or the client MUST add those items back to the server after completing the full resynchronization
+                        */
+                TbSync.eventlog.add("warning", syncData.eventLogInfo, "Forced Folder Resync", "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
+                syncData.currentFolderData.remove();
+                throw eas.sync.finish("resyncFolder", statusType);
+
+            case "Sync.4": //Malformed request
+            case "Sync.5": //Temporary server issues or invalid item
+            case "Sync.6": //Invalid item
+            case "Sync.8": //Object not found
+                if (allowSoftFail) return statusType;
+                throw eas.sync.finish("warning", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
+
+            case "Sync.7": //The client has changed an item for which the conflict policy indicates that the server's changes take precedence.
+            case "Sync.9": //User account could be out of disk space, also send if no write permission (TODO)
+                return "";
+
+            case "FolderDelete.3": // special system folder - fatal error
+            case "FolderDelete.6": // error on server
+                throw eas.sync.finish("warning", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
+
+            case "FolderDelete.4": // folder does not exist - resync ( we allow delete only if folder is not subscribed )
+            case "FolderDelete.9": // invalid synchronization key - resync
+            case "FolderSync.9": // invalid synchronization key - resync
+            case "Sync.12": // folder hierarchy changed
+                {
+                    let folders = syncData.accountData.getAllFoldersIncludingCache();
+                    for (let folder of folders) {
+                        folder.remove();
+                    }
+                    // reset account
+                    eas.Base.onEnableAccount(syncData.accountData);
+                    throw eas.sync.finish("resyncAccount", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
+                }
+        }
+
+        //handle global error (https://msdn.microsoft.com/en-us/library/ee218647(v=exchg.80).aspx)
+        let descriptions = {};
+        switch (status) {
+            case "101": //invalid content
+            case "102": //invalid wbxml
+            case "103": //invalid xml
+                throw eas.sync.finish("error", "global." + status, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
+
+            case "109": descriptions["109"] = "DeviceTypeMissingOrInvalid";
+            case "112": descriptions["112"] = "ActiveDirectoryAccessDenied";
+            case "126": descriptions["126"] = "UserDisabledForSync";
+            case "127": descriptions["127"] = "UserOnNewMailboxCannotSync";
+            case "128": descriptions["128"] = "UserOnLegacyMailboxCannotSync";
+            case "129": descriptions["129"] = "DeviceIsBlockedForThisUser";
+            case "130": descriptions["120"] = "AccessDenied";
+            case "131": descriptions["131"] = "AccountDisabled";
+                throw eas.sync.finish("error", "global.clientdenied" + "::" + status + "::" + descriptions[status]);
+
+            case "110": //server error - abort and disable autoSync for 30 minutes
+                {
+                    let noAutosyncUntil = 30 * 60000 + Date.now();
+                    let humanDate = new Date(noAutosyncUntil).toUTCString();
+                    syncData.accountData.setAccountProperty("noAutosyncUntil", noAutosyncUntil);
+                    throw eas.sync.finish("error", "global." + status, "AutoSync disabled until: " + humanDate + " \n\nRequest:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
+
+                    /*                     // reset account
+                     *                     let folders = syncData.accountData.getAllFoldersIncludingCache();
+                     *                     for (let folder of folders) {
+                     *                         folder.remove();
+                     *                     }		    
+                     *                     // reset account
+                     *                     eas.Base.onEnableAccount(syncData.accountData);
+                     *                     throw eas.sync.finish("resyncAccount", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
+                     */
+                }
+
+            case "141": // The device is not provisionable
+            case "142": // DeviceNotProvisioned
+            case "143": // PolicyRefresh
+            case "144": // InvalidPolicyKey
+                //enable provision
+                syncData.accountData.setAccountProperty("provision", true);
+                syncData.accountData.resetAccountProperty("policykey");
+                throw eas.sync.finish("resyncAccount", statusType);
+
+            default:
+                if (allowSoftFail) return statusType;
+                throw eas.sync.finish("error", statusType, "Request:\n" + syncData.request + "\n\nResponse:\n" + syncData.response);
+
+        }
+    },
+
+
+
+
+
+
+
+
+
+
+    // WBXML COMM STUFF
+
+    setDeviceInformation: async function (syncData) {
+        if (syncData.accountData.getAccountProperty("asversion") == "2.5" || !syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("Settings")) {
+            return;
+        }
+
+        syncData.setSyncState("prepare.request.setdeviceinfo");
+
+        let wbxml = wbxmltools.createWBXML();
+        wbxml.switchpage("Settings");
+        wbxml.otag("Settings");
+        wbxml.otag("DeviceInformation");
+        wbxml.otag("Set");
+        wbxml.atag("Model", "Computer");
+        wbxml.atag("FriendlyName", "TbSync on Device " + syncData.accountData.getAccountProperty("deviceId").substring(4));
+        wbxml.atag("OS", Services.appinfo.OS);
+        wbxml.atag("UserAgent", syncData.accountData.getAccountProperty("useragent"));
+        wbxml.ctag();
+        wbxml.ctag();
+        wbxml.ctag();
+
+        syncData.setSyncState("send.request.setdeviceinfo");
+        let response = await eas.network.sendRequest(wbxml.getBytes(), "Settings", syncData);
+
+        syncData.setSyncState("eval.response.setdeviceinfo");
+        let wbxmlData = eas.network.getDataFromResponse(response);
+
+        eas.network.checkStatus(syncData, wbxmlData, "Settings.Status");
+    },
+
+    getPolicykey: async function (syncData) {
+        //build WBXML to request provision
+        syncData.setSyncState("prepare.request.provision");
+        let wbxml = eas.wbxmltools.createWBXML();
+        wbxml.switchpage("Provision");
+        wbxml.otag("Provision");
+        wbxml.otag("Policies");
+        wbxml.otag("Policy");
+        wbxml.atag("PolicyType", (syncData.accountData.getAccountProperty("asversion") == "2.5") ? "MS-WAP-Provisioning-XML" : "MS-EAS-Provisioning-WBXML");
+        wbxml.ctag();
+        wbxml.ctag();
+        wbxml.ctag();
+
+        for (let loop = 0; loop < 2; loop++) {
+            syncData.setSyncState("send.request.provision");
+            let response = await eas.network.sendRequest(wbxml.getBytes(), "Provision", syncData);
+
+            syncData.setSyncState("eval.response.provision");
+            let wbxmlData = eas.network.getDataFromResponse(response);
+            let policyStatus = eas.xmltools.getWbxmlDataField(wbxmlData, "Provision.Policies.Policy.Status");
+            let provisionStatus = eas.xmltools.getWbxmlDataField(wbxmlData, "Provision.Status");
+            if (provisionStatus === false) {
+                throw eas.sync.finish("error", "wbxmlmissingfield::Provision.Status");
+            } else if (provisionStatus != "1") {
+                //dump policy status as well
+                if (policyStatus) TbSync.dump("PolicyKey", "Received policy status: " + policyStatus);
+                throw eas.sync.finish("error", "provision::" + provisionStatus);
+            }
+
+            //reaching this point: provision status was ok
+            let policykey = eas.xmltools.getWbxmlDataField(wbxmlData, "Provision.Policies.Policy.PolicyKey");
+            switch (policyStatus) {
+                case false:
+                    throw eas.sync.finish("error", "wbxmlmissingfield::Provision.Policies.Policy.Status");
+
+                case "2":
+                    //server does not have a policy for this device: disable provisioning
+                    syncData.accountData.setAccountProperty("provision", false)
+                    syncData.accountData.resetAccountProperty("policykey");
+                    throw eas.sync.finish("resyncAccount", "NoPolicyForThisDevice");
+
+                case "1":
+                    if (policykey === false) {
+                        throw eas.sync.finish("error", "wbxmlmissingfield::Provision.Policies.Policy.PolicyKey");
+                    }
+                    TbSync.dump("PolicyKey", "Received policykey (" + loop + "): " + policykey);
+                    syncData.accountData.setAccountProperty("policykey", policykey);
+                    break;
+
+                default:
+                    throw eas.sync.finish("error", "policy." + policyStatus);
+            }
+
+            //build WBXML to acknowledge provision
+            syncData.setSyncState("prepare.request.provision");
+            wbxml = eas.wbxmltools.createWBXML();
+            wbxml.switchpage("Provision");
+            wbxml.otag("Provision");
+            wbxml.otag("Policies");
+            wbxml.otag("Policy");
+            wbxml.atag("PolicyType", (syncData.accountData.getAccountProperty("asversion") == "2.5") ? "MS-WAP-Provisioning-XML" : "MS-EAS-Provisioning-WBXML");
+            wbxml.atag("PolicyKey", policykey);
+            wbxml.atag("Status", "1");
+            wbxml.ctag();
+            wbxml.ctag();
+            wbxml.ctag();
+
+            //this wbxml will be used by Send at the top of this loop
+        }
+    },
+
+    getSynckey: async function (syncData) {
+        syncData.setSyncState("prepare.request.synckey");
+        //build WBXML to request a new syncKey
+        let wbxml = eas.wbxmltools.createWBXML();
+        wbxml.otag("Sync");
+        wbxml.otag("Collections");
+        wbxml.otag("Collection");
+        if (syncData.accountData.getAccountProperty("asversion") == "2.5") wbxml.atag("Class", syncData.type);
+        wbxml.atag("SyncKey", "0");
+        wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID"));
+        wbxml.ctag();
+        wbxml.ctag();
+        wbxml.ctag();
+
+        syncData.setSyncState("send.request.synckey");
+        let response = await eas.network.sendRequest(wbxml.getBytes(), "Sync", syncData);
+
+        syncData.setSyncState("eval.response.synckey");
+        // get data from wbxml response
+        let wbxmlData = eas.network.getDataFromResponse(response);
+        //check status
+        eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status");
+        //update synckey
+        eas.network.updateSynckey(syncData, wbxmlData);
+    },
+
+    getItemEstimate: async function (syncData) {
+        syncData.progressData.reset();
+
+        if (!syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("GetItemEstimate")) {
+            return; //do not throw, this is optional
+        }
+
+        syncData.setSyncState("prepare.request.estimate");
+
+        // BUILD WBXML
+        let wbxml = eas.wbxmltools.createWBXML();
+        wbxml.switchpage("GetItemEstimate");
+        wbxml.otag("GetItemEstimate");
+        wbxml.otag("Collections");
+        wbxml.otag("Collection");
+        if (syncData.accountData.getAccountProperty("asversion") == "2.5") { //got this order for 2.5 directly from Microsoft support
+            wbxml.atag("Class", syncData.type); //only 2.5
+            wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID"));
+            wbxml.switchpage("AirSync");
+            // required !
+            // https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-ascmd/ffbefa62-e315-40b9-9cc6-f8d74b5f65d4
+            if (syncData.type == "Calendar") wbxml.atag("FilterType", syncData.currentFolderData.accountData.getAccountProperty("synclimit"));
+            else wbxml.atag("FilterType", "0"); // we may filter incomplete tasks
+
+            wbxml.atag("SyncKey", syncData.synckey);
+            wbxml.switchpage("GetItemEstimate");
+        } else { //14.0
+            wbxml.switchpage("AirSync");
+            wbxml.atag("SyncKey", syncData.synckey);
+            wbxml.switchpage("GetItemEstimate");
+            wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID"));
+            wbxml.switchpage("AirSync");
+            wbxml.otag("Options");
+            // optional
+            if (syncData.type == "Calendar") wbxml.atag("FilterType", syncData.currentFolderData.accountData.getAccountProperty("synclimit"));
+            wbxml.atag("Class", syncData.type);
+            wbxml.ctag();
+            wbxml.switchpage("GetItemEstimate");
+        }
+        wbxml.ctag();
+        wbxml.ctag();
+        wbxml.ctag();
+
+        //SEND REQUEST
+        syncData.setSyncState("send.request.estimate");
+        let response = await eas.network.sendRequest(wbxml.getBytes(), "GetItemEstimate", syncData, /* allowSoftFail */ true);
+
+        //VALIDATE RESPONSE
+        syncData.setSyncState("eval.response.estimate");
+
+        // get data from wbxml response, some servers send empty response if there are no changes, which is not an error
+        let wbxmlData = eas.network.getDataFromResponse(response, eas.flags.allowEmptyResponse);
+        if (wbxmlData === null) return;
+
+        let status = eas.xmltools.getWbxmlDataField(wbxmlData, "GetItemEstimate.Response.Status");
+        let estimate = eas.xmltools.getWbxmlDataField(wbxmlData, "GetItemEstimate.Response.Collection.Estimate");
+
+        if (status && status == "1") { //do not throw on error, with EAS v2.5 I get error 2 for tasks and calendars ???
+            syncData.progressData.reset(0, estimate);
+        }
+    },
+
+    getUserInfo: async function (syncData) {
+        if (!syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("Settings")) {
+            return;
+        }
+
+        syncData.setSyncState("prepare.request.getuserinfo");
+
+        let wbxml = eas.wbxmltools.createWBXML();
+        wbxml.switchpage("Settings");
+        wbxml.otag("Settings");
+        wbxml.otag("UserInformation");
+        wbxml.atag("Get");
+        wbxml.ctag();
+        wbxml.ctag();
+
+        syncData.setSyncState("send.request.getuserinfo");
+        let response = await eas.network.sendRequest(wbxml.getBytes(), "Settings", syncData);
+
+
+        syncData.setSyncState("eval.response.getuserinfo");
+        let wbxmlData = eas.network.getDataFromResponse(response);
+
+        eas.network.checkStatus(syncData, wbxmlData, "Settings.Status");
+    },
+
+
+
+
+
+
+
+
+
+
+    // SEARCH
+
+    getSearchResults: async function (accountData, currentQuery) {
+
+        let _wbxml = eas.wbxmltools.createWBXML();
+        _wbxml.switchpage("Search");
+        _wbxml.otag("Search");
+        _wbxml.otag("Store");
+        _wbxml.atag("Name", "GAL");
+        _wbxml.atag("Query", currentQuery);
+        _wbxml.otag("Options");
+        _wbxml.atag("Range", "0-99"); //Z-Push needs a Range
+        //Not valid for GAL: https://msdn.microsoft.com/en-us/library/gg675461(v=exchg.80).aspx
+        //_wbxml.atag("DeepTraversal");
+        //_wbxml.atag("RebuildResults");
+        _wbxml.ctag();
+        _wbxml.ctag();
+        _wbxml.ctag();
+
+        let wbxml = _wbxml.getBytes();
+
+        eas.network.logXML(wbxml, "Send (GAL Search)");
+        let command = "Search";
+
+        let authData = eas.network.getAuthData(accountData);
+        let oauthData = eas.network.getOAuthObj({ accountData });
+        let userAgent = accountData.getAccountProperty("useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2
+        let deviceType = accountData.getAccountProperty("devicetype");
+        let deviceId = accountData.getAccountProperty("deviceId");
+
+        TbSync.dump("Sending (EAS v" + accountData.getAccountProperty("asversion") + ")", "POST " + eas.network.getEasURL(accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(authData.user) + '&DeviceType=' + deviceType + '&DeviceId=' + deviceId, true);
+
+        for (let i = 0; i < 2; i++) {
+            // check OAuth situation before connecting
+            if (oauthData && (!oauthData.getToken("accessToken") || oauthData.isExpired())) {
+                let _rv = {}
+                if (!(await oauthData.asyncConnect(_rv))) {
+                    throw eas.sync.finish("error", _rv.error);
+                }
+            }
+
+            try {
+                let contextData = eas.network.getContextData({ accountData });
+                let uri = Services.io.newURI(eas.network.getEasURL(accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(authData.user) + '&DeviceType=' + encodeURIComponent(deviceType) + '&DeviceId=' + deviceId);
+                let response = await new Promise(function (resolve, reject) {
+                    let req = getSandBoxedXHR(contextData, uri);
+                    req.mozBackgroundRequest = true;
+                    req.open("POST", uri.spec, true);
+                    req.overrideMimeType("text/plain");
+                    req.setRequestHeader("User-Agent", userAgent);
+                    req.setRequestHeader("Content-Type", "application/vnd.ms-sync.wbxml");
+
+                    if (authData.password) {
+                        if (eas.network.getOAuthObj({ accountData })) {
+                            req.setRequestHeader("Authorization", 'Bearer ' + eas.network.getOAuthValue(authData.password, "access"));
+                        } else {
+                            req.setRequestHeader("Authorization", 'Basic ' + TbSync.tools.b64encode(authData.user + ':' + authData.password));
+                        }
+                    }
+
+                    if (accountData.getAccountProperty("asversion") == "2.5") {
+                        req.setRequestHeader("MS-ASProtocolVersion", "2.5");
+                    } else {
+                        req.setRequestHeader("MS-ASProtocolVersion", "14.0");
+                    }
+                    req.setRequestHeader("Content-Length", wbxml.length);
+                    if (accountData.getAccountProperty("provision")) {
+                        req.setRequestHeader("X-MS-PolicyKey", accountData.getAccountProperty("policykey"));
+                        TbSync.dump("PolicyKey used", accountData.getAccountProperty("policykey"));
+                    }
+
+                    req.timeout = eas.Base.getConnectionTimeout();
+
+                    req.ontimeout = function () {
+                        reject("GAL Search timeout");
+                    };
+
+                    req.onerror = function () {
+                        reject("GAL Search Error");
+                    };
+
+                    req.onload = function () {
+                        let response = req.responseText;
+
+                        // Debug: Log received cookies.
+                        const channel = req.channel.QueryInterface(Ci.nsIHttpChannel);
+                        const SET_COOKIE_REGEXP = /set-cookie/i;
+                        channel.visitOriginalResponseHeaders({
+                            visitHeader(name, value) {
+                                if (SET_COOKIE_REGEXP.test(name)) {
+                                    console.log("Received cookie", value);
+                                }
+                            },
+                        });
+
+                        switch (req.status) {
+
+                            case 200: //OK
+                                eas.network.logXML(response, "Received (GAL Search");
+
+                                //What to do on error? IS this an error? Yes!
+                                if (response.length !== 0 && response.substr(0, 4) !== String.fromCharCode(0x03, 0x01, 0x6A, 0x00)) {
+                                    TbSync.dump("Recieved Data", "Expecting WBXML but got junk (request status = " + req.status + ", ready state = " + req.readyState + "\n>>>>>>>>>>\n" + response + "\n<<<<<<<<<<\n");
+                                    reject("GAL Search Response Invalid");
+                                } else {
+                                    resolve(response);
+                                }
+                                break;
+
+                            case 401: // bad auth
+                                resolve("401");
+                                break;
+
+                            default:
+                                reject("GAL Search Failed: " + req.status);
+                        }
+                    };
+
+                    req.send(wbxml);
+
+                });
+
+                if (response === "401") {
+                    // try to recover from bad auth via token refresh
+                    if (oauthData) {
+                        await oauthData.setToken("accessToken", "");
+                        continue;
+                    }
+                }
+
+                return response;
+            } catch (e) {
+                Components.utils.reportError(e);
+                return;
+            }
+        }
+    },
+
+
+
+
+
+
+
+
+
+
+    // OPTIONS
+
+    getServerOptions: async function (syncData) {
+        syncData.setSyncState("prepare.request.options");
+        let authData = eas.network.getAuthData(syncData.accountData);
+
+        let userAgent = syncData.accountData.getAccountProperty("useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2
+        TbSync.dump("Sending", "OPTIONS " + eas.network.getEasURL(syncData.accountData));
+
+        let allowedRetries = 5;
+        let retry;
+        let oauthData = eas.network.getOAuthObj({ accountData: syncData.accountData });
+
+        do {
+            retry = false;
+
+            // Check OAuth situation before connecting
+            if (oauthData && (!oauthData.getToken("accessToken") || oauthData.isExpired())) {
+                let _rv = {};
+                syncData.setSyncState("oauthprompt");
+                if (!(await oauthData.asyncConnect(_rv))) {
+                    throw eas.sync.finish("error", _rv.error);
+                }
+            }
+
+            let contextData = eas.network.getContextData({ accountData: syncData.accountData });
+            let uri = Services.io.newURI(eas.network.getEasURL(syncData.accountData));
+            let result = await new Promise(function (resolve, reject) {
+                syncData.req = getSandBoxedXHR(contextData, uri);
+                syncData.req.mozBackgroundRequest = true;
+                syncData.req.open("OPTIONS", uri.spec, true);
+                syncData.req.overrideMimeType("text/plain");
+                syncData.req.setRequestHeader("User-Agent", userAgent);
+                if (authData.password) {
+                    if (eas.network.getOAuthObj({ accountData: syncData.accountData })) {
+                        syncData.req.setRequestHeader("Authorization", 'Bearer ' + eas.network.getOAuthValue(authData.password, "access"));
+                    } else {
+                        syncData.req.setRequestHeader("Authorization", 'Basic ' + TbSync.tools.b64encode(authData.user + ':' + authData.password));
+                    }
+                }
+                syncData.req.timeout = eas.Base.getConnectionTimeout();
+
+                syncData.req.ontimeout = function () {
+                    resolve();
+                };
+
+                syncData.req.onerror = function () {
+                    let responseData = {};
+                    responseData["MS-ASProtocolVersions"] = syncData.req.getResponseHeader("MS-ASProtocolVersions");
+                    responseData["MS-ASProtocolCommands"] = syncData.req.getResponseHeader("MS-ASProtocolCommands");
+
+                    TbSync.dump("EAS OPTIONS with response (status: " + syncData.req.status + ")", "\n" +
+                        "responseText: " + syncData.req.responseText + "\n" +
+                        "responseHeader(MS-ASProtocolVersions): " + responseData["MS-ASProtocolVersions"] + "\n" +
+                        "responseHeader(MS-ASProtocolCommands): " + responseData["MS-ASProtocolCommands"]);
+                    resolve();
+                };
+
+                syncData.req.onload = function () {
+                    syncData.setSyncState("eval.request.options");
+                    let responseData = {};
+
+                    // Debug: Log received cookies.
+                    const channel = syncData.req.channel.QueryInterface(Ci.nsIHttpChannel);
+                    const SET_COOKIE_REGEXP = /set-cookie/i;
+                    channel.visitOriginalResponseHeaders({
+                        visitHeader(name, value) {
+                            if (SET_COOKIE_REGEXP.test(name)) {
+                                console.log("Received cookie", value);
+                            }
+                        },
+                    });
+
+                    switch (syncData.req.status) {
+                        case 401: // AuthError
+                            let rv = {};
+                            rv.errorObj = eas.sync.finish("error", "401");
+                            rv.errorType = "PasswordPrompt";
+                            resolve(rv);
+                            break;
+
+                        case 200:
+                            responseData["MS-ASProtocolVersions"] = syncData.req.getResponseHeader("MS-ASProtocolVersions");
+                            responseData["MS-ASProtocolCommands"] = syncData.req.getResponseHeader("MS-ASProtocolCommands");
+
+                            TbSync.dump("EAS OPTIONS with response (status: 200)", "\n" +
+                                "responseText: " + syncData.req.responseText + "\n" +
+                                "responseHeader(MS-ASProtocolVersions): " + responseData["MS-ASProtocolVersions"] + "\n" +
+                                "responseHeader(MS-ASProtocolCommands): " + responseData["MS-ASProtocolCommands"]);
+
+                            if (responseData && responseData["MS-ASProtocolCommands"] && responseData["MS-ASProtocolVersions"]) {
+                                syncData.accountData.setAccountProperty("allowedEasCommands", responseData["MS-ASProtocolCommands"]);
+                                syncData.accountData.setAccountProperty("allowedEasVersions", responseData["MS-ASProtocolVersions"]);
+                                syncData.accountData.setAccountProperty("lastEasOptionsUpdate", Date.now());
+                            }
+                            resolve();
+                            break;
+
+                        default:
+                            resolve();
+                            break;
+
+                    }
+                };
+
+                syncData.setSyncState("send.request.options");
+                syncData.req.send();
+
+            });
+
+            if (result && result.hasOwnProperty("errorType") && result.errorType == "PasswordPrompt") {
+                if (allowedRetries > 0) {
+                    if (oauthData) {
+                        await oauthData.setToken("accessToken", "");
+                        retry = true;
+                    } else {
+                        syncData.setSyncState("passwordprompt");
+                        let authData = eas.network.getAuthData(syncData.accountData);
+                        let promptData = {
+                            windowID: "auth:" + syncData.accountData.accountID,
+                            accountname: syncData.accountData.getAccountProperty("accountname"),
+                            usernameLocked: syncData.accountData.isConnected(),
+                            username: authData.user
+                        }
+                        let credentials = await TbSync.passwordManager.asyncPasswordPrompt(promptData, eas.openWindows);
+                        if (credentials) {
+                            await authData.updateLoginData(credentials.username, credentials.password);
+                            retry = true;
+                        }
+                    }
+                }
+
+                if (!retry) {
+                    throw result.errorObj;
+                }
+            }
+
+            allowedRetries--;
+        } while (retry);
+    },
+
+
+
+
+
+
+
+
+
+
+    // AUTODISCOVER
+
+    updateServerConnectionViaAutodiscover: async function (syncData) {
+        syncData.setSyncState("prepare.request.autodiscover");
+        let authData = eas.network.getAuthData(syncData.accountData);
+
+        syncData.setSyncState("send.request.autodiscover");
+        let result = await eas.network.getServerConnectionViaAutodiscover(authData.accountname, authData.user, authData.password, 30 * 1000);
+
+        syncData.setSyncState("eval.response.autodiscover");
+        if (result.errorcode == 200) {
+            //update account
+            syncData.accountData.setAccountProperty("host", eas.network.stripAutodiscoverUrl(result.server));
+            syncData.accountData.setAccountProperty("user", result.user);
+            syncData.accountData.setAccountProperty("https", (result.server.substring(0, 5) == "https"));
+        }
+
+        return result.errorcode;
+    },
+
+    stripAutodiscoverUrl: function (url) {
+        let u = url;
+        while (u.endsWith("/")) { u = u.slice(0, -1); }
+        if (u.endsWith("/Microsoft-Server-ActiveSync")) u = u.slice(0, -28);
+        else TbSync.dump("Received non-standard EAS url via autodiscover:", url);
+
+        return u.split("//")[1]; //cut off protocol
+    },
+
+    getServerConnectionViaAutodiscover: async function (accountname, user, password, maxtimeout) {
+        let urls = [];
+        let parts = user.split("@");
+
+        urls.push({ "url": "https://autodiscover." + parts[1] + "/autodiscover/autodiscover.xml", "user": user });
+        urls.push({ "url": "https://" + parts[1] + "/autodiscover/autodiscover.xml", "user": user });
+        urls.push({ "url": "https://autodiscover." + parts[1] + "/Autodiscover/Autodiscover.xml", "user": user });
+        urls.push({ "url": "https://" + parts[1] + "/Autodiscover/Autodiscover.xml", "user": user });
+
+        urls.push({ "url": "http://autodiscover." + parts[1] + "/autodiscover/autodiscover.xml", "user": user });
+        urls.push({ "url": "http://" + parts[1] + "/autodiscover/autodiscover.xml", "user": user });
+        urls.push({ "url": "http://autodiscover." + parts[1] + "/Autodiscover/Autodiscover.xml", "user": user });
+        urls.push({ "url": "http://" + parts[1] + "/Autodiscover/Autodiscover.xml", "user": user });
+
+        let requests = [];
+        let responses = []; //array of objects {url, error, server}
+
+        for (let i = 0; i < urls.length; i++) {
+            await TbSync.tools.sleep(200);
+            requests.push(eas.network.getServerConnectionViaAutodiscoverRedirectWrapper(
+                accountname,
+                urls[i].url,
+                urls[i].user,
+                password,
+                maxtimeout
+            ));
+        }
+
+        try {
+            responses = await Promise.all(requests);
+        } catch (e) {
+            responses.push(e.result); //this is actually a success, see return value of getServerConnectionViaAutodiscoverRedirectWrapper()
+        }
+
+        let result;
+        let log = [];
+        for (let r = 0; r < responses.length; r++) {
+            log.push("*  " + responses[r].url + " @ " + responses[r].user + " : " + (responses[r].server ? responses[r].server : responses[r].error));
+
+            if (responses[r].server) {
+                result = { "server": responses[r].server, "user": responses[r].user, "error": "", "errorcode": 200 };
+                break;
+            }
+
+            if (responses[r].error == 403 || responses[r].error == 401) {
+                //we could still find a valid server, so just store this state
+                result = { "server": "", "user": responses[r].user, "errorcode": responses[r].error, "error": TbSync.getString("status." + responses[r].error, "eas") };
+            }
+        }
+
+        //this is only reached on fail, if no result defined yet, use general error
+        if (!result) {
+            result = { "server": "", "user": user, "error": TbSync.getString("autodiscover.Failed", "eas").replace("##user##", user), "errorcode": 503 };
+        }
+
+        TbSync.eventlog.add("error", new TbSync.EventLogInfo("eas"), result.error, log.join("\n"));
+        return result;
+    },
+
+    getServerConnectionViaAutodiscoverRedirectWrapper: async function (accountname, url, user, password, maxtimeout) {
+        let result = {};
+        let method = "POST";
+        let connection = { accountname, url, user };
+
+        do {
+            await TbSync.tools.sleep(200);
+            result = await eas.network.getServerConnectionViaAutodiscoverRequest(method, connection, password, maxtimeout);
+            method = "";
+
+            if (result.error == "redirect found") {
+                TbSync.dump("EAS autodiscover URL redirect", "\n" + connection.url + " @ " + connection.user + " => \n" + result.url + " @ " + result.user);
+                connection.url = result.url;
+                connection.user = result.user;
+                method = "POST";
+            }
+
+        } while (method);
+
+        //invert reject and resolve, so we exit the promise group on success right away
+        if (result.server) {
+            let e = new Error("Not an error (early exit from promise group)");
+            e.result = result;
+            throw e;
+        } else {
+            return result;
+        }
+    },
+
+    getServerConnectionViaAutodiscoverRequest: function (method, connection, password, maxtimeout) {
+        TbSync.dump("Querry EAS autodiscover URL", connection.url + " @ " + connection.user);
+
+        return new Promise(function (resolve, reject) {
+
+            let xml = '<?xml version="1.0" encoding="utf-8"?>\r\n';
+            xml += '<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/requestschema/2006">\r\n';
+            xml += '<Request>\r\n';
+            xml += '<EMailAddress>' + connection.user + '</EMailAddress>\r\n';
+            xml += '<AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006</AcceptableResponseSchema>\r\n';
+            xml += '</Request>\r\n';
+            xml += '</Autodiscover>\r\n';
+
+            let userAgent = eas.prefs.getCharPref("clientID.useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2
+            let uri = Services.io.newURI(connection.url);
+            let req = getSandBoxedXHR(connection, uri);
+            req.mozBackgroundRequest = true;
+            req.open(method, uri.spec, true);
+            req.timeout = maxtimeout;
+            req.setRequestHeader("User-Agent", userAgent);
+
+            let secure = (connection.url.substring(0, 8).toLowerCase() == "https://");
+
+            if (method == "POST") {
+                req.setRequestHeader("Content-Length", xml.length);
+                req.setRequestHeader("Content-Type", "text/xml");
+                if (secure && password) {
+                    // OAUTH accounts cannot authenticate against the standard discovery services
+                    // updateServerConnectionViaAutodiscover() is not passing them on
+                    req.setRequestHeader("Authorization", "Basic " + TbSync.tools.b64encode(connection.user + ":" + password));
+                }
+            }
+
+            req.ontimeout = function () {
+                TbSync.dump("EAS autodiscover with timeout", "\n" + connection.url + " => \n" + req.responseURL);
+                resolve({ "url": req.responseURL, "error": "timeout", "server": "", "user": connection.user });
+            };
+
+            req.onerror = function () {
+                let error = TbSync.network.createTCPErrorFromFailedXHR(req);
+                if (!error) error = req.responseText;
+
+                // CORS violations can happen on redirects. They come back as NS_ERROR_DOM_BAD_URI.
+                if (error == "network::NS_ERROR_DOM_BAD_URI" && req.channel.URI.spec != uri.spec) {
+                    resolve({ "url": req.channel.URI.spec, "error": "redirect found", "server": "", "user": connection.user });
+                    return;
+                }
+
+                TbSync.dump("EAS autodiscover with error (" + error + ")", "\n" + connection.url + " => \n" + req.responseURL);
+                resolve({ "url": req.responseURL, "error": error, "server": "", "user": connection.user });
+            };
+
+            req.onload = function () {
+                //initiate rerun on redirects
+                if (req.responseURL != connection.url) {
+                    resolve({ "url": req.responseURL, "error": "redirect found", "server": "", "user": connection.user });
+                    return;
+                }
+
+                //ignore POST without autherization (we just do them to get redirect information)
+                if (!secure) {
+                    resolve({ "url": req.responseURL, "error": "unsecure POST", "server": "", "user": connection.user });
+                    return;
+                }
+
+                //evaluate secure POST requests which have not been redirected
+                TbSync.dump("EAS autodiscover POST with status (" + req.status + ")", "\n" + connection.url + " => \n" + req.responseURL + "\n[" + req.responseText + "]");
+
+                if (req.status === 200) {
+                    let data = null;
+                    // getDataFromXMLString may throw an error which cannot be catched outside onload,
+                    // because we are in an async callback of the surrounding Promise
+                    // Alternatively we could just return the responseText and do any data analysis outside of the Promise
+                    try {
+                        data = eas.xmltools.getDataFromXMLString(req.responseText);
+                    } catch (e) {
+                        resolve({ "url": req.responseURL, "error": "bad response", "server": "", "user": connection.user });
+                        return;
+                    }
+
+                    if (!(data === null) && data.Autodiscover && data.Autodiscover.Response && data.Autodiscover.Response.Action) {
+                        // "Redirect" or "Settings" are possible
+                        if (data.Autodiscover.Response.Action.Redirect) {
+                            // redirect, start again with new user
+                            let newuser = action.Redirect;
+                            resolve({ "url": req.responseURL, "error": "redirect found", "server": "", "user": newuser });
+
+                        } else if (data.Autodiscover.Response.Action.Settings) {
+                            // get server settings
+                            let server = eas.xmltools.nodeAsArray(data.Autodiscover.Response.Action.Settings.Server);
+
+                            for (let count = 0; count < server.length; count++) {
+                                if (server[count].Type == "MobileSync" && server[count].Url) {
+                                    resolve({ "url": req.responseURL, "error": "", "server": server[count].Url, "user": connection.user });
+                                    return;
+                                }
+                            }
+                        }
+                    } else {
+                        resolve({ "url": req.responseURL, "error": "invalid", "server": "", "user": connection.user });
+                    }
+                } else {
+                    resolve({ "url": req.responseURL, "error": req.status, "server": "", "user": connection.user });
+                }
+            };
+
+            req.send(xml);
+        });
+    },
+
+    getServerConnectionViaAutodiscoverV2JsonRequest: function (accountname, user, url, maxtimeout) {
+        TbSync.dump("Querry EAS autodiscover V2 URL", url);
+
+        return new Promise(function (resolve, reject) {
+
+            let userAgent = eas.prefs.getCharPref("clientID.useragent"); //plus calendar.useragent.extra = Lightning/5.4.5.2
+            let uri = Services.io.newURI(url);
+            let req = getSandBoxedXHR({ accountname, user }, uri);
+            req.mozBackgroundRequest = true;
+            req.open("GET", uri.spec, true);
+            req.timeout = maxtimeout;
+            req.setRequestHeader("User-Agent", userAgent);
+
+            req.ontimeout = function () {
+                TbSync.dump("EAS autodiscover V2 with timeout", "\n" + url + " => \n" + req.responseURL);
+                resolve({ "url": req.responseURL, "error": "timeout", "server": "" });
+            };
+
+            req.onerror = function () {
+                let error = TbSync.network.createTCPErrorFromFailedXHR(req);
+                if (!error) error = req.responseText;
+                TbSync.dump("EAS autodiscover V2 with error (" + error + ")", "\n" + url + " => \n" + req.responseURL);
+                resolve({ "url": req.responseURL, "error": error, "server": "" });
+            };
+
+            req.onload = function () {
+                if (req.status === 200) {
+                    let data = JSON.parse(req.responseText);
+
+                    if (data && data.Url) {
+                        resolve({ "url": req.responseURL, "error": "", "server": eas.network.stripAutodiscoverUrl(data.Url) });
+                    } else {
+                        resolve({ "url": req.responseURL, "error": "invalid", "server": "" });
+                    }
+                    return;
+                }
+
+                resolve({ "url": req.responseURL, "error": req.status, "server": "" });
+            };
+
+            req.send();
+        });
+    }
+}
diff -Nru eas4tbsync-4.11/content/includes/sync.js eas4tbsync-4.17/content/includes/sync.js
--- eas4tbsync-4.11/content/includes/sync.js	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/includes/sync.js	2025-05-15 13:21:20.000000000 +0200
@@ -1,1505 +1,1510 @@
-/*
- * This file is part of EAS-4-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");
-var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
-
-XPCOMUtils.defineLazyModuleGetters(this, {
-    CalRecurrenceInfo: "resource:///modules/CalRecurrenceInfo.jsm",
-}); 
-
-// - https://dxr.mozilla.org/comm-central/source/calendar/base/public/calIEvent.idl
-// - https://dxr.mozilla.org/comm-central/source/calendar/base/public/calIItemBase.idl
-// - https://dxr.mozilla.org/comm-central/source/calendar/base/public/calICalendar.idl
-// - https://dxr.mozilla.org/comm-central/source/calendar/base/modules/calAsyncUtils.jsm
-
-// https://msdn.microsoft.com/en-us/library/dd299454(v=exchg.80).aspx
-
-var sync = {
-
-    
-        
-    finish: function (aStatus = "", msg = "", details = "") {
-        let status = TbSync.StatusData.SUCCESS
-        switch (aStatus) {
-            
-            case "":
-            case "ok":
-                status = TbSync.StatusData.SUCCESS;
-                break;
-            
-            case "info":
-                status = TbSync.StatusData.INFO;
-                break;
-            
-            case "resyncAccount":
-                status = TbSync.StatusData.ACCOUNT_RERUN;
-                break;
-
-            case "resyncFolder":
-                status = TbSync.StatusData.FOLDER_RERUN;
-                break;
-            
-            case "warning":
-                status = TbSync.StatusData.WARNING;
-                break;
-            
-            case "error":
-                status = TbSync.StatusData.ERROR;
-                break;
-
-            default:
-                console.log("TbSync/EAS: Unknown status <"+aStatus+">");
-                status = TbSync.StatusData.ERROR;
-                break;
-        }
-        
-        let e = new Error(); 
-        e.name = "eas4tbsync";
-        e.message = status.toUpperCase() + ": " + msg.toString() + " (" + details.toString() + ")";
-        e.statusData = new TbSync.StatusData(status, msg.toString(), details.toString());        
-        return e; 
-    }, 
-
-    
-    resetFolderSyncInfo: function (folderData) {
-        folderData.resetFolderProperty("synckey");
-        folderData.resetFolderProperty("lastsynctime");
-    },
-
-    
-    // update folders avail on server and handle added, removed and renamed
-    // folders
-    folderList: async function(syncData) {
-        //should we recheck options/commands? Always check, if we have no info about asversion!
-        if (syncData.accountData.getAccountProperty("asversion", "") == "" || (Date.now() - syncData.accountData.getAccountProperty("lastEasOptionsUpdate")) > 86400000 ) {
-            await eas.network.getServerOptions(syncData);
-        }
-
-        //only update the actual used asversion, if we are currently not connected or it has not yet been set
-        if (syncData.accountData.getAccountProperty("asversion", "") == "" || !syncData.accountData.isConnected()) {
-            //eval the currently in the UI selected EAS version
-            let asversionselected = syncData.accountData.getAccountProperty("asversionselected");
-            let allowedVersionsString = syncData.accountData.getAccountProperty("allowedEasVersions").trim();
-            let allowedVersionsArray = allowedVersionsString.split(",");
-
-            if (asversionselected == "auto") {
-                if (allowedVersionsArray.includes("14.0")) syncData.accountData.setAccountProperty("asversion", "14.0");
-                else if (allowedVersionsArray.includes("2.5")) syncData.accountData.setAccountProperty("asversion", "2.5");
-                else if (allowedVersionsString == "") {
-                    throw eas.sync.finish("error", "InvalidServerOptions");
-                } else {
-                    throw eas.sync.finish("error", "nosupportedeasversion::"+allowedVersionsArray.join(", "));
-                }
-            } else if (allowedVersionsString != "" && !allowedVersionsArray.includes(asversionselected)) {
-                throw eas.sync.finish("error", "notsupportedeasversion::"+asversionselected+"::"+allowedVersionsArray.join(", "));
-            } else {
-                //just use the value set by the user
-                syncData.accountData.setAccountProperty("asversion", asversionselected);
-            }
-        }
-        
-        //do we need to get a new policy key?
-        if (syncData.accountData.getAccountProperty("provision") && syncData.accountData.getAccountProperty("policykey") == "0") {
-            await eas.network.getPolicykey(syncData);
-        }
-        
-        //set device info
-        await eas.network.setDeviceInformation(syncData);
-
-        syncData.setSyncState("prepare.request.folders"); 
-        let foldersynckey = syncData.accountData.getAccountProperty("foldersynckey");
-
-        //build WBXML to request foldersync
-        let wbxml = eas.wbxmltools.createWBXML();
-        wbxml.switchpage("FolderHierarchy");
-        wbxml.otag("FolderSync");
-            wbxml.atag("SyncKey", foldersynckey);
-        wbxml.ctag();
-
-        syncData.setSyncState("send.request.folders"); 
-        let response = await eas.network.sendRequest(wbxml.getBytes(), "FolderSync", syncData);
-
-        syncData.setSyncState("eval.response.folders"); 
-        let wbxmlData = eas.network.getDataFromResponse(response);
-        eas.network.checkStatus(syncData, wbxmlData,"FolderSync.Status");
-
-        let synckey = eas.xmltools.getWbxmlDataField(wbxmlData,"FolderSync.SyncKey");
-        if (synckey) {
-            syncData.accountData.setAccountProperty("foldersynckey", synckey);
-        } else {
-            throw eas.sync.finish("error", "wbxmlmissingfield::FolderSync.SyncKey");
-        }
-        
-        // If we reach this point, wbxmlData contains FolderSync node, 
-        // so the next "if" will not fail with an javascript error, no need 
-        // to use save getWbxmlDataField function.
-        
-        // Are there any changes in folder hierarchy?
-        if (wbxmlData.FolderSync.Changes) {
-            // Looking for additions.
-            let add = eas.xmltools.nodeAsArray(wbxmlData.FolderSync.Changes.Add);
-            for (let count = 0; count < add.length; count++) {
-                // Only add allowed folder types to DB (include trash(4), so we can find trashed folders.
-                if (!["9","14","8","13","7","15", "4"].includes(add[count].Type))
-                    continue;
-
-                let existingFolder = syncData.accountData.getFolder("serverID", add[count].ServerId);
-                if (existingFolder) {
-                    // Server has send us an ADD for a folder we alreay have, treat as update.
-                    existingFolder.setFolderProperty("foldername", add[count].DisplayName);
-                    existingFolder.setFolderProperty("type", add[count].Type);
-                    existingFolder.setFolderProperty("parentID", add[count].ParentId);
-                } else {
-                    // Create folder obj for new  folder settings.
-                    let newFolder = syncData.accountData.createNewFolder();
-                    switch (add[count].Type) {
-                        case "9": // contact
-                        case "14": 
-                            newFolder.setFolderProperty("targetType", "addressbook");
-                            break;
-                        case "8": // event
-                        case "13":
-                            newFolder.setFolderProperty("targetType", "calendar");
-                            break;
-                        case "7": // todo
-                        case "15":
-                            newFolder.setFolderProperty("targetType", "calendar");
-                            break;
-                        default:
-                            newFolder.setFolderProperty("targetType", "unknown type ("+add[count].Type+")");
-                            break;
-                        
-                    }
-                    
-                    newFolder.setFolderProperty("serverID", add[count].ServerId);
-                    newFolder.setFolderProperty("foldername", add[count].DisplayName);
-                    newFolder.setFolderProperty("type", add[count].Type);
-                    newFolder.setFolderProperty("parentID", add[count].ParentId);
-
-                    // Do we have a cached folder?
-                    let cachedFolderData = syncData.accountData.getFolderFromCache("serverID",  add[count].ServerId);
-                    if (cachedFolderData) {
-                        // Copy fields from cache which we want to re-use.
-                        newFolder.setFolderProperty("targetColor", cachedFolderData.getFolderProperty("targetColor"));
-                        newFolder.setFolderProperty("targetName", cachedFolderData.getFolderProperty("targetName"));
-                        newFolder.setFolderProperty("downloadonly", cachedFolderData.getFolderProperty("downloadonly"));
-                    }
-                }
-            }
-            
-            // Looking for updates.
-            let update = eas.xmltools.nodeAsArray(wbxmlData.FolderSync.Changes.Update);
-            for (let count = 0; count < update.length; count++) {
-                let existingFolder = syncData.accountData.getFolder("serverID", update[count].ServerId);
-                if (existingFolder) {
-                    // Update folder.
-                    existingFolder.setFolderProperty("foldername", update[count].DisplayName);
-                    existingFolder.setFolderProperty("type", update[count].Type);
-                    existingFolder.setFolderProperty("parentID", update[count].ParentId);
-                }
-            }
-
-            // Looking for deletes. Do not delete the targets, 
-            // but keep them as stale/unconnected elements.
-            let del = eas.xmltools.nodeAsArray(wbxmlData.FolderSync.Changes.Delete);
-            for (let count = 0; count < del.length; count++) {
-                let existingFolder = syncData.accountData.getFolder("serverID", del[count].ServerId);
-                if (existingFolder) {
-                    existingFolder.remove("[deleted on server]");
-                }
-            }
-        }
-    },
-    
-
-
-
-
-    deleteFolder: async function (syncData)  {
-        if (!syncData.currentFolderData) {
-            return;
-        }
-        
-        if (!syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("FolderDelete")) {
-            throw eas.sync.finish("error", "notsupported::FolderDelete");
-        }
-
-        syncData.setSyncState("prepare.request.deletefolder");
-        let foldersynckey = syncData.accountData.getAccountProperty("foldersynckey");
-
-        //request foldersync
-        let wbxml = eas.wbxmltools.createWBXML();
-        wbxml.switchpage("FolderHierarchy");
-        wbxml.otag("FolderDelete");
-            wbxml.atag("SyncKey", foldersynckey);
-            wbxml.atag("ServerId", syncData.currentFolderData.getFolderProperty("serverID"));
-        wbxml.ctag();
-
-        syncData.setSyncState("send.request.deletefolder");
-        let response = await eas.network.sendRequest(wbxml.getBytes(), "FolderDelete", syncData);
-
-        syncData.setSyncState("eval.response.deletefolder");
-        let wbxmlData = eas.network.getDataFromResponse(response);
-
-        eas.network.checkStatus(syncData, wbxmlData,"FolderDelete.Status");
-
-        let synckey = eas.xmltools.getWbxmlDataField(wbxmlData,"FolderDelete.SyncKey");
-        if (synckey) {
-            syncData.accountData.setAccountProperty("foldersynckey", synckey);
-            syncData.currentFolderData.remove();
-        } else {
-            throw eas.sync.finish("error", "wbxmlmissingfield::FolderDelete.SyncKey");
-        }
-    },
-
-
-
-
-
-    singleFolder: async function (syncData)  {
-        // add target to syncData
-        try {
-            // accessing the target for the first time will check if it is avail and if not will create it (if possible)
-            syncData.target = await syncData.currentFolderData.targetData.getTarget();
-        } catch (e) {
-            Components.utils.reportError(e);        
-            throw eas.sync.finish("warning", e.message);
-        }
-        
-        //get syncData type, which is also used in WBXML for the CLASS element
-        syncData.type = null;
-        switch (syncData.currentFolderData.getFolderProperty("type")) {
-            case "9": //contact
-            case "14": 
-                syncData.type = "Contacts";
-                break;
-            case "8": //event
-            case "13":
-                syncData.type = "Calendar";
-                break;
-            case "7": //todo
-            case "15":
-                syncData.type = "Tasks";
-                break;
-            default:
-                 throw eas.sync.finish("info", "skipped");
-                break;
-        }
-
-        syncData.setSyncState("preparing");
-        
-        //get synckey if needed
-        syncData.synckey = syncData.currentFolderData.getFolderProperty("synckey");                
-        if (syncData.synckey == "") {
-            await eas.network.getSynckey(syncData);
-        }
-        
-        //sync folder
-        syncData.timeOfLastSync = syncData.currentFolderData.getFolderProperty( "lastsynctime") / 1000;
-        syncData.timeOfThisSync = (Date.now() / 1000) - 1;
-        
-        let lightningBatch = false;
-        let lightningReadOnly = "";
-        let error = null;
-        
-        // We ned to intercept any throw error, because lightning needs a few operations after sync finished
-        try {
-            switch (syncData.type) {
-                case "Contacts": 
-                    await eas.sync.easFolder(syncData);
-                    break;
-
-                case "Calendar":
-                case "Tasks":                            
-                    //save current value of readOnly (or take it from the setting)
-                    lightningReadOnly = syncData.target.calendar.getProperty("readOnly") || syncData.currentFolderData.getFolderProperty( "downloadonly");                       
-                    syncData.target.calendar.setProperty("readOnly", false);
-                    
-                    lightningBatch = true;
-                    syncData.target.calendar.startBatch();
-
-                    await eas.sync.easFolder(syncData);
-                    break;
-            }
-        } catch (report) {
-            error = report;
-        }
-        
-        if (lightningBatch) {
-            syncData.target.calendar.endBatch();
-            syncData.target.calendar.setProperty("readOnly", lightningReadOnly);
-        }
-        
-        if (error) throw error;
-    },
-
-
-
-
-
-
-
-
-
-
-    // ---------------------------------------------------------------------------
-    // MAIN FUNCTIONS TO SYNC AN EAS FOLDER
-    // ---------------------------------------------------------------------------
-
-    easFolder: async function (syncData)  {
-        syncData.progressData.reset();
-
-        if (syncData.currentFolderData.getFolderProperty("downloadonly")) {		
-            await eas.sync.revertLocalChanges(syncData);
-        }
-
-        await eas.network.getItemEstimate(syncData);
-        await eas.sync.requestRemoteChanges(syncData); 
-
-        if (!syncData.currentFolderData.getFolderProperty("downloadonly")) {		
-            let sendChanges = await eas.sync.sendLocalChanges(syncData);
-            if (sendChanges) {
-                // This is ugly as hell, but Microsoft sometimes sets the state of the
-                // remote account to "changed" after we have send a local change (even
-                // though it has acked the change) and this will cause the server to
-                // send a change request with our next sync. Because we follow the
-                // "server wins" policy, this will overwrite any additional local change
-                // we have done in the meantime. This is stupid, but we wait 2s and
-                // hope it is enough to catch this second ack of the local change.
-                let timer =  Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
-                await new Promise(function(resolve, reject) {
-                    let event = {
-                        notify: function(timer) {
-                            resolve();
-                        }
-                    }
-                    timer.initWithCallback(event, 2000, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
-                });
-                await eas.sync.requestRemoteChanges(syncData);
-            }
-        }
-    },
-    
-
-    requestRemoteChanges: async function (syncData)  {
-        do {
-            syncData.setSyncState("prepare.request.remotechanges");
-            syncData.request = "";
-            syncData.response = "";
-        
-            // BUILD WBXML
-            let wbxml = eas.wbxmltools.createWBXML();
-            wbxml.otag("Sync");
-                wbxml.otag("Collections");
-                    wbxml.otag("Collection");
-                        if (syncData.accountData.getAccountProperty("asversion") == "2.5") wbxml.atag("Class", syncData.type);
-                        wbxml.atag("SyncKey", syncData.synckey);
-                        wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID"));
-                        wbxml.atag("DeletesAsMoves");
-                        wbxml.atag("GetChanges");
-                        wbxml.atag("WindowSize",  eas.prefs.getIntPref("maxitems").toString());
-
-                        if (syncData.accountData.getAccountProperty("asversion") != "2.5") {
-                            wbxml.otag("Options");
-                                if (syncData.type == "Calendar") wbxml.atag("FilterType", syncData.currentFolderData.accountData.getAccountProperty("synclimit"));
-                                wbxml.atag("Class", syncData.type);
-                                wbxml.switchpage("AirSyncBase");
-                                wbxml.otag("BodyPreference");
-                                    wbxml.atag("Type", "1");
-                                wbxml.ctag();
-                                wbxml.switchpage("AirSync");
-                            wbxml.ctag();
-                        } else if (syncData.type == "Calendar") { //in 2.5 we only send it to filter Calendar
-                            wbxml.otag("Options");
-                                 wbxml.atag("FilterType", syncData.currentFolderData.accountData.getAccountProperty("synclimit"));
-                            wbxml.ctag();
-                        }
-
-                    wbxml.ctag();
-                wbxml.ctag();
-            wbxml.ctag();
-
-            //SEND REQUEST
-            syncData.setSyncState("send.request.remotechanges");
-            let response = await eas.network.sendRequest(wbxml.getBytes(), "Sync", syncData);
-
-            //VALIDATE RESPONSE
-            // get data from wbxml response, some servers send empty response if there are no changes, which is not an error
-            let wbxmlData = eas.network.getDataFromResponse(response, eas.flags.allowEmptyResponse);
-            if (wbxmlData === null) return;
-        
-            //check status, throw on error
-            eas.network.checkStatus(syncData, wbxmlData,"Sync.Collections.Collection.Status");
-
-            //PROCESS COMMANDS        
-            await eas.sync.processCommands(wbxmlData, syncData);
-
-            //Update count in UI
-            syncData.setSyncState("eval.response.remotechanges");
-
-            //update synckey
-            eas.network.updateSynckey(syncData, wbxmlData);
-            
-            if (!eas.xmltools.hasWbxmlDataField(wbxmlData,"Sync.Collections.Collection.MoreAvailable")) {
-                //Feedback from users: They want to see the final count
-                await TbSync.tools.sleep(100);
-                return;
-            }
-        } while (true);
-                
-    },
-
-
-    sendLocalChanges: async function (syncData)  {        
-        let maxnumbertosend = eas.prefs.getIntPref("maxitems");
-        syncData.progressData.reset(0, syncData.target.getItemsFromChangeLog().length);
-
-        //keep track of failed items
-        syncData.failedItems = [];
-        
-        let done = false;
-        let numberOfItemsToSend = maxnumbertosend;
-        let sendChanges = false;
-        do {
-            syncData.setSyncState("prepare.request.localchanges");
-            syncData.request = "";
-            syncData.response = "";
-
-            //get changed items from ChangeLog
-            let changes = syncData.target.getItemsFromChangeLog(numberOfItemsToSend);
-            //console.log("chnages", changes);
-            let c=0;
-            let e=0;
-
-            //keep track of send items during this request
-            let changedItems = [];
-            let addedItems = {};
-            let sendItems = [];
-                
-            // BUILD WBXML
-            let wbxml = eas.wbxmltools.createWBXML();
-            wbxml.otag("Sync");
-                wbxml.otag("Collections");
-                    wbxml.otag("Collection");
-                        if (syncData.accountData.getAccountProperty("asversion") == "2.5") wbxml.atag("Class", syncData.type);
-                        wbxml.atag("SyncKey", syncData.synckey);
-                        wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID"));
-                        wbxml.otag("Commands");
-
-                            for (let i=0; i<changes.length; i++) if (!syncData.failedItems.includes(changes[i].itemId)) {
-                                //TbSync.dump("CHANGES",(i+1) + "/" + changes.length + " ("+changes[i].status+"," + changes[i].itemId + ")");
-                                let item = null;
-                                switch (changes[i].status) {
-
-                                    case "added_by_user":
-                                        item = await syncData.target.getItem(changes[i].itemId);
-                                        if (item) {
-                                            //filter out bad object types for this folder
-                                            if (syncData.type == "Contacts" && item.isMailList) {
-                                                // Mailing lists are not supported, this is not an error
-                                                TbSync.eventlog.add("warning", syncData.eventLogInfo, "MailingListNotSupportedItemSkipped");
-                                                syncData.target.removeItemFromChangeLog(changes[i].itemId);
-                                            } else if (syncData.type == eas.sync.getEasItemType(item)) {
-                                                //create a temp clientId, to cope with too long or invalid clientIds (for EAS)
-                                                let clientId = Date.now() + "-" + c;
-                                                addedItems[clientId] = changes[i].itemId;
-                                                sendItems.push({type: changes[i].status, id: changes[i].itemId});
-                                                
-                                                wbxml.otag("Add");
-                                                wbxml.atag("ClientId", clientId); //Our temp clientId will get replaced by an id generated by the server
-                                                    wbxml.otag("ApplicationData");
-                                                        wbxml.switchpage(syncData.type);
-
-/*wbxml.atag("TimeZone", "xP///0UAdQByAG8AcABlAC8AQgBlAHIAbABpAG4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAIAAAAAAAAAAAAAAEUAdQByAG8AcABlAC8AQgBlAHIAbABpAG4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAEAAAAAAAAAxP///w==");
-wbxml.atag("AllDayEvent", "0");
-wbxml.switchpage("AirSyncBase");
-wbxml.otag("Body");
-    wbxml.atag("Type", "1");
-    wbxml.atag("EstimatedDataSize", "0");
-    wbxml.atag("Data");
-wbxml.ctag();
-
-wbxml.switchpage(syncData.type);						
-wbxml.atag("BusyStatus", "2");
-wbxml.atag("OrganizerName", "REDACTED.REDACTED");
-wbxml.atag("OrganizerEmail", "REDACTED.REDACTED at REDACTED");
-wbxml.atag("DtStamp", "20190131T091024Z");
-wbxml.atag("EndTime", "20180906T083000Z");
-wbxml.atag("Location");
-wbxml.atag("Reminder", "5");
-wbxml.atag("Sensitivity", "0");
-wbxml.atag("Subject", "SE-CN weekly sync");
-wbxml.atag("StartTime", "20180906T080000Z");
-wbxml.atag("UID", "1D51E503-9DFE-4A46-A6C2-9129E5E00C1D");
-wbxml.atag("MeetingStatus", "3");
-wbxml.otag("Attendees");
-    wbxml.otag("Attendee");
-        wbxml.atag("Email", "REDACTED.REDACTED at REDACTED");
-        wbxml.atag("Name", "REDACTED.REDACTED");
-        wbxml.atag("AttendeeType", "1");
-    wbxml.ctag();
-wbxml.ctag();
-wbxml.atag("Categories");
-wbxml.otag("Recurrence");
-    wbxml.atag("Type", "1");
-    wbxml.atag("DayOfWeek", "16");
-    wbxml.atag("Interval", "1");
-wbxml.ctag();
-wbxml.otag("Exceptions");
-    wbxml.otag("Exception");
-        wbxml.atag("ExceptionStartTime", "20181227T090000Z");
-        wbxml.atag("Deleted", "1");
-    wbxml.ctag();
-wbxml.ctag();*/
-
-                                                        wbxml.append(await eas.sync.getWbxmlFromThunderbirdItem(item, syncData));
-                                                        wbxml.switchpage("AirSync");
-                                                    wbxml.ctag();
-                                                wbxml.ctag();
-                                                c++;
-                                            } else {
-                                                eas.sync.updateFailedItems(syncData, "forbidden" + eas.sync.getEasItemType(item) +"ItemIn" + syncData.type + "Folder", item.primaryKey, item.toString());
-                                                e++;
-                                            }
-                                        } else {
-                                            syncData.target.removeItemFromChangeLog(changes[i].itemId);
-                                        }
-                                        break;
-                                    
-                                    case "modified_by_user":
-                                        item = await syncData.target.getItem(changes[i].itemId);
-                                        if (item) {
-                                            //filter out bad object types for this folder
-                                            if (syncData.type == eas.sync.getEasItemType(item)) {
-                                                wbxml.otag("Change");
-                                                wbxml.atag("ServerId", changes[i].itemId);
-                                                    wbxml.otag("ApplicationData");
-                                                        wbxml.switchpage(syncData.type);
-                                                        wbxml.append(await eas.sync.getWbxmlFromThunderbirdItem(item, syncData));
-                                                        wbxml.switchpage("AirSync");
-                                                    wbxml.ctag();
-                                                wbxml.ctag();
-                                                changedItems.push(changes[i].itemId);
-                                                sendItems.push({type: changes[i].status, id: changes[i].itemId});
-                                                c++;
-                                            } else {
-                                                eas.sync.updateFailedItems(syncData, "forbidden" + eas.sync.getEasItemType(item) +"ItemIn" + syncData.type + "Folder", item.primaryKey, item.toString());
-                                                e++;
-                                            }
-                                        } else {
-                                            syncData.target.removeItemFromChangeLog(changes[i].itemId);
-                                        }
-                                        break;
-                                    
-                                    case "deleted_by_user":
-                                        wbxml.otag("Delete");
-                                        wbxml.atag("ServerId", changes[i].itemId);
-                                        wbxml.ctag();
-                                        changedItems.push(changes[i].itemId);
-                                        sendItems.push({type: changes[i].status, id: changes[i].itemId});
-                                        c++;
-                                        break;
-                                }
-                            }
-
-                        wbxml.ctag(); //Commands
-                    wbxml.ctag(); //Collection
-                wbxml.ctag(); //Collections
-            wbxml.ctag(); //Sync
-
-
-            if (c > 0) { //if there was at least one actual local change, send request
-                sendChanges = true;
-                //SEND REQUEST & VALIDATE RESPONSE
-                syncData.setSyncState("send.request.localchanges");
-                let response = await eas.network.sendRequest(wbxml.getBytes(), "Sync", syncData);
-                
-                syncData.setSyncState("eval.response.localchanges");
-
-                //get data from wbxml response
-                let wbxmlData = eas.network.getDataFromResponse(response);
-            
-                //check status and manually handle error states which support softfails
-                let errorcause = eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status", "", true);
-                switch (errorcause) {
-                    case "":
-                        break;
-                    
-                    case "Sync.4": //Malformed request
-                    case "Sync.6": //Invalid item
-                        //some servers send a global error - to catch this, we reduce the number of items we send to the server
-                        if (sendItems.length == 1) {
-                            //the request contained only one item, so we know which one failed
-                            if (sendItems[0].type == "deleted_by_user") {
-                                //we failed to delete an item, discard and place message in log
-                                syncData.target.removeItemFromChangeLog(sendItems[0].id);
-                                TbSync.eventlog.add("warning", syncData.eventLogInfo, "ErrorOnDelete::"+sendItems[0].id);
-                            } else {
-                                let foundItem = await syncData.target.getItem(sendItems[0].id);                    
-                                if (foundItem) {
-                                    eas.sync.updateFailedItems(syncData, errorcause, foundItem.primaryKey, foundItem.toString());
-                                } else {
-                                    //should not happen
-                                    syncData.target.removeItemFromChangeLog(sendItems[0].id);                                    
-                                }
-                            }
-                            syncData.progressData.inc();
-                            //restore numberOfItemsToSend
-                            numberOfItemsToSend = maxnumbertosend;                            
-                        } else if (sendItems.length > 1) {
-                            //reduce further
-                            numberOfItemsToSend = Math.min(1, Math.round(sendItems.length / 5));
-                        } else {
-                            //sendItems.length == 0 ??? recheck but this time let it handle all cases
-                            eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status");
-                        }
-                        break;
-
-                    default:
-                        //recheck but this time let it handle all cases
-                        eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status");
-                }        
-                
-                await TbSync.tools.sleep(10, true);
-
-                if (errorcause == "") {
-                    //PROCESS RESPONSE        
-                    await eas.sync.processResponses(wbxmlData, syncData, addedItems, changedItems);
-                
-                    //PROCESS COMMANDS        
-                    await eas.sync.processCommands(wbxmlData, syncData);
-
-                    //remove all items from changelog that did not fail
-                    for (let a=0; a < changedItems.length; a++) {
-                        syncData.target.removeItemFromChangeLog(changedItems[a]);
-                        syncData.progressData.inc();
-                    }
-
-                    //update synckey
-                    eas.network.updateSynckey(syncData, wbxmlData);
-                }
-            
-            } else if (e==0) { //if there was no local change and also no error (which will not happen twice) finish
-
-                done = true;
-
-            }
-        
-        } while (!done);
-        
-        //was there an error?
-        if (syncData.failedItems.length > 0) {
-            throw eas.sync.finish("warning", "ServerRejectedSomeItems::" + syncData.failedItems.length);                            
-        }
-        return sendChanges;
-    },
-
-
-
-
-    revertLocalChanges: async function (syncData)  {       
-        let maxnumbertosend = eas.prefs.getIntPref("maxitems");
-        syncData.progressData.reset(0, syncData.target.getItemsFromChangeLog().length);
-        if (syncData.progressData.todo == 0) {
-            return;
-        }
-
-        let viaItemOperations = (syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("ItemOperations"));
-
-        //get changed items from ChangeLog
-        do {
-            syncData.setSyncState("prepare.request.revertlocalchanges");
-            let changes = syncData.target.getItemsFromChangeLog(maxnumbertosend);
-            let c=0;
-            syncData.request = "";
-            syncData.response = "";
-            
-            // BUILD WBXML
-            let wbxml = eas.wbxmltools.createWBXML();
-            if (viaItemOperations) {
-                wbxml.switchpage("ItemOperations");
-                wbxml.otag("ItemOperations");
-            } else {
-                wbxml.otag("Sync");
-                    wbxml.otag("Collections");
-                        wbxml.otag("Collection");
-                            if (syncData.accountData.getAccountProperty("asversion") == "2.5") wbxml.atag("Class", syncData.type);
-                            wbxml.atag("SyncKey", syncData.synckey);
-                            wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID"));
-                            wbxml.otag("Commands");
-            }
-
-            for (let i=0; i<changes.length; i++) {
-                let item = null;
-                let ServerId = changes[i].itemId;
-                let foundItem = await syncData.target.getItem(ServerId);
-
-                switch (changes[i].status) {
-                    case "added_by_user": //remove
-                        if (foundItem) {
-                            await syncData.target.deleteItem(foundItem);
-                        }
-                    break;
-                    
-                    case "modified_by_user":
-                        if (foundItem) { //delete item so it can be replaced with a fresh copy, the changelog entry will be changed from modified to deleted
-                            await syncData.target.deleteItem(foundItem);
-                        }
-                    case "deleted_by_user":
-                        if (viaItemOperations) {
-                            wbxml.otag("Fetch");
-                                wbxml.atag("Store", "Mailbox");
-                                wbxml.switchpage("AirSync");
-                                wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID"));
-                                wbxml.atag("ServerId", ServerId);
-                                wbxml.switchpage("ItemOperations");
-                                wbxml.otag("Options");
-                                    wbxml.switchpage("AirSyncBase");
-                                    wbxml.otag("BodyPreference");
-                                        wbxml.atag("Type","1");
-                                    wbxml.ctag();
-                                    wbxml.switchpage("ItemOperations");
-                                wbxml.ctag();
-                            wbxml.ctag();
-                        } else {
-                            wbxml.otag("Fetch");
-                                wbxml.atag("ServerId", ServerId);
-                            wbxml.ctag();
-                        }
-                        c++;
-                        break;
-                }
-            }
-
-            if (viaItemOperations) {
-                wbxml.ctag(); //ItemOperations
-            } else {
-                            wbxml.ctag(); //Commands
-                        wbxml.ctag(); //Collection
-                    wbxml.ctag(); //Collections
-                wbxml.ctag(); //Sync
-            }
-
-            if (c > 0) { //if there was at least one actual local change, send request
-                let error = false;
-                let wbxmlData = "";
-                
-                //SEND REQUEST & VALIDATE RESPONSE
-                try {
-                    syncData.setSyncState("send.request.revertlocalchanges");
-                    let response = await eas.network.sendRequest(wbxml.getBytes(), (viaItemOperations) ? "ItemOperations" : "Sync", syncData);
-                        
-                    syncData.setSyncState("eval.response.revertlocalchanges");
-
-                    //get data from wbxml response
-                    wbxmlData = eas.network.getDataFromResponse(response);
-                } catch (e) {
-                    //we do not handle errors, IF there was an error, wbxmlData is empty and will trigger the fallback
-                }
-                
-                let fetchPath = (viaItemOperations) ? "ItemOperations.Response.Fetch" : "Sync.Collections.Collection.Responses.Fetch";
-                if (eas.xmltools.hasWbxmlDataField(wbxmlData, fetchPath)) {
-                
-                    //looking for additions
-                    let add = eas.xmltools.nodeAsArray(eas.xmltools.getWbxmlDataField(wbxmlData, fetchPath));
-                    for (let count = 0; count < add.length; count++) {
-                        await TbSync.tools.sleep(10, true);
-
-                        let ServerId = add[count].ServerId;
-                        let data = (viaItemOperations) ? add[count].Properties : add[count].ApplicationData;
-                        
-                        if (data && ServerId) {
-                            let foundItem = await syncData.target.getItem(ServerId);
-                            if (!foundItem) { //do NOT add, if an item with that ServerId was found
-                                    let newItem = eas.sync.createItem(syncData);
-                                    try {
-                                        eas.sync[syncData.type].setThunderbirdItemFromWbxml(newItem, data, ServerId, syncData);
-                                        await syncData.target.addItem(newItem);
-                                    } catch (e) {
-                                        eas.xmltools.printXmlData(add[count], true); //include application data in log                  
-                                        TbSync.eventlog.add("warning", syncData.eventLogInfo, "BadItemSkipped::JavaScriptError", newItem.toString());
-                                        throw e; // unable to add item to Thunderbird - fatal error
-                                    }
-                            } else {
-                                //should not happen, since we deleted that item beforehand
-                                syncData.target.removeItemFromChangeLog(ServerId);
-                            }
-                            syncData.progressData.inc();
-                        } else {
-                            error = true;
-                            break;
-                        }
-                    }
-                } else {
-                    error = true;
-                }
-                
-                if (error) {
-                    //if ItemOperations.Fetch fails, fall back to Sync.Fetch, if that fails, fall back to resync
-                    if (viaItemOperations) {
-                        viaItemOperations = false;
-                        TbSync.eventlog.add("info", syncData.eventLogInfo, "Server returned error during ItemOperations.Fetch, falling back to Sync.Fetch.");
-                    } else {
-                        await eas.sync.revertLocalChangesViaResync(syncData);
-                        return;
-                    }
-                }
-                            
-            } else { //if there was no more local change we need to revert, return
-
-                return;
-
-            }
-        
-        } while (true);
-        
-    },
-
-    revertLocalChangesViaResync: async function (syncData) {
-        TbSync.eventlog.add("info", syncData.eventLogInfo, "Server does not support ItemOperations.Fetch and/or Sync.Fetch, must revert via resync.");
-        let changes = syncData.target.getItemsFromChangeLog();
-
-        syncData.progressData.reset(0, changes.length);
-        syncData.setSyncState("prepare.request.revertlocalchanges");
-        
-        //remove all changes, so we can get them fresh from the server
-        for (let i=0; i<changes.length; i++) {
-            let item = null;
-            let ServerId = changes[i].itemId;
-            syncData.target.removeItemFromChangeLog(ServerId);
-            let foundItem = await syncData.target.getItem(ServerId);
-            if (foundItem) { //delete item with that ServerId
-                await syncData.target.deleteItem(foundItem);
-            }
-            syncData.progressData.inc();
-        }
-        
-        //This will resync all missing items fresh from the server
-        TbSync.eventlog.add("info", syncData.eventLogInfo, "RevertViaFolderResync");
-        eas.sync.resetFolderSyncInfo(syncData.currentFolderData);
-        throw eas.sync.finish("resyncFolder", "RevertViaFolderResync"); 
-    },
-
-
-
-
-    // ---------------------------------------------------------------------------
-    // SUB FUNCTIONS CALLED BY  MAIN FUNCTION
-    // ---------------------------------------------------------------------------
-    
-    processCommands:  async function (wbxmlData, syncData)  {
-        //any commands for us to work on? If we reach this point, Sync.Collections.Collection is valid, 
-        //no need to use the save getWbxmlDataField function
-        if (wbxmlData.Sync.Collections.Collection.Commands) {
-        
-            //looking for additions
-            let add = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Commands.Add);
-            for (let count = 0; count < add.length; count++) {
-                await TbSync.tools.sleep(10, true);
-
-                let ServerId = add[count].ServerId;
-                let data = add[count].ApplicationData;
-
-                let foundItem = await syncData.target.getItem(ServerId);
-                if (!foundItem) {
-                    //do NOT add, if an item with that ServerId was found
-                    let newItem = eas.sync.createItem(syncData);
-                    try {
-                        eas.sync[syncData.type].setThunderbirdItemFromWbxml(newItem, data, ServerId, syncData);
-                        await syncData.target.addItem(newItem);
-                    } catch (e) {
-                        eas.xmltools.printXmlData(add[count], true); //include application data in log                  
-                        TbSync.eventlog.add("warning", syncData.eventLogInfo, "BadItemSkipped::JavaScriptError", newItem.toString());
-                        throw e; // unable to add item to Thunderbird - fatal error
-                    }
-                } else {
-                    TbSync.eventlog.add("info", syncData.eventLogInfo, "Add request, but element exists already, skipped.", ServerId);
-                }
-                syncData.progressData.inc();
-            }
-
-            //looking for changes
-            let upd = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Commands.Change);
-            //inject custom change object for debug
-            //upd = JSON.parse('[{"ServerId":"2tjoanTeS0CJ3QTsq5vdNQAAAAABDdrY6Gp03ktAid0E7Kub3TUAAAoZy4A1","ApplicationData":{"DtStamp":"20171109T142149Z"}}]');
-            for (let count = 0; count < upd.length; count++) {
-                await TbSync.tools.sleep(10, true);
-
-                let ServerId = upd[count].ServerId;
-                let data = upd[count].ApplicationData;
-
-                syncData.progressData.inc();
-                let foundItem = await syncData.target.getItem(ServerId);
-                if (foundItem) { //only update, if an item with that ServerId was found
-                                        
-                    let keys = Object.keys(data);
-                    //replace by smart merge
-                    if (keys.length == 1 && keys[0] == "DtStamp") TbSync.dump("DtStampOnly", keys); //ignore DtStamp updates (fix with smart merge)
-                    else {
-                        
-                        if (foundItem.changelogStatus !== null) {
-                            TbSync.eventlog.add("info", syncData.eventLogInfo, "Change request from server, but also local modifications, server wins!", ServerId);
-                            foundItem.changelogStatus = null;
-                        }
-                        
-                        let newItem = foundItem.clone();
-                        try {
-                            eas.sync[syncData.type].setThunderbirdItemFromWbxml(newItem, data, ServerId, syncData);
-                            await syncData.target.modifyItem(newItem, foundItem);
-                        } catch (e) {
-                            TbSync.eventlog.add("warning", syncData.eventLogInfo, "BadItemSkipped::JavaScriptError", newItem.toString());
-                            eas.xmltools.printXmlData(upd[count], true);  //include application data in log                   
-                            throw e; // unable to mod item to Thunderbird - fatal error
-                        }
-                    }
-                    
-                }
-            }
-            
-            //looking for deletes
-            let del = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Commands.Delete).concat(eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Commands.SoftDelete));
-            for (let count = 0; count < del.length; count++) {
-                await TbSync.tools.sleep(10, true);
-
-                let ServerId = del[count].ServerId;
-
-                let foundItem = await syncData.target.getItem(ServerId);
-                if (foundItem) { //delete item with that ServerId
-                    await syncData.target.deleteItem(foundItem);
-                }
-                syncData.progressData.inc();
-            }
-        
-        }
-    },
-
-
-    updateFailedItems: function (syncData, cause, id, data) {                
-        //something is wrong with this item, move it to the end of changelog and go on
-        if (!syncData.failedItems.includes(id)) {
-            //the extra parameter true will re-add the item to the end of the changelog
-            syncData.target.removeItemFromChangeLog(id, true);                        
-            syncData.failedItems.push(id);            
-            TbSync.eventlog.add("info", syncData.eventLogInfo, "BadItemSkipped::" + TbSync.getString("status." + cause ,"eas"), "\n\nRequest:\n" + syncData.request + "\n\nResponse:\n" + syncData.response + "\n\nElement:\n" + data);
-        }
-    },
-
-
-    processResponses: async function (wbxmlData, syncData, addedItems, changedItems)  {
-            //any responses for us to work on?  If we reach this point, Sync.Collections.Collection is valid, 
-            //no need to use the save getWbxmlDataField function
-            if (wbxmlData.Sync.Collections.Collection.Responses) {
-
-                //looking for additions (Add node contains, status, old ClientId and new ServerId)
-                let add = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Responses.Add);
-                for (let count = 0; count < add.length; count++) {
-                    await TbSync.tools.sleep(10, true);
-
-                    //get the true Thunderbird UID of this added item (we created a temp clientId during add)
-                    add[count].ClientId = addedItems[add[count].ClientId];
-
-                    //look for an item identfied by ClientId and update its id to the new id received from the server
-                    let foundItem = await syncData.target.getItem(add[count].ClientId);                    
-                    if (foundItem) {
-
-                        //Check status, stop sync if bad, allow soft fail
-                        let errorcause = eas.network.checkStatus(syncData, add[count],"Status","Sync.Collections.Collection.Responses.Add["+count+"].Status", true);
-                        if (errorcause !== "") {
-                            //something is wrong with this item, move it to the end of changelog and go on
-                            eas.sync.updateFailedItems(syncData, errorcause, foundItem.primaryKey, foundItem.toString());
-                        } else {
-                            let newItem = foundItem.clone();
-                            newItem.primaryKey = add[count].ServerId;
-                            syncData.target.removeItemFromChangeLog(add[count].ClientId);
-                            await syncData.target.modifyItem(newItem, foundItem);
-                            syncData.progressData.inc();
-                        }
-
-                    }
-                }
-
-                //looking for modifications 
-                let upd = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Responses.Change);
-                for (let count = 0; count < upd.length; count++) {
-                    let foundItem = await syncData.target.getItem(upd[count].ServerId);                    
-                    if (foundItem) {
-
-                        //Check status, stop sync if bad, allow soft fail
-                        let errorcause = eas.network.checkStatus(syncData, upd[count],"Status","Sync.Collections.Collection.Responses.Change["+count+"].Status", true);
-                        if (errorcause !== "") {
-                            //something is wrong with this item, move it to the end of changelog and go on
-                            eas.sync.updateFailedItems(syncData, errorcause, foundItem.primaryKey, foundItem.toString());
-                            //also remove from changedItems
-                            let p = changedItems.indexOf(upd[count].ServerId);
-                            if (p>-1) changedItems.splice(p,1);
-                        }
-
-                    }
-                }
-
-                //looking for deletions 
-                let del = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Responses.Delete);
-                for (let count = 0; count < del.length; count++) {
-                    //What can we do about failed deletes? SyncLog
-                    eas.network.checkStatus(syncData, del[count],"Status","Sync.Collections.Collection.Responses.Delete["+count+"].Status", true);
-                }
-                
-            }
-    },
-
-
-
-
-
-
-
-
-
-
-    // ---------------------------------------------------------------------------
-    // HELPER FUNCTIONS AND DEFINITIONS
-    // ---------------------------------------------------------------------------
-        
-    MAP_EAS2TB : {
-        //EAS Importance: 0 = LOW | 1 = NORMAL | 2 = HIGH
-        Importance : { "0":"9", "1":"5", "2":"1"}, //to PRIORITY
-        //EAS Sensitivity :  0 = Normal  |  1 = Personal  |  2 = Private  |  3 = Confidential
-        Sensitivity : { "0":"PUBLIC", "1":"PRIVATE", "2":"PRIVATE", "3":"CONFIDENTIAL"}, //to CLASS
-        //EAS BusyStatus:  0 = Free  |  1 = Tentative  |  2 = Busy  |  3 = Work  |  4 = Elsewhere
-        BusyStatus : {"0":"TRANSPARENT", "1":"unset", "2":"OPAQUE", "3":"OPAQUE", "4":"OPAQUE"}, //to TRANSP
-        //EAS AttendeeStatus: 0 =Response unknown (but needed) |  2 = Tentative  |  3 = Accept  |  4 = Decline  |  5 = Not responded (and not needed) || 1 = Organizer in ResponseType
-        ATTENDEESTATUS : {"0": "NEEDS-ACTION", "1":"Orga", "2":"TENTATIVE", "3":"ACCEPTED", "4":"DECLINED", "5":"ACCEPTED"},
-        },
-
-    MAP_TB2EAS : {
-        //TB PRIORITY: 9 = LOW | 5 = NORMAL | 1 = HIGH
-        PRIORITY : { "9":"0", "5":"1", "1":"2","unset":"1"}, //to Importance
-        //TB CLASS: PUBLIC, PRIVATE, CONFIDENTIAL)
-        CLASS : { "PUBLIC":"0", "PRIVATE":"2", "CONFIDENTIAL":"3", "unset":"0"}, //to Sensitivity
-        //TB TRANSP : free = TRANSPARENT, busy = OPAQUE)
-        TRANSP : {"TRANSPARENT":"0", "unset":"1", "OPAQUE":"2"}, // to BusyStatus
-        //TB STATUS: NEEDS-ACTION, ACCEPTED, DECLINED, TENTATIVE, (DELEGATED, COMPLETED, IN-PROCESS - for todo)
-        ATTENDEESTATUS : {"NEEDS-ACTION":"0", "ACCEPTED":"3", "DECLINED":"4", "TENTATIVE":"2", "DELEGATED":"5","COMPLETED":"5", "IN-PROCESS":"5"},
-        },
-    
-    mapEasPropertyToThunderbird : function (easProp, tbProp, data, item) {
-        if (data[easProp]) {
-            //store original EAS value
-            let easPropValue = eas.xmltools.checkString(data[easProp]);
-            item.setProperty("X-EAS-" + easProp, easPropValue);
-            //map EAS value to TB value  (use setCalItemProperty if there is one option which can unset/delete the property)
-            eas.tools.setCalItemProperty(item, tbProp, eas.sync.MAP_EAS2TB[easProp][easPropValue]);
-        }
-    },
-
-    mapThunderbirdPropertyToEas: function (tbProp, easProp, item) {
-        if (item.hasProperty("X-EAS-" + easProp) && eas.tools.getCalItemProperty(item, tbProp) == eas.sync.MAP_EAS2TB[easProp][item.getProperty("X-EAS-" + easProp)]) {
-            //we can use our stored EAS value, because it still maps to the current TB value
-            return item.getProperty("X-EAS-" + easProp);
-        } else {
-            return eas.sync.MAP_TB2EAS[tbProp][eas.tools.getCalItemProperty(item, tbProp)]; 
-        }
-    },
-
-    getEasItemType(aItem) {
-        if (aItem instanceof TbSync.addressbook.AbItem) {
-            return "Contacts";
-        } else if (aItem instanceof TbSync.lightning.TbItem) {
-            return aItem.isTodo ? "Tasks" : "Calendar";
-        } else  {
-            throw "Unknown aItem.";
-        }
-    },
-
-    createItem(syncData) {
-        switch (syncData.type) {
-            case "Contacts":
-                return syncData.target.createNewCard();
-                break;
-            
-            case "Tasks":
-                return syncData.target.createNewTodo();
-                break;
-            
-            case "Calendar":
-                return syncData.target.createNewEvent();
-                break;
-            
-            default:
-                throw "Unknown item type <" + syncData.type + ">";
-        }
-    },
-    
-    async getWbxmlFromThunderbirdItem(item, syncData, isException = false) {
-        try {
-            let wbxml = await eas.sync[syncData.type].getWbxmlFromThunderbirdItem(item, syncData, isException);
-            return wbxml;
-        } catch (e) {
-            TbSync.eventlog.add("warning", syncData.eventLogInfo, "BadItemSkipped::JavaScriptError", item.toString());
-            throw e; // unable to read item from Thunderbird - fatal error
-        }        
-    },
-
-
-
-
-
-
-
-    // ---------------------------------------------------------------------------
-    // LIGHTNING HELPER FUNCTIONS AND DEFINITIONS
-    // These functions are needed only by tasks and events, so they
-    // are placed here, even though they are not type independent,
-    // but I did not want to add another "lightning" sub layer.
-    //
-    // The item in these functions is a native lightning item.
-    // ---------------------------------------------------------------------------
-        
-    setItemSubject: function (item, syncData, data) {
-        if (data.Subject) item.title = eas.xmltools.checkString(data.Subject);
-    },
-    
-    setItemLocation: function (item, syncData, data) {
-        if (data.Location) item.setProperty("location", eas.xmltools.checkString(data.Location));
-    },
-
-
-    setItemCategories: function (item, syncData, data) {
-        if (data.Categories && data.Categories.Category) {
-            let cats = [];
-            if (Array.isArray(data.Categories.Category)) cats = data.Categories.Category;
-            else cats.push(data.Categories.Category);
-            item.setCategories(cats);
-        }
-    },
-    
-    getItemCategories: function (item, syncData) {
-        let asversion = syncData.accountData.getAccountProperty("asversion");
-        let wbxml = eas.wbxmltools.createWBXML("", syncData.type); //init wbxml with "" and not with precodes, also activate type codePage (Calendar, Tasks, Contacts etc)
-
-        //to properly "blank" categories, we need to always include the container
-        let categories = item.getCategories({});
-        if (categories.length > 0) {
-            wbxml.otag("Categories");
-                for (let i=0; i<categories.length; i++) wbxml.atag("Category", categories[i]);
-            wbxml.ctag();
-        } else {
-            wbxml.atag("Categories");
-        }
-        return wbxml.getBytes();
-    },
-
-
-    setItemBody: function (item, syncData, data) {
-        let asversion = syncData.accountData.getAccountProperty("asversion");
-        if (asversion == "2.5") {
-            if (data.Body) item.setProperty("description", eas.xmltools.checkString(data.Body));
-        } else {
-            if (data.Body && /* data.Body.EstimatedDataSize > 0  && */ data.Body.Data) item.setProperty("description", eas.xmltools.checkString(data.Body.Data)); //EstimatedDataSize is optional
-        }
-    },
-
-    getItemBody: function (item, syncData) {
-        let asversion = syncData.accountData.getAccountProperty("asversion");
-        let wbxml = eas.wbxmltools.createWBXML("", syncData.type); //init wbxml with "" and not with precodes, also activate type codePage (Calendar, Tasks, Contacts etc)
-
-        let description = (item.hasProperty("description")) ? item.getProperty("description") : "";
-        if (asversion == "2.5") {
-            wbxml.atag("Body", description);
-        } else {
-            wbxml.switchpage("AirSyncBase");
-            wbxml.otag("Body");
-                wbxml.atag("Type", "1");
-                wbxml.atag("EstimatedDataSize", "" + description.length);
-                wbxml.atag("Data", description);
-            wbxml.ctag();
-            //does not work with horde at the moment, does not work with task, does not work with exceptions
-            //if (syncData.accountData.getAccountProperty("horde") == "0") wbxml.atag("NativeBodyType", "1");
-
-            //return to code page of this type
-            wbxml.switchpage(syncData.type);
-        }
-        return wbxml.getBytes();
-    },
-
-    //item is a native lightning item
-    setItemRecurrence: function (item, syncData, data, timezone) {
-        if (data.Recurrence) {
-            item.recurrenceInfo = new CalRecurrenceInfo();
-            item.recurrenceInfo.item = item;
-            let recRule = TbSync.lightning.cal.createRecurrenceRule();
-            switch (data.Recurrence.Type) {
-            case "0":
-                recRule.type = "DAILY";
-                break;
-            case "1":
-                recRule.type = "WEEKLY";
-                break;
-            case "2":
-            case "3":
-                recRule.type = "MONTHLY";
-                break;
-            case "5":
-            case "6":
-                recRule.type = "YEARLY";
-                break;
-            }
-
-            if (data.Recurrence.CalendarType) {
-                // TODO
-            }
-            if (data.Recurrence.DayOfMonth) {
-                recRule.setComponent("BYMONTHDAY", [data.Recurrence.DayOfMonth]);
-            }
-            if (data.Recurrence.DayOfWeek) {
-                let DOW = data.Recurrence.DayOfWeek;
-                if (DOW == 127 && (recRule.type == "MONTHLY" || recRule.type == "YEARLY")) {
-                    recRule.setComponent("BYMONTHDAY", [-1]);
-                }
-                else {
-                    let days = [];
-                    for (let i = 0; i < 7; ++i) {
-                        if (DOW & 1 << i) days.push(i + 1);
-                    }
-                    if (data.Recurrence.WeekOfMonth) {
-                        for (let i = 0; i < days.length; ++i) {
-                            if (data.Recurrence.WeekOfMonth == 5) {
-                                days[i] = -1 * (days[i] + 8);
-                            }
-                            else {
-                                days[i] += 8 * (data.Recurrence.WeekOfMonth - 0);
-                            }
-                        }
-                    }
-                    recRule.setComponent("BYDAY", days);
-                }
-            }
-            if (data.Recurrence.FirstDayOfWeek) {
-                //recRule.setComponent("WKST", [data.Recurrence.FirstDayOfWeek]); // WKST is not a valid component
-                //recRule.weekStart = data.Recurrence.FirstDayOfWeek; // - (NS_ERROR_NOT_IMPLEMENTED) [calIRecurrenceRule.weekStart]
-                TbSync.eventlog.add("info", syncData.eventLogInfo, "FirstDayOfWeek tag ignored (not supported).", item.icalString);                
-            }
-
-            if (data.Recurrence.Interval) {
-                recRule.interval = data.Recurrence.Interval;
-            }
-            if (data.Recurrence.IsLeapMonth) {
-                // TODO
-            }
-            if (data.Recurrence.MonthOfYear) {
-                recRule.setComponent("BYMONTH", [data.Recurrence.MonthOfYear]);
-            }
-            if (data.Recurrence.Occurrences) {
-                recRule.count = data.Recurrence.Occurrences;
-            }
-            if (data.Recurrence.Until) {
-                //time string could be in compact/basic or extended form of ISO 8601, 
-                //cal.createDateTime only supports  compact/basic, our own method takes both styles
-                recRule.untilDate = eas.tools.createDateTime(data.Recurrence.Until);
-            }
-            if (data.Recurrence.Start) {
-                TbSync.eventlog.add("info", syncData.eventLogInfo, "Start tag in recurring task is ignored, recurrence will start with first entry.", item.icalString);
-            }
-        
-            item.recurrenceInfo.insertRecurrenceItemAt(recRule, 0);
-
-            if (data.Exceptions && syncData.type == "Calendar") { // only events, tasks cannot have exceptions
-                // Exception could be an object or an array of objects
-                let exceptions = [].concat(data.Exceptions.Exception);
-                for (let exception of exceptions) {
-                    //exception.ExceptionStartTime is in UTC, but the Recurrence Object is in local timezone
-                    let dateTime = TbSync.lightning.cal.createDateTime(exception.ExceptionStartTime).getInTimezone(timezone);
-                    if (data.AllDayEvent == "1") {
-                        dateTime.isDate = true;
-                        // Pass to replacement event unless overriden
-                        if (!exception.AllDayEvent) {
-                            exception.AllDayEvent = "1";
-                        }
-                    }
-                    if (exception.Deleted == "1") {
-                        item.recurrenceInfo.removeOccurrenceAt(dateTime);
-                    }
-                    else {
-                        let replacement = item.recurrenceInfo.getOccurrenceFor(dateTime);
-                        // replacement is a native lightning item, so we can access its id via .id
-                        eas.sync[syncData.type].setThunderbirdItemFromWbxml(replacement, exception, replacement.id, syncData, "recurrence");
-                        // Reminders should carry over from parent, but setThunderbirdItemFromWbxml clears all alarms
-                        if (!exception.Reminder && item.getAlarms({}).length) {
-                            replacement.addAlarm(item.getAlarms({})[0]);
-                        }
-                        // Removing a reminder requires EAS 16.0
-                        item.recurrenceInfo.modifyException(replacement, true);
-                    }
-                }
-            }
-        }
-    },
-
-    getItemRecurrence: async function (item, syncData, localStartDate = null) {
-        let asversion = syncData.accountData.getAccountProperty("asversion");
-        let wbxml = eas.wbxmltools.createWBXML("", syncData.type); //init wbxml with "" and not with precodes, also activate type codePage (Calendar, Tasks etc)
-
-        if (item.recurrenceInfo && (syncData.type == "Calendar" || syncData.type == "Tasks")) {
-            let deleted = [];
-            let hasRecurrence = false;
-            let startDate = (syncData.type == "Calendar") ? item.startDate : item.entryDate;
-
-            for (let recRule of item.recurrenceInfo.getRecurrenceItems({})) {
-                if (recRule.date) {
-                    if (recRule.isNegative) {
-                        // EXDATE
-                        deleted.push(recRule);
-                    }
-                    else {
-                        // RDATE
-                        TbSync.eventlog.add("info", syncData.eventLogInfo, "Ignoring RDATE rule (not supported)", recRule.icalString);
-                    }
-                    continue;
-                }
-                if (recRule.isNegative) {
-                    // EXRULE
-                    TbSync.eventlog.add("info", syncData.eventLogInfo, "Ignoring EXRULE rule (not supported)", recRule.icalString);
-                    continue;
-                }
-
-                // RRULE
-                wbxml.otag("Recurrence");
-                hasRecurrence = true;
-
-                let type = 0;
-                let monthDays = recRule.getComponent("BYMONTHDAY", {});
-                let weekDays  = recRule.getComponent("BYDAY", {});
-                let months    = recRule.getComponent("BYMONTH", {});
-                let weeks     = [];
-
-                // Unpack 1MO style days
-                for (let i = 0; i < weekDays.length; ++i) {
-                    if (weekDays[i] > 8) {
-                        weeks[i] = Math.floor(weekDays[i] / 8);
-                        weekDays[i] = weekDays[i] % 8;
-                    }
-                    else if (weekDays[i] < -8) {
-                        // EAS only supports last week as a special value, treat
-                        // all as last week or assume every month has 5 weeks?
-                        // Change to last week
-                        //weeks[i] = 5;
-                        // Assumes 5 weeks per month for week <= -2
-                        weeks[i] = 6 - Math.floor(-weekDays[i] / 8);
-                        weekDays[i] = -weekDays[i] % 8;
-                    }
-                }
-                if (monthDays[0] && monthDays[0] == -1) {
-                    weeks = [5];
-                    weekDays = [1, 2, 3, 4, 5, 6, 7]; // 127
-                    monthDays[0] = null;
-                }
-                // Type
-                if (recRule.type == "WEEKLY") {
-                    type = 1;
-                    if (!weekDays.length) {
-                        weekDays = [startDate.weekday + 1];
-                    }
-                }
-                else if (recRule.type == "MONTHLY" && weeks.length) {
-                    type = 3;
-                }
-                else if (recRule.type == "MONTHLY") {
-                    type = 2;
-                    if (!monthDays.length) {
-                        monthDays = [startDate.day];
-                    }
-                }
-                else if (recRule.type == "YEARLY" && weeks.length) {
-                    type = 6;
-                }
-                else if (recRule.type == "YEARLY") {
-                    type = 5;
-                    if (!monthDays.length) {
-                        monthDays = [startDate.day];
-                    }
-                    if (!months.length) {
-                        months = [startDate.month + 1];
-                    }
-                }
-                wbxml.atag("Type", type.toString());
-                
-                //Tasks need a Start tag, but we cannot allow a start date different from the start of the main item (thunderbird does not support that)
-                if (localStartDate) wbxml.atag("Start", localStartDate);
-                
-                // TODO: CalendarType: 14.0 and up
-                // DayOfMonth
-                if (monthDays[0]) {
-                    // TODO: Multiple days of month - multiple Recurrence tags?
-                    wbxml.atag("DayOfMonth", monthDays[0].toString());
-                }
-                // DayOfWeek
-                if (weekDays.length) {
-                    let bitfield = 0;
-                    for (let day of weekDays) {
-                        bitfield |= 1 << (day - 1);
-                    }
-                    wbxml.atag("DayOfWeek", bitfield.toString());
-                }
-                // FirstDayOfWeek: 14.1 and up
-                //wbxml.atag("FirstDayOfWeek", recRule.weekStart); - (NS_ERROR_NOT_IMPLEMENTED) [calIRecurrenceRule.weekStart]
-                // Interval
-                wbxml.atag("Interval", recRule.interval.toString());
-                // TODO: IsLeapMonth: 14.0 and up
-                // MonthOfYear
-                if (months.length) {
-                    wbxml.atag("MonthOfYear", months[0].toString());
-                }
-                // Occurrences
-                if (recRule.isByCount) {
-                    wbxml.atag("Occurrences", recRule.count.toString());
-                }
-                // Until
-                else if (recRule.untilDate != null) {
-                    //Events need the Until data in compact form, Tasks in the basic form
-                    wbxml.atag("Until", eas.tools.getIsoUtcString(recRule.untilDate, (syncData.type == "Tasks")));
-                }
-                // WeekOfMonth
-                if (weeks.length) {
-                    wbxml.atag("WeekOfMonth", weeks[0].toString());
-                }
-                wbxml.ctag();
-            }
-            
-            if (syncData.type == "Calendar" && hasRecurrence) { //Exceptions only allowed in Calendar and only if a valid Recurrence was added
-                let modifiedIds = item.recurrenceInfo.getExceptionIds({});
-                if (deleted.length || modifiedIds.length) {
-                    wbxml.otag("Exceptions");
-                    for (let exception of deleted) {
-                        wbxml.otag("Exception");
-                            wbxml.atag("ExceptionStartTime", eas.tools.getIsoUtcString(exception.date));
-                            wbxml.atag("Deleted", "1");
-                            //Docs say it is allowed, but if present, it does not work
-                            //if (asversion == "2.5") {
-                            //    wbxml.atag("UID", item.id); //item.id is not valid, use UID or primaryKey
-                            //}
-                        wbxml.ctag();
-                    }
-                    for (let exceptionId of modifiedIds) {
-                        let replacement = item.recurrenceInfo.getExceptionFor(exceptionId);
-                        wbxml.otag("Exception");
-                            wbxml.atag("ExceptionStartTime", eas.tools.getIsoUtcString(exceptionId));
-                            wbxml.append(await eas.sync.getWbxmlFromThunderbirdItem(replacement, syncData, true));
-                        wbxml.ctag();
-                    }
-                    wbxml.ctag();
-                }
-            }
-        }
-
-        return wbxml.getBytes();
-    }
-
-}
+/*
+ * This file is part of EAS-4-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, {
+    CalRecurrenceInfo: "resource:///modules/CalRecurrenceInfo.sys.mjs",
+});
+
+// - https://dxr.mozilla.org/comm-central/source/calendar/base/public/calIEvent.idl
+// - https://dxr.mozilla.org/comm-central/source/calendar/base/public/calIItemBase.idl
+// - https://dxr.mozilla.org/comm-central/source/calendar/base/public/calICalendar.idl
+// - https://dxr.mozilla.org/comm-central/source/calendar/base/modules/calAsyncUtils.sys.mjs
+
+// https://msdn.microsoft.com/en-us/library/dd299454(v=exchg.80).aspx
+
+var sync = {
+    finish: function (aStatus = "", msg = "", details = "") {
+        let status = TbSync.StatusData.SUCCESS
+        switch (aStatus) {
+
+            case "":
+            case "ok":
+                status = TbSync.StatusData.SUCCESS;
+                break;
+
+            case "info":
+                status = TbSync.StatusData.INFO;
+                break;
+
+            case "resyncAccount":
+                status = TbSync.StatusData.ACCOUNT_RERUN;
+                break;
+
+            case "resyncFolder":
+                status = TbSync.StatusData.FOLDER_RERUN;
+                break;
+
+            case "warning":
+                status = TbSync.StatusData.WARNING;
+                break;
+
+            case "error":
+                status = TbSync.StatusData.ERROR;
+                break;
+
+            default:
+                console.log("TbSync/EAS: Unknown status <" + aStatus + ">");
+                status = TbSync.StatusData.ERROR;
+                break;
+        }
+
+        let e = new Error();
+        e.name = "eas4tbsync";
+        e.message = status.toUpperCase() + ": " + msg.toString() + " (" + details.toString() + ")";
+        e.statusData = new TbSync.StatusData(status, msg.toString(), details.toString());
+        return e;
+    },
+
+
+    resetFolderSyncInfo: function (folderData) {
+        folderData.resetFolderProperty("synckey");
+        folderData.resetFolderProperty("lastsynctime");
+    },
+
+
+    // update folders avail on server and handle added, removed and renamed
+    // folders
+    folderList: async function (syncData) {
+        //should we recheck options/commands? Always check, if we have no info about asversion!
+        if (syncData.accountData.getAccountProperty("asversion", "") == "" || (Date.now() - syncData.accountData.getAccountProperty("lastEasOptionsUpdate")) > 86400000) {
+            await eas.network.getServerOptions(syncData);
+        }
+
+        //only update the actual used asversion, if we are currently not connected or it has not yet been set
+        if (syncData.accountData.getAccountProperty("asversion", "") == "" || !syncData.accountData.isConnected()) {
+            //eval the currently in the UI selected EAS version
+            let asversionselected = syncData.accountData.getAccountProperty("asversionselected");
+            let allowedVersionsString = syncData.accountData.getAccountProperty("allowedEasVersions").trim();
+            let allowedVersionsArray = allowedVersionsString.split(",");
+
+            if (asversionselected == "auto") {
+                if (allowedVersionsArray.includes("14.0")) syncData.accountData.setAccountProperty("asversion", "14.0");
+                else if (allowedVersionsArray.includes("2.5")) syncData.accountData.setAccountProperty("asversion", "2.5");
+                else if (allowedVersionsString == "") {
+                    throw eas.sync.finish("error", "InvalidServerOptions");
+                } else {
+                    throw eas.sync.finish("error", "nosupportedeasversion::" + allowedVersionsArray.join(", "));
+                }
+            } else if (allowedVersionsString != "" && !allowedVersionsArray.includes(asversionselected)) {
+                throw eas.sync.finish("error", "notsupportedeasversion::" + asversionselected + "::" + allowedVersionsArray.join(", "));
+            } else {
+                //just use the value set by the user
+                syncData.accountData.setAccountProperty("asversion", asversionselected);
+            }
+        }
+
+        //do we need to get a new policy key?
+        if (syncData.accountData.getAccountProperty("provision") && syncData.accountData.getAccountProperty("policykey") == "0") {
+            await eas.network.getPolicykey(syncData);
+        }
+
+        //set device info
+        await eas.network.setDeviceInformation(syncData);
+
+        syncData.setSyncState("prepare.request.folders");
+        let foldersynckey = syncData.accountData.getAccountProperty("foldersynckey");
+
+        //build WBXML to request foldersync
+        let wbxml = eas.wbxmltools.createWBXML();
+        wbxml.switchpage("FolderHierarchy");
+        wbxml.otag("FolderSync");
+        wbxml.atag("SyncKey", foldersynckey);
+        wbxml.ctag();
+
+        syncData.setSyncState("send.request.folders");
+        let response = await eas.network.sendRequest(wbxml.getBytes(), "FolderSync", syncData);
+
+        syncData.setSyncState("eval.response.folders");
+        let wbxmlData = eas.network.getDataFromResponse(response);
+        eas.network.checkStatus(syncData, wbxmlData, "FolderSync.Status");
+
+        let synckey = eas.xmltools.getWbxmlDataField(wbxmlData, "FolderSync.SyncKey");
+        if (synckey) {
+            syncData.accountData.setAccountProperty("foldersynckey", synckey);
+        } else {
+            throw eas.sync.finish("error", "wbxmlmissingfield::FolderSync.SyncKey");
+        }
+
+        // If we reach this point, wbxmlData contains FolderSync node, 
+        // so the next "if" will not fail with an javascript error, no need 
+        // to use save getWbxmlDataField function.
+
+        // Are there any changes in folder hierarchy?
+        if (wbxmlData.FolderSync.Changes) {
+            // Looking for additions.
+            let add = eas.xmltools.nodeAsArray(wbxmlData.FolderSync.Changes.Add);
+            for (let count = 0; count < add.length; count++) {
+                // Only add allowed folder types to DB (include trash(4), so we can find trashed folders.
+                if (!["9", "14", "8", "13", "7", "15", "4"].includes(add[count].Type))
+                    continue;
+
+                let existingFolder = syncData.accountData.getFolder("serverID", add[count].ServerId);
+                if (existingFolder) {
+                    // Server has send us an ADD for a folder we alreay have, treat as update.
+                    existingFolder.setFolderProperty("foldername", add[count].DisplayName);
+                    existingFolder.setFolderProperty("type", add[count].Type);
+                    existingFolder.setFolderProperty("parentID", add[count].ParentId);
+                } else {
+                    // Create folder obj for new  folder settings.
+                    let newFolder = syncData.accountData.createNewFolder();
+                    switch (add[count].Type) {
+                        case "9": // contact
+                        case "14":
+                            newFolder.setFolderProperty("targetType", "addressbook");
+                            break;
+                        case "8": // event
+                        case "13":
+                            newFolder.setFolderProperty("targetType", "calendar");
+                            break;
+                        case "7": // todo
+                        case "15":
+                            newFolder.setFolderProperty("targetType", "calendar");
+                            break;
+                        default:
+                            newFolder.setFolderProperty("targetType", "unknown type (" + add[count].Type + ")");
+                            break;
+
+                    }
+
+                    newFolder.setFolderProperty("serverID", add[count].ServerId);
+                    newFolder.setFolderProperty("foldername", add[count].DisplayName);
+                    newFolder.setFolderProperty("type", add[count].Type);
+                    newFolder.setFolderProperty("parentID", add[count].ParentId);
+
+                    // Do we have a cached folder?
+                    let cachedFolderData = syncData.accountData.getFolderFromCache("serverID", add[count].ServerId);
+                    if (cachedFolderData) {
+                        // Copy fields from cache which we want to re-use.
+                        newFolder.setFolderProperty("targetColor", cachedFolderData.getFolderProperty("targetColor"));
+                        newFolder.setFolderProperty("targetName", cachedFolderData.getFolderProperty("targetName"));
+                        newFolder.setFolderProperty("downloadonly", cachedFolderData.getFolderProperty("downloadonly"));
+                    }
+                }
+            }
+
+            // Looking for updates.
+            let update = eas.xmltools.nodeAsArray(wbxmlData.FolderSync.Changes.Update);
+            for (let count = 0; count < update.length; count++) {
+                let existingFolder = syncData.accountData.getFolder("serverID", update[count].ServerId);
+                if (existingFolder) {
+                    // Update folder.
+                    existingFolder.setFolderProperty("foldername", update[count].DisplayName);
+                    existingFolder.setFolderProperty("type", update[count].Type);
+                    existingFolder.setFolderProperty("parentID", update[count].ParentId);
+                }
+            }
+
+            // Looking for deletes. Do not delete the targets, 
+            // but keep them as stale/unconnected elements.
+            let del = eas.xmltools.nodeAsArray(wbxmlData.FolderSync.Changes.Delete);
+            for (let count = 0; count < del.length; count++) {
+                let existingFolder = syncData.accountData.getFolder("serverID", del[count].ServerId);
+                if (existingFolder) {
+                    existingFolder.remove("[deleted on server]");
+                }
+            }
+        }
+    },
+
+
+
+
+
+    deleteFolder: async function (syncData) {
+        if (!syncData.currentFolderData) {
+            return;
+        }
+
+        if (!syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("FolderDelete")) {
+            throw eas.sync.finish("error", "notsupported::FolderDelete");
+        }
+
+        syncData.setSyncState("prepare.request.deletefolder");
+        let foldersynckey = syncData.accountData.getAccountProperty("foldersynckey");
+
+        //request foldersync
+        let wbxml = eas.wbxmltools.createWBXML();
+        wbxml.switchpage("FolderHierarchy");
+        wbxml.otag("FolderDelete");
+        wbxml.atag("SyncKey", foldersynckey);
+        wbxml.atag("ServerId", syncData.currentFolderData.getFolderProperty("serverID"));
+        wbxml.ctag();
+
+        syncData.setSyncState("send.request.deletefolder");
+        let response = await eas.network.sendRequest(wbxml.getBytes(), "FolderDelete", syncData);
+
+        syncData.setSyncState("eval.response.deletefolder");
+        let wbxmlData = eas.network.getDataFromResponse(response);
+
+        eas.network.checkStatus(syncData, wbxmlData, "FolderDelete.Status");
+
+        let synckey = eas.xmltools.getWbxmlDataField(wbxmlData, "FolderDelete.SyncKey");
+        if (synckey) {
+            syncData.accountData.setAccountProperty("foldersynckey", synckey);
+            syncData.currentFolderData.remove();
+        } else {
+            throw eas.sync.finish("error", "wbxmlmissingfield::FolderDelete.SyncKey");
+        }
+    },
+
+
+
+
+
+    singleFolder: async function (syncData) {
+        // add target to syncData
+        try {
+            // accessing the target for the first time will check if it is avail and if not will create it (if possible)
+            syncData.target = await syncData.currentFolderData.targetData.getTarget();
+        } catch (e) {
+            Components.utils.reportError(e);
+            throw eas.sync.finish("warning", e.message);
+        }
+
+        //get syncData type, which is also used in WBXML for the CLASS element
+        syncData.type = null;
+        switch (syncData.currentFolderData.getFolderProperty("type")) {
+            case "9": //contact
+            case "14":
+                syncData.type = "Contacts";
+                break;
+            case "8": //event
+            case "13":
+                syncData.type = "Calendar";
+                break;
+            case "7": //todo
+            case "15":
+                syncData.type = "Tasks";
+                break;
+            default:
+                throw eas.sync.finish("info", "skipped");
+                break;
+        }
+
+        syncData.setSyncState("preparing");
+
+        //get synckey if needed
+        syncData.synckey = syncData.currentFolderData.getFolderProperty("synckey");
+        if (syncData.synckey == "") {
+            await eas.network.getSynckey(syncData);
+        }
+
+        //sync folder
+        syncData.timeOfLastSync = syncData.currentFolderData.getFolderProperty("lastsynctime") / 1000;
+        syncData.timeOfThisSync = (Date.now() / 1000) - 1;
+
+        let lightningBatch = false;
+        let lightningReadOnly = "";
+        let error = null;
+
+        // We ned to intercept any throw error, because lightning needs a few operations after sync finished
+        try {
+            switch (syncData.type) {
+                case "Contacts":
+                    await eas.sync.easFolder(syncData);
+                    break;
+
+                case "Calendar":
+                case "Tasks":
+                    //save current value of readOnly (or take it from the setting)
+                    lightningReadOnly = syncData.target.calendar.getProperty("readOnly") || syncData.currentFolderData.getFolderProperty("downloadonly");
+                    syncData.target.calendar.setProperty("readOnly", false);
+
+                    lightningBatch = true;
+                    syncData.target.calendar.startBatch();
+
+                    await eas.sync.easFolder(syncData);
+                    break;
+            }
+        } catch (report) {
+            error = report;
+        }
+
+        if (lightningBatch) {
+            syncData.target.calendar.endBatch();
+            syncData.target.calendar.setProperty("readOnly", lightningReadOnly);
+        }
+
+        if (error) throw error;
+    },
+
+
+
+
+
+
+
+
+
+
+    // ---------------------------------------------------------------------------
+    // MAIN FUNCTIONS TO SYNC AN EAS FOLDER
+    // ---------------------------------------------------------------------------
+
+    easFolder: async function (syncData) {
+        syncData.progressData.reset();
+
+        if (syncData.currentFolderData.getFolderProperty("downloadonly")) {
+            await eas.sync.revertLocalChanges(syncData);
+        }
+
+        await eas.network.getItemEstimate(syncData);
+        await eas.sync.requestRemoteChanges(syncData);
+
+        if (!syncData.currentFolderData.getFolderProperty("downloadonly")) {
+            let sendChanges = await eas.sync.sendLocalChanges(syncData);
+            if (sendChanges) {
+                // This is ugly as hell, but Microsoft sometimes sets the state of the
+                // remote account to "changed" after we have send a local change (even
+                // though it has acked the change) and this will cause the server to
+                // send a change request with our next sync. Because we follow the
+                // "server wins" policy, this will overwrite any additional local change
+                // we have done in the meantime. This is stupid, but we wait 2s and
+                // hope it is enough to catch this second ack of the local change.
+                let timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
+                await new Promise(function (resolve, reject) {
+                    let event = {
+                        notify: function (timer) {
+                            resolve();
+                        }
+                    }
+                    timer.initWithCallback(event, 2000, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+                });
+                await eas.sync.requestRemoteChanges(syncData);
+            }
+        }
+    },
+
+
+    requestRemoteChanges: async function (syncData) {
+        do {
+            syncData.setSyncState("prepare.request.remotechanges");
+            syncData.request = "";
+            syncData.response = "";
+
+            // BUILD WBXML
+            let wbxml = eas.wbxmltools.createWBXML();
+            wbxml.otag("Sync");
+            wbxml.otag("Collections");
+            wbxml.otag("Collection");
+            if (syncData.accountData.getAccountProperty("asversion") == "2.5") wbxml.atag("Class", syncData.type);
+            wbxml.atag("SyncKey", syncData.synckey);
+            wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID"));
+            wbxml.atag("DeletesAsMoves");
+            wbxml.atag("GetChanges");
+            wbxml.atag("WindowSize", eas.prefs.getIntPref("maxitems").toString());
+
+            if (syncData.accountData.getAccountProperty("asversion") != "2.5") {
+                wbxml.otag("Options");
+                if (syncData.type == "Calendar") wbxml.atag("FilterType", syncData.currentFolderData.accountData.getAccountProperty("synclimit"));
+                wbxml.atag("Class", syncData.type);
+                wbxml.switchpage("AirSyncBase");
+                wbxml.otag("BodyPreference");
+                wbxml.atag("Type", "1");
+                wbxml.ctag();
+                wbxml.switchpage("AirSync");
+                wbxml.ctag();
+            } else if (syncData.type == "Calendar") { //in 2.5 we only send it to filter Calendar
+                wbxml.otag("Options");
+                wbxml.atag("FilterType", syncData.currentFolderData.accountData.getAccountProperty("synclimit"));
+                wbxml.ctag();
+            }
+
+            wbxml.ctag();
+            wbxml.ctag();
+            wbxml.ctag();
+
+            //SEND REQUEST
+            syncData.setSyncState("send.request.remotechanges");
+            let response = await eas.network.sendRequest(wbxml.getBytes(), "Sync", syncData);
+
+            //VALIDATE RESPONSE
+            // get data from wbxml response, some servers send empty response if there are no changes, which is not an error
+            let wbxmlData = eas.network.getDataFromResponse(response, eas.flags.allowEmptyResponse);
+            if (wbxmlData === null) return;
+
+            //check status, throw on error
+            eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status");
+
+            //PROCESS COMMANDS        
+            await eas.sync.processCommands(wbxmlData, syncData);
+
+            //Update count in UI
+            syncData.setSyncState("eval.response.remotechanges");
+
+            //update synckey
+            eas.network.updateSynckey(syncData, wbxmlData);
+
+            if (!eas.xmltools.hasWbxmlDataField(wbxmlData, "Sync.Collections.Collection.MoreAvailable")) {
+                //Feedback from users: They want to see the final count
+                await TbSync.tools.sleep(100);
+                return;
+            }
+        } while (true);
+
+    },
+
+
+    sendLocalChanges: async function (syncData) {
+        let maxnumbertosend = eas.prefs.getIntPref("maxitems");
+        syncData.progressData.reset(0, syncData.target.getItemsFromChangeLog().length);
+
+        //keep track of failed items
+        syncData.failedItems = [];
+
+        let done = false;
+        let numberOfItemsToSend = maxnumbertosend;
+        let sendChanges = false;
+        do {
+            syncData.setSyncState("prepare.request.localchanges");
+            syncData.request = "";
+            syncData.response = "";
+
+            //get changed items from ChangeLog
+            let changes = syncData.target.getItemsFromChangeLog(numberOfItemsToSend);
+            //console.log("chnages", changes);
+            let c = 0;
+            let e = 0;
+
+            //keep track of send items during this request
+            let changedItems = [];
+            let addedItems = {};
+            let sendItems = [];
+
+            // BUILD WBXML
+            let wbxml = eas.wbxmltools.createWBXML();
+            wbxml.otag("Sync");
+            wbxml.otag("Collections");
+            wbxml.otag("Collection");
+            if (syncData.accountData.getAccountProperty("asversion") == "2.5") wbxml.atag("Class", syncData.type);
+            wbxml.atag("SyncKey", syncData.synckey);
+            wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID"));
+            wbxml.otag("Commands");
+
+            for (let i = 0; i < changes.length; i++) if (!syncData.failedItems.includes(changes[i].itemId)) {
+                //TbSync.dump("CHANGES",(i+1) + "/" + changes.length + " ("+changes[i].status+"," + changes[i].itemId + ")");
+                let item = null;
+                switch (changes[i].status) {
+
+                    case "added_by_user":
+                        item = await syncData.target.getItem(changes[i].itemId);
+                        if (item) {
+                            //filter out bad object types for this folder
+                            if (syncData.type == "Contacts" && item.isMailList) {
+                                // Mailing lists are not supported, this is not an error
+                                TbSync.eventlog.add("warning", syncData.eventLogInfo, "MailingListNotSupportedItemSkipped");
+                                syncData.target.removeItemFromChangeLog(changes[i].itemId);
+                            } else if (syncData.type == eas.sync.getEasItemType(item)) {
+                                //create a temp clientId, to cope with too long or invalid clientIds (for EAS)
+                                let clientId = Date.now() + "-" + c;
+                                addedItems[clientId] = changes[i].itemId;
+                                sendItems.push({ type: changes[i].status, id: changes[i].itemId });
+
+                                wbxml.otag("Add");
+                                wbxml.atag("ClientId", clientId); //Our temp clientId will get replaced by an id generated by the server
+                                wbxml.otag("ApplicationData");
+                                wbxml.switchpage(syncData.type);
+
+                                /*wbxml.atag("TimeZone", "xP///0UAdQByAG8AcABlAC8AQgBlAHIAbABpAG4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAIAAAAAAAAAAAAAAEUAdQByAG8AcABlAC8AQgBlAHIAbABpAG4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAEAAAAAAAAAxP///w==");
+                                wbxml.atag("AllDayEvent", "0");
+                                wbxml.switchpage("AirSyncBase");
+                                wbxml.otag("Body");
+                                    wbxml.atag("Type", "1");
+                                    wbxml.atag("EstimatedDataSize", "0");
+                                    wbxml.atag("Data");
+                                wbxml.ctag();
+                                
+                                wbxml.switchpage(syncData.type);						
+                                wbxml.atag("BusyStatus", "2");
+                                wbxml.atag("OrganizerName", "REDACTED.REDACTED");
+                                wbxml.atag("OrganizerEmail", "REDACTED.REDACTED at REDACTED");
+                                wbxml.atag("DtStamp", "20190131T091024Z");
+                                wbxml.atag("EndTime", "20180906T083000Z");
+                                wbxml.atag("Location");
+                                wbxml.atag("Reminder", "5");
+                                wbxml.atag("Sensitivity", "0");
+                                wbxml.atag("Subject", "SE-CN weekly sync");
+                                wbxml.atag("StartTime", "20180906T080000Z");
+                                wbxml.atag("UID", "1D51E503-9DFE-4A46-A6C2-9129E5E00C1D");
+                                wbxml.atag("MeetingStatus", "3");
+                                wbxml.otag("Attendees");
+                                    wbxml.otag("Attendee");
+                                        wbxml.atag("Email", "REDACTED.REDACTED at REDACTED");
+                                        wbxml.atag("Name", "REDACTED.REDACTED");
+                                        wbxml.atag("AttendeeType", "1");
+                                    wbxml.ctag();
+                                wbxml.ctag();
+                                wbxml.atag("Categories");
+                                wbxml.otag("Recurrence");
+                                    wbxml.atag("Type", "1");
+                                    wbxml.atag("DayOfWeek", "16");
+                                    wbxml.atag("Interval", "1");
+                                wbxml.ctag();
+                                wbxml.otag("Exceptions");
+                                    wbxml.otag("Exception");
+                                        wbxml.atag("ExceptionStartTime", "20181227T090000Z");
+                                        wbxml.atag("Deleted", "1");
+                                    wbxml.ctag();
+                                wbxml.ctag();*/
+
+                                wbxml.append(await eas.sync.getWbxmlFromThunderbirdItem(item, syncData));
+                                wbxml.switchpage("AirSync");
+                                wbxml.ctag();
+                                wbxml.ctag();
+                                c++;
+                            } else {
+                                eas.sync.updateFailedItems(syncData, "forbidden" + eas.sync.getEasItemType(item) + "ItemIn" + syncData.type + "Folder", item.primaryKey, item.toString());
+                                e++;
+                            }
+                        } else {
+                            syncData.target.removeItemFromChangeLog(changes[i].itemId);
+                        }
+                        break;
+
+                    case "modified_by_user":
+                        item = await syncData.target.getItem(changes[i].itemId);
+                        if (item) {
+                            //filter out bad object types for this folder
+                            if (syncData.type == eas.sync.getEasItemType(item)) {
+                                wbxml.otag("Change");
+                                wbxml.atag("ServerId", changes[i].itemId);
+                                wbxml.otag("ApplicationData");
+                                wbxml.switchpage(syncData.type);
+                                wbxml.append(await eas.sync.getWbxmlFromThunderbirdItem(item, syncData));
+                                wbxml.switchpage("AirSync");
+                                wbxml.ctag();
+                                wbxml.ctag();
+                                changedItems.push(changes[i].itemId);
+                                sendItems.push({ type: changes[i].status, id: changes[i].itemId });
+                                c++;
+                            } else {
+                                eas.sync.updateFailedItems(syncData, "forbidden" + eas.sync.getEasItemType(item) + "ItemIn" + syncData.type + "Folder", item.primaryKey, item.toString());
+                                e++;
+                            }
+                        } else {
+                            syncData.target.removeItemFromChangeLog(changes[i].itemId);
+                        }
+                        break;
+
+                    case "deleted_by_user":
+                        wbxml.otag("Delete");
+                        wbxml.atag("ServerId", changes[i].itemId);
+                        wbxml.ctag();
+                        changedItems.push(changes[i].itemId);
+                        sendItems.push({ type: changes[i].status, id: changes[i].itemId });
+                        c++;
+                        break;
+                }
+            }
+
+            wbxml.ctag(); //Commands
+            wbxml.ctag(); //Collection
+            wbxml.ctag(); //Collections
+            wbxml.ctag(); //Sync
+
+
+            if (c > 0) { //if there was at least one actual local change, send request
+                sendChanges = true;
+                //SEND REQUEST & VALIDATE RESPONSE
+                syncData.setSyncState("send.request.localchanges");
+                let response = await eas.network.sendRequest(wbxml.getBytes(), "Sync", syncData);
+
+                syncData.setSyncState("eval.response.localchanges");
+
+                //get data from wbxml response
+                let wbxmlData = eas.network.getDataFromResponse(response);
+
+                //check status and manually handle error states which support softfails
+                let errorcause = eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status", "", true);
+                switch (errorcause) {
+                    case "":
+                        break;
+
+                    case "Sync.4": //Malformed request
+                    case "Sync.6": //Invalid item
+                        //some servers send a global error - to catch this, we reduce the number of items we send to the server
+                        if (sendItems.length == 1) {
+                            //the request contained only one item, so we know which one failed
+                            if (sendItems[0].type == "deleted_by_user") {
+                                //we failed to delete an item, discard and place message in log
+                                syncData.target.removeItemFromChangeLog(sendItems[0].id);
+                                TbSync.eventlog.add("warning", syncData.eventLogInfo, "ErrorOnDelete::" + sendItems[0].id);
+                            } else {
+                                let foundItem = await syncData.target.getItem(sendItems[0].id);
+                                if (foundItem) {
+                                    eas.sync.updateFailedItems(syncData, errorcause, foundItem.primaryKey, foundItem.toString());
+                                } else {
+                                    //should not happen
+                                    syncData.target.removeItemFromChangeLog(sendItems[0].id);
+                                }
+                            }
+                            syncData.progressData.inc();
+                            //restore numberOfItemsToSend
+                            numberOfItemsToSend = maxnumbertosend;
+                        } else if (sendItems.length > 1) {
+                            //reduce further
+                            numberOfItemsToSend = Math.min(1, Math.round(sendItems.length / 5));
+                        } else {
+                            //sendItems.length == 0 ??? recheck but this time let it handle all cases
+                            eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status");
+                        }
+                        break;
+
+                    default:
+                        //recheck but this time let it handle all cases
+                        eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status");
+                }
+
+                await TbSync.tools.sleep(10, true);
+
+                if (errorcause == "") {
+                    //PROCESS RESPONSE        
+                    await eas.sync.processResponses(wbxmlData, syncData, addedItems, changedItems);
+
+                    //PROCESS COMMANDS        
+                    await eas.sync.processCommands(wbxmlData, syncData);
+
+                    //remove all items from changelog that did not fail
+                    for (let a = 0; a < changedItems.length; a++) {
+                        syncData.target.removeItemFromChangeLog(changedItems[a]);
+                        syncData.progressData.inc();
+                    }
+
+                    //update synckey
+                    eas.network.updateSynckey(syncData, wbxmlData);
+                }
+
+            } else if (e == 0) { //if there was no local change and also no error (which will not happen twice) finish
+
+                done = true;
+
+            }
+
+        } while (!done);
+
+        //was there an error?
+        if (syncData.failedItems.length > 0) {
+            throw eas.sync.finish("warning", "ServerRejectedSomeItems::" + syncData.failedItems.length);
+        }
+        return sendChanges;
+    },
+
+
+
+
+    revertLocalChanges: async function (syncData) {
+        let maxnumbertosend = eas.prefs.getIntPref("maxitems");
+        syncData.progressData.reset(0, syncData.target.getItemsFromChangeLog().length);
+        if (syncData.progressData.todo == 0) {
+            return;
+        }
+
+        let viaItemOperations = (syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("ItemOperations"));
+
+        //get changed items from ChangeLog
+        do {
+            syncData.setSyncState("prepare.request.revertlocalchanges");
+            let changes = syncData.target.getItemsFromChangeLog(maxnumbertosend);
+            let c = 0;
+            syncData.request = "";
+            syncData.response = "";
+
+            // BUILD WBXML
+            let wbxml = eas.wbxmltools.createWBXML();
+            if (viaItemOperations) {
+                wbxml.switchpage("ItemOperations");
+                wbxml.otag("ItemOperations");
+            } else {
+                wbxml.otag("Sync");
+                wbxml.otag("Collections");
+                wbxml.otag("Collection");
+                if (syncData.accountData.getAccountProperty("asversion") == "2.5") wbxml.atag("Class", syncData.type);
+                wbxml.atag("SyncKey", syncData.synckey);
+                wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID"));
+                wbxml.otag("Commands");
+            }
+
+            for (let i = 0; i < changes.length; i++) {
+                let item = null;
+                let ServerId = changes[i].itemId;
+                let foundItem = await syncData.target.getItem(ServerId);
+
+                switch (changes[i].status) {
+                    case "added_by_user": //remove
+                        if (foundItem) {
+                            await syncData.target.deleteItem(foundItem);
+                        }
+                        break;
+
+                    case "modified_by_user":
+                        if (foundItem) { //delete item so it can be replaced with a fresh copy, the changelog entry will be changed from modified to deleted
+                            await syncData.target.deleteItem(foundItem);
+                        }
+                    case "deleted_by_user":
+                        if (viaItemOperations) {
+                            wbxml.otag("Fetch");
+                            wbxml.atag("Store", "Mailbox");
+                            wbxml.switchpage("AirSync");
+                            wbxml.atag("CollectionId", syncData.currentFolderData.getFolderProperty("serverID"));
+                            wbxml.atag("ServerId", ServerId);
+                            wbxml.switchpage("ItemOperations");
+                            wbxml.otag("Options");
+                            wbxml.switchpage("AirSyncBase");
+                            wbxml.otag("BodyPreference");
+                            wbxml.atag("Type", "1");
+                            wbxml.ctag();
+                            wbxml.switchpage("ItemOperations");
+                            wbxml.ctag();
+                            wbxml.ctag();
+                        } else {
+                            wbxml.otag("Fetch");
+                            wbxml.atag("ServerId", ServerId);
+                            wbxml.ctag();
+                        }
+                        c++;
+                        break;
+                }
+            }
+
+            if (viaItemOperations) {
+                wbxml.ctag(); //ItemOperations
+            } else {
+                wbxml.ctag(); //Commands
+                wbxml.ctag(); //Collection
+                wbxml.ctag(); //Collections
+                wbxml.ctag(); //Sync
+            }
+
+            if (c > 0) { //if there was at least one actual local change, send request
+                let error = false;
+                let wbxmlData = "";
+
+                //SEND REQUEST & VALIDATE RESPONSE
+                try {
+                    syncData.setSyncState("send.request.revertlocalchanges");
+                    let response = await eas.network.sendRequest(wbxml.getBytes(), (viaItemOperations) ? "ItemOperations" : "Sync", syncData);
+
+                    syncData.setSyncState("eval.response.revertlocalchanges");
+
+                    //get data from wbxml response
+                    wbxmlData = eas.network.getDataFromResponse(response);
+                } catch (e) {
+                    //we do not handle errors, IF there was an error, wbxmlData is empty and will trigger the fallback
+                }
+
+                let fetchPath = (viaItemOperations) ? "ItemOperations.Response.Fetch" : "Sync.Collections.Collection.Responses.Fetch";
+                if (eas.xmltools.hasWbxmlDataField(wbxmlData, fetchPath)) {
+
+                    //looking for additions
+                    let add = eas.xmltools.nodeAsArray(eas.xmltools.getWbxmlDataField(wbxmlData, fetchPath));
+                    for (let count = 0; count < add.length; count++) {
+                        await TbSync.tools.sleep(10, true);
+
+                        let ServerId = add[count].ServerId;
+                        let data = (viaItemOperations) ? add[count].Properties : add[count].ApplicationData;
+
+                        if (data && ServerId) {
+                            let foundItem = await syncData.target.getItem(ServerId);
+                            if (!foundItem) { //do NOT add, if an item with that ServerId was found
+                                let newItem = eas.sync.createItem(syncData);
+                                try {
+                                    eas.sync[syncData.type].setThunderbirdItemFromWbxml(newItem, data, ServerId, syncData);
+                                    await syncData.target.addItem(newItem);
+                                } catch (e) {
+                                    eas.xmltools.printXmlData(add[count], true); //include application data in log                  
+                                    TbSync.eventlog.add("warning", syncData.eventLogInfo, "BadItemSkipped::JavaScriptError", newItem.toString());
+                                    throw e; // unable to add item to Thunderbird - fatal error
+                                }
+                            } else {
+                                //should not happen, since we deleted that item beforehand
+                                syncData.target.removeItemFromChangeLog(ServerId);
+                            }
+                            syncData.progressData.inc();
+                        } else {
+                            error = true;
+                            break;
+                        }
+                    }
+                } else {
+                    error = true;
+                }
+
+                if (error) {
+                    //if ItemOperations.Fetch fails, fall back to Sync.Fetch, if that fails, fall back to resync
+                    if (viaItemOperations) {
+                        viaItemOperations = false;
+                        TbSync.eventlog.add("info", syncData.eventLogInfo, "Server returned error during ItemOperations.Fetch, falling back to Sync.Fetch.");
+                    } else {
+                        await eas.sync.revertLocalChangesViaResync(syncData);
+                        return;
+                    }
+                }
+
+            } else { //if there was no more local change we need to revert, return
+
+                return;
+
+            }
+
+        } while (true);
+
+    },
+
+    revertLocalChangesViaResync: async function (syncData) {
+        TbSync.eventlog.add("info", syncData.eventLogInfo, "Server does not support ItemOperations.Fetch and/or Sync.Fetch, must revert via resync.");
+        let changes = syncData.target.getItemsFromChangeLog();
+
+        syncData.progressData.reset(0, changes.length);
+        syncData.setSyncState("prepare.request.revertlocalchanges");
+
+        //remove all changes, so we can get them fresh from the server
+        for (let i = 0; i < changes.length; i++) {
+            let item = null;
+            let ServerId = changes[i].itemId;
+            syncData.target.removeItemFromChangeLog(ServerId);
+            let foundItem = await syncData.target.getItem(ServerId);
+            if (foundItem) { //delete item with that ServerId
+                await syncData.target.deleteItem(foundItem);
+            }
+            syncData.progressData.inc();
+        }
+
+        //This will resync all missing items fresh from the server
+        TbSync.eventlog.add("info", syncData.eventLogInfo, "RevertViaFolderResync");
+        eas.sync.resetFolderSyncInfo(syncData.currentFolderData);
+        throw eas.sync.finish("resyncFolder", "RevertViaFolderResync");
+    },
+
+
+
+
+    // ---------------------------------------------------------------------------
+    // SUB FUNCTIONS CALLED BY  MAIN FUNCTION
+    // ---------------------------------------------------------------------------
+
+    processCommands: async function (wbxmlData, syncData) {
+        //any commands for us to work on? If we reach this point, Sync.Collections.Collection is valid, 
+        //no need to use the save getWbxmlDataField function
+        if (wbxmlData.Sync.Collections.Collection.Commands) {
+
+            //looking for additions
+            let add = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Commands.Add);
+            for (let count = 0; count < add.length; count++) {
+                await TbSync.tools.sleep(10, true);
+
+                let ServerId = add[count].ServerId;
+                let data = add[count].ApplicationData;
+
+                let foundItem = await syncData.target.getItem(ServerId);
+                if (!foundItem) {
+                    //do NOT add, if an item with that ServerId was found
+                    let newItem = eas.sync.createItem(syncData);
+                    try {
+                        eas.sync[syncData.type].setThunderbirdItemFromWbxml(newItem, data, ServerId, syncData);
+                        await syncData.target.addItem(newItem);
+                    } catch (e) {
+                        eas.xmltools.printXmlData(add[count], true); //include application data in log                  
+                        TbSync.eventlog.add("warning", syncData.eventLogInfo, "BadItemSkipped::JavaScriptError", newItem.toString());
+                        throw e; // unable to add item to Thunderbird - fatal error
+                    }
+                } else {
+                    TbSync.eventlog.add("info", syncData.eventLogInfo, "Add request, but element exists already, skipped.", ServerId);
+                }
+                syncData.progressData.inc();
+            }
+
+            //looking for changes
+            let upd = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Commands.Change);
+            //inject custom change object for debug
+            //upd = JSON.parse('[{"ServerId":"2tjoanTeS0CJ3QTsq5vdNQAAAAABDdrY6Gp03ktAid0E7Kub3TUAAAoZy4A1","ApplicationData":{"DtStamp":"20171109T142149Z"}}]');
+            for (let count = 0; count < upd.length; count++) {
+                await TbSync.tools.sleep(10, true);
+
+                let ServerId = upd[count].ServerId;
+                let data = upd[count].ApplicationData;
+
+                syncData.progressData.inc();
+                let foundItem = await syncData.target.getItem(ServerId);
+                if (foundItem) { //only update, if an item with that ServerId was found
+
+                    let keys = Object.keys(data);
+                    //replace by smart merge
+                    if (keys.length == 1 && keys[0] == "DtStamp") TbSync.dump("DtStampOnly", keys); //ignore DtStamp updates (fix with smart merge)
+                    else {
+
+                        if (foundItem.changelogStatus !== null) {
+                            TbSync.eventlog.add("info", syncData.eventLogInfo, "Change request from server, but also local modifications, server wins!", ServerId);
+                            foundItem.changelogStatus = null;
+                        }
+
+                        let newItem = foundItem.clone();
+                        try {
+                            eas.sync[syncData.type].setThunderbirdItemFromWbxml(newItem, data, ServerId, syncData);
+                            await syncData.target.modifyItem(newItem, foundItem);
+                        } catch (e) {
+                            TbSync.eventlog.add("warning", syncData.eventLogInfo, "BadItemSkipped::JavaScriptError", newItem.toString());
+                            eas.xmltools.printXmlData(upd[count], true);  //include application data in log                   
+                            throw e; // unable to mod item to Thunderbird - fatal error
+                        }
+                    }
+
+                }
+            }
+
+            //looking for deletes
+            let del = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Commands.Delete).concat(eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Commands.SoftDelete));
+            for (let count = 0; count < del.length; count++) {
+                await TbSync.tools.sleep(10, true);
+
+                let ServerId = del[count].ServerId;
+
+                let foundItem = await syncData.target.getItem(ServerId);
+                if (foundItem) { //delete item with that ServerId
+                    await syncData.target.deleteItem(foundItem);
+                }
+                syncData.progressData.inc();
+            }
+
+        }
+    },
+
+
+    updateFailedItems: function (syncData, cause, id, data) {
+        //something is wrong with this item, move it to the end of changelog and go on
+        if (!syncData.failedItems.includes(id)) {
+            //the extra parameter true will re-add the item to the end of the changelog
+            syncData.target.removeItemFromChangeLog(id, true);
+            syncData.failedItems.push(id);
+            TbSync.eventlog.add("info", syncData.eventLogInfo, "BadItemSkipped::" + TbSync.getString("status." + cause, "eas"), "\n\nRequest:\n" + syncData.request + "\n\nResponse:\n" + syncData.response + "\n\nElement:\n" + data);
+        }
+    },
+
+
+    processResponses: async function (wbxmlData, syncData, addedItems, changedItems) {
+        //any responses for us to work on?  If we reach this point, Sync.Collections.Collection is valid, 
+        //no need to use the save getWbxmlDataField function
+        if (wbxmlData.Sync.Collections.Collection.Responses) {
+
+            //looking for additions (Add node contains, status, old ClientId and new ServerId)
+            let add = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Responses.Add);
+            for (let count = 0; count < add.length; count++) {
+                await TbSync.tools.sleep(10, true);
+
+                //get the true Thunderbird UID of this added item (we created a temp clientId during add)
+                add[count].ClientId = addedItems[add[count].ClientId];
+
+                //look for an item identfied by ClientId and update its id to the new id received from the server
+                let foundItem = await syncData.target.getItem(add[count].ClientId);
+                if (foundItem) {
+
+                    //Check status, stop sync if bad, allow soft fail
+                    let errorcause = eas.network.checkStatus(syncData, add[count], "Status", "Sync.Collections.Collection.Responses.Add[" + count + "].Status", true);
+                    if (errorcause !== "") {
+                        //something is wrong with this item, move it to the end of changelog and go on
+                        eas.sync.updateFailedItems(syncData, errorcause, foundItem.primaryKey, foundItem.toString());
+                    } else {
+                        let newItem = foundItem.clone();
+                        newItem.primaryKey = add[count].ServerId;
+                        syncData.target.removeItemFromChangeLog(add[count].ClientId);
+                        await syncData.target.modifyItem(newItem, foundItem);
+                        syncData.progressData.inc();
+                    }
+
+                }
+            }
+
+            //looking for modifications 
+            let upd = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Responses.Change);
+            for (let count = 0; count < upd.length; count++) {
+                let foundItem = await syncData.target.getItem(upd[count].ServerId);
+                if (foundItem) {
+
+                    //Check status, stop sync if bad, allow soft fail
+                    let errorcause = eas.network.checkStatus(syncData, upd[count], "Status", "Sync.Collections.Collection.Responses.Change[" + count + "].Status", true);
+                    if (errorcause !== "") {
+                        //something is wrong with this item, move it to the end of changelog and go on
+                        eas.sync.updateFailedItems(syncData, errorcause, foundItem.primaryKey, foundItem.toString());
+                        //also remove from changedItems
+                        let p = changedItems.indexOf(upd[count].ServerId);
+                        if (p > -1) changedItems.splice(p, 1);
+                    }
+
+                }
+            }
+
+            //looking for deletions 
+            let del = eas.xmltools.nodeAsArray(wbxmlData.Sync.Collections.Collection.Responses.Delete);
+            for (let count = 0; count < del.length; count++) {
+                //What can we do about failed deletes? SyncLog
+                eas.network.checkStatus(syncData, del[count], "Status", "Sync.Collections.Collection.Responses.Delete[" + count + "].Status", true);
+            }
+
+        }
+    },
+
+
+
+
+
+
+
+
+
+
+    // ---------------------------------------------------------------------------
+    // HELPER FUNCTIONS AND DEFINITIONS
+    // ---------------------------------------------------------------------------
+
+    MAP_EAS2TB: {
+        //EAS Importance: 0 = LOW | 1 = NORMAL | 2 = HIGH
+        Importance: { "0": "9", "1": "5", "2": "1" }, //to PRIORITY
+        //EAS Sensitivity :  0 = Normal  |  1 = Personal  |  2 = Private  |  3 = Confidential
+        Sensitivity: { "0": "PUBLIC", "1": "PRIVATE", "2": "PRIVATE", "3": "CONFIDENTIAL" }, //to CLASS
+        //EAS BusyStatus:  0 = Free  |  1 = Tentative  |  2 = Busy  |  3 = Work  |  4 = Elsewhere
+        BusyStatus: { "0": "TRANSPARENT", "1": "unset", "2": "OPAQUE", "3": "OPAQUE", "4": "OPAQUE" }, //to TRANSP
+        //EAS AttendeeStatus: 0 =Response unknown (but needed) |  2 = Tentative  |  3 = Accept  |  4 = Decline  |  5 = Not responded (and not needed) || 1 = Organizer in ResponseType
+        ATTENDEESTATUS: { "0": "NEEDS-ACTION", "1": "Orga", "2": "TENTATIVE", "3": "ACCEPTED", "4": "DECLINED", "5": "ACCEPTED" },
+    },
+
+    MAP_TB2EAS: {
+        //TB PRIORITY: 9 = LOW | 5 = NORMAL | 1 = HIGH
+        PRIORITY: { "9": "0", "5": "1", "1": "2", "unset": "1" }, //to Importance
+        //TB CLASS: PUBLIC, PRIVATE, CONFIDENTIAL)
+        CLASS: { "PUBLIC": "0", "PRIVATE": "2", "CONFIDENTIAL": "3", "unset": "0" }, //to Sensitivity
+        //TB TRANSP : free = TRANSPARENT, busy = OPAQUE)
+        TRANSP: { "TRANSPARENT": "0", "unset": "1", "OPAQUE": "2" }, // to BusyStatus
+        //TB STATUS: NEEDS-ACTION, ACCEPTED, DECLINED, TENTATIVE, (DELEGATED, COMPLETED, IN-PROCESS - for todo)
+        ATTENDEESTATUS: { "NEEDS-ACTION": "0", "ACCEPTED": "3", "DECLINED": "4", "TENTATIVE": "2", "DELEGATED": "5", "COMPLETED": "5", "IN-PROCESS": "5" },
+    },
+
+    mapEasPropertyToThunderbird: function (easProp, tbProp, data, item) {
+        if (data[easProp]) {
+            //store original EAS value
+            let easPropValue = eas.xmltools.checkString(data[easProp]);
+            item.setProperty("X-EAS-" + easProp, easPropValue);
+            //map EAS value to TB value  (use setCalItemProperty if there is one option which can unset/delete the property)
+            eas.tools.setCalItemProperty(item, tbProp, eas.sync.MAP_EAS2TB[easProp][easPropValue]);
+        }
+    },
+
+    mapThunderbirdPropertyToEas: function (tbProp, easProp, item) {
+        if (item.hasProperty("X-EAS-" + easProp) && eas.tools.getCalItemProperty(item, tbProp) == eas.sync.MAP_EAS2TB[easProp][item.getProperty("X-EAS-" + easProp)]) {
+            //we can use our stored EAS value, because it still maps to the current TB value
+            return item.getProperty("X-EAS-" + easProp);
+        } else {
+            return eas.sync.MAP_TB2EAS[tbProp][eas.tools.getCalItemProperty(item, tbProp)];
+        }
+    },
+
+    getEasItemType(aItem) {
+        if (aItem instanceof TbSync.addressbook.AbItem) {
+            return "Contacts";
+        } else if (aItem instanceof TbSync.lightning.TbItem) {
+            return aItem.isTodo ? "Tasks" : "Calendar";
+        } else {
+            throw "Unknown aItem.";
+        }
+    },
+
+    createItem(syncData) {
+        switch (syncData.type) {
+            case "Contacts":
+                return syncData.target.createNewCard();
+                break;
+
+            case "Tasks":
+                return syncData.target.createNewTodo();
+                break;
+
+            case "Calendar":
+                return syncData.target.createNewEvent();
+                break;
+
+            default:
+                throw "Unknown item type <" + syncData.type + ">";
+        }
+    },
+
+    async getWbxmlFromThunderbirdItem(item, syncData, isException = false) {
+        try {
+            let wbxml = await eas.sync[syncData.type].getWbxmlFromThunderbirdItem(item, syncData, isException);
+            return wbxml;
+        } catch (e) {
+            TbSync.eventlog.add("warning", syncData.eventLogInfo, "BadItemSkipped::JavaScriptError", item.toString());
+            throw e; // unable to read item from Thunderbird - fatal error
+        }
+    },
+
+
+
+
+
+
+
+    // ---------------------------------------------------------------------------
+    // LIGHTNING HELPER FUNCTIONS AND DEFINITIONS
+    // These functions are needed only by tasks and events, so they
+    // are placed here, even though they are not type independent,
+    // but I did not want to add another "lightning" sub layer.
+    //
+    // The item in these functions is a native lightning item.
+    // ---------------------------------------------------------------------------
+
+    setItemSubject: function (item, syncData, data) {
+        if (data.Subject) item.title = eas.xmltools.checkString(data.Subject);
+    },
+
+    setItemLocation: function (item, syncData, data) {
+        if (data.Location) item.setProperty("location", eas.xmltools.checkString(data.Location));
+    },
+
+
+    setItemCategories: function (item, syncData, data) {
+        if (data.Categories && data.Categories.Category) {
+            let cats = [];
+            if (Array.isArray(data.Categories.Category)) cats = data.Categories.Category;
+            else cats.push(data.Categories.Category);
+            item.setCategories(cats);
+        }
+    },
+
+    getItemCategories: function (item, syncData) {
+        let asversion = syncData.accountData.getAccountProperty("asversion");
+        let wbxml = eas.wbxmltools.createWBXML("", syncData.type); //init wbxml with "" and not with precodes, also activate type codePage (Calendar, Tasks, Contacts etc)
+
+        //to properly "blank" categories, we need to always include the container
+        let categories = item.getCategories({});
+        if (categories.length > 0) {
+            wbxml.otag("Categories");
+            for (let i = 0; i < categories.length; i++) wbxml.atag("Category", categories[i]);
+            wbxml.ctag();
+        } else {
+            wbxml.atag("Categories");
+        }
+        return wbxml.getBytes();
+    },
+
+
+    setItemBody: function (item, syncData, data) {
+        let asversion = syncData.accountData.getAccountProperty("asversion");
+        if (asversion == "2.5") {
+            if (data.Body) item.setProperty("description", eas.xmltools.checkString(data.Body));
+        } else {
+            if (data.Body && /* data.Body.EstimatedDataSize > 0  && */ data.Body.Data) item.setProperty("description", eas.xmltools.checkString(data.Body.Data)); //EstimatedDataSize is optional
+        }
+    },
+
+    getItemBody: function (item, syncData) {
+        let asversion = syncData.accountData.getAccountProperty("asversion");
+        let wbxml = eas.wbxmltools.createWBXML("", syncData.type); //init wbxml with "" and not with precodes, also activate type codePage (Calendar, Tasks, Contacts etc)
+
+        let description = (item.hasProperty("description")) ? item.getProperty("description") : "";
+        if (asversion == "2.5") {
+            wbxml.atag("Body", description);
+        } else {
+            wbxml.switchpage("AirSyncBase");
+            wbxml.otag("Body");
+            wbxml.atag("Type", "1");
+            wbxml.atag("EstimatedDataSize", "" + description.length);
+            wbxml.atag("Data", description);
+            wbxml.ctag();
+            //does not work with horde at the moment, does not work with task, does not work with exceptions
+            //if (syncData.accountData.getAccountProperty("horde") == "0") wbxml.atag("NativeBodyType", "1");
+
+            //return to code page of this type
+            wbxml.switchpage(syncData.type);
+        }
+        return wbxml.getBytes();
+    },
+
+    //item is a native lightning item
+    setItemRecurrence: function (item, syncData, data, timezone) {
+        if (data.Recurrence) {
+            item.recurrenceInfo = new CalRecurrenceInfo();
+            item.recurrenceInfo.item = item;
+            let recRule = TbSync.lightning.cal.createRecurrenceRule();
+            switch (data.Recurrence.Type) {
+                case "0":
+                    recRule.type = "DAILY";
+                    break;
+                case "1":
+                    recRule.type = "WEEKLY";
+                    break;
+                case "2":
+                case "3":
+                    recRule.type = "MONTHLY";
+                    break;
+                case "5":
+                case "6":
+                    recRule.type = "YEARLY";
+                    break;
+            }
+
+            if (data.Recurrence.CalendarType) {
+                // TODO
+            }
+            if (data.Recurrence.DayOfMonth) {
+                recRule.setComponent("BYMONTHDAY", [data.Recurrence.DayOfMonth]);
+            }
+            if (data.Recurrence.DayOfWeek) {
+                let DOW = data.Recurrence.DayOfWeek;
+                if (DOW == 127 && (recRule.type == "MONTHLY" || recRule.type == "YEARLY")) {
+                    recRule.setComponent("BYMONTHDAY", [-1]);
+                }
+                else {
+                    let days = [];
+                    for (let i = 0; i < 7; ++i) {
+                        if (DOW & 1 << i) days.push(i + 1);
+                    }
+                    if (data.Recurrence.WeekOfMonth) {
+                        for (let i = 0; i < days.length; ++i) {
+                            if (data.Recurrence.WeekOfMonth == 5) {
+                                days[i] = -1 * (days[i] + 8);
+                            }
+                            else {
+                                days[i] += 8 * (data.Recurrence.WeekOfMonth - 0);
+                            }
+                        }
+                    }
+                    recRule.setComponent("BYDAY", days);
+                }
+            }
+            if (data.Recurrence.FirstDayOfWeek) {
+                //recRule.setComponent("WKST", [data.Recurrence.FirstDayOfWeek]); // WKST is not a valid component
+                //recRule.weekStart = data.Recurrence.FirstDayOfWeek; // - (NS_ERROR_NOT_IMPLEMENTED) [calIRecurrenceRule.weekStart]
+                TbSync.eventlog.add("info", syncData.eventLogInfo, "FirstDayOfWeek tag ignored (not supported).", item.icalString);
+            }
+
+            if (data.Recurrence.Interval) {
+                recRule.interval = data.Recurrence.Interval;
+            }
+            if (data.Recurrence.IsLeapMonth) {
+                // TODO
+            }
+            if (data.Recurrence.MonthOfYear) {
+                recRule.setComponent("BYMONTH", [data.Recurrence.MonthOfYear]);
+            }
+            if (data.Recurrence.Occurrences) {
+                recRule.count = data.Recurrence.Occurrences;
+            }
+            if (data.Recurrence.Until) {
+                //time string could be in compact/basic or extended form of ISO 8601, 
+                //cal.createDateTime only supports  compact/basic, our own method takes both styles
+                recRule.untilDate = eas.tools.createDateTime(data.Recurrence.Until);
+            }
+            if (data.Recurrence.Start) {
+                TbSync.eventlog.add("info", syncData.eventLogInfo, "Start tag in recurring task is ignored, recurrence will start with first entry.", item.icalString);
+            }
+
+            item.recurrenceInfo.insertRecurrenceItemAt(recRule, 0);
+
+            if (data.Exceptions && syncData.type == "Calendar") { // only events, tasks cannot have exceptions
+                // Exception could be an object or an array of objects
+                let exceptions = [].concat(data.Exceptions.Exception);
+                for (let exception of exceptions) {
+                    //exception.ExceptionStartTime is in UTC, but the Recurrence Object is in local timezone
+                    let dateTime = TbSync.lightning.cal.createDateTime(exception.ExceptionStartTime).getInTimezone(timezone);
+                    if (data.AllDayEvent == "1") {
+                        dateTime.isDate = true;
+                        // Pass to replacement event unless overriden
+                        if (!exception.AllDayEvent) {
+                            exception.AllDayEvent = "1";
+                        }
+                    }
+                    if (exception.Deleted == "1") {
+                        item.recurrenceInfo.removeOccurrenceAt(dateTime);
+                    }
+                    else {
+                        let replacement = item.recurrenceInfo.getOccurrenceFor(dateTime);
+                        // replacement is a native lightning item, so we can access its id via .id
+                        eas.sync[syncData.type].setThunderbirdItemFromWbxml(replacement, exception, replacement.id, syncData, "recurrence");
+                        // Reminders should carry over from parent, but setThunderbirdItemFromWbxml clears all alarms
+                        if (!exception.Reminder && item.getAlarms({}).length) {
+                            replacement.addAlarm(item.getAlarms({})[0]);
+                        }
+                        // Removing a reminder requires EAS 16.0
+                        item.recurrenceInfo.modifyException(replacement, true);
+                    }
+                }
+            }
+        }
+    },
+
+    getItemRecurrence: async function (item, syncData, localStartDate = null) {
+        let asversion = syncData.accountData.getAccountProperty("asversion");
+        let wbxml = eas.wbxmltools.createWBXML("", syncData.type); //init wbxml with "" and not with precodes, also activate type codePage (Calendar, Tasks etc)
+
+        if (item.recurrenceInfo && (syncData.type == "Calendar" || syncData.type == "Tasks")) {
+            let deleted = [];
+            let hasRecurrence = false;
+            let startDate = (syncData.type == "Calendar") ? item.startDate : item.entryDate;
+
+            for (let recRule of item.recurrenceInfo.getRecurrenceItems({})) {
+                if (recRule.date) {
+                    if (recRule.isNegative) {
+                        // EXDATE
+                        deleted.push(recRule);
+                    }
+                    else {
+                        // RDATE
+                        TbSync.eventlog.add("info", syncData.eventLogInfo, "Ignoring RDATE rule (not supported)", recRule.icalString);
+                    }
+                    continue;
+                }
+                if (recRule.isNegative) {
+                    // EXRULE
+                    TbSync.eventlog.add("info", syncData.eventLogInfo, "Ignoring EXRULE rule (not supported)", recRule.icalString);
+                    continue;
+                }
+
+                // RRULE
+                wbxml.otag("Recurrence");
+                hasRecurrence = true;
+
+                let type = 0;
+                let monthDays = recRule.getComponent("BYMONTHDAY", {});
+                let weekDays = recRule.getComponent("BYDAY", {});
+                let months = recRule.getComponent("BYMONTH", {});
+                let weeks = [];
+
+                // Unpack 1MO style days
+                for (let i = 0; i < weekDays.length; ++i) {
+                    if (weekDays[i] > 8) {
+                        weeks[i] = Math.floor(weekDays[i] / 8);
+                        weekDays[i] = weekDays[i] % 8;
+                    }
+                    else if (weekDays[i] < -8) {
+                        // EAS only supports last week as a special value, treat
+                        // all as last week or assume every month has 5 weeks?
+                        // Change to last week
+                        //weeks[i] = 5;
+                        // Assumes 5 weeks per month for week <= -2
+                        weeks[i] = 6 - Math.floor(-weekDays[i] / 8);
+                        weekDays[i] = -weekDays[i] % 8;
+                    }
+                }
+                if (monthDays[0] && monthDays[0] == -1) {
+                    weeks = [5];
+                    weekDays = [1, 2, 3, 4, 5, 6, 7]; // 127
+                    monthDays[0] = null;
+                }
+                // Type
+                if (recRule.type == "WEEKLY") {
+                    type = 1;
+                    if (!weekDays.length) {
+                        weekDays = [startDate.weekday + 1];
+                    }
+                }
+                else if (recRule.type == "MONTHLY" && weeks.length) {
+                    type = 3;
+                }
+                else if (recRule.type == "MONTHLY") {
+                    type = 2;
+                    if (!monthDays.length) {
+                        monthDays = [startDate.day];
+                    }
+                }
+                else if (recRule.type == "YEARLY" && weeks.length) {
+                    type = 6;
+                }
+                else if (recRule.type == "YEARLY") {
+                    type = 5;
+                    if (!monthDays.length) {
+                        monthDays = [startDate.day];
+                    }
+                    if (!months.length) {
+                        months = [startDate.month + 1];
+                    }
+                }
+                wbxml.atag("Type", type.toString());
+
+                //Tasks need a Start tag, but we cannot allow a start date different from the start of the main item (thunderbird does not support that)
+                if (localStartDate) wbxml.atag("Start", localStartDate);
+
+                // TODO: CalendarType: 14.0 and up
+                // DayOfMonth
+                if (monthDays[0]) {
+                    // TODO: Multiple days of month - multiple Recurrence tags?
+                    wbxml.atag("DayOfMonth", monthDays[0].toString());
+                }
+                // DayOfWeek
+                if (weekDays.length) {
+                    let bitfield = 0;
+                    for (let day of weekDays) {
+                        bitfield |= 1 << (day - 1);
+                    }
+                    wbxml.atag("DayOfWeek", bitfield.toString());
+                }
+                // FirstDayOfWeek: 14.1 and up
+                //wbxml.atag("FirstDayOfWeek", recRule.weekStart); - (NS_ERROR_NOT_IMPLEMENTED) [calIRecurrenceRule.weekStart]
+                // Interval
+                wbxml.atag("Interval", recRule.interval.toString());
+                // TODO: IsLeapMonth: 14.0 and up
+                // MonthOfYear
+                if (months.length) {
+                    wbxml.atag("MonthOfYear", months[0].toString());
+                }
+                // Occurrences
+                if (recRule.isByCount) {
+                    wbxml.atag("Occurrences", recRule.count.toString());
+                }
+                // Until
+                else if (recRule.untilDate != null) {
+                    //Events need the Until data in compact form, Tasks in the basic form
+                    wbxml.atag("Until", eas.tools.getIsoUtcString(recRule.untilDate, (syncData.type == "Tasks")));
+                }
+                // WeekOfMonth
+                if (weeks.length) {
+                    wbxml.atag("WeekOfMonth", weeks[0].toString());
+                }
+                wbxml.ctag();
+            }
+
+            if (syncData.type == "Calendar" && hasRecurrence) { //Exceptions only allowed in Calendar and only if a valid Recurrence was added
+                let modifiedIds = item.recurrenceInfo.getExceptionIds({});
+                if (deleted.length || modifiedIds.length) {
+                    wbxml.otag("Exceptions");
+                    for (let exception of deleted) {
+                        wbxml.otag("Exception");
+                        wbxml.atag("ExceptionStartTime", eas.tools.getIsoUtcString(exception.date));
+                        wbxml.atag("Deleted", "1");
+                        //Docs say it is allowed, but if present, it does not work
+                        //if (asversion == "2.5") {
+                        //    wbxml.atag("UID", item.id); //item.id is not valid, use UID or primaryKey
+                        //}
+                        wbxml.ctag();
+                    }
+                    for (let exceptionId of modifiedIds) {
+                        let replacement = item.recurrenceInfo.getExceptionFor(exceptionId);
+                        wbxml.otag("Exception");
+                        wbxml.atag("ExceptionStartTime", eas.tools.getIsoUtcString(exceptionId));
+                        wbxml.append(await eas.sync.getWbxmlFromThunderbirdItem(replacement, syncData, true));
+                        wbxml.ctag();
+                    }
+                    wbxml.ctag();
+                }
+            }
+        }
+
+        return wbxml.getBytes();
+    }
+
+}
diff -Nru eas4tbsync-4.11/content/includes/tasksync.js eas4tbsync-4.17/content/includes/tasksync.js
--- eas4tbsync-4.11/content/includes/tasksync.js	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/includes/tasksync.js	2025-05-15 13:21:20.000000000 +0200
@@ -1,212 +1,217 @@
-/*
- * This file is part of EAS-4-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");
-var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.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 Tasks = {
-
-    // --------------------------------------------------------------------------- //
-    // Read WBXML and set Thunderbird item
-    // --------------------------------------------------------------------------- //
-    setThunderbirdItemFromWbxml: function (tbItem, data, id, syncdata, mode = "standard") {
-
-        let item = tbItem instanceof TbSync.lightning.TbItem ? tbItem.nativeItem : tbItem;
-        
-        let asversion = syncdata.accountData.getAccountProperty("asversion");
-        item.id = id;
-        eas.sync.setItemSubject(item, syncdata, data);
-        if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Processing " + mode + " task item", item.title + " (" + id + ")");
-
-        eas.sync.setItemBody(item, syncdata, data);
-        eas.sync.setItemCategories(item, syncdata, data);
-        eas.sync.setItemRecurrence(item, syncdata, data);
-
-        let dueDate = null;
-        if (data.DueDate && data.UtcDueDate) {
-            //extract offset from EAS data
-            let DueDate = new Date(data.DueDate);
-            let UtcDueDate = new Date(data.UtcDueDate);
-            let offset = (UtcDueDate.getTime() - DueDate.getTime())/60000;
-
-            //timezone is identified by its offset
-            let utc = cal.createDateTime(eas.tools.dateToBasicISOString(UtcDueDate)); //format "19800101T000000Z" - UTC
-            dueDate = utc.getInTimezone(eas.tools.guessTimezoneByCurrentOffset(offset, utc));
-            item.dueDate = dueDate;
-        }
-
-        if (data.StartDate && data.UtcStartDate) {
-            //extract offset from EAS data
-            let StartDate = new Date(data.StartDate);
-            let UtcStartDate = new Date(data.UtcStartDate);
-            let offset = (UtcStartDate.getTime() - StartDate.getTime())/60000;
-
-            //timezone is identified by its offset
-            let utc = cal.createDateTime(eas.tools.dateToBasicISOString(UtcStartDate)); //format "19800101T000000Z" - UTC
-            item.entryDate = utc.getInTimezone(eas.tools.guessTimezoneByCurrentOffset(offset, utc));
-        } else {
-            //there is no start date? if this is a recurring item, we MUST add an entryDate, otherwise Thunderbird will not display the recurring items
-            if (data.Recurrence) {
-                if (dueDate) {
-                    item.entryDate = dueDate; 
-                    TbSync.eventlog.add("info", syncdata, "Copy task dueData to task startDate, because Thunderbird needs a startDate for recurring items.", item.icalString);
-                } else {
-                    TbSync.eventlog.add("info", syncdata, "Task without startDate and without dueDate but with recurrence info is not supported by Thunderbird. Recurrence will be lost.", item.icalString);
-                }
-            }
-        }
-
-        eas.sync.mapEasPropertyToThunderbird ("Sensitivity", "CLASS", data, item);
-        eas.sync.mapEasPropertyToThunderbird ("Importance", "PRIORITY", data, item);
-
-        let msTodoCompat = eas.prefs.getBoolPref("msTodoCompat");
-        
-        item.clearAlarms();
-        if (data.ReminderSet && data.ReminderTime) {
-            let UtcAlarmDate = eas.tools.createDateTime(data.ReminderTime);
-            let alarm = new CalAlarm();
-            alarm.action = "DISPLAY";
-            
-            if (msTodoCompat)
-            {
-                // Microsoft To-Do only uses due dates (no start dates) an doesn't have a time part in the due date
-                // dirty hack: Use the reminder date as due date and set a reminder exactly to the due date
-                // drawback: only works if due date and reminder is set to the same day - this could maybe checked here but I don't know how
-                item.entryDate = UtcAlarmDate;
-                item.dueDate = UtcAlarmDate;
-                alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_START;
-                alarm.offset = TbSync.lightning.cal.createDuration();
-                alarm.offset.inSeconds = 0;
-            }
-            else if (data.UtcStartDate)
-            {
-                let UtcDate = eas.tools.createDateTime(data.UtcStartDate);
-                alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_START;
-                alarm.offset = UtcAlarmDate.subtractDate(UtcDate);
-            }
-            else
-            {
-                // Alternative solution for Microsoft To-Do:
-                // alarm correctly set but because time part of due date is always "0:00", all tasks for today are shown as overdue
-                alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_ABSOLUTE;
-                alarm.alarmDate = UtcAlarmDate;
-            }
-            item.addAlarm(alarm);
-        }
-        
-        //status/percentage cannot be mapped
-        if (data.Complete) {
-          if (data.Complete == "0") {
-            item.isCompleted = false;
-          } else {
-            item.isCompleted = true;
-            if (data.DateCompleted) item.completedDate = eas.tools.createDateTime(data.DateCompleted);
-          }
-        }            
-    },
-
-/*
-    Regenerate: After complete, the completed task is removed from the series and stored as an new entry. The series starts an week (as set) after complete date with one less occurence
-
-    */
-
-
-
-
-
-
-
-    // --------------------------------------------------------------------------- //
-    //read TB event and return its data as WBXML
-    // --------------------------------------------------------------------------- //
-    getWbxmlFromThunderbirdItem: async function (tbItem, syncdata) {
-        let item = tbItem instanceof TbSync.lightning.TbItem ? tbItem.nativeItem : tbItem;
-
-        let asversion = syncdata.accountData.getAccountProperty("asversion");
-        let wbxml = eas.wbxmltools.createWBXML("", syncdata.type); //init wbxml with "" and not with precodes, and set initial codepage
-
-        //Order of tags taken from: https://msdn.microsoft.com/en-us/library/dn338924(v=exchg.80).aspx
-        
-        //Subject
-        wbxml.atag("Subject", (item.title) ? item.title : "");
-        
-        //Body
-        wbxml.append(eas.sync.getItemBody(item, syncdata));
-
-        //Importance
-        wbxml.atag("Importance", eas.sync.mapThunderbirdPropertyToEas("PRIORITY", "Importance", item));
-
-        //tasks is using extended ISO 8601 (2019-01-18T00:00:00.000Z)  instead of basic (20190118T000000Z), 
-        //eas.tools.getIsoUtcString returns extended if true as second parameter is present
-        
-        // TB will enforce a StartDate if it has a recurrence
-        let localStartDate = null;
-        if (item.entryDate) {
-            wbxml.atag("UtcStartDate", eas.tools.getIsoUtcString(item.entryDate, true));
-            //to fake the local time as UTC, getIsoUtcString needs the third parameter to be true
-            localStartDate = eas.tools.getIsoUtcString(item.entryDate, true, true);
-            wbxml.atag("StartDate", localStartDate);
-        }
-
-        // Tasks without DueDate are breaking O365 - use StartDate as DueDate
-        if (item.entryDate || item.dueDate) {
-            wbxml.atag("UtcDueDate", eas.tools.getIsoUtcString(item.dueDate ? item.dueDate : item.entryDate, true));
-            //to fake the local time as UTC, getIsoUtcString needs the third parameter to be true
-            wbxml.atag("DueDate", eas.tools.getIsoUtcString(item.dueDate ? item.dueDate : item.entryDate, true, true));
-        }
-        
-        //Categories
-        wbxml.append(eas.sync.getItemCategories(item, syncdata));
-
-        //Recurrence (only if localStartDate has been set)
-        if (localStartDate) wbxml.append(await eas.sync.getItemRecurrence(item, syncdata, localStartDate));
-        
-        //Complete
-        if (item.isCompleted) {
-                wbxml.atag("Complete", "1");
-                wbxml.atag("DateCompleted", eas.tools.getIsoUtcString(item.completedDate, true));		
-        } else {
-                wbxml.atag("Complete", "0");
-        }
-
-        //Sensitivity
-        wbxml.atag("Sensitivity", eas.sync.mapThunderbirdPropertyToEas("CLASS", "Sensitivity", item));
-
-        //ReminderTime and ReminderSet
-        let alarms = item.getAlarms({});
-        if (alarms.length>0 && (item.entryDate || item.dueDate)) {
-            let reminderTime;
-            if (alarms[0].offset) {
-                //create Date obj from entryDate by converting item.entryDate to an extended UTC ISO string, which can be parsed by Date
-                //if entryDate is missing, the startDate of this object is set to its dueDate
-                let UtcDate = new Date(eas.tools.getIsoUtcString(item.entryDate ? item.entryDate : item.dueDate, true));
-                //add offset
-                UtcDate.setSeconds(UtcDate.getSeconds() + alarms[0].offset.inSeconds);
-                reminderTime = UtcDate.toISOString();
-            } else {
-                reminderTime = eas.tools.getIsoUtcString(alarms[0].alarmDate, true);
-            }                
-            wbxml.atag("ReminderTime", reminderTime);
-            wbxml.atag("ReminderSet", "1");
-        } else {
-            wbxml.atag("ReminderSet", "0");
-        }
-        
-        return wbxml.getBytes();
-    },
-}
+/*
+ * This file is part of EAS-4-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 Tasks = {
+
+    // --------------------------------------------------------------------------- //
+    // Read WBXML and set Thunderbird item
+    // --------------------------------------------------------------------------- //
+    setThunderbirdItemFromWbxml: function (tbItem, data, id, syncdata, mode = "standard") {
+
+        let item = tbItem instanceof TbSync.lightning.TbItem ? tbItem.nativeItem : tbItem;
+
+        let asversion = syncdata.accountData.getAccountProperty("asversion");
+        item.id = id;
+        eas.sync.setItemSubject(item, syncdata, data);
+        if (TbSync.prefs.getIntPref("log.userdatalevel") > 2) TbSync.dump("Processing " + mode + " task item", item.title + " (" + id + ")");
+
+        eas.sync.setItemBody(item, syncdata, data);
+        eas.sync.setItemCategories(item, syncdata, data);
+        eas.sync.setItemRecurrence(item, syncdata, data);
+
+        let dueDate = null;
+        if (data.DueDate && data.UtcDueDate) {
+            //extract offset from EAS data
+            let DueDate = new Date(data.DueDate);
+            let UtcDueDate = new Date(data.UtcDueDate);
+            let offset = (UtcDueDate.getTime() - DueDate.getTime()) / 60000;
+
+            //timezone is identified by its offset
+            let utc = cal.createDateTime(eas.tools.dateToBasicISOString(UtcDueDate)); //format "19800101T000000Z" - UTC
+            dueDate = utc.getInTimezone(eas.tools.guessTimezoneByCurrentOffset(offset, utc));
+            item.dueDate = dueDate;
+        }
+
+        if (data.StartDate && data.UtcStartDate) {
+            //extract offset from EAS data
+            let StartDate = new Date(data.StartDate);
+            let UtcStartDate = new Date(data.UtcStartDate);
+            let offset = (UtcStartDate.getTime() - StartDate.getTime()) / 60000;
+
+            //timezone is identified by its offset
+            let utc = cal.createDateTime(eas.tools.dateToBasicISOString(UtcStartDate)); //format "19800101T000000Z" - UTC
+            item.entryDate = utc.getInTimezone(eas.tools.guessTimezoneByCurrentOffset(offset, utc));
+        } else {
+            //there is no start date? if this is a recurring item, we MUST add an entryDate, otherwise Thunderbird will not display the recurring items
+            if (data.Recurrence) {
+                if (dueDate) {
+                    item.entryDate = dueDate;
+                    TbSync.eventlog.add("info", syncdata, "Copy task dueData to task startDate, because Thunderbird needs a startDate for recurring items.", item.icalString);
+                } else {
+                    TbSync.eventlog.add("info", syncdata, "Task without startDate and without dueDate but with recurrence info is not supported by Thunderbird. Recurrence will be lost.", item.icalString);
+                }
+            }
+        }
+
+        eas.sync.mapEasPropertyToThunderbird("Sensitivity", "CLASS", data, item);
+        eas.sync.mapEasPropertyToThunderbird("Importance", "PRIORITY", data, item);
+
+        let msTodoCompat = eas.prefs.getBoolPref("msTodoCompat");
+
+        item.clearAlarms();
+        if (data.ReminderSet && data.ReminderTime) {
+            let UtcAlarmDate = eas.tools.createDateTime(data.ReminderTime);
+            let alarm = new CalAlarm();
+            alarm.action = "DISPLAY";
+
+            if (msTodoCompat) {
+                // Microsoft To-Do only uses due dates (no start dates) an doesn't have a time part in the due date
+                // dirty hack: Use the reminder date as due date and set a reminder exactly to the due date
+                // drawback: only works if due date and reminder is set to the same day - this could maybe checked here but I don't know how
+                item.entryDate = UtcAlarmDate;
+                item.dueDate = UtcAlarmDate;
+                alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_START;
+                alarm.offset = TbSync.lightning.cal.createDuration();
+                alarm.offset.inSeconds = 0;
+            }
+            else if (data.UtcStartDate) {
+                let UtcDate = eas.tools.createDateTime(data.UtcStartDate);
+                alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_START;
+                alarm.offset = UtcAlarmDate.subtractDate(UtcDate);
+            }
+            else {
+                // Alternative solution for Microsoft To-Do:
+                // alarm correctly set but because time part of due date is always "0:00", all tasks for today are shown as overdue
+                alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_ABSOLUTE;
+                alarm.alarmDate = UtcAlarmDate;
+            }
+            item.addAlarm(alarm);
+        }
+
+        //status/percentage cannot be mapped
+        if (data.Complete) {
+            if (data.Complete == "0") {
+                item.isCompleted = false;
+            } else {
+                item.isCompleted = true;
+                if (data.DateCompleted) item.completedDate = eas.tools.createDateTime(data.DateCompleted);
+            }
+        }
+    },
+
+    /*
+        Regenerate: After complete, the completed task is removed from the series and stored as an new entry. The series starts an week (as set) after complete date with one less occurence
+    
+        */
+
+
+
+
+
+
+
+    // --------------------------------------------------------------------------- //
+    //read TB event and return its data as WBXML
+    // --------------------------------------------------------------------------- //
+    getWbxmlFromThunderbirdItem: async function (tbItem, syncdata) {
+        let item = tbItem instanceof TbSync.lightning.TbItem ? tbItem.nativeItem : tbItem;
+
+        let asversion = syncdata.accountData.getAccountProperty("asversion");
+        let wbxml = eas.wbxmltools.createWBXML("", syncdata.type); //init wbxml with "" and not with precodes, and set initial codepage
+
+        //Order of tags taken from: https://msdn.microsoft.com/en-us/library/dn338924(v=exchg.80).aspx
+
+        //Subject
+        wbxml.atag("Subject", (item.title) ? item.title : "");
+
+        //Body
+        wbxml.append(eas.sync.getItemBody(item, syncdata));
+
+        //Importance
+        wbxml.atag("Importance", eas.sync.mapThunderbirdPropertyToEas("PRIORITY", "Importance", item));
+
+        //tasks is using extended ISO 8601 (2019-01-18T00:00:00.000Z)  instead of basic (20190118T000000Z), 
+        //eas.tools.getIsoUtcString returns extended if true as second parameter is present
+
+        // TB will enforce a StartDate if it has a recurrence
+        let localStartDate = null;
+        if (item.entryDate) {
+            wbxml.atag("UtcStartDate", eas.tools.getIsoUtcString(item.entryDate, true));
+            //to fake the local time as UTC, getIsoUtcString needs the third parameter to be true
+            localStartDate = eas.tools.getIsoUtcString(item.entryDate, true, true);
+            wbxml.atag("StartDate", localStartDate);
+        }
+
+        // Tasks without DueDate are breaking O365 - use StartDate as DueDate
+        if (item.entryDate || item.dueDate) {
+            wbxml.atag("UtcDueDate", eas.tools.getIsoUtcString(item.dueDate ? item.dueDate : item.entryDate, true));
+            //to fake the local time as UTC, getIsoUtcString needs the third parameter to be true
+            wbxml.atag("DueDate", eas.tools.getIsoUtcString(item.dueDate ? item.dueDate : item.entryDate, true, true));
+        }
+
+        //Categories
+        wbxml.append(eas.sync.getItemCategories(item, syncdata));
+
+        //Recurrence (only if localStartDate has been set)
+        if (localStartDate) wbxml.append(await eas.sync.getItemRecurrence(item, syncdata, localStartDate));
+
+        //Complete
+        if (item.isCompleted) {
+            wbxml.atag("Complete", "1");
+            wbxml.atag("DateCompleted", eas.tools.getIsoUtcString(item.completedDate, true));
+        } else {
+            wbxml.atag("Complete", "0");
+        }
+
+        //Sensitivity
+        wbxml.atag("Sensitivity", eas.sync.mapThunderbirdPropertyToEas("CLASS", "Sensitivity", item));
+
+        //ReminderTime and ReminderSet
+        let alarms = item.getAlarms({});
+        if (alarms.length > 0 && (item.entryDate || item.dueDate)) {
+            let reminderTime;
+            if (alarms[0].offset) {
+                //create Date obj from entryDate by converting item.entryDate to an extended UTC ISO string, which can be parsed by Date
+                //if entryDate is missing, the startDate of this object is set to its dueDate
+                let UtcDate = new Date(eas.tools.getIsoUtcString(item.entryDate ? item.entryDate : item.dueDate, true));
+                //add offset
+                UtcDate.setSeconds(UtcDate.getSeconds() + alarms[0].offset.inSeconds);
+                reminderTime = UtcDate.toISOString();
+            } else {
+                reminderTime = eas.tools.getIsoUtcString(alarms[0].alarmDate, true);
+            }
+            wbxml.atag("ReminderTime", reminderTime);
+            wbxml.atag("ReminderSet", "1");
+        } else {
+            wbxml.atag("ReminderSet", "0");
+        }
+
+        return wbxml.getBytes();
+    },
+}
diff -Nru eas4tbsync-4.11/content/includes/tools.js eas4tbsync-4.17/content/includes/tools.js
--- eas4tbsync-4.11/content/includes/tools.js	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/includes/tools.js	2025-05-15 13:21:20.000000000 +0200
@@ -1,535 +1,548 @@
-/*
- * This file is part of EAS-4-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 { MailServices } = ChromeUtils.import("resource:///modules/MailServices.jsm");
-var { NetUtil } = ChromeUtils.importESModule(
-    "resource://gre/modules/NetUtil.sys.mjs"
-);
-
-var tools = {
-
-    setCalItemProperty: function (item, prop, value) {
-        if (value == "unset") item.deleteProperty(prop);
-        else item.setProperty(prop, value);
-    },
-    
-    getCalItemProperty: function (item, prop) {
-        if (item.hasProperty(prop)) return item.getProperty(prop);
-        else return "unset";
-    },
-
-    isString: function (s) {
-        return (typeof s == 'string' || s instanceof String);
-    },
-
-    getIdentityKey: function (email) {
-        for (let account of MailServices.accounts.accounts) {
-            if (account.defaultIdentity && account.defaultIdentity.email == email) return account.defaultIdentity.key;
-        }
-        return "";
-    },
-
-    parentIsTrash: function (folderData) {
-        let parentID = folderData.getFolderProperty("parentID");
-        if (parentID == "0") return false;
-        
-        let parentFolder = folderData.accountData.getFolder("serverID", parentID);
-        if (parentFolder && parentFolder.getFolderProperty("type") == "4") return true;
-        
-        return false;
-    },
-
-    getNewDeviceId: function () {
-        //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;
-    },
-    
-    getUriFromDirectoryId: function(ownerId) {
-        let directories = MailServices.ab.directories;
-        for (let directory of directories) {
-          if (directory instanceof Components.interfaces.nsIAbDirectory) {
-                if (ownerId.startsWith(directory.dirPrefId)) return directory.URI;
-          }
-        }
-        return null;
-    },
-    
-    //function to get correct uri of current card for global book as well for mailLists
-    getSelectedUri : function(aUri, aCard) {       
-        if (aUri == "moz-abdirectory://?") {
-            //get parent via card owner
-            return eas.tools.getUriFromDirectoryId(aCard.directoryId);            
-        } else if (MailServices.ab.getDirectory(aUri).isMailList) {
-            //MailList suck, we have to cut the url to get the parent
-            return aUri.substring(0, aUri.lastIndexOf("/"))     
-        } else {
-            return aUri;
-        }
-    },
-    
-    //read file from within the XPI package
-    fetchFile: function (aURL, returnType = "Array") {
-        return new Promise((resolve, reject) => {
-            let uri = Services.io.newURI(aURL);
-            let channel = Services.io.newChannelFromURI(uri,
-                                 null,
-                                 Services.scriptSecurityManager.getSystemPrincipal(),
-                                 null,
-                                 Components.interfaces.nsILoadInfo.SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT,
-                                 Components.interfaces.nsIContentPolicy.TYPE_OTHER);
-
-            NetUtil.asyncFetch(channel, (inputStream, status) => {
-                if (!Components.isSuccessCode(status)) {
-                    reject(status);
-                    return;
-                }
-
-                try {
-                    let data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
-                    if (returnType == "Array") {
-                        resolve(data.replace("\r","").split("\n"))
-                    } else {
-                        resolve(data);
-                    }
-                } catch (ex) {
-                    reject(ex);
-                }
-            });
-        });
-    },
-
-
-
-
-
-
-
-
-    
-    
-    // TIMEZONE STUFF
-    
-    TimeZoneDataStructure : class {
-        constructor() {
-            this.buf = new DataView(new ArrayBuffer(172));
-        }
-        
-/*		
-        Buffer structure:
-            @000    utcOffset (4x8bit as 1xLONG)
-
-            @004     standardName (64x8bit as 32xWCHAR)
-            @068     standardDate (16x8 as 1xSYSTEMTIME)
-            @084     standardBias (4x8bit as 1xLONG)
-
-            @088     daylightName (64x8bit as 32xWCHAR)
-            @152    daylightDate (16x8 as 1xSTRUCT)
-            @168    daylightBias (4x8bit as 1xLONG)
-*/
-        
-        set easTimeZone64 (b64) {
-            //clear buffer
-            for (let i=0; i<172; i++) this.buf.setUint8(i, 0);
-            //load content into buffer
-            let content = (b64 == "") ? "" : atob(b64);
-            for (let i=0; i<content.length; i++) this.buf.setUint8(i, content.charCodeAt(i));
-        }
-        
-        get easTimeZone64 () {
-            let content = "";
-            for (let i=0; i<172; i++) content += String.fromCharCode(this.buf.getUint8(i));
-            return (btoa(content));
-        }
-        
-        getstr (byteoffset) {
-            let str = "";
-            //walk thru the buffer in 32 steps of 16bit (wchars)
-            for (let i=0;i<32;i++) {
-                let cc = this.buf.getUint16(byteoffset+i*2, true);
-                if (cc == 0) break;
-                str += String.fromCharCode(cc);
-            }
-            return str;
-        }
-
-        setstr (byteoffset, str) {
-            //clear first
-            for (let i=0;i<32;i++) this.buf.setUint16(byteoffset+i*2, 0);
-            //walk thru the buffer in steps of 16bit (wchars)
-            for (let i=0;i<str.length && i<32; i++) this.buf.setUint16(byteoffset+i*2, str.charCodeAt(i), true);
-        }
-        
-        getsystemtime (buf, offset) {
-            let systemtime = {
-                get wYear () { return buf.getUint16(offset + 0, true); },
-                get wMonth () { return buf.getUint16(offset + 2, true); },
-                get wDayOfWeek () { return buf.getUint16(offset + 4, true); },
-                get wDay () { return buf.getUint16(offset + 6, true); },
-                get wHour () { return buf.getUint16(offset + 8, true); },
-                get wMinute () { return buf.getUint16(offset + 10, true); },
-                get wSecond () { return buf.getUint16(offset + 12, true); },
-                get wMilliseconds () { return buf.getUint16(offset + 14, true); },
-                toString() { return [this.wYear, this.wMonth, this.wDay].join("-") + ", " + this.wDayOfWeek + ", " + [this.wHour,this.wMinute,this.wSecond].join(":") + "." + this.wMilliseconds},
-
-                set wYear (v) { buf.setUint16(offset + 0, v, true); },
-                set wMonth (v) { buf.setUint16(offset + 2, v, true); },
-                set wDayOfWeek (v) { buf.setUint16(offset + 4, v, true); },
-                set wDay (v) { buf.setUint16(offset + 6, v, true); },
-                set wHour (v) { buf.setUint16(offset + 8, v, true); },
-                set wMinute (v) { buf.setUint16(offset + 10, v, true); },
-                set wSecond (v) { buf.setUint16(offset + 12, v, true); },
-                set wMilliseconds (v) { buf.setUint16(offset + 14, v, true); },
-                };
-            return systemtime;
-        }
-        
-        get standardDate () {return this.getsystemtime (this.buf, 68); }
-        get daylightDate () {return this.getsystemtime (this.buf, 152); }
-            
-        get utcOffset () { return this.buf.getInt32(0, true); }
-        set utcOffset (v) { this.buf.setInt32(0, v, true); }
-
-        get standardBias () { return this.buf.getInt32(84, true); }
-        set standardBias (v) { this.buf.setInt32(84, v, true); }
-        get daylightBias () { return this.buf.getInt32(168, true); }
-        set daylightBias (v) { this.buf.setInt32(168, v, true); }
-        
-        get standardName () {return this.getstr(4); }
-        set standardName (v) {return this.setstr(4, v); }
-        get daylightName () {return this.getstr(88); }
-        set daylightName (v) {return this.setstr(88, v); }
-        
-        toString () { return ["", 
-            "utcOffset: "+ this.utcOffset,
-            "standardName: "+ this.standardName,
-            "standardDate: "+ this.standardDate.toString(),
-            "standardBias: "+ this.standardBias,
-            "daylightName: "+ this.daylightName,
-            "daylightDate: "+ this.daylightDate.toString(),
-            "daylightBias: "+ this.daylightBias].join("\n"); }
-    },
-
-
-    //Date has a toISOString method, which returns the Date obj as extended ISO 8601,
-    //however EAS MS-ASCAL uses compact/basic ISO 8601,
-    dateToBasicISOString : function (date) {
-        function pad(number) {
-          if (number < 10) {
-            return '0' + number;
-          }
-          return number.toString();
-        }
-
-        return pad(date.getUTCFullYear()) +
-            pad(date.getUTCMonth() + 1) +
-            pad(date.getUTCDate()) +
-            'T' + 
-            pad(date.getUTCHours()) +
-            pad(date.getUTCMinutes()) +
-            pad(date.getUTCSeconds()) +
-            'Z';
-    },
-
-
-    //Save replacement for cal.createDateTime, which accepts compact/basic and also extended ISO 8601, 
-    //cal.createDateTime only supports compact/basic
-    createDateTime: function(str) {
-        let datestring = str;
-        if (str.indexOf("-") == 4) {
-            //this looks like extended ISO 8601
-            let tempDate = new Date(str);
-            datestring = eas.tools.dateToBasicISOString(tempDate);
-        }
-        return TbSync.lightning.cal.createDateTime(datestring);
-    },    
-
-
-    // Convert TB date to UTC and return it as  basic or extended ISO 8601  String
-    getIsoUtcString: function(origdate, requireExtendedISO = false, fakeUTC = false) {
-        let date = origdate.clone();
-        //floating timezone cannot be converted to UTC (cause they float) - we have to overwrite it with the local timezone
-        if (date.timezone.tzid == "floating") date.timezone = eas.defaultTimezoneInfo.timezone;
-        //to get the UTC string we could use icalString (which does not work on allDayEvents, or calculate it from nativeTime)
-        date.isDate = 0;
-        let UTC = date.getInTimezone(eas.utcTimezone);        
-        if (fakeUTC) UTC = date.clone();
-        
-        function pad(number) {
-            if (number < 10) {
-                return '0' + number;
-            }
-            return number;
-        }
-        
-        if (requireExtendedISO) {
-            return UTC.year + 
-                    "-" + pad(UTC.month + 1 ) + 
-                    "-" + pad(UTC.day) +
-                    "T" + pad(UTC.hour) +
-                    ":" + pad(UTC.minute) + 
-                    ":" + pad(UTC.second) + 
-                    "." + "000" +
-                    "Z";            
-        } else {            
-            return UTC.icalString;
-        }
-    },
-
-    getNowUTC : function() {
-        return TbSync.lightning.cal.dtz.jsDateToDateTime(new Date()).getInTimezone(TbSync.lightning.cal.dtz.UTC);
-    },
-    
-    //guess the IANA timezone (used by TB) based on the current offset (standard or daylight)
-    guessTimezoneByCurrentOffset: function(curOffset, utcDateTime) {
-        //if we only now the current offset and the current date, we need to actually try each TZ.
-        let tzService = TbSync.lightning.cal.timezoneService;
-
-        //first try default tz
-        let test = utcDateTime.getInTimezone(eas.defaultTimezoneInfo.timezone);
-        TbSync.dump("Matching TZ via current offset: " + test.timezone.tzid + " @ " + curOffset, test.timezoneOffset/-60);
-        if (test.timezoneOffset/-60 == curOffset) return test.timezone;
-        
-        //second try UTC
-        test = utcDateTime.getInTimezone(eas.utcTimezone);
-        TbSync.dump("Matching TZ via current offset: " + test.timezone.tzid + " @ " + curOffset, test.timezoneOffset/-60);
-        if (test.timezoneOffset/-60 == curOffset) return test.timezone;
-        
-        //third try all others
-        for (let timezoneId of tzService.timezoneIds) {
-            let test = utcDateTime.getInTimezone(tzService.getTimezone(timezoneId));
-            TbSync.dump("Matching TZ via current offset: " + test.timezone.tzid + " @ " + curOffset, test.timezoneOffset/-60);
-            if (test.timezoneOffset/-60 == curOffset) return test.timezone;
-        }
-        
-        //return default TZ as fallback
-        return eas.defaultTimezoneInfo.timezone;
-    },
-
-
-  //guess the IANA timezone (used by TB) based on stdandard offset, daylight offset and standard name
-    guessTimezoneByStdDstOffset: function(stdOffset, dstOffset, stdName = "") {
-                    
-            //get a list of all zones
-            //alternativly use cal.fromRFC3339 - but this is only doing this:
-            //https://dxr.mozilla.org/comm-central/source/calendar/base/modules/calProviderUtils.jsm
-
-            //cache timezone data on first attempt
-            if (eas.cachedTimezoneData === null) {
-                eas.cachedTimezoneData = {};
-                eas.cachedTimezoneData.iana = {};
-                eas.cachedTimezoneData.abbreviations = {};
-                eas.cachedTimezoneData.stdOffset = {};
-                eas.cachedTimezoneData.bothOffsets = {};
-                    
-                let tzService = TbSync.lightning.cal.timezoneService;
-
-                //cache timezones data from internal IANA data
-                for (let timezoneId of tzService.timezoneIds) {
-                    let timezone = tzService.getTimezone(timezoneId);
-                    let tzInfo = eas.tools.getTimezoneInfo(timezone);
-
-                    eas.cachedTimezoneData.bothOffsets[tzInfo.std.offset+":"+tzInfo.dst.offset] = timezone;
-                    eas.cachedTimezoneData.stdOffset[tzInfo.std.offset] = timezone;
-
-                    eas.cachedTimezoneData.abbreviations[tzInfo.std.abbreviation] = timezoneId;
-                    eas.cachedTimezoneData.iana[timezoneId] = tzInfo;
-                    
-                    //TbSync.dump("TZ ("+ tzInfo.std.id + " :: " + tzInfo.dst.id +  " :: " + tzInfo.std.displayname + " :: " + tzInfo.dst.displayname + " :: " + tzInfo.std.offset + " :: " + tzInfo.dst.offset + ")", tzService.getTimezone(id));
-                }
-
-                //make sure, that UTC timezone is there
-                eas.cachedTimezoneData.bothOffsets["0:0"] = eas.utcTimezone;
-
-                //multiple TZ share the same offset and abbreviation, make sure the default timezone is present
-                eas.cachedTimezoneData.abbreviations[eas.defaultTimezoneInfo.std.abbreviation] = eas.defaultTimezoneInfo.std.id;
-                eas.cachedTimezoneData.bothOffsets[eas.defaultTimezoneInfo.std.offset+":"+eas.defaultTimezoneInfo.dst.offset] = eas.defaultTimezoneInfo.timezone;
-                eas.cachedTimezoneData.stdOffset[eas.defaultTimezoneInfo.std.offset] = eas.defaultTimezoneInfo.timezone;
-                
-            }
-
-            /*
-                1. Try to find name in Windows names and map to IANA -> if found, does the stdOffset match? -> if so, done
-                2. Try to parse our own format, split name and test each chunk for IANA -> if found, does the stdOffset match? -> if so, done
-                3. Try if one of the chunks matches international code -> if found, does the stdOffset match? -> if so, done
-                4. Fallback: Use just the offsets  */
-
-
-            //check for windows timezone name
-            if (eas.windowsToIanaTimezoneMap[stdName] && eas.cachedTimezoneData.iana[eas.windowsToIanaTimezoneMap[stdName]] && eas.cachedTimezoneData.iana[eas.windowsToIanaTimezoneMap[stdName]].std.offset == stdOffset ) {
-                //the windows timezone maps multiple IANA zones to one (Berlin*, Rome, Bruessel)
-                //check the windowsZoneName of the default TZ and of the winning, if they match, use default TZ
-                //so Rome could win, even Berlin is the default IANA zone
-                if (eas.defaultTimezoneInfo.std.windowsZoneName && eas.windowsToIanaTimezoneMap[stdName] != eas.defaultTimezoneInfo.std.id && eas.cachedTimezoneData.iana[eas.windowsToIanaTimezoneMap[stdName]].std.offset == eas.defaultTimezoneInfo.std.offset && stdName == eas.defaultTimezoneInfo.std.windowsZoneName) {
-                    TbSync.dump("Timezone matched via windows timezone name ("+stdName+") with default TZ overtake", eas.windowsToIanaTimezoneMap[stdName] + " -> " + eas.defaultTimezoneInfo.std.id);
-                    return eas.defaultTimezoneInfo.timezone;
-                }
-                
-                TbSync.dump("Timezone matched via windows timezone name ("+stdName+")", eas.windowsToIanaTimezoneMap[stdName]);
-                return eas.cachedTimezoneData.iana[eas.windowsToIanaTimezoneMap[stdName]].timezone;
-            }
-
-            let parts = stdName.replace(/[;,()\[\]]/g," ").split(" ");
-            for (let i = 0; i < parts.length; i++) {
-                //check for IANA
-                if (eas.cachedTimezoneData.iana[parts[i]] && eas.cachedTimezoneData.iana[parts[i]].std.offset == stdOffset) {
-                    TbSync.dump("Timezone matched via IANA", parts[i]);
-                    return eas.cachedTimezoneData.iana[parts[i]].timezone;
-                }
-
-                //check for international abbreviation for standard period (CET, CAT, ...)
-                if (eas.cachedTimezoneData.abbreviations[parts[i]] && eas.cachedTimezoneData.iana[eas.cachedTimezoneData.abbreviations[parts[i]]] && eas.cachedTimezoneData.iana[eas.cachedTimezoneData.abbreviations[parts[i]]].std.offset == stdOffset) {
-                    TbSync.dump("Timezone matched via international abbreviation (" + parts[i] +")", eas.cachedTimezoneData.abbreviations[parts[i]]);
-                    return eas.cachedTimezoneData.iana[eas.cachedTimezoneData.abbreviations[parts[i]]].timezone;
-                }
-            }
-
-            //fallback to zone based on stdOffset and dstOffset, if we have that cached
-            if (eas.cachedTimezoneData.bothOffsets[stdOffset+":"+dstOffset]) {
-                TbSync.dump("Timezone matched via both offsets (std:" + stdOffset +", dst:" + dstOffset + ")", eas.cachedTimezoneData.bothOffsets[stdOffset+":"+dstOffset].tzid);
-                return eas.cachedTimezoneData.bothOffsets[stdOffset+":"+dstOffset];
-            }
-
-            //fallback to zone based on stdOffset only, if we have that cached
-            if (eas.cachedTimezoneData.stdOffset[stdOffset]) {
-                TbSync.dump("Timezone matched via std offset (" + stdOffset +")", eas.cachedTimezoneData.stdOffset[stdOffset].tzid);
-                return eas.cachedTimezoneData.stdOffset[stdOffset];
-            }
-            
-            //return default timezone, if everything else fails
-            TbSync.dump("Timezone could not be matched via offsets (std:" + stdOffset +", dst:" + dstOffset + "), using default timezone", eas.defaultTimezoneInfo.std.id);
-            return eas.defaultTimezoneInfo.timezone;
-    },
-
-
-    //extract standard and daylight timezone data
-    getTimezoneInfo: function (timezone) {        
-        let tzInfo = {};
-
-        tzInfo.std = eas.tools.getTimezoneInfoObject(timezone, "standard");
-        tzInfo.dst = eas.tools.getTimezoneInfoObject(timezone, "daylight");
-        
-        if (tzInfo.dst === null) tzInfo.dst  = tzInfo.std;        
-
-        tzInfo.timezone = timezone;
-        return tzInfo;
-    },
-
-
-     //get timezone info for standard/daylight
-    getTimezoneInfoObject: function (timezone, standardOrDaylight) {       
-        
-        //handle UTC
-        if (timezone.isUTC) {
-            let obj = {}
-            obj.id = "UTC";
-            obj.offset = 0;
-            obj.abbreviation = "UTC";
-            obj.displayname = "Coordinated Universal Time (UTC)";
-            return obj;
-        }
-
-        //we could parse the icalstring by ourself, but I wanted to use ICAL.parse - TODO try catch
-        let info = TbSync.lightning.ICAL.parse("BEGIN:VCALENDAR\r\n" + timezone.icalComponent.toString() + "\r\nEND:VCALENDAR");
-        let comp = new TbSync.lightning.ICAL.Component(info);
-        let vtimezone =comp.getFirstSubcomponent("vtimezone");
-        let id = vtimezone.getFirstPropertyValue("tzid").toString();
-        let zone = vtimezone.getFirstSubcomponent(standardOrDaylight);
-
-        if (zone) { 
-            let obj = {};
-            obj.id = id;
-            
-            //get offset
-            let utcOffset = zone.getFirstPropertyValue("tzoffsetto").toString();
-            let o = parseInt(utcOffset.replace(":","")); //-330 =  - 3h 30min
-            let h = Math.floor(o / 100); //-3 -> -180min
-            let m = o - (h*100) //-330 - -300 = -30
-            obj.offset = -1*((h*60) + m);
-
-            //get international abbreviation (CEST, CET, CAT ... )
-            obj.abbreviation = "";
-            try {
-                obj.abbreviation = zone.getFirstPropertyValue("tzname").toString();
-            } catch(e) {
-                TbSync.dump("Failed TZ", timezone.icalComponent.toString());
-            }
-            
-            //get displayname
-            obj.displayname = /*"("+utcOffset+") " +*/ obj.id;// + ", " + obj.abbreviation;
-                
-            //get DST switch date
-            let rrule = zone.getFirstPropertyValue("rrule");
-            let dtstart = zone.getFirstPropertyValue("dtstart");
-            if (rrule && dtstart) {
-                /*
-
-                    THE switchdate PART OF THE OBJECT IS MICROSOFT SPECIFIC, EVERYTHING ELSE IS THUNDERBIRD GENERIC, I LET IT SIT HERE ANYHOW
-                    
-                    https://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx
-
-                    To select the correct day in the month, set the wYear member to zero, the wHour and wMinute members to
-                    the transition time, the wDayOfWeek member to the appropriate weekday, and the wDay member to indicate
-                    the occurrence of the day of the week within the month (1 to 5, where 5 indicates the final occurrence during the
-                    month if that day of the week does not occur 5 times).
-
-                    Using this notation, specify 02:00 on the first Sunday in April as follows: 
-                        wHour = 2, wMonth = 4, wDayOfWeek = 0, wDay = 1. 
-                    Specify 02:00 on the last Thursday in October as follows: 
-                        wHour = 2, wMonth = 10, wDayOfWeek = 4, wDay = 5.
-                        
-                    So we have to parse the RRULE to exract wDay
-                    RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 */         
-
-                let parts =rrule.toString().split(";");
-                let rules = {};
-                for (let i = 0; i< parts.length; i++) {
-                    let sub = parts[i].split("=");
-                    if (sub.length == 2) rules[sub[0]] = sub[1];
-                }
-                
-                if (rules.FREQ == "YEARLY" && rules.BYDAY && rules.BYMONTH && rules.BYDAY.length > 2) {
-                    obj.switchdate = {};
-                    obj.switchdate.month = parseInt(rules.BYMONTH);
-
-                    let days = ["SU","MO","TU","WE","TH","FR","SA"];
-                    obj.switchdate.dayOfWeek = days.indexOf(rules.BYDAY.substring(rules.BYDAY.length-2));                
-                    obj.switchdate.weekOfMonth = parseInt(rules.BYDAY.substring(0, rules.BYDAY.length-2));
-                    if (obj.switchdate.weekOfMonth<0 || obj.switchdate.weekOfMonth>5) obj.switchdate.weekOfMonth = 5;
-
-                    //get switch time from dtstart
-                    let dttime = eas.tools.createDateTime(dtstart.toString());
-                    obj.switchdate.hour = dttime.hour;
-                    obj.switchdate.minute = dttime.minute;
-                    obj.switchdate.second = dttime.second;                                    
-                }            
-            }
-
-            return obj;
-        }
-        return null;
-    },   
-}
-
-//TODO: Invites
-/*
-    cal.itip.checkAndSendOrigial = cal.itip.checkAndSend;
-    cal.itip.checkAndSend = function(aOpType, aItem, aOriginalItem) {
-        //if this item is added_by_user, do not call checkAndSend yet, because the UID is wrong, we need to sync first to get the correct ID - TODO
-        TbSync.dump("cal.checkAndSend", aOpType);
-        cal.itip.checkAndSendOrigial(aOpType, aItem, aOriginalItem);
-    }
-*/
+/*
+ * This file is part of EAS-4-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 { NetUtil } = ChromeUtils.importESModule(
+    "resource://gre/modules/NetUtil.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 = {
+
+    setCalItemProperty: function (item, prop, value) {
+        if (value == "unset") item.deleteProperty(prop);
+        else item.setProperty(prop, value);
+    },
+
+    getCalItemProperty: function (item, prop) {
+        if (item.hasProperty(prop)) return item.getProperty(prop);
+        else return "unset";
+    },
+
+    isString: function (s) {
+        return (typeof s == 'string' || s instanceof String);
+    },
+
+    getIdentityKey: function (email) {
+        for (let account of MailServices.accounts.accounts) {
+            if (account.defaultIdentity && account.defaultIdentity.email == email) return account.defaultIdentity.key;
+        }
+        return "";
+    },
+
+    parentIsTrash: function (folderData) {
+        let parentID = folderData.getFolderProperty("parentID");
+        if (parentID == "0") return false;
+
+        let parentFolder = folderData.accountData.getFolder("serverID", parentID);
+        if (parentFolder && parentFolder.getFolderProperty("type") == "4") return true;
+
+        return false;
+    },
+
+    getNewDeviceId: function () {
+        //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;
+    },
+
+    getUriFromDirectoryId: function (ownerId) {
+        let directories = MailServices.ab.directories;
+        for (let directory of directories) {
+            if (directory instanceof Components.interfaces.nsIAbDirectory) {
+                if (ownerId.startsWith(directory.dirPrefId)) return directory.URI;
+            }
+        }
+        return null;
+    },
+
+    //function to get correct uri of current card for global book as well for mailLists
+    getSelectedUri: function (aUri, aCard) {
+        if (aUri == "moz-abdirectory://?") {
+            //get parent via card owner
+            return eas.tools.getUriFromDirectoryId(aCard.directoryId);
+        } else if (MailServices.ab.getDirectory(aUri).isMailList) {
+            //MailList suck, we have to cut the url to get the parent
+            return aUri.substring(0, aUri.lastIndexOf("/"))
+        } else {
+            return aUri;
+        }
+    },
+
+    //read file from within the XPI package
+    fetchFile: function (aURL, returnType = "Array") {
+        return new Promise((resolve, reject) => {
+            let uri = Services.io.newURI(aURL);
+            let channel = Services.io.newChannelFromURI(uri,
+                null,
+                Services.scriptSecurityManager.getSystemPrincipal(),
+                null,
+                Components.interfaces.nsILoadInfo.SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT,
+                Components.interfaces.nsIContentPolicy.TYPE_OTHER);
+
+            NetUtil.asyncFetch(channel, (inputStream, status) => {
+                if (!Components.isSuccessCode(status)) {
+                    reject(status);
+                    return;
+                }
+
+                try {
+                    let data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
+                    if (returnType == "Array") {
+                        resolve(data.replace("\r", "").split("\n"))
+                    } else {
+                        resolve(data);
+                    }
+                } catch (ex) {
+                    reject(ex);
+                }
+            });
+        });
+    },
+
+
+
+
+
+
+
+
+
+
+    // TIMEZONE STUFF
+
+    TimeZoneDataStructure: class {
+        constructor() {
+            this.buf = new DataView(new ArrayBuffer(172));
+        }
+
+        /*		
+                Buffer structure:
+                    @000    utcOffset (4x8bit as 1xLONG)
+        
+                    @004     standardName (64x8bit as 32xWCHAR)
+                    @068     standardDate (16x8 as 1xSYSTEMTIME)
+                    @084     standardBias (4x8bit as 1xLONG)
+        
+                    @088     daylightName (64x8bit as 32xWCHAR)
+                    @152    daylightDate (16x8 as 1xSTRUCT)
+                    @168    daylightBias (4x8bit as 1xLONG)
+        */
+
+        set easTimeZone64(b64) {
+            //clear buffer
+            for (let i = 0; i < 172; i++) this.buf.setUint8(i, 0);
+            //load content into buffer
+            let content = (b64 == "") ? "" : atob(b64);
+            for (let i = 0; i < content.length; i++) this.buf.setUint8(i, content.charCodeAt(i));
+        }
+
+        get easTimeZone64() {
+            let content = "";
+            for (let i = 0; i < 172; i++) content += String.fromCharCode(this.buf.getUint8(i));
+            return (btoa(content));
+        }
+
+        getstr(byteoffset) {
+            let str = "";
+            //walk thru the buffer in 32 steps of 16bit (wchars)
+            for (let i = 0; i < 32; i++) {
+                let cc = this.buf.getUint16(byteoffset + i * 2, true);
+                if (cc == 0) break;
+                str += String.fromCharCode(cc);
+            }
+            return str;
+        }
+
+        setstr(byteoffset, str) {
+            //clear first
+            for (let i = 0; i < 32; i++) this.buf.setUint16(byteoffset + i * 2, 0);
+            //walk thru the buffer in steps of 16bit (wchars)
+            for (let i = 0; i < str.length && i < 32; i++) this.buf.setUint16(byteoffset + i * 2, str.charCodeAt(i), true);
+        }
+
+        getsystemtime(buf, offset) {
+            let systemtime = {
+                get wYear() { return buf.getUint16(offset + 0, true); },
+                get wMonth() { return buf.getUint16(offset + 2, true); },
+                get wDayOfWeek() { return buf.getUint16(offset + 4, true); },
+                get wDay() { return buf.getUint16(offset + 6, true); },
+                get wHour() { return buf.getUint16(offset + 8, true); },
+                get wMinute() { return buf.getUint16(offset + 10, true); },
+                get wSecond() { return buf.getUint16(offset + 12, true); },
+                get wMilliseconds() { return buf.getUint16(offset + 14, true); },
+                toString() { return [this.wYear, this.wMonth, this.wDay].join("-") + ", " + this.wDayOfWeek + ", " + [this.wHour, this.wMinute, this.wSecond].join(":") + "." + this.wMilliseconds },
+
+                set wYear(v) { buf.setUint16(offset + 0, v, true); },
+                set wMonth(v) { buf.setUint16(offset + 2, v, true); },
+                set wDayOfWeek(v) { buf.setUint16(offset + 4, v, true); },
+                set wDay(v) { buf.setUint16(offset + 6, v, true); },
+                set wHour(v) { buf.setUint16(offset + 8, v, true); },
+                set wMinute(v) { buf.setUint16(offset + 10, v, true); },
+                set wSecond(v) { buf.setUint16(offset + 12, v, true); },
+                set wMilliseconds(v) { buf.setUint16(offset + 14, v, true); },
+            };
+            return systemtime;
+        }
+
+        get standardDate() { return this.getsystemtime(this.buf, 68); }
+        get daylightDate() { return this.getsystemtime(this.buf, 152); }
+
+        get utcOffset() { return this.buf.getInt32(0, true); }
+        set utcOffset(v) { this.buf.setInt32(0, v, true); }
+
+        get standardBias() { return this.buf.getInt32(84, true); }
+        set standardBias(v) { this.buf.setInt32(84, v, true); }
+        get daylightBias() { return this.buf.getInt32(168, true); }
+        set daylightBias(v) { this.buf.setInt32(168, v, true); }
+
+        get standardName() { return this.getstr(4); }
+        set standardName(v) { return this.setstr(4, v); }
+        get daylightName() { return this.getstr(88); }
+        set daylightName(v) { return this.setstr(88, v); }
+
+        toString() {
+            return ["",
+                "utcOffset: " + this.utcOffset,
+                "standardName: " + this.standardName,
+                "standardDate: " + this.standardDate.toString(),
+                "standardBias: " + this.standardBias,
+                "daylightName: " + this.daylightName,
+                "daylightDate: " + this.daylightDate.toString(),
+                "daylightBias: " + this.daylightBias].join("\n");
+        }
+    },
+
+
+    //Date has a toISOString method, which returns the Date obj as extended ISO 8601,
+    //however EAS MS-ASCAL uses compact/basic ISO 8601,
+    dateToBasicISOString: function (date) {
+        function pad(number) {
+            if (number < 10) {
+                return '0' + number;
+            }
+            return number.toString();
+        }
+
+        return pad(date.getUTCFullYear()) +
+            pad(date.getUTCMonth() + 1) +
+            pad(date.getUTCDate()) +
+            'T' +
+            pad(date.getUTCHours()) +
+            pad(date.getUTCMinutes()) +
+            pad(date.getUTCSeconds()) +
+            'Z';
+    },
+
+
+    //Save replacement for cal.createDateTime, which accepts compact/basic and also extended ISO 8601, 
+    //cal.createDateTime only supports compact/basic
+    createDateTime: function (str) {
+        let datestring = str;
+        if (str.indexOf("-") == 4) {
+            //this looks like extended ISO 8601
+            let tempDate = new Date(str);
+            datestring = eas.tools.dateToBasicISOString(tempDate);
+        }
+        return TbSync.lightning.cal.createDateTime(datestring);
+    },
+
+
+    // Convert TB date to UTC and return it as  basic or extended ISO 8601  String
+    getIsoUtcString: function (origdate, requireExtendedISO = false, fakeUTC = false) {
+        let date = origdate.clone();
+        //floating timezone cannot be converted to UTC (cause they float) - we have to overwrite it with the local timezone
+        if (date.timezone.tzid == "floating") date.timezone = eas.defaultTimezoneInfo.timezone;
+        //to get the UTC string we could use icalString (which does not work on allDayEvents, or calculate it from nativeTime)
+        date.isDate = 0;
+        let UTC = date.getInTimezone(eas.utcTimezone);
+        if (fakeUTC) UTC = date.clone();
+
+        function pad(number) {
+            if (number < 10) {
+                return '0' + number;
+            }
+            return number;
+        }
+
+        if (requireExtendedISO) {
+            return UTC.year +
+                "-" + pad(UTC.month + 1) +
+                "-" + pad(UTC.day) +
+                "T" + pad(UTC.hour) +
+                ":" + pad(UTC.minute) +
+                ":" + pad(UTC.second) +
+                "." + "000" +
+                "Z";
+        } else {
+            return UTC.icalString;
+        }
+    },
+
+    getNowUTC: function () {
+        return TbSync.lightning.cal.dtz.jsDateToDateTime(new Date()).getInTimezone(TbSync.lightning.cal.dtz.UTC);
+    },
+
+    //guess the IANA timezone (used by TB) based on the current offset (standard or daylight)
+    guessTimezoneByCurrentOffset: function (curOffset, utcDateTime) {
+        //if we only now the current offset and the current date, we need to actually try each TZ.
+        let tzService = TbSync.lightning.cal.timezoneService;
+
+        //first try default tz
+        let test = utcDateTime.getInTimezone(eas.defaultTimezoneInfo.timezone);
+        TbSync.dump("Matching TZ via current offset: " + test.timezone.tzid + " @ " + curOffset, test.timezoneOffset / -60);
+        if (test.timezoneOffset / -60 == curOffset) return test.timezone;
+
+        //second try UTC
+        test = utcDateTime.getInTimezone(eas.utcTimezone);
+        TbSync.dump("Matching TZ via current offset: " + test.timezone.tzid + " @ " + curOffset, test.timezoneOffset / -60);
+        if (test.timezoneOffset / -60 == curOffset) return test.timezone;
+
+        //third try all others
+        for (let timezoneId of tzService.timezoneIds) {
+            let test = utcDateTime.getInTimezone(tzService.getTimezone(timezoneId));
+            TbSync.dump("Matching TZ via current offset: " + test.timezone.tzid + " @ " + curOffset, test.timezoneOffset / -60);
+            if (test.timezoneOffset / -60 == curOffset) return test.timezone;
+        }
+
+        //return default TZ as fallback
+        return eas.defaultTimezoneInfo.timezone;
+    },
+
+
+    //guess the IANA timezone (used by TB) based on stdandard offset, daylight offset and standard name
+    guessTimezoneByStdDstOffset: function (stdOffset, dstOffset, stdName = "") {
+
+        //get a list of all zones
+        //alternativly use cal.fromRFC3339 - but this is only doing this:
+        //https://dxr.mozilla.org/comm-central/source/calendar/base/modules/calProviderUtils.sys.mjs
+
+        //cache timezone data on first attempt
+        if (eas.cachedTimezoneData === null) {
+            eas.cachedTimezoneData = {};
+            eas.cachedTimezoneData.iana = {};
+            eas.cachedTimezoneData.abbreviations = {};
+            eas.cachedTimezoneData.stdOffset = {};
+            eas.cachedTimezoneData.bothOffsets = {};
+
+            let tzService = TbSync.lightning.cal.timezoneService;
+
+            //cache timezones data from internal IANA data
+            for (let timezoneId of tzService.timezoneIds) {
+                let timezone = tzService.getTimezone(timezoneId);
+                let tzInfo = eas.tools.getTimezoneInfo(timezone);
+
+                eas.cachedTimezoneData.bothOffsets[tzInfo.std.offset + ":" + tzInfo.dst.offset] = timezone;
+                eas.cachedTimezoneData.stdOffset[tzInfo.std.offset] = timezone;
+
+                eas.cachedTimezoneData.abbreviations[tzInfo.std.abbreviation] = timezoneId;
+                eas.cachedTimezoneData.iana[timezoneId] = tzInfo;
+
+                //TbSync.dump("TZ ("+ tzInfo.std.id + " :: " + tzInfo.dst.id +  " :: " + tzInfo.std.displayname + " :: " + tzInfo.dst.displayname + " :: " + tzInfo.std.offset + " :: " + tzInfo.dst.offset + ")", tzService.getTimezone(id));
+            }
+
+            //make sure, that UTC timezone is there
+            eas.cachedTimezoneData.bothOffsets["0:0"] = eas.utcTimezone;
+
+            //multiple TZ share the same offset and abbreviation, make sure the default timezone is present
+            eas.cachedTimezoneData.abbreviations[eas.defaultTimezoneInfo.std.abbreviation] = eas.defaultTimezoneInfo.std.id;
+            eas.cachedTimezoneData.bothOffsets[eas.defaultTimezoneInfo.std.offset + ":" + eas.defaultTimezoneInfo.dst.offset] = eas.defaultTimezoneInfo.timezone;
+            eas.cachedTimezoneData.stdOffset[eas.defaultTimezoneInfo.std.offset] = eas.defaultTimezoneInfo.timezone;
+
+        }
+
+        /*
+            1. Try to find name in Windows names and map to IANA -> if found, does the stdOffset match? -> if so, done
+            2. Try to parse our own format, split name and test each chunk for IANA -> if found, does the stdOffset match? -> if so, done
+            3. Try if one of the chunks matches international code -> if found, does the stdOffset match? -> if so, done
+            4. Fallback: Use just the offsets  */
+
+
+        //check for windows timezone name
+        if (eas.windowsToIanaTimezoneMap[stdName] && eas.cachedTimezoneData.iana[eas.windowsToIanaTimezoneMap[stdName]] && eas.cachedTimezoneData.iana[eas.windowsToIanaTimezoneMap[stdName]].std.offset == stdOffset) {
+            //the windows timezone maps multiple IANA zones to one (Berlin*, Rome, Bruessel)
+            //check the windowsZoneName of the default TZ and of the winning, if they match, use default TZ
+            //so Rome could win, even Berlin is the default IANA zone
+            if (eas.defaultTimezoneInfo.std.windowsZoneName && eas.windowsToIanaTimezoneMap[stdName] != eas.defaultTimezoneInfo.std.id && eas.cachedTimezoneData.iana[eas.windowsToIanaTimezoneMap[stdName]].std.offset == eas.defaultTimezoneInfo.std.offset && stdName == eas.defaultTimezoneInfo.std.windowsZoneName) {
+                TbSync.dump("Timezone matched via windows timezone name (" + stdName + ") with default TZ overtake", eas.windowsToIanaTimezoneMap[stdName] + " -> " + eas.defaultTimezoneInfo.std.id);
+                return eas.defaultTimezoneInfo.timezone;
+            }
+
+            TbSync.dump("Timezone matched via windows timezone name (" + stdName + ")", eas.windowsToIanaTimezoneMap[stdName]);
+            return eas.cachedTimezoneData.iana[eas.windowsToIanaTimezoneMap[stdName]].timezone;
+        }
+
+        let parts = stdName.replace(/[;,()\[\]]/g, " ").split(" ");
+        for (let i = 0; i < parts.length; i++) {
+            //check for IANA
+            if (eas.cachedTimezoneData.iana[parts[i]] && eas.cachedTimezoneData.iana[parts[i]].std.offset == stdOffset) {
+                TbSync.dump("Timezone matched via IANA", parts[i]);
+                return eas.cachedTimezoneData.iana[parts[i]].timezone;
+            }
+
+            //check for international abbreviation for standard period (CET, CAT, ...)
+            if (eas.cachedTimezoneData.abbreviations[parts[i]] && eas.cachedTimezoneData.iana[eas.cachedTimezoneData.abbreviations[parts[i]]] && eas.cachedTimezoneData.iana[eas.cachedTimezoneData.abbreviations[parts[i]]].std.offset == stdOffset) {
+                TbSync.dump("Timezone matched via international abbreviation (" + parts[i] + ")", eas.cachedTimezoneData.abbreviations[parts[i]]);
+                return eas.cachedTimezoneData.iana[eas.cachedTimezoneData.abbreviations[parts[i]]].timezone;
+            }
+        }
+
+        //fallback to zone based on stdOffset and dstOffset, if we have that cached
+        if (eas.cachedTimezoneData.bothOffsets[stdOffset + ":" + dstOffset]) {
+            TbSync.dump("Timezone matched via both offsets (std:" + stdOffset + ", dst:" + dstOffset + ")", eas.cachedTimezoneData.bothOffsets[stdOffset + ":" + dstOffset].tzid);
+            return eas.cachedTimezoneData.bothOffsets[stdOffset + ":" + dstOffset];
+        }
+
+        //fallback to zone based on stdOffset only, if we have that cached
+        if (eas.cachedTimezoneData.stdOffset[stdOffset]) {
+            TbSync.dump("Timezone matched via std offset (" + stdOffset + ")", eas.cachedTimezoneData.stdOffset[stdOffset].tzid);
+            return eas.cachedTimezoneData.stdOffset[stdOffset];
+        }
+
+        //return default timezone, if everything else fails
+        TbSync.dump("Timezone could not be matched via offsets (std:" + stdOffset + ", dst:" + dstOffset + "), using default timezone", eas.defaultTimezoneInfo.std.id);
+        return eas.defaultTimezoneInfo.timezone;
+    },
+
+
+    //extract standard and daylight timezone data
+    getTimezoneInfo: function (timezone) {
+        let tzInfo = {};
+
+        tzInfo.std = eas.tools.getTimezoneInfoObject(timezone, "standard");
+        tzInfo.dst = eas.tools.getTimezoneInfoObject(timezone, "daylight");
+
+        if (tzInfo.dst === null) tzInfo.dst = tzInfo.std;
+
+        tzInfo.timezone = timezone;
+        return tzInfo;
+    },
+
+
+    //get timezone info for standard/daylight
+    getTimezoneInfoObject: function (timezone, standardOrDaylight) {
+
+        //handle UTC
+        if (timezone.isUTC) {
+            let obj = {}
+            obj.id = "UTC";
+            obj.offset = 0;
+            obj.abbreviation = "UTC";
+            obj.displayname = "Coordinated Universal Time (UTC)";
+            return obj;
+        }
+
+        //we could parse the icalstring by ourself, but I wanted to use ICAL.parse - TODO try catch
+        let info = TbSync.lightning.ICAL.parse("BEGIN:VCALENDAR\r\n" + timezone.icalComponent.toString() + "\r\nEND:VCALENDAR");
+        let comp = new TbSync.lightning.ICAL.Component(info);
+        let vtimezone = comp.getFirstSubcomponent("vtimezone");
+        let id = vtimezone.getFirstPropertyValue("tzid").toString();
+        let zone = vtimezone.getFirstSubcomponent(standardOrDaylight);
+
+        if (zone) {
+            let obj = {};
+            obj.id = id;
+
+            //get offset
+            let utcOffset = zone.getFirstPropertyValue("tzoffsetto").toString();
+            let o = parseInt(utcOffset.replace(":", "")); //-330 =  - 3h 30min
+            let h = Math.floor(o / 100); //-3 -> -180min
+            let m = o - (h * 100) //-330 - -300 = -30
+            obj.offset = -1 * ((h * 60) + m);
+
+            //get international abbreviation (CEST, CET, CAT ... )
+            obj.abbreviation = "";
+            try {
+                obj.abbreviation = zone.getFirstPropertyValue("tzname").toString();
+            } catch (e) {
+                TbSync.dump("Failed TZ", timezone.icalComponent.toString());
+            }
+
+            //get displayname
+            obj.displayname = /*"("+utcOffset+") " +*/ obj.id;// + ", " + obj.abbreviation;
+
+            //get DST switch date
+            let rrule = zone.getFirstPropertyValue("rrule");
+            let dtstart = zone.getFirstPropertyValue("dtstart");
+            if (rrule && dtstart) {
+                /*
+
+                    THE switchdate PART OF THE OBJECT IS MICROSOFT SPECIFIC, EVERYTHING ELSE IS THUNDERBIRD GENERIC, I LET IT SIT HERE ANYHOW
+                    
+                    https://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx
+
+                    To select the correct day in the month, set the wYear member to zero, the wHour and wMinute members to
+                    the transition time, the wDayOfWeek member to the appropriate weekday, and the wDay member to indicate
+                    the occurrence of the day of the week within the month (1 to 5, where 5 indicates the final occurrence during the
+                    month if that day of the week does not occur 5 times).
+
+                    Using this notation, specify 02:00 on the first Sunday in April as follows: 
+                        wHour = 2, wMonth = 4, wDayOfWeek = 0, wDay = 1. 
+                    Specify 02:00 on the last Thursday in October as follows: 
+                        wHour = 2, wMonth = 10, wDayOfWeek = 4, wDay = 5.
+                        
+                    So we have to parse the RRULE to exract wDay
+                    RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 */
+
+                let parts = rrule.toString().split(";");
+                let rules = {};
+                for (let i = 0; i < parts.length; i++) {
+                    let sub = parts[i].split("=");
+                    if (sub.length == 2) rules[sub[0]] = sub[1];
+                }
+
+                if (rules.FREQ == "YEARLY" && rules.BYDAY && rules.BYMONTH && rules.BYDAY.length > 2) {
+                    obj.switchdate = {};
+                    obj.switchdate.month = parseInt(rules.BYMONTH);
+
+                    let days = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"];
+                    obj.switchdate.dayOfWeek = days.indexOf(rules.BYDAY.substring(rules.BYDAY.length - 2));
+                    obj.switchdate.weekOfMonth = parseInt(rules.BYDAY.substring(0, rules.BYDAY.length - 2));
+                    if (obj.switchdate.weekOfMonth < 0 || obj.switchdate.weekOfMonth > 5) obj.switchdate.weekOfMonth = 5;
+
+                    //get switch time from dtstart
+                    let dttime = eas.tools.createDateTime(dtstart.toString());
+                    obj.switchdate.hour = dttime.hour;
+                    obj.switchdate.minute = dttime.minute;
+                    obj.switchdate.second = dttime.second;
+                }
+            }
+
+            return obj;
+        }
+        return null;
+    },
+}
+
+//TODO: Invites
+/*
+    cal.itip.checkAndSendOrigial = cal.itip.checkAndSend;
+    cal.itip.checkAndSend = function(aOpType, aItem, aOriginalItem) {
+        //if this item is added_by_user, do not call checkAndSend yet, because the UID is wrong, we need to sync first to get the correct ID - TODO
+        TbSync.dump("cal.checkAndSend", aOpType);
+        cal.itip.checkAndSendOrigial(aOpType, aItem, aOriginalItem);
+    }
+*/
diff -Nru eas4tbsync-4.11/content/includes/wbxmltools.js eas4tbsync-4.17/content/includes/wbxmltools.js
--- eas4tbsync-4.11/content/includes/wbxmltools.js	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/includes/wbxmltools.js	2025-05-15 13:21:20.000000000 +0200
@@ -1,878 +1,888 @@
-/*
- * This file is part of EAS-4-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 wbxmltools = {
-
-    // Convert a WBXML (WAP Binary XML) to plain XML - returns save xml with all special chars in the user data encoded by encodeURIComponent
-    convert2xml: function (wbxml) {
-
-        let num = 4; //skip the 4 first bytes which are mostly 0x03 (WBXML Version 1.3), 0x01 (unknown public identifier), 0x6A (utf-8), 0x00 (Length of string table)
-
-        //the main code page will be set to the the first codepage used
-        let mainCodePage = null;
-
-        let tagStack = [];
-        let xml = "";
-        let codepage = 0;
-        
-        while (num < wbxml.length) {
-            let data = wbxml.substr(num, 1).charCodeAt(0);
-            let token = data & 0x3F; //removes content bit(6) and attribute bit(7)
-            let tokenHasContent = ((data & 0x40) != 0); //checks if content bit is set
-            let tokenHasAttributes = ((data & 0x80) != 0); //checks if attribute bit is set
-        
-            switch(token) {
-                case 0x00: // switch of codepage (new codepage is next byte)
-                    num = num + 1;
-                    codepage = (wbxml.substr(num, 1)).charCodeAt(0) & 0xFF;
-                    break;
-                    
-                case 0x01: // Indicates the end of an attribute list or the end of an element
-                        // tagStack contains a list of opened tags, which await to be closed
-                        xml = xml + tagStack.pop();
-                    break;
-                    
-                case 0x02: // A character entity. Followed by a mb_u_int32 encoding the character entity number.
-                    TbSync.dump("wbxml", "Encoded character entity has not yet been implemented. Sorry.");
-                    return false;
-                    break;
-                
-                case 0x03: // Inline string followed by a termstr. (0x00)
-                    let termpos = wbxml.indexOf(String.fromCharCode(0x00), num);
-                    //encode all special chars in the user data by encodeURIComponent which does not encode the apostrophe, so we need to do that by hand
-                    xml = xml + encodeURIComponent(wbxml.substring(num + 1, termpos)).replace(/'/g, "%27");
-                    num = termpos;
-                    break;
-                
-                case 0x04: // An unknown tag or attribute name. Followed by an mb_u_int32 that encodes an offset into the string table.
-                case 0x40: // Inline string document-type-specific extension token. Token is followed by a termstr.
-                case 0x41: // Inline string document-type-specific extension token. Token is followed by a termstr.
-                case 0x42: // Inline string document-type-specific extension token. Token is followed by a termstr.
-                case 0x43: // Processing instruction.
-                case 0x44: // Unknown tag, with content.
-                case 0x80: // Inline integer document-type-specific extension token. Token is followed by a mb_uint_32.
-                case 0x81: // Inline integer document-type-specific extension token. Token is followed by a mb_uint_32.
-                case 0x82: // Inline integer document-type-specific extension token. Token is followed by a mb_uint_32.
-                case 0x83: // String table reference. Followed by a mb_u_int32 encoding a byte offset from the beginning of the string table.
-                case 0x84: // Unknown tag, with attributes.
-                case 0xC0: // Single-byte document-type-specific extension token.
-                case 0xC1: // Single-byte document-type-specific extension token.
-                case 0xC2: // Single-byte document-type-specific extension token.
-                case 0xC3: // Opaque document-type-specific data.
-                case 0xC4: // Unknown tag, with content and attributes.
-                    TbSync.dump("wbxml", "Global token <" + token + "> has not yet been implemented. Sorry.");
-                    return false;
-                    break;
-                    
-                default:
-                    // if this code page is not the mainCodePage (or mainCodePage is not yet set =  very first tag), add codePageTag with current codepage
-                    let codePageTag = (codepage != mainCodePage) ? " xmlns='" + this.getNamespace(codepage) + "'" : "";
-
-                    // if no mainCodePage has been defined yet, use the current codepage, which is either the initialized/default value of codepage or a value set by SWITCH_PAGE
-                    if (mainCodePage === null) mainCodePage = codepage;
-
-                    if (!tokenHasContent) {
-                        xml = xml + "<" + this. getCodepageToken(codepage, token) + codePageTag + "/>";
-                    } else {
-                        xml = xml + "<" +this. getCodepageToken(codepage, token) + codePageTag +">";
-                        //add the closing tag to the stack, so it can get properly closed later
-                        tagStack.push("</" +this. getCodepageToken(codepage, token) + ">");
-                    }
-
-                    if (this.isUnknownToken(codepage, token)) {
-                        TbSync.eventlog.add("warning", null, "WBXML: Unknown token <" + token + "> for codepage <"+codepage+">.");
-                    }
-            }
-            num = num + 1;
-        }
-        return (xml == "") ? "" : '<?xml version="1.0"?>' + xml;
-    },
-
-    isUnknownToken: function (codepage, token) {
-        if (this.codepages[codepage] && token in this.codepages[codepage]) return false;
-        else return true;
-    },
-    
-    getNamespace: function (codepage) {
-        return (this.namespaces[codepage]) ? this.namespaces[codepage] : "UnknownCodePage" + codepage ;
-    },
-
-    getCodepageToken: function (codepage, token) {
-        return this.isUnknownToken(codepage, token) ? "Unknown." + codepage + "." + token : this.codepages[codepage][token];   
-    },
-
-    // This returns a wbxml object, which allows to add tags (using names), switch codepages, or open and close tags, it is also possible to append pure (binary) wbxml
-    // If no wbxmlstring is present, default to the "init" string ( WBXML Version 1.3, unknown public identifier, UTF-8, Length of string table)
-    createWBXML: function (wbxmlstring = String.fromCharCode(0x03, 0x01, 0x6A, 0x00), initialCodepage = "") {
-        let wbxml = {
-            _codepage : 0,
-            _wbxml : wbxmlstring, 
-
-            append : function (wbxmlstring) {
-                this._wbxml = this._wbxml + wbxmlstring;
-            },
-            
-            // adding a string content tag as <tagname>contentstring</tagname>
-            atag : function (tokenname, content = "") {
-                //check if tokenname is in current codepage
-                if ((this._codepage in wbxmltools.codepages2) == false) throw "[wbxmltools] Unknown codepage <"+this._codepage+">";
-                if ((tokenname in wbxmltools.codepages2[this._codepage]) == false) throw "[wbxmltools] Unknown tokenname <"+tokenname+"> for codepage <"+wbxmltools.namespaces[this._codepage]+">";  
-
-                if (content == "") {
-                    //empty, just add token
-                    this._wbxml += String.fromCharCode(wbxmltools.codepages2[this._codepage][tokenname]);
-                } else {
-                    //not empty,add token with enabled content bit and also add inlinestringidentifier
-                    this._wbxml += String.fromCharCode(wbxmltools.codepages2[this._codepage][tokenname] | 0x40, 0x03);
-                    //add content
-                    for (let i=0; i< content.length; i++) this._wbxml += String.fromCharCode(content.charCodeAt(i));
-                    //add string termination and tag close
-                    this._wbxml += String.fromCharCode(0x00, 0x01);
-                }
-            },
-
-            switchpage : function (name) {
-                let codepage = wbxmltools.namespaces.indexOf(name);
-                if (codepage == -1) throw "[wbxmltools] Unknown codepage <"+ name +">";
-                this._codepage = codepage;
-                this._wbxml += String.fromCharCode(0x00, codepage);
-            },
-
-            ctag : function () {
-                this._wbxml += String.fromCharCode(0x01);
-            },
-
-            //opentag is assumed to add a token with content, otherwise use addtag
-            otag : function (tokenname) {
-                this._wbxml += String.fromCharCode(wbxmltools.codepages2[this._codepage][tokenname] | 0x40);
-            },
-
-            getCharCodes : function () {
-                let value = "";
-                for (let i=0; i<this._wbxml.length; i++) value += ("00" + this._wbxml.charCodeAt(i).toString(16)).substr(-2) + " ";
-                return value;
-            },
-
-            getBytes : function () {
-                return this._wbxml;
-            }
-        };
-	if (initialCodepage) wbxml._codepage = wbxmltools.namespaces.indexOf(initialCodepage);
-        return wbxml;
-    },
-
-
-
-
-
-    codepages2 : [],
-
-    buildCodepages2 : function () {
-        for (let i=0; i<this.codepages.length; i++) {
-            let inverted = {};
-            for (let token in this.codepages[i]) {
-                inverted[this.codepages[i][token]] = token;
-            }
-            this.codepages2.push(inverted);
-        }
-    },
-
-
-
-
-
-    codepages : [
-        // Code Page 0: AirSync
-        {
-            0x05: 'Sync',
-            0x06: 'Responses',
-            0x07: 'Add',
-            0x08: 'Change',
-            0x09: 'Delete',
-            0x0A: 'Fetch',
-            0x0B: 'SyncKey',
-            0x0C: 'ClientId',
-            0x0D: 'ServerId',
-            0x0E: 'Status',
-            0x0F: 'Collection',
-            0x10: 'Class',
-            0x12: 'CollectionId',
-            0x13: 'GetChanges',
-            0x14: 'MoreAvailable',
-            0x15: 'WindowSize',
-            0x16: 'Commands',
-            0x17: 'Options',
-            0x18: 'FilterType',
-            0x1B: 'Conflict',
-            0x1C: 'Collections',
-            0x1D: 'ApplicationData',
-            0x1E: 'DeletesAsMoves',
-            0x20: 'Supported',
-            0x21: 'SoftDelete',
-            0x22: 'MIMESupport',
-            0x23: 'MIMETruncation',
-            0x24: 'Wait',
-            0x25: 'Limit',
-            0x26: 'Partial',
-            0x27: 'ConversationMode',
-            0x28: 'MaxItems',
-            0x29: 'HeartbeatInterval'
-        },
-        // Code Page 1: Contacts
-        {
-            0x05: 'Anniversary',
-            0x06: 'AssistantName',
-            0x07: 'AssistantPhoneNumber',
-            0x08: 'Birthday',
-            0x09: 'Body',
-            0x0A: 'BodySize',
-            0x0B: 'BodyTruncated',
-            0x0C: 'Business2PhoneNumber',
-            0x0D: 'BusinessAddressCity',
-            0x0E: 'BusinessAddressCountry',
-            0x0F: 'BusinessAddressPostalCode',
-            0x10: 'BusinessAddressState',
-            0x11: 'BusinessAddressStreet',
-            0x12: 'BusinessFaxNumber',
-            0x13: 'BusinessPhoneNumber',
-            0x14: 'CarPhoneNumber',
-            0x15: 'Categories',
-            0x16: 'Category',
-            0x17: 'Children',
-            0x18: 'Child',
-            0x19: 'CompanyName',
-            0x1A: 'Department',
-            0x1B: 'Email1Address',
-            0x1C: 'Email2Address',
-            0x1D: 'Email3Address',
-            0x1E: 'FileAs',
-            0x1F: 'FirstName',
-            0x20: 'Home2PhoneNumber',
-            0x21: 'HomeAddressCity',
-            0x22: 'HomeAddressCountry',
-            0x23: 'HomeAddressPostalCode',
-            0x24: 'HomeAddressState',
-            0x25: 'HomeAddressStreet',
-            0x26: 'HomeFaxNumber',
-            0x27: 'HomePhoneNumber',
-            0x28: 'JobTitle',
-            0x29: 'LastName',
-            0x2A: 'MiddleName',
-            0x2B: 'MobilePhoneNumber',
-            0x2C: 'OfficeLocation',
-            0x2D: 'OtherAddressCity',
-            0x2E: 'OtherAddressCountry',
-            0x2F: 'OtherAddressPostalCode',
-            0x30: 'OtherAddressState',
-            0x31: 'OtherAddressStreet',
-            0x32: 'PagerNumber',
-            0x33: 'RadioPhoneNumber',
-            0x34: 'Spouse',
-            0x35: 'Suffix',
-            0x36: 'Title',
-            0x37: 'WebPage',
-            0x38: 'YomiCompanyName',
-            0x39: 'YomiFirstName',
-            0x3A: 'YomiLastName',
-            0x3B: 'CompressedRTF',
-            0x3C: 'Picture',
-            0x3D: 'Alias',
-            0x3E: 'WeightedRank'
-        },
-        // Code Page 2: Email
-        {
-            0x05: 'Attachment',
-            0x06: 'Attachments',
-            0x07: 'AttName',
-            0x08: 'AttSize',
-            0x09: 'Att0Id',
-            0x0a: 'AttMethod',
-            0x0b: 'AttRemoved',
-            0x0c: 'Body',
-            0x0d: 'BodySize',
-            0x0e: 'BodyTruncated',
-            0x0f: 'DateReceived',
-            0x10: 'DisplayName',
-            0x11: 'DisplayTo',
-            0x12: 'Importance',
-            0x13: 'MessageClass',
-            0x14: 'Subject',
-            0x15: 'Read',
-            0x16: 'To',
-            0x17: 'Cc',
-            0x18: 'From',
-            0x19: 'ReplyTo',
-            0x1a: 'AllDayEvent',
-            0x1b: 'Categories',
-            0x1c: 'Category',
-            0x1d: 'DTStamp',
-            0x1e: 'EndTime',
-            0x1f: 'InstanceType',
-            0x20: 'BusyStatus',
-            0x21: 'Location',
-            0x22: 'MeetingRequest',
-            0x23: 'Organizer',
-            0x24: 'RecurrenceId',
-            0x25: 'Reminder',
-            0x26: 'ResponseRequested',
-            0x27: 'Recurrences',
-            0x28: 'Recurrence',
-            0x29: 'Recurrence_Type',
-            0x2a: 'Recurrence_Until',
-            0x2b: 'Recurrence_Occurrences',
-            0x2c: 'Recurrence_Interval',
-            0x2d: 'Recurrence_DayOfWeek',
-            0x2e: 'Recurrence_DayOfMonth',
-            0x2f: 'Recurrence_WeekOfMonth',
-            0x30: 'Recurrence_MonthOfYear',
-            0x31: 'StartTime',
-            0x32: 'Sensitivity',
-            0x33: 'TimeZone',
-            0x34: 'GlobalObjId',
-            0x35: 'ThreadTopic',
-            0x36: 'MIMEData',
-            0x37: 'MIMETruncated',
-            0x38: 'MIMESize',
-            0x39: 'InternetCPID',
-            0x3a: 'Flag',
-            0x3b: 'Status',
-            0x3c: 'ContentClass',
-            0x3d: 'FlagType',
-            0x3e: 'CompleteTime',
-            0x3f: 'DisallowNewTimeProposal'
-        },
-        // Code Page 3: AirNotify (WBXML code page 3 is no longer in use)
-        {},
-        // Code Page 4: Calendar
-        {
-            0x05: 'TimeZone',
-            0x06: 'AllDayEvent',
-            0x07: 'Attendees',
-            0x08: 'Attendee',
-            0x09: 'Email',
-            0x0a: 'Name',
-            0x0b: 'Body',
-            0x0c: 'BodyTruncated',
-            0x0d: 'BusyStatus',
-            0x0e: 'Categories',
-            0x0f: 'Category',
-            0x10: 'CompressedRTF',
-            0x11: 'DtStamp',
-            0x12: 'EndTime',
-            0x13: 'Exception',
-            0x14: 'Exceptions',
-            0x15: 'Deleted',
-            0x16: 'ExceptionStartTime',
-            0x17: 'Location',
-            0x18: 'MeetingStatus',
-            0x19: 'OrganizerEmail',
-            0x1a: 'OrganizerName',
-            0x1b: 'Recurrence',
-            0x1c: 'Type',
-            0x1d: 'Until',
-            0x1e: 'Occurrences',
-            0x1f: 'Interval',
-            0x20: 'DayOfWeek',
-            0x21: 'DayOfMonth',
-            0x22: 'WeekOfMonth',
-            0x23: 'MonthOfYear',
-            0x24: 'Reminder',
-            0x25: 'Sensitivity',
-            0x26: 'Subject',
-            0x27: 'StartTime',
-            0x28: 'UID',
-            0x29: 'AttendeeStatus',
-            0x2a: 'AttendeeType',
-            0x2b: 'Attachment',
-            0x2c: 'Attachments',
-            0x2d: 'AttName',
-            0x2e: 'AttSize',
-            0x2f: 'AttOid',
-            0x30: 'AttMethod',
-            0x31: 'AttRemoved',
-            0x32: 'DisplayName',
-            0x33: 'DisallowNewTimeProposal',
-            0x34: 'ResponseRequested',
-            0x35: 'AppointmentReplyTime',
-            0x36: 'ResponseType',
-            0x37: 'CalendarType',
-            0x38: 'IsLeapMonth',
-            0x39: 'FirstDayOfWeek',
-            0x3a: 'OnlineMeetingConfLink',
-            0x3b: 'OnlineMeetingExternalLink'
-        },
-        // Code Page 5: Move
-        {
-            0x05: 'MoveItems',
-            0x06: 'Move',
-            0x07: 'SrcMsgId',
-            0x08: 'SrcFldId',
-            0x09: 'DstFldId',
-            0x0A: 'Response',
-            0x0B: 'Status',
-            0x0C: 'DstMsgId'
-        },
-        // Code Page 6: GetItemEstimate
-        {
-            0x05: 'GetItemEstimate',
-            0x06: 'Version',
-            0x07: 'Collections',
-            0x08: 'Collection',
-            0x09: 'Class',
-            0x0A: 'CollectionId',
-            0x0B: 'DateTime',
-            0x0C: 'Estimate',
-            0x0D: 'Response',
-            0x0E: 'Status'
-        },
-        // Code Page 7: FolderHierarchy
-        {
-            0x07: 'DisplayName',
-            0x08: 'ServerId',
-            0x09: 'ParentId',
-            0x0A: 'Type',
-            0x0C: 'Status',
-            0x0E: 'Changes',
-            0x0F: 'Add',
-            0x10: 'Delete',
-            0x11: 'Update',
-            0x12: 'SyncKey',
-            0x13: 'FolderCreate',
-            0x14: 'FolderDelete',
-            0x15: 'FolderUpdate',
-            0x16: 'FolderSync',
-            0x17: 'Count'
-        },
-        // Code Page 8: MeetingResponse
-        {
-            0x05: 'CalendarId',
-            0x06: 'CollectionId',
-            0x07: 'MeetingResponse',
-            0x08: 'RequestId',
-            0x09: 'Request',
-            0x0a: 'Result',
-            0x0b: 'Status',
-            0x0c: 'UserResponse',
-            0x0e: 'InstanceId'
-        },
-        // Code Page 9: Tasks
-        {
-            0x05: 'Body',
-            0x06: 'BodySize',
-            0x07: 'BodyTruncated',
-            0x08: 'Categories',
-            0x09: 'Category',
-            0x0A: 'Complete',
-            0x0B: 'DateCompleted',
-            0x0C: 'DueDate',
-            0x0D: 'UtcDueDate',
-            0x0E: 'Importance',
-            0x0F: 'Recurrence',
-            0x10: 'Type',
-            0x11: 'Start',
-            0x12: 'Until',
-            0x13: 'Occurrences',
-            0x14: 'Interval',
-            0x15: 'DayOfMonth',
-            0x16: 'DayOfWeek',
-            0x17: 'WeekOfMonth',
-            0x18: 'MonthOfYear',
-            0x19: 'Regenerate',
-            0x1A: 'DeadOccur',
-            0x1B: 'ReminderSet',
-            0x1C: 'ReminderTime',
-            0x1D: 'Sensitivity',
-            0x1E: 'StartDate',
-            0x1F: 'UtcStartDate',
-            0x20: 'Subject',
-            0x22: 'OrdinalDate',
-            0x23: 'SubOrdinalDate',
-            0x24: 'CalendarType',
-            0x25: 'IsLeapMonth',
-            0x26: 'FirstDayOfWeek'
-        },
-        // Code Page 10: ResolveRecipients
-        {
-            0x05: 'ResolveRecipients',
-            0x06: 'Response',
-            0x07: 'Status',
-            0x08: 'Type',
-            0x09: 'Recipient',
-            0x0a: 'DisplayName',
-            0x0b: 'EmailAddress',
-            0x0c: 'Certificates',
-            0x0d: 'Certificate',
-            0x0e: 'MiniCertificate',
-            0x0f: 'Options',
-            0x10: 'To',
-            0x11: 'CertificateRetrieval',
-            0x12: 'RecipientCount',
-            0x13: 'MaxCertificates',
-            0x14: 'MaxAmbiguousRecipients',
-            0x15: 'CertificateCount',
-            0x16: 'Availability',
-            0x17: 'StartTime',
-            0x18: 'EndTime',
-            0x19: 'MergedFreeBusy',
-            0x1a: 'Picture',
-            0x1b: 'MaxSize',
-            0x1c: 'Data',
-            0x1d: 'MaxPictures'
-        },
-        // Code Page 11: ValidateCert
-        {
-            0x05: 'ValidateCert',
-            0x06: 'Certificates',
-            0x07: 'Certificate',
-            0x08: 'CertificateChain',
-            0x09: 'CheckCRL',
-            0x0a: 'Status'
-        },
-        // Code Page 12: Contacts2
-        {
-            0x05: 'CustomerId',
-            0x06: 'GovernmentId',
-            0x07: 'IMAddress',
-            0x08: 'IMAddress2',
-            0x09: 'IMAddress3',
-            0x0a: 'ManagerName',
-            0x0b: 'CompanyMainPhone',
-            0x0c: 'AccountName',
-            0x0d: 'NickName',
-            0x0e: 'MMS'
-        },
-        // Code Page 13: Ping
-        {
-            0x05: 'Ping',
-            0x06: 'AutdState',
-            //(Not used)
-            0x07: 'Status',
-            0x08: 'HeartbeatInterval',
-            0x09: 'Folders',
-            0x0A: 'Folder',
-            0x0B: 'Id',
-            0x0C: 'Class',
-            0x0D: 'MaxFolders'
-        },
-        // Code Page 14: Provision
-        {
-            0x05: 'Provision',
-            0x06: 'Policies',
-            0x07: 'Policy',
-            0x08: 'PolicyType',
-            0x09: 'PolicyKey',
-            0x0A: 'Data',
-            0x0B: 'Status',
-            0x0C: 'RemoteWipe',
-            0x0D: 'EASProvisionDoc',
-            0x0E: 'DevicePasswordEnabled',
-            0x0F: 'AlphanumericDevicePasswordRequired',
-            0x10: 'DeviceEncryptionEnabled',
-            0x10: 'RequireStorageCardEncryption',
-            0x11: 'PasswordRecoveryEnabled',
-            0x13: 'AttachmentsEnabled',
-            0x14: 'MinDevicePasswordLength',
-            0x15: 'MaxInactivityTimeDeviceLock',
-            0x16: 'MaxDevicePasswordFailedAttempts',
-            0x17: 'MaxAttachmentSize',
-            0x18: 'AllowSimpleDevicePassword',
-            0x19: 'DevicePasswordExpiration',
-            0x1A: 'DevicePasswordHistory',
-            0x1B: 'AllowStorageCard',
-            0x1C: 'AllowCamera',
-            0x1D: 'RequireDeviceEncryption',
-            0x1E: 'AllowUnsignedApplications',
-            0x1F: 'AllowUnsignedInstallationPackages',
-            0x20: 'MinDevicePasswordComplexCharacters',
-            0x21: 'AllowWiFi',
-            0x22: 'AllowTextMessaging',
-            0x23: 'AllowPOPIMAPEmail',
-            0x24: 'AllowBluetooth',
-            0x25: 'AllowIrDA',
-            0x26: 'RequireManualSyncWhenRoaming',
-            0x27: 'AllowDesktopSync',
-            0x28: 'MaxCalendarAgeFilter',
-            0x29: 'AllowHTMLEmail',
-            0x2A: 'MaxEmailAgeFilter',
-            0x2B: 'MaxEmailBodyTruncationSize',
-            0x2C: 'MaxEmailHTMLBodyTruncationSize',
-            0x2D: 'RequireSignedSMIMEMessages',
-            0x2E: 'RequireEncryptedSMIMEMessages',
-            0x2F: 'RequireSignedSMIMEAlgorithm',
-            0x30: 'RequireEncryptionSMIMEAlgorithm',
-            0x31: 'AllowSMIMEEncryptionAlgorithmNegotiation',
-            0x32: 'AllowSMIMESoftCerts',
-            0x33: 'AllowBrowser',
-            0x34: 'AllowConsumerEmail',
-            0x35: 'AllowRemoteDesktop',
-            0x36: 'AllowInternetSharing',
-            0x37: 'UnapprovedInROMApplicationList',
-            0x38: 'ApplicationName',
-            0x39: 'ApprovedApplicationList',
-            0x3A: 'Hash'
-        },
-        // Code Page 15: Search
-        {
-            0x05: 'Search',
-            0x06: 'Stores',
-            0x07: 'Store',
-            0x08: 'Name',
-            0x09: 'Query',
-            0x0a: 'Options',
-            0x0b: 'Range',
-            0x0c: 'Status',
-            0x0d: 'Response',
-            0x0e: 'Result',
-            0x0f: 'Properties',
-            0x10: 'Total',
-            0x11: 'EqualTo',
-            0x12: 'Value',
-            0x13: 'And',
-            0x14: 'Or',
-            0x15: 'FreeText',
-            0x17: 'DeepTraversal',
-            0x18: 'LongId',
-            0x19: 'RebuildResults',
-            0x1a: 'LessThan',
-            0x1b: 'GreaterThan',
-            0x1c: 'Schema',
-            0x1d: 'Supported',
-            0x1e: 'UserName',
-            0x1f: 'Password',
-            0x20: 'ConversationId',
-            0x21: 'Picture',
-            0x22: 'MaxSize',
-            0x23: 'MaxPictures'
-        },
-        // Code Page 16: GAL
-        {
-            0x05: 'DisplayName',
-            0x06: 'Phone',
-            0x07: 'Office',
-            0x08: 'Title',
-            0x09: 'Company',
-            0x0a: 'Alias',
-            0x0b: 'FirstName',
-            0x0c: 'LastName',
-            0x0d: 'HomePhone',
-            0x0e: 'MobilePhone',
-            0x0f: 'EmailAddress',
-            0x10: 'Picture',
-            0x11: 'Status',
-            0x12: 'Data'
-        },
-        // Code Page 17: AirSyncBase
-        {
-            0x05: 'BodyPreference',
-            0x06: 'Type',
-            0x07: 'TruncationSize',
-            0x08: 'AllOrNone',
-            0x0A: 'Body',
-            0x0B: 'Data',
-            0x0C: 'EstimatedDataSize',
-            0x0D: 'Truncated',
-            0x0E: 'Attachments',
-            0x0F: 'Attachment',
-            0x10: 'DisplayName',
-            0x11: 'FileReference',
-            0x12: 'Method',
-            0x13: 'ContentId',
-            0x14: 'ContentLocation',
-            0x15: 'IsInline',
-            0x16: 'NativeBodyType',
-            0x17: 'ContentType',
-            0x18: 'Preview',
-            0x19: 'BodyPartPreference',
-            0x1A: 'BodyPart',
-            0x1B: 'Status'
-        },
-        // Code Page 18: Settings
-        {
-            0x05: 'Settings',
-            0x06: 'Status',
-            0x07: 'Get',
-            0x08: 'Set',
-            0x09: 'Oof',
-            0x0A: 'OofState',
-            0x0B: 'StartTime',
-            0x0C: 'EndTime',
-            0x0D: 'OofMessage',
-            0x0E: 'AppliesToInternal',
-            0x0F: 'AppliesToExternalKnown',
-            0x10: 'AppliesToExternalUnknown',
-            0x11: 'Enabled',
-            0x12: 'ReplyMessage',
-            0x13: 'BodyType',
-            0x14: 'DevicePassword',
-            0x15: 'Password',
-            0x16: 'DeviceInformation',
-            0x17: 'Model',
-            0x18: 'IMEI',
-            0x19: 'FriendlyName',
-            0x1A: 'OS',
-            0x1B: 'OSLanguage',
-            0x1C: 'PhoneNumber',
-            0x1D: 'UserInformation',
-            0x1E: 'EmailAddresses',
-            0x1F: 'SMTPAddress',
-            0x20: 'UserAgent',
-            0x21: 'EnableOutboundSMS',
-            0x22: 'MobileOperator',
-            0x23: 'PrimarySmtpAddress',
-            0x24: 'Accounts',
-            0x25: 'Account',
-            0x26: 'AccountId',
-            0x27: 'AccountName',
-            0x28: 'UserDisplayName',
-            0x29: 'SendDisabled',
-            0x2B: 'RightsManagementInformation'
-        },
-        // Code Page 19: DocumentLibrary
-        {
-            0x05: 'LinkId',
-            0x06: 'DisplayName',
-            0x07: 'IsFolder',
-            0x08: 'CreationDate',
-            0x09: 'LastModifiedDate',
-            0x0a: 'IsHidden',
-            0x0b: 'ContentLength',
-            0x0c: 'ContentType'
-        },
-        // Code Page 20: ItemOperations
-        {
-            0x05: 'ItemOperations',
-            0x06: 'Fetch',
-            0x07: 'Store',
-            0x08: 'Options',
-            0x09: 'Range',
-            0x0A: 'Total',
-            0x0B: 'Properties',
-            0x0C: 'Data',
-            0x0D: 'Status',
-            0x0E: 'Response',
-            0x0F: 'Version',
-            0x10: 'Schema',
-            0x11: 'Part',
-            0x12: 'EmptyFolderContents',
-            0x13: 'DeleteSubFolders',
-            0x14: 'UserName',
-            0x15: 'Password',
-            0x16: 'Move',
-            0x17: 'DstFldId',
-            0x18: 'ConversationId',
-            0x19: 'MoveAlways'
-        },
-        // Code Page 21: ComposeMail
-        {
-            0x05: 'SendMail',
-            0x06: 'SmartForward',
-            0x07: 'SmartReply',
-            0x08: 'SaveInSentItems',
-            0x09: 'ReplaceMime',
-            0x0b: 'Source',
-            0x0c: 'FolderId',
-            0x0d: 'ItemId',
-            0x0e: 'LongId',
-            0x0f: 'InstanceId',
-            0x10: 'Mime',
-            0x11: 'ClientId',
-            0x12: 'Status',
-            0x13: 'AccountId',
-            0x15: 'Forwardees',
-            0x16: 'Forwardee',
-            0x17: 'ForwardeeName',
-            0x18: 'ForwardeeEmail'
-        },
-        // Code Page 22: Email2
-        {
-            0x05: 'UmCallerID',
-            0x06: 'UmUserNotes',
-            0x07: 'UmAttDuration',
-            0x08: 'UmAttOrder',
-            0x09: 'ConversationId',
-            0x0a: 'ConversationIndex',
-            0x0b: 'LastVerbExecuted',
-            0x0c: 'LastVerbExecutionTime',
-            0x0d: 'ReceivedAsBcc',
-            0x0e: 'Sender',
-            0x0f: 'CalendarType',
-            0x10: 'IsLeapMonth',
-            0x11: 'AccountId',
-            0x12: 'FirstDayOfWeek',
-            0x13: 'MeetingMessageType',
-            0x15: 'IsDraft',
-            0x16: 'Bcc',
-            0x17: 'Send'
-        },
-        // Code Page 23: Notes
-        {
-            0x05: 'Subject',
-            0x06: 'MessageClass',
-            0x07: 'LastModifiedDate',
-            0x08: 'Categories',
-            0x09: 'Category'
-        },
-        // Code Page 24: RightsManagement
-        {
-            0x05: 'RightsManagementSupport',
-            0x06: 'RightsManagementTemplates',
-            0x07: 'RightsManagementTemplate',
-            0x08: 'RightsManagementLicense',
-            0x09: 'EditAllowed',
-            0x0a: 'ReplyAllowed',
-            0x0b: 'ReplyAllAllowed',
-            0x0c: 'ForwardAllowed',
-            0x0d: 'ModifyRecipientsAllowed',
-            0x0e: 'ExtractAllowed',
-            0x0f: 'PrintAllowed',
-            0x10: 'ExportAllowed',
-            0x11: 'ProgrammaticAccessAllowed',
-            0x12: 'Owner',
-            0x13: 'ContentExpiryDate',
-            0x14: 'TemplateID',
-            0x15: 'TemplateName',
-            0x16: 'TemplateDescription',
-            0x17: 'ContentOwner',
-            0x18: 'RemoveRightsManagementDistribution'
-        }
-    ],
-
-    namespaces : [
-        'AirSync',
-        'Contacts',
-        'Email',
-        'AirNotify',
-        'Calendar',
-        'Move',
-        'GetItemEstimate',
-        'FolderHierarchy',
-        'MeetingResponse',
-        'Tasks',
-        'ResolveRecipients',
-        'ValidateCert',
-        'Contacts2',
-        'Ping',
-        'Provision',
-        'Search',
-        'Gal',
-        'AirSyncBase',
-        'Settings',
-        'DocumentLibrary',
-        'ItemOperations',
-        'ComposeMail',
-        'Email2',
-        'Notes',
-        'RightsManagement'
-    ]
-    
-};
-
-wbxmltools.buildCodepages2();
+/*
+ * This file is part of EAS-4-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 wbxmltools = {
+
+    // Convert a WBXML (WAP Binary XML) to plain XML - returns save xml with all special chars in the user data encoded by encodeURIComponent
+    convert2xml: function (wbxml) {
+
+        let num = 4; //skip the 4 first bytes which are mostly 0x03 (WBXML Version 1.3), 0x01 (unknown public identifier), 0x6A (utf-8), 0x00 (Length of string table)
+
+        //the main code page will be set to the the first codepage used
+        let mainCodePage = null;
+
+        let tagStack = [];
+        let xml = "";
+        let codepage = 0;
+
+        while (num < wbxml.length) {
+            let data = wbxml.substr(num, 1).charCodeAt(0);
+            let token = data & 0x3F; //removes content bit(6) and attribute bit(7)
+            let tokenHasContent = ((data & 0x40) != 0); //checks if content bit is set
+            let tokenHasAttributes = ((data & 0x80) != 0); //checks if attribute bit is set
+
+            switch (token) {
+                case 0x00: // switch of codepage (new codepage is next byte)
+                    num = num + 1;
+                    codepage = (wbxml.substr(num, 1)).charCodeAt(0) & 0xFF;
+                    break;
+
+                case 0x01: // Indicates the end of an attribute list or the end of an element
+                    // tagStack contains a list of opened tags, which await to be closed
+                    xml = xml + tagStack.pop();
+                    break;
+
+                case 0x02: // A character entity. Followed by a mb_u_int32 encoding the character entity number.
+                    TbSync.dump("wbxml", "Encoded character entity has not yet been implemented. Sorry.");
+                    return false;
+                    break;
+
+                case 0x03: // Inline string followed by a termstr. (0x00)
+                    let termpos = wbxml.indexOf(String.fromCharCode(0x00), num);
+                    //encode all special chars in the user data by encodeURIComponent which does not encode the apostrophe, so we need to do that by hand
+                    xml = xml + encodeURIComponent(wbxml.substring(num + 1, termpos)).replace(/'/g, "%27");
+                    num = termpos;
+                    break;
+
+                case 0x04: // An unknown tag or attribute name. Followed by an mb_u_int32 that encodes an offset into the string table.
+                case 0x40: // Inline string document-type-specific extension token. Token is followed by a termstr.
+                case 0x41: // Inline string document-type-specific extension token. Token is followed by a termstr.
+                case 0x42: // Inline string document-type-specific extension token. Token is followed by a termstr.
+                case 0x43: // Processing instruction.
+                case 0x44: // Unknown tag, with content.
+                case 0x80: // Inline integer document-type-specific extension token. Token is followed by a mb_uint_32.
+                case 0x81: // Inline integer document-type-specific extension token. Token is followed by a mb_uint_32.
+                case 0x82: // Inline integer document-type-specific extension token. Token is followed by a mb_uint_32.
+                case 0x83: // String table reference. Followed by a mb_u_int32 encoding a byte offset from the beginning of the string table.
+                case 0x84: // Unknown tag, with attributes.
+                case 0xC0: // Single-byte document-type-specific extension token.
+                case 0xC1: // Single-byte document-type-specific extension token.
+                case 0xC2: // Single-byte document-type-specific extension token.
+                case 0xC3: // Opaque document-type-specific data.
+                case 0xC4: // Unknown tag, with content and attributes.
+                    TbSync.dump("wbxml", "Global token <" + token + "> has not yet been implemented. Sorry.");
+                    return false;
+                    break;
+
+                default:
+                    // if this code page is not the mainCodePage (or mainCodePage is not yet set =  very first tag), add codePageTag with current codepage
+                    let codePageTag = (codepage != mainCodePage) ? " xmlns='" + this.getNamespace(codepage) + "'" : "";
+
+                    // if no mainCodePage has been defined yet, use the current codepage, which is either the initialized/default value of codepage or a value set by SWITCH_PAGE
+                    if (mainCodePage === null) mainCodePage = codepage;
+
+                    if (!tokenHasContent) {
+                        xml = xml + "<" + this.getCodepageToken(codepage, token) + codePageTag + "/>";
+                    } else {
+                        xml = xml + "<" + this.getCodepageToken(codepage, token) + codePageTag + ">";
+                        //add the closing tag to the stack, so it can get properly closed later
+                        tagStack.push("</" + this.getCodepageToken(codepage, token) + ">");
+                    }
+
+                    if (this.isUnknownToken(codepage, token)) {
+                        TbSync.eventlog.add("warning", null, "WBXML: Unknown token <" + token + "> for codepage <" + codepage + ">.");
+                    }
+            }
+            num = num + 1;
+        }
+        return (xml == "") ? "" : '<?xml version="1.0"?>' + xml;
+    },
+
+    isUnknownToken: function (codepage, token) {
+        if (this.codepages[codepage] && token in this.codepages[codepage]) return false;
+        else return true;
+    },
+
+    getNamespace: function (codepage) {
+        return (this.namespaces[codepage]) ? this.namespaces[codepage] : "UnknownCodePage" + codepage;
+    },
+
+    getCodepageToken: function (codepage, token) {
+        return this.isUnknownToken(codepage, token) ? "Unknown." + codepage + "." + token : this.codepages[codepage][token];
+    },
+
+    // This returns a wbxml object, which allows to add tags (using names), switch codepages, or open and close tags, it is also possible to append pure (binary) wbxml
+    // If no wbxmlstring is present, default to the "init" string ( WBXML Version 1.3, unknown public identifier, UTF-8, Length of string table)
+    createWBXML: function (wbxmlstring = String.fromCharCode(0x03, 0x01, 0x6A, 0x00), initialCodepage = "") {
+        let wbxml = {
+            _codepage: 0,
+            _wbxml: wbxmlstring,
+
+            append: function (wbxmlstring) {
+                this._wbxml = this._wbxml + wbxmlstring;
+            },
+
+            // adding a string content tag as <tagname>contentstring</tagname>
+            atag: function (tokenname, content = "") {
+                //check if tokenname is in current codepage
+                if ((this._codepage in wbxmltools.codepages2) == false) throw "[wbxmltools] Unknown codepage <" + this._codepage + ">";
+                if ((tokenname in wbxmltools.codepages2[this._codepage]) == false) throw "[wbxmltools] Unknown tokenname <" + tokenname + "> for codepage <" + wbxmltools.namespaces[this._codepage] + ">";
+
+                if (content == "") {
+                    //empty, just add token
+                    this._wbxml += String.fromCharCode(wbxmltools.codepages2[this._codepage][tokenname]);
+                } else {
+                    //not empty,add token with enabled content bit and also add inlinestringidentifier
+                    this._wbxml += String.fromCharCode(wbxmltools.codepages2[this._codepage][tokenname] | 0x40, 0x03);
+                    //add content
+                    for (let i = 0; i < content.length; i++) this._wbxml += String.fromCharCode(content.charCodeAt(i));
+                    //add string termination and tag close
+                    this._wbxml += String.fromCharCode(0x00, 0x01);
+                }
+            },
+
+            switchpage: function (name) {
+                let codepage = wbxmltools.namespaces.indexOf(name);
+                if (codepage == -1) throw "[wbxmltools] Unknown codepage <" + name + ">";
+                this._codepage = codepage;
+                this._wbxml += String.fromCharCode(0x00, codepage);
+            },
+
+            ctag: function () {
+                this._wbxml += String.fromCharCode(0x01);
+            },
+
+            //opentag is assumed to add a token with content, otherwise use addtag
+            otag: function (tokenname) {
+                this._wbxml += String.fromCharCode(wbxmltools.codepages2[this._codepage][tokenname] | 0x40);
+            },
+
+            getCharCodes: function () {
+                let value = "";
+                for (let i = 0; i < this._wbxml.length; i++) value += ("00" + this._wbxml.charCodeAt(i).toString(16)).substr(-2) + " ";
+                return value;
+            },
+
+            getBytes: function () {
+                return this._wbxml;
+            }
+        };
+        if (initialCodepage) wbxml._codepage = wbxmltools.namespaces.indexOf(initialCodepage);
+        return wbxml;
+    },
+
+
+
+
+
+    codepages2: [],
+
+    buildCodepages2: function () {
+        for (let i = 0; i < this.codepages.length; i++) {
+            let inverted = {};
+            for (let token in this.codepages[i]) {
+                inverted[this.codepages[i][token]] = token;
+            }
+            this.codepages2.push(inverted);
+        }
+    },
+
+
+
+
+
+    codepages: [
+        // Code Page 0: AirSync
+        {
+            0x05: 'Sync',
+            0x06: 'Responses',
+            0x07: 'Add',
+            0x08: 'Change',
+            0x09: 'Delete',
+            0x0A: 'Fetch',
+            0x0B: 'SyncKey',
+            0x0C: 'ClientId',
+            0x0D: 'ServerId',
+            0x0E: 'Status',
+            0x0F: 'Collection',
+            0x10: 'Class',
+            0x12: 'CollectionId',
+            0x13: 'GetChanges',
+            0x14: 'MoreAvailable',
+            0x15: 'WindowSize',
+            0x16: 'Commands',
+            0x17: 'Options',
+            0x18: 'FilterType',
+            0x1B: 'Conflict',
+            0x1C: 'Collections',
+            0x1D: 'ApplicationData',
+            0x1E: 'DeletesAsMoves',
+            0x20: 'Supported',
+            0x21: 'SoftDelete',
+            0x22: 'MIMESupport',
+            0x23: 'MIMETruncation',
+            0x24: 'Wait',
+            0x25: 'Limit',
+            0x26: 'Partial',
+            0x27: 'ConversationMode',
+            0x28: 'MaxItems',
+            0x29: 'HeartbeatInterval'
+        },
+        // Code Page 1: Contacts
+        {
+            0x05: 'Anniversary',
+            0x06: 'AssistantName',
+            0x07: 'AssistantPhoneNumber',
+            0x08: 'Birthday',
+            0x09: 'Body',
+            0x0A: 'BodySize',
+            0x0B: 'BodyTruncated',
+            0x0C: 'Business2PhoneNumber',
+            0x0D: 'BusinessAddressCity',
+            0x0E: 'BusinessAddressCountry',
+            0x0F: 'BusinessAddressPostalCode',
+            0x10: 'BusinessAddressState',
+            0x11: 'BusinessAddressStreet',
+            0x12: 'BusinessFaxNumber',
+            0x13: 'BusinessPhoneNumber',
+            0x14: 'CarPhoneNumber',
+            0x15: 'Categories',
+            0x16: 'Category',
+            0x17: 'Children',
+            0x18: 'Child',
+            0x19: 'CompanyName',
+            0x1A: 'Department',
+            0x1B: 'Email1Address',
+            0x1C: 'Email2Address',
+            0x1D: 'Email3Address',
+            0x1E: 'FileAs',
+            0x1F: 'FirstName',
+            0x20: 'Home2PhoneNumber',
+            0x21: 'HomeAddressCity',
+            0x22: 'HomeAddressCountry',
+            0x23: 'HomeAddressPostalCode',
+            0x24: 'HomeAddressState',
+            0x25: 'HomeAddressStreet',
+            0x26: 'HomeFaxNumber',
+            0x27: 'HomePhoneNumber',
+            0x28: 'JobTitle',
+            0x29: 'LastName',
+            0x2A: 'MiddleName',
+            0x2B: 'MobilePhoneNumber',
+            0x2C: 'OfficeLocation',
+            0x2D: 'OtherAddressCity',
+            0x2E: 'OtherAddressCountry',
+            0x2F: 'OtherAddressPostalCode',
+            0x30: 'OtherAddressState',
+            0x31: 'OtherAddressStreet',
+            0x32: 'PagerNumber',
+            0x33: 'RadioPhoneNumber',
+            0x34: 'Spouse',
+            0x35: 'Suffix',
+            0x36: 'Title',
+            0x37: 'WebPage',
+            0x38: 'YomiCompanyName',
+            0x39: 'YomiFirstName',
+            0x3A: 'YomiLastName',
+            0x3B: 'CompressedRTF',
+            0x3C: 'Picture',
+            0x3D: 'Alias',
+            0x3E: 'WeightedRank'
+        },
+        // Code Page 2: Email
+        {
+            0x05: 'Attachment',
+            0x06: 'Attachments',
+            0x07: 'AttName',
+            0x08: 'AttSize',
+            0x09: 'Att0Id',
+            0x0a: 'AttMethod',
+            0x0b: 'AttRemoved',
+            0x0c: 'Body',
+            0x0d: 'BodySize',
+            0x0e: 'BodyTruncated',
+            0x0f: 'DateReceived',
+            0x10: 'DisplayName',
+            0x11: 'DisplayTo',
+            0x12: 'Importance',
+            0x13: 'MessageClass',
+            0x14: 'Subject',
+            0x15: 'Read',
+            0x16: 'To',
+            0x17: 'Cc',
+            0x18: 'From',
+            0x19: 'ReplyTo',
+            0x1a: 'AllDayEvent',
+            0x1b: 'Categories',
+            0x1c: 'Category',
+            0x1d: 'DTStamp',
+            0x1e: 'EndTime',
+            0x1f: 'InstanceType',
+            0x20: 'BusyStatus',
+            0x21: 'Location',
+            0x22: 'MeetingRequest',
+            0x23: 'Organizer',
+            0x24: 'RecurrenceId',
+            0x25: 'Reminder',
+            0x26: 'ResponseRequested',
+            0x27: 'Recurrences',
+            0x28: 'Recurrence',
+            0x29: 'Recurrence_Type',
+            0x2a: 'Recurrence_Until',
+            0x2b: 'Recurrence_Occurrences',
+            0x2c: 'Recurrence_Interval',
+            0x2d: 'Recurrence_DayOfWeek',
+            0x2e: 'Recurrence_DayOfMonth',
+            0x2f: 'Recurrence_WeekOfMonth',
+            0x30: 'Recurrence_MonthOfYear',
+            0x31: 'StartTime',
+            0x32: 'Sensitivity',
+            0x33: 'TimeZone',
+            0x34: 'GlobalObjId',
+            0x35: 'ThreadTopic',
+            0x36: 'MIMEData',
+            0x37: 'MIMETruncated',
+            0x38: 'MIMESize',
+            0x39: 'InternetCPID',
+            0x3a: 'Flag',
+            0x3b: 'Status',
+            0x3c: 'ContentClass',
+            0x3d: 'FlagType',
+            0x3e: 'CompleteTime',
+            0x3f: 'DisallowNewTimeProposal'
+        },
+        // Code Page 3: AirNotify (WBXML code page 3 is no longer in use)
+        {},
+        // Code Page 4: Calendar
+        {
+            0x05: 'TimeZone',
+            0x06: 'AllDayEvent',
+            0x07: 'Attendees',
+            0x08: 'Attendee',
+            0x09: 'Email',
+            0x0a: 'Name',
+            0x0b: 'Body',
+            0x0c: 'BodyTruncated',
+            0x0d: 'BusyStatus',
+            0x0e: 'Categories',
+            0x0f: 'Category',
+            0x10: 'CompressedRTF',
+            0x11: 'DtStamp',
+            0x12: 'EndTime',
+            0x13: 'Exception',
+            0x14: 'Exceptions',
+            0x15: 'Deleted',
+            0x16: 'ExceptionStartTime',
+            0x17: 'Location',
+            0x18: 'MeetingStatus',
+            0x19: 'OrganizerEmail',
+            0x1a: 'OrganizerName',
+            0x1b: 'Recurrence',
+            0x1c: 'Type',
+            0x1d: 'Until',
+            0x1e: 'Occurrences',
+            0x1f: 'Interval',
+            0x20: 'DayOfWeek',
+            0x21: 'DayOfMonth',
+            0x22: 'WeekOfMonth',
+            0x23: 'MonthOfYear',
+            0x24: 'Reminder',
+            0x25: 'Sensitivity',
+            0x26: 'Subject',
+            0x27: 'StartTime',
+            0x28: 'UID',
+            0x29: 'AttendeeStatus',
+            0x2a: 'AttendeeType',
+            0x2b: 'Attachment',
+            0x2c: 'Attachments',
+            0x2d: 'AttName',
+            0x2e: 'AttSize',
+            0x2f: 'AttOid',
+            0x30: 'AttMethod',
+            0x31: 'AttRemoved',
+            0x32: 'DisplayName',
+            0x33: 'DisallowNewTimeProposal',
+            0x34: 'ResponseRequested',
+            0x35: 'AppointmentReplyTime',
+            0x36: 'ResponseType',
+            0x37: 'CalendarType',
+            0x38: 'IsLeapMonth',
+            0x39: 'FirstDayOfWeek',
+            0x3a: 'OnlineMeetingConfLink',
+            0x3b: 'OnlineMeetingExternalLink'
+        },
+        // Code Page 5: Move
+        {
+            0x05: 'MoveItems',
+            0x06: 'Move',
+            0x07: 'SrcMsgId',
+            0x08: 'SrcFldId',
+            0x09: 'DstFldId',
+            0x0A: 'Response',
+            0x0B: 'Status',
+            0x0C: 'DstMsgId'
+        },
+        // Code Page 6: GetItemEstimate
+        {
+            0x05: 'GetItemEstimate',
+            0x06: 'Version',
+            0x07: 'Collections',
+            0x08: 'Collection',
+            0x09: 'Class',
+            0x0A: 'CollectionId',
+            0x0B: 'DateTime',
+            0x0C: 'Estimate',
+            0x0D: 'Response',
+            0x0E: 'Status'
+        },
+        // Code Page 7: FolderHierarchy
+        {
+            0x07: 'DisplayName',
+            0x08: 'ServerId',
+            0x09: 'ParentId',
+            0x0A: 'Type',
+            0x0C: 'Status',
+            0x0E: 'Changes',
+            0x0F: 'Add',
+            0x10: 'Delete',
+            0x11: 'Update',
+            0x12: 'SyncKey',
+            0x13: 'FolderCreate',
+            0x14: 'FolderDelete',
+            0x15: 'FolderUpdate',
+            0x16: 'FolderSync',
+            0x17: 'Count'
+        },
+        // Code Page 8: MeetingResponse
+        {
+            0x05: 'CalendarId',
+            0x06: 'CollectionId',
+            0x07: 'MeetingResponse',
+            0x08: 'RequestId',
+            0x09: 'Request',
+            0x0a: 'Result',
+            0x0b: 'Status',
+            0x0c: 'UserResponse',
+            0x0e: 'InstanceId'
+        },
+        // Code Page 9: Tasks
+        {
+            0x05: 'Body',
+            0x06: 'BodySize',
+            0x07: 'BodyTruncated',
+            0x08: 'Categories',
+            0x09: 'Category',
+            0x0A: 'Complete',
+            0x0B: 'DateCompleted',
+            0x0C: 'DueDate',
+            0x0D: 'UtcDueDate',
+            0x0E: 'Importance',
+            0x0F: 'Recurrence',
+            0x10: 'Type',
+            0x11: 'Start',
+            0x12: 'Until',
+            0x13: 'Occurrences',
+            0x14: 'Interval',
+            0x15: 'DayOfMonth',
+            0x16: 'DayOfWeek',
+            0x17: 'WeekOfMonth',
+            0x18: 'MonthOfYear',
+            0x19: 'Regenerate',
+            0x1A: 'DeadOccur',
+            0x1B: 'ReminderSet',
+            0x1C: 'ReminderTime',
+            0x1D: 'Sensitivity',
+            0x1E: 'StartDate',
+            0x1F: 'UtcStartDate',
+            0x20: 'Subject',
+            0x22: 'OrdinalDate',
+            0x23: 'SubOrdinalDate',
+            0x24: 'CalendarType',
+            0x25: 'IsLeapMonth',
+            0x26: 'FirstDayOfWeek'
+        },
+        // Code Page 10: ResolveRecipients
+        {
+            0x05: 'ResolveRecipients',
+            0x06: 'Response',
+            0x07: 'Status',
+            0x08: 'Type',
+            0x09: 'Recipient',
+            0x0a: 'DisplayName',
+            0x0b: 'EmailAddress',
+            0x0c: 'Certificates',
+            0x0d: 'Certificate',
+            0x0e: 'MiniCertificate',
+            0x0f: 'Options',
+            0x10: 'To',
+            0x11: 'CertificateRetrieval',
+            0x12: 'RecipientCount',
+            0x13: 'MaxCertificates',
+            0x14: 'MaxAmbiguousRecipients',
+            0x15: 'CertificateCount',
+            0x16: 'Availability',
+            0x17: 'StartTime',
+            0x18: 'EndTime',
+            0x19: 'MergedFreeBusy',
+            0x1a: 'Picture',
+            0x1b: 'MaxSize',
+            0x1c: 'Data',
+            0x1d: 'MaxPictures'
+        },
+        // Code Page 11: ValidateCert
+        {
+            0x05: 'ValidateCert',
+            0x06: 'Certificates',
+            0x07: 'Certificate',
+            0x08: 'CertificateChain',
+            0x09: 'CheckCRL',
+            0x0a: 'Status'
+        },
+        // Code Page 12: Contacts2
+        {
+            0x05: 'CustomerId',
+            0x06: 'GovernmentId',
+            0x07: 'IMAddress',
+            0x08: 'IMAddress2',
+            0x09: 'IMAddress3',
+            0x0a: 'ManagerName',
+            0x0b: 'CompanyMainPhone',
+            0x0c: 'AccountName',
+            0x0d: 'NickName',
+            0x0e: 'MMS'
+        },
+        // Code Page 13: Ping
+        {
+            0x05: 'Ping',
+            0x06: 'AutdState',
+            //(Not used)
+            0x07: 'Status',
+            0x08: 'HeartbeatInterval',
+            0x09: 'Folders',
+            0x0A: 'Folder',
+            0x0B: 'Id',
+            0x0C: 'Class',
+            0x0D: 'MaxFolders'
+        },
+        // Code Page 14: Provision
+        {
+            0x05: 'Provision',
+            0x06: 'Policies',
+            0x07: 'Policy',
+            0x08: 'PolicyType',
+            0x09: 'PolicyKey',
+            0x0A: 'Data',
+            0x0B: 'Status',
+            0x0C: 'RemoteWipe',
+            0x0D: 'EASProvisionDoc',
+            0x0E: 'DevicePasswordEnabled',
+            0x0F: 'AlphanumericDevicePasswordRequired',
+            0x10: 'DeviceEncryptionEnabled',
+            0x10: 'RequireStorageCardEncryption',
+            0x11: 'PasswordRecoveryEnabled',
+            0x13: 'AttachmentsEnabled',
+            0x14: 'MinDevicePasswordLength',
+            0x15: 'MaxInactivityTimeDeviceLock',
+            0x16: 'MaxDevicePasswordFailedAttempts',
+            0x17: 'MaxAttachmentSize',
+            0x18: 'AllowSimpleDevicePassword',
+            0x19: 'DevicePasswordExpiration',
+            0x1A: 'DevicePasswordHistory',
+            0x1B: 'AllowStorageCard',
+            0x1C: 'AllowCamera',
+            0x1D: 'RequireDeviceEncryption',
+            0x1E: 'AllowUnsignedApplications',
+            0x1F: 'AllowUnsignedInstallationPackages',
+            0x20: 'MinDevicePasswordComplexCharacters',
+            0x21: 'AllowWiFi',
+            0x22: 'AllowTextMessaging',
+            0x23: 'AllowPOPIMAPEmail',
+            0x24: 'AllowBluetooth',
+            0x25: 'AllowIrDA',
+            0x26: 'RequireManualSyncWhenRoaming',
+            0x27: 'AllowDesktopSync',
+            0x28: 'MaxCalendarAgeFilter',
+            0x29: 'AllowHTMLEmail',
+            0x2A: 'MaxEmailAgeFilter',
+            0x2B: 'MaxEmailBodyTruncationSize',
+            0x2C: 'MaxEmailHTMLBodyTruncationSize',
+            0x2D: 'RequireSignedSMIMEMessages',
+            0x2E: 'RequireEncryptedSMIMEMessages',
+            0x2F: 'RequireSignedSMIMEAlgorithm',
+            0x30: 'RequireEncryptionSMIMEAlgorithm',
+            0x31: 'AllowSMIMEEncryptionAlgorithmNegotiation',
+            0x32: 'AllowSMIMESoftCerts',
+            0x33: 'AllowBrowser',
+            0x34: 'AllowConsumerEmail',
+            0x35: 'AllowRemoteDesktop',
+            0x36: 'AllowInternetSharing',
+            0x37: 'UnapprovedInROMApplicationList',
+            0x38: 'ApplicationName',
+            0x39: 'ApprovedApplicationList',
+            0x3A: 'Hash'
+        },
+        // Code Page 15: Search
+        {
+            0x05: 'Search',
+            0x06: 'Stores',
+            0x07: 'Store',
+            0x08: 'Name',
+            0x09: 'Query',
+            0x0a: 'Options',
+            0x0b: 'Range',
+            0x0c: 'Status',
+            0x0d: 'Response',
+            0x0e: 'Result',
+            0x0f: 'Properties',
+            0x10: 'Total',
+            0x11: 'EqualTo',
+            0x12: 'Value',
+            0x13: 'And',
+            0x14: 'Or',
+            0x15: 'FreeText',
+            0x17: 'DeepTraversal',
+            0x18: 'LongId',
+            0x19: 'RebuildResults',
+            0x1a: 'LessThan',
+            0x1b: 'GreaterThan',
+            0x1c: 'Schema',
+            0x1d: 'Supported',
+            0x1e: 'UserName',
+            0x1f: 'Password',
+            0x20: 'ConversationId',
+            0x21: 'Picture',
+            0x22: 'MaxSize',
+            0x23: 'MaxPictures'
+        },
+        // Code Page 16: GAL
+        {
+            0x05: 'DisplayName',
+            0x06: 'Phone',
+            0x07: 'Office',
+            0x08: 'Title',
+            0x09: 'Company',
+            0x0a: 'Alias',
+            0x0b: 'FirstName',
+            0x0c: 'LastName',
+            0x0d: 'HomePhone',
+            0x0e: 'MobilePhone',
+            0x0f: 'EmailAddress',
+            0x10: 'Picture',
+            0x11: 'Status',
+            0x12: 'Data'
+        },
+        // Code Page 17: AirSyncBase
+        {
+            0x05: 'BodyPreference',
+            0x06: 'Type',
+            0x07: 'TruncationSize',
+            0x08: 'AllOrNone',
+            0x0A: 'Body',
+            0x0B: 'Data',
+            0x0C: 'EstimatedDataSize',
+            0x0D: 'Truncated',
+            0x0E: 'Attachments',
+            0x0F: 'Attachment',
+            0x10: 'DisplayName',
+            0x11: 'FileReference',
+            0x12: 'Method',
+            0x13: 'ContentId',
+            0x14: 'ContentLocation',
+            0x15: 'IsInline',
+            0x16: 'NativeBodyType',
+            0x17: 'ContentType',
+            0x18: 'Preview',
+            0x19: 'BodyPartPreference',
+            0x1A: 'BodyPart',
+            0x1B: 'Status'
+        },
+        // Code Page 18: Settings
+        {
+            0x05: 'Settings',
+            0x06: 'Status',
+            0x07: 'Get',
+            0x08: 'Set',
+            0x09: 'Oof',
+            0x0A: 'OofState',
+            0x0B: 'StartTime',
+            0x0C: 'EndTime',
+            0x0D: 'OofMessage',
+            0x0E: 'AppliesToInternal',
+            0x0F: 'AppliesToExternalKnown',
+            0x10: 'AppliesToExternalUnknown',
+            0x11: 'Enabled',
+            0x12: 'ReplyMessage',
+            0x13: 'BodyType',
+            0x14: 'DevicePassword',
+            0x15: 'Password',
+            0x16: 'DeviceInformation',
+            0x17: 'Model',
+            0x18: 'IMEI',
+            0x19: 'FriendlyName',
+            0x1A: 'OS',
+            0x1B: 'OSLanguage',
+            0x1C: 'PhoneNumber',
+            0x1D: 'UserInformation',
+            0x1E: 'EmailAddresses',
+            0x1F: 'SMTPAddress',
+            0x20: 'UserAgent',
+            0x21: 'EnableOutboundSMS',
+            0x22: 'MobileOperator',
+            0x23: 'PrimarySmtpAddress',
+            0x24: 'Accounts',
+            0x25: 'Account',
+            0x26: 'AccountId',
+            0x27: 'AccountName',
+            0x28: 'UserDisplayName',
+            0x29: 'SendDisabled',
+            0x2B: 'RightsManagementInformation'
+        },
+        // Code Page 19: DocumentLibrary
+        {
+            0x05: 'LinkId',
+            0x06: 'DisplayName',
+            0x07: 'IsFolder',
+            0x08: 'CreationDate',
+            0x09: 'LastModifiedDate',
+            0x0a: 'IsHidden',
+            0x0b: 'ContentLength',
+            0x0c: 'ContentType'
+        },
+        // Code Page 20: ItemOperations
+        {
+            0x05: 'ItemOperations',
+            0x06: 'Fetch',
+            0x07: 'Store',
+            0x08: 'Options',
+            0x09: 'Range',
+            0x0A: 'Total',
+            0x0B: 'Properties',
+            0x0C: 'Data',
+            0x0D: 'Status',
+            0x0E: 'Response',
+            0x0F: 'Version',
+            0x10: 'Schema',
+            0x11: 'Part',
+            0x12: 'EmptyFolderContents',
+            0x13: 'DeleteSubFolders',
+            0x14: 'UserName',
+            0x15: 'Password',
+            0x16: 'Move',
+            0x17: 'DstFldId',
+            0x18: 'ConversationId',
+            0x19: 'MoveAlways'
+        },
+        // Code Page 21: ComposeMail
+        {
+            0x05: 'SendMail',
+            0x06: 'SmartForward',
+            0x07: 'SmartReply',
+            0x08: 'SaveInSentItems',
+            0x09: 'ReplaceMime',
+            0x0b: 'Source',
+            0x0c: 'FolderId',
+            0x0d: 'ItemId',
+            0x0e: 'LongId',
+            0x0f: 'InstanceId',
+            0x10: 'Mime',
+            0x11: 'ClientId',
+            0x12: 'Status',
+            0x13: 'AccountId',
+            0x15: 'Forwardees',
+            0x16: 'Forwardee',
+            0x17: 'ForwardeeName',
+            0x18: 'ForwardeeEmail'
+        },
+        // Code Page 22: Email2
+        {
+            0x05: 'UmCallerID',
+            0x06: 'UmUserNotes',
+            0x07: 'UmAttDuration',
+            0x08: 'UmAttOrder',
+            0x09: 'ConversationId',
+            0x0a: 'ConversationIndex',
+            0x0b: 'LastVerbExecuted',
+            0x0c: 'LastVerbExecutionTime',
+            0x0d: 'ReceivedAsBcc',
+            0x0e: 'Sender',
+            0x0f: 'CalendarType',
+            0x10: 'IsLeapMonth',
+            0x11: 'AccountId',
+            0x12: 'FirstDayOfWeek',
+            0x13: 'MeetingMessageType',
+            0x15: 'IsDraft',
+            0x16: 'Bcc',
+            0x17: 'Send'
+        },
+        // Code Page 23: Notes
+        {
+            0x05: 'Subject',
+            0x06: 'MessageClass',
+            0x07: 'LastModifiedDate',
+            0x08: 'Categories',
+            0x09: 'Category'
+        },
+        // Code Page 24: RightsManagement
+        {
+            0x05: 'RightsManagementSupport',
+            0x06: 'RightsManagementTemplates',
+            0x07: 'RightsManagementTemplate',
+            0x08: 'RightsManagementLicense',
+            0x09: 'EditAllowed',
+            0x0a: 'ReplyAllowed',
+            0x0b: 'ReplyAllAllowed',
+            0x0c: 'ForwardAllowed',
+            0x0d: 'ModifyRecipientsAllowed',
+            0x0e: 'ExtractAllowed',
+            0x0f: 'PrintAllowed',
+            0x10: 'ExportAllowed',
+            0x11: 'ProgrammaticAccessAllowed',
+            0x12: 'Owner',
+            0x13: 'ContentExpiryDate',
+            0x14: 'TemplateID',
+            0x15: 'TemplateName',
+            0x16: 'TemplateDescription',
+            0x17: 'ContentOwner',
+            0x18: 'RemoveRightsManagementDistribution'
+        }
+    ],
+
+    namespaces: [
+        'AirSync',
+        'Contacts',
+        'Email',
+        'AirNotify',
+        'Calendar',
+        'Move',
+        'GetItemEstimate',
+        'FolderHierarchy',
+        'MeetingResponse',
+        'Tasks',
+        'ResolveRecipients',
+        'ValidateCert',
+        'Contacts2',
+        'Ping',
+        'Provision',
+        'Search',
+        'Gal',
+        'AirSyncBase',
+        'Settings',
+        'DocumentLibrary',
+        'ItemOperations',
+        'ComposeMail',
+        'Email2',
+        'Notes',
+        'RightsManagement'
+    ]
+
+};
+
+wbxmltools.buildCodepages2();
diff -Nru eas4tbsync-4.11/content/includes/xmltools.js eas4tbsync-4.17/content/includes/xmltools.js
--- eas4tbsync-4.11/content/includes/xmltools.js	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/includes/xmltools.js	2025-05-15 13:21:20.000000000 +0200
@@ -1,156 +1,166 @@
-/*
- * This file is part of EAS-4-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 xmltools = {
-
-    isString : function (obj) {
-        return (Object.prototype.toString.call(obj) === '[object String]');
-    },
-        
-    checkString : function(d, fallback = "") {
-        if (this.isString(d)) return d;
-        else return fallback;
-    },	    
-        
-    nodeAsArray : function (node) {
-        let a = [];
-        if (node) {
-            //return, if already an array
-            if (node instanceof Array) return node;
-
-            //else push node into an array
-            a.push(node);
-        }
-        return a;
-    },
-
-    hasWbxmlDataField: function(wbxmlData, path) {
-        if (wbxmlData) {		
-            let pathElements = path.split(".");
-            let data = wbxmlData;
-            for (let x = 0; x < pathElements.length; x++) {
-                if (data[pathElements[x]]) data = data[pathElements[x]];
-                else return false;
-            }
-            return true;
-        }
-        return false;
-    },
-
-    getWbxmlDataField: function(wbxmlData,path) {
-        if (wbxmlData) {		
-            let pathElements = path.split(".");
-            let data = wbxmlData;
-            let valid = true;
-            for (let x = 0; valid && x < pathElements.length; x++) {
-                if (data[pathElements[x]]) data = data[pathElements[x]];
-                else valid = false;
-            }
-            if (valid) return data;
-        }
-        return false
-    },
-
-    //print content of xml data object (if debug output enabled)
-    printXmlData : function (data, printApplicationData) {
-        if (TbSync.prefs.getIntPref("log.userdatalevel") > 1 || (TbSync.prefs.getIntPref("log.userdatalevel") == 1 && printApplicationData)) {
-            let dump = JSON.stringify(data);
-            TbSync.dump("Extracted XML data", "\n" + dump);
-        }
-    },
-
-    getDataFromXMLString: function (str) {
-        let data = null;
-        let xml = "";        
-        if (str == "") return data;
-        
-        let oParser = (Services.vc.compare(Services.appinfo.platformVersion, "61.*") >= 0) ? new DOMParser() : Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser);
-        try {
-            xml = 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
-            throw eas.sync.finish("error", "malformed-xml");
-        }
-
-        //check if xml is error document
-        if (xml.documentElement.nodeName == "parsererror") {
-            TbSync.dump("BAD XML", "The above XML and WBXML could not be parsed correctly, something is wrong.");
-            throw eas.sync.finish("error", "malformed-xml");
-        }
-
-        try {
-            data = this.getDataFromXML(xml);
-        } catch (e) {
-            throw eas.sync.finish("error", "mailformed-data");
-        }
-        
-        return data;
-    },
-    
-    //create data object from XML node
-    getDataFromXML : function (nodes) {
-        
-        /*
-         * The passed nodes value could be an entire 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.
-         */        
-        
-        // create the return object
-        let obj = {};
-        let nodeList = [];
-        let multiplicity = {};
-        
-        if (nodes.length === undefined) nodeList.push(nodes);
-        else nodeList = nodes;
-        
-        // nodelist contains all childs, if two childs have the same name, we cannot add the chils as an object, but as an array of objects
-        for (let node of nodeList) { 
-            if (node.nodeType == 1 || node.nodeType == 3) {
-                if (!multiplicity.hasOwnProperty(node.nodeName)) multiplicity[node.nodeName] = 0;
-                multiplicity[node.nodeName]++;
-                //if this nodeName has multiplicity > 1, prepare obj  (but only once)
-                if (multiplicity[node.nodeName]==2) obj[node.nodeName] = [];
-            }
-        }
-
-        // process nodes
-        for (let node of nodeList) { 
-            switch (node.nodeType) {
-                case 9: 
-                    //document node, dive directly and process all children
-                    if (node.hasChildNodes) obj = this.getDataFromXML(node.childNodes);
-                    break;
-                case 1: 
-                    //element node
-                    if (node.hasChildNodes) {
-                        //if this is an element with only one text child, do not dive, but get text childs value
-                        let o;
-                        if (node.childNodes.length == 1 && node.childNodes.item(0).nodeType==3) {
-                            //the passed xml is a save xml with all special chars in the user data encoded by encodeURIComponent
-                            o = decodeURIComponent(node.childNodes.item(0).nodeValue);
-                        } else {
-                            o = this.getDataFromXML(node.childNodes);
-                        }
-                        //check, if we can add the object directly, or if we have to push it into an array
-                        if (multiplicity[node.nodeName]>1) obj[node.nodeName].push(o)
-                        else obj[node.nodeName] = o; 
-                    }
-                    break;
-            }
-        }
-        return obj;
-    }
-    
-};
+/*
+ * This file is part of EAS-4-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 xmltools = {
+
+    isString: function (obj) {
+        return (Object.prototype.toString.call(obj) === '[object String]');
+    },
+
+    checkString: function (d, fallback = "") {
+        if (this.isString(d)) return d;
+        else return fallback;
+    },
+
+    nodeAsArray: function (node) {
+        let a = [];
+        if (node) {
+            //return, if already an array
+            if (node instanceof Array) return node;
+
+            //else push node into an array
+            a.push(node);
+        }
+        return a;
+    },
+
+    hasWbxmlDataField: function (wbxmlData, path) {
+        if (wbxmlData) {
+            let pathElements = path.split(".");
+            let data = wbxmlData;
+            for (let x = 0; x < pathElements.length; x++) {
+                if (data[pathElements[x]]) data = data[pathElements[x]];
+                else return false;
+            }
+            return true;
+        }
+        return false;
+    },
+
+    getWbxmlDataField: function (wbxmlData, path) {
+        if (wbxmlData) {
+            let pathElements = path.split(".");
+            let data = wbxmlData;
+            let valid = true;
+            for (let x = 0; valid && x < pathElements.length; x++) {
+                if (data[pathElements[x]]) data = data[pathElements[x]];
+                else valid = false;
+            }
+            if (valid) return data;
+        }
+        return false
+    },
+
+    //print content of xml data object (if debug output enabled)
+    printXmlData: function (data, printApplicationData) {
+        if (TbSync.prefs.getIntPref("log.userdatalevel") > 1 || (TbSync.prefs.getIntPref("log.userdatalevel") == 1 && printApplicationData)) {
+            let dump = JSON.stringify(data);
+            TbSync.dump("Extracted XML data", "\n" + dump);
+        }
+    },
+
+    getDataFromXMLString: function (str) {
+        let data = null;
+        let xml = "";
+        if (str == "") return data;
+
+        let oParser = (Services.vc.compare(Services.appinfo.platformVersion, "61.*") >= 0) ? new DOMParser() : Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser);
+        try {
+            xml = 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
+            throw eas.sync.finish("error", "malformed-xml");
+        }
+
+        //check if xml is error document
+        if (xml.documentElement.nodeName == "parsererror") {
+            TbSync.dump("BAD XML", "The above XML and WBXML could not be parsed correctly, something is wrong.");
+            throw eas.sync.finish("error", "malformed-xml");
+        }
+
+        try {
+            data = this.getDataFromXML(xml);
+        } catch (e) {
+            throw eas.sync.finish("error", "mailformed-data");
+        }
+
+        return data;
+    },
+
+    //create data object from XML node
+    getDataFromXML: function (nodes) {
+
+        /*
+         * The passed nodes value could be an entire 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.
+         */
+
+        // create the return object
+        let obj = {};
+        let nodeList = [];
+        let multiplicity = {};
+
+        if (nodes.length === undefined) nodeList.push(nodes);
+        else nodeList = nodes;
+
+        // nodelist contains all childs, if two childs have the same name, we cannot add the chils as an object, but as an array of objects
+        for (let node of nodeList) {
+            if (node.nodeType == 1 || node.nodeType == 3) {
+                if (!multiplicity.hasOwnProperty(node.nodeName)) multiplicity[node.nodeName] = 0;
+                multiplicity[node.nodeName]++;
+                //if this nodeName has multiplicity > 1, prepare obj  (but only once)
+                if (multiplicity[node.nodeName] == 2) obj[node.nodeName] = [];
+            }
+        }
+
+        // process nodes
+        for (let node of nodeList) {
+            switch (node.nodeType) {
+                case 9:
+                    //document node, dive directly and process all children
+                    if (node.hasChildNodes) obj = this.getDataFromXML(node.childNodes);
+                    break;
+                case 1:
+                    //element node
+                    if (node.hasChildNodes) {
+                        //if this is an element with only one text child, do not dive, but get text childs value
+                        let o;
+                        if (node.childNodes.length == 1 && node.childNodes.item(0).nodeType == 3) {
+                            //the passed xml is a save xml with all special chars in the user data encoded by encodeURIComponent
+                            o = decodeURIComponent(node.childNodes.item(0).nodeValue);
+                        } else {
+                            o = this.getDataFromXML(node.childNodes);
+                        }
+                        //check, if we can add the object directly, or if we have to push it into an array
+                        if (multiplicity[node.nodeName] > 1) obj[node.nodeName].push(o)
+                        else obj[node.nodeName] = o;
+                    }
+                    break;
+            }
+        }
+        return obj;
+    }
+
+};
diff -Nru eas4tbsync-4.11/content/locales.js eas4tbsync-4.17/content/locales.js
--- eas4tbsync-4.11/content/locales.js	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/locales.js	2025-05-15 13:21:20.000000000 +0200
@@ -1,3 +1,12 @@
-var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
-
-TbSync.localizeOnLoad(window, "eas");
+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, "eas");
diff -Nru eas4tbsync-4.11/content/manager/createAccount.js eas4tbsync-4.17/content/manager/createAccount.js
--- eas4tbsync-4.11/content/manager/createAccount.js	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/manager/createAccount.js	2025-05-15 13:21:20.000000000 +0200
@@ -1,254 +1,263 @@
-/*
- * This file is part of EAS-4-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");
-
-const eas = TbSync.providers.eas;
-
-var tbSyncEasNewAccount = {
-
-    startTime: 0,
-    maxTimeout: 30,
-    validating: false,
-
-    onClose: function () {
-        //disallow closing of wizard while validating
-        return !this.validating;
-    },
-
-    onCancel: function (event) {
-        //disallow closing of wizard while validating
-        if (this.validating) {
-            event.preventDefault();
-        }
-    },
-
-    onLoad: function () {
-        this.providerData = new TbSync.ProviderData("eas");
-
-        this.elementName = document.getElementById('tbsync.newaccount.name');
-        this.elementUser = document.getElementById('tbsync.newaccount.user');
-        this.elementUrl = document.getElementById('tbsync.newaccount.url');
-        this.elementPass = document.getElementById('tbsync.newaccount.password');
-        this.elementServertype = document.getElementById('tbsync.newaccount.servertype');
-        
-        document.getElementById("tbsync.newaccount.wizard").getButton("back").hidden = true;
-        this.onUserDropdown();
-
-        document.getElementById("tbsync.error").hidden = true;
-        document.getElementById("tbsync.spinner").hidden = true;
-
-        document.addEventListener("wizardfinish", tbSyncEasNewAccount.onFinish.bind(this));
-        document.addEventListener("wizardcancel", tbSyncEasNewAccount.onCancel.bind(this));
-        // bug https://bugzilla.mozilla.org/show_bug.cgi?id=1618252
-        document.getElementById('tbsync.newaccount.wizard')._adjustWizardHeader();        
-    },
-
-    onUnload: function () {
-    },
-
-    onUserTextInput: function () {
-        document.getElementById("tbsync.error").hidden = true;
-        switch (this.elementServertype.value) {
-            case "select":            
-                document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = true;
-                break;
-
-            case "auto":            
-                document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = (this.elementName.value.trim() == "" || this.elementUser.value == "" || this.elementPass.value == "");
-                break;
-            
-            case "office365":            
-                document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = (this.elementName.value.trim() == "" || this.elementUser.value == "");
-                break;
-
-            case "custom":
-            default:
-                document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = (this.elementName.value.trim() == "" || this.elementUser.value == "" || this.elementPass.value == "" ||  this.elementUrl.value.trim() == "");
-                break;
-        }
-    },
-
-    onUserDropdown: function () {
-        if (this.elementServertype) {
-            switch (this.elementServertype.value) {
-                case "select":            
-                    document.getElementById('tbsync.newaccount.user.box').hidden = true;
-                    document.getElementById('tbsync.newaccount.url.box').hidden = true;
-                    document.getElementById('tbsync.newaccount.password.box').hidden = true;
-                    document.getElementById("tbsync.newaccount.wizard").getButton("finish").label = TbSync.getString("newaccount.add_custom","eas");
-                    break;
-
-                case "auto":            
-                    document.getElementById('tbsync.newaccount.user.box').hidden = false;
-                    document.getElementById('tbsync.newaccount.url.box').hidden = true;
-                    document.getElementById('tbsync.newaccount.password.box').hidden = false;
-                    document.getElementById("tbsync.newaccount.wizard").getButton("finish").label = TbSync.getString("newaccount.add_auto","eas");
-                    break;
-                
-                case "office365":            
-                    document.getElementById('tbsync.newaccount.user.box').hidden = false;
-                    document.getElementById('tbsync.newaccount.url.box').hidden = true;
-                    document.getElementById('tbsync.newaccount.password.box').hidden = true;
-                    document.getElementById("tbsync.newaccount.wizard").getButton("finish").label = TbSync.getString("newaccount.add_custom","eas");
-                    break;
-
-                case "custom":
-                default:
-                    document.getElementById('tbsync.newaccount.user.box').hidden = false;
-                    document.getElementById('tbsync.newaccount.url.box').hidden = false;
-                    document.getElementById('tbsync.newaccount.password.box').hidden = false;
-                    document.getElementById("tbsync.newaccount.wizard").getButton("finish").label = TbSync.getString("newaccount.add_custom","eas");
-                    break;
-            }
-            this.onUserTextInput();
-            //document.getElementById("tbsync.newaccount.name").focus();
-        }
-    },
-
-    onFinish: function (event) {
-        if (document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled == false) {
-            //initiate validation of server connection
-            this.validate();
-        }
-        event.preventDefault();
-    },
-
-    validate: async function () {
-        let user = this.elementUser.value;
-        let servertype = this.elementServertype.value;
-        let accountname = this.elementName.value.trim();
-
-        let url = (servertype == "custom") ?this.elementUrl.value.trim() : "";
-        let password = (servertype == "auto" || servertype == "custom") ? this.elementPass.value : "";
-
-        if ((servertype == "auto" || servertype == "office365") && user.split("@").length != 2) {
-            alert(TbSync.getString("autodiscover.NeedEmail","eas"))
-            return;
-        }
-        
-        this.validating = true;
-        let error = "";
-        
-        //document.getElementById("tbsync.newaccount.wizard").canRewind = false;        
-        document.getElementById("tbsync.error").hidden = true;
-        document.getElementById("tbsync.newaccount.wizard").getButton("cancel").disabled = true;
-        document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = true;
-        document.getElementById("tbsync.newaccount.name").disabled = true;
-        document.getElementById("tbsync.newaccount.user").disabled = true;
-        document.getElementById("tbsync.newaccount.password").disabled = true;
-        document.getElementById("tbsync.newaccount.servertype").disabled = true;
-
-        tbSyncEasNewAccount.startTime = Date.now();
-        tbSyncEasNewAccount.updateAutodiscoverStatus();
-        document.getElementById("tbsync.spinner").hidden = false;
-        
-        //do autodiscover
-        if (servertype == "office365" || servertype == "auto") {
-            let updateTimer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
-            updateTimer.initWithCallback({notify : function () {tbSyncEasNewAccount.updateAutodiscoverStatus()}}, 1000, 3);
-
-            if (servertype == "office365") {
-                let v2 = await eas.network.getServerConnectionViaAutodiscoverV2JsonRequest(
-                    accountname,
-                    user,
-                    "https://autodiscover-s.outlook.com/autodiscover/autodiscover.json?Email="+encodeURIComponent(user)+"&Protocol=ActiveSync",
-                );
-                let oauthData = eas.network.getOAuthObj({ host: v2.server, user, accountname, servertype });
-                if (oauthData) {
-                    // ask for token
-                    document.getElementById("tbsync.spinner").hidden = true;
-                    let _rv = {};
-                    if (await oauthData.asyncConnect(_rv)) {
-                        password = _rv.tokens;
-                    } else {
-                        error = TbSync.getString("status." + _rv.error, "eas");
-                    }
-                    document.getElementById("tbsync.spinner").hidden = false;                
-                    url=v2.server;
-                } else {
-                    error = TbSync.getString("status.404", "eas");
-                }
-            } else {
-                let result = await eas.network.getServerConnectionViaAutodiscover(
-                    accountname,
-                    user,
-                    password,
-                    tbSyncEasNewAccount.maxTimeout*1000
-                );
-                if (result.server) {
-                    user = result.user;
-                    url = result.server;
-                } else {                    
-                    error = result.error; // is a localized string
-                }
-            }
-
-            updateTimer.cancel();
-        }
-
-        //now validate the information
-        if (!error) {
-            if (!password) error = TbSync.getString("status.401", "eas");
-        }
-
-        //add if valid
-        if (!error) {
-            await tbSyncEasNewAccount.addAccount(user, password, servertype, accountname, url);
-        }
-        
-        //end validation
-        document.getElementById("tbsync.newaccount.name").disabled = false;
-        document.getElementById("tbsync.newaccount.user").disabled = false;
-        document.getElementById("tbsync.newaccount.password").disabled = false;
-        document.getElementById("tbsync.newaccount.servertype").disabled = false;
-        document.getElementById("tbsync.newaccount.wizard").getButton("cancel").disabled = false;
-        document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = false;
-        document.getElementById("tbsync.spinner").hidden = true;
-        //document.getElementById("tbsync.newaccount.wizard").canRewind = true;
-        
-        this.validating = false;
-        
-        //close wizard, if done
-        if (!error) {
-            document.getElementById("tbsync.newaccount.wizard").cancel();        
-        } else {
-            document.getElementById("tbsync.error.message").textContent = error;
-            document.getElementById("tbsync.error").hidden = false;
-        }            
-        window.sizeToContent();
-    },
-
-    updateAutodiscoverStatus: function () {
-        let offset = Math.round(((Date.now() - tbSyncEasNewAccount.startTime)/1000));
-        let timeout = (offset>2) ? " (" + (tbSyncEasNewAccount.maxTimeout - offset) + ")" : "";
-
-        document.getElementById('tbsync.newaccount.autodiscoverstatus').value  = TbSync.getString("autodiscover.Querying","eas") + timeout;
-    },
-
-    async addAccount (user, password, servertype, accountname, url) {
-        let newAccountEntry = this.providerData.getDefaultAccountEntries();
-        newAccountEntry.user = user;
-        newAccountEntry.servertype = servertype;
-
-        if (url) {
-            //if no protocoll is given, prepend "https://"
-            if (url.substring(0,4) != "http" || url.indexOf("://") == -1) url = "https://" + url.split("://").join("/");
-            newAccountEntry.host = eas.network.stripAutodiscoverUrl(url);
-            newAccountEntry.https = (url.substring(0,5) == "https");
-        }
-
-        // Add the new account.
-        let newAccountData = this.providerData.addAccount(accountname, newAccountEntry);
-        await eas.network.getAuthData(newAccountData).updateLoginData(user, password);
-
-        window.close();
-    }
-};
+/*
+ * This file is part of EAS-4-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}`
+);
+
+const eas = TbSync.providers.eas;
+
+var tbSyncEasNewAccount = {
+
+    startTime: 0,
+    maxTimeout: 30,
+    validating: false,
+
+    onClose: function () {
+        //disallow closing of wizard while validating
+        return !this.validating;
+    },
+
+    onCancel: function (event) {
+        //disallow closing of wizard while validating
+        if (this.validating) {
+            event.preventDefault();
+        }
+    },
+
+    onLoad: function () {
+        this.providerData = new TbSync.ProviderData("eas");
+
+        this.elementName = document.getElementById('tbsync.newaccount.name');
+        this.elementUser = document.getElementById('tbsync.newaccount.user');
+        this.elementUrl = document.getElementById('tbsync.newaccount.url');
+        this.elementPass = document.getElementById('tbsync.newaccount.password');
+        this.elementServertype = document.getElementById('tbsync.newaccount.servertype');
+
+        document.getElementById("tbsync.newaccount.wizard").getButton("back").hidden = true;
+        this.onUserDropdown();
+
+        document.getElementById("tbsync.error").hidden = true;
+        document.getElementById("tbsync.spinner").hidden = true;
+
+        document.addEventListener("wizardfinish", tbSyncEasNewAccount.onFinish.bind(this));
+        document.addEventListener("wizardcancel", tbSyncEasNewAccount.onCancel.bind(this));
+        // bug https://bugzilla.mozilla.org/show_bug.cgi?id=1618252
+        document.getElementById('tbsync.newaccount.wizard')._adjustWizardHeader();
+    },
+
+    onUnload: function () {
+    },
+
+    onUserTextInput: function () {
+        document.getElementById("tbsync.error").hidden = true;
+        switch (this.elementServertype.value) {
+            case "select":
+                document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = true;
+                break;
+
+            case "auto":
+                document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = (this.elementName.value.trim() == "" || this.elementUser.value == "" || this.elementPass.value == "");
+                break;
+
+            case "office365":
+                document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = (this.elementName.value.trim() == "" || this.elementUser.value == "");
+                break;
+
+            case "custom":
+            default:
+                document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = (this.elementName.value.trim() == "" || this.elementUser.value == "" || this.elementPass.value == "" || this.elementUrl.value.trim() == "");
+                break;
+        }
+    },
+
+    onUserDropdown: function () {
+        if (this.elementServertype) {
+            switch (this.elementServertype.value) {
+                case "select":
+                    document.getElementById('tbsync.newaccount.user.box').hidden = true;
+                    document.getElementById('tbsync.newaccount.url.box').hidden = true;
+                    document.getElementById('tbsync.newaccount.password.box').hidden = true;
+                    document.getElementById("tbsync.newaccount.wizard").getButton("finish").label = TbSync.getString("newaccount.add_custom", "eas");
+                    break;
+
+                case "auto":
+                    document.getElementById('tbsync.newaccount.user.box').hidden = false;
+                    document.getElementById('tbsync.newaccount.url.box').hidden = true;
+                    document.getElementById('tbsync.newaccount.password.box').hidden = false;
+                    document.getElementById("tbsync.newaccount.wizard").getButton("finish").label = TbSync.getString("newaccount.add_auto", "eas");
+                    break;
+
+                case "office365":
+                    document.getElementById('tbsync.newaccount.user.box').hidden = false;
+                    document.getElementById('tbsync.newaccount.url.box').hidden = true;
+                    document.getElementById('tbsync.newaccount.password.box').hidden = true;
+                    document.getElementById("tbsync.newaccount.wizard").getButton("finish").label = TbSync.getString("newaccount.add_custom", "eas");
+                    break;
+
+                case "custom":
+                default:
+                    document.getElementById('tbsync.newaccount.user.box').hidden = false;
+                    document.getElementById('tbsync.newaccount.url.box').hidden = false;
+                    document.getElementById('tbsync.newaccount.password.box').hidden = false;
+                    document.getElementById("tbsync.newaccount.wizard").getButton("finish").label = TbSync.getString("newaccount.add_custom", "eas");
+                    break;
+            }
+            this.onUserTextInput();
+            //document.getElementById("tbsync.newaccount.name").focus();
+        }
+    },
+
+    onFinish: function (event) {
+        if (document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled == false) {
+            //initiate validation of server connection
+            this.validate();
+        }
+        event.preventDefault();
+    },
+
+    validate: async function () {
+        let user = this.elementUser.value;
+        let servertype = this.elementServertype.value;
+        let accountname = this.elementName.value.trim();
+
+        let url = (servertype == "custom") ? this.elementUrl.value.trim() : "";
+        let password = (servertype == "auto" || servertype == "custom") ? this.elementPass.value : "";
+
+        if ((servertype == "auto" || servertype == "office365") && user.split("@").length != 2) {
+            alert(TbSync.getString("autodiscover.NeedEmail", "eas"))
+            return;
+        }
+
+        this.validating = true;
+        let error = "";
+
+        //document.getElementById("tbsync.newaccount.wizard").canRewind = false;        
+        document.getElementById("tbsync.error").hidden = true;
+        document.getElementById("tbsync.newaccount.wizard").getButton("cancel").disabled = true;
+        document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = true;
+        document.getElementById("tbsync.newaccount.name").disabled = true;
+        document.getElementById("tbsync.newaccount.user").disabled = true;
+        document.getElementById("tbsync.newaccount.password").disabled = true;
+        document.getElementById("tbsync.newaccount.servertype").disabled = true;
+
+        tbSyncEasNewAccount.startTime = Date.now();
+        tbSyncEasNewAccount.updateAutodiscoverStatus();
+        document.getElementById("tbsync.spinner").hidden = false;
+
+        //do autodiscover
+        if (servertype == "office365" || servertype == "auto") {
+            let updateTimer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
+            updateTimer.initWithCallback({ notify: function () { tbSyncEasNewAccount.updateAutodiscoverStatus() } }, 1000, 3);
+
+            if (servertype == "office365") {
+                let v2 = await eas.network.getServerConnectionViaAutodiscoverV2JsonRequest(
+                    accountname,
+                    user,
+                    "https://autodiscover-s.outlook.com/autodiscover/autodiscover.json?Email=" + encodeURIComponent(user) + "&Protocol=ActiveSync",
+                );
+                let oauthData = eas.network.getOAuthObj({ host: v2.server, user, accountname, servertype });
+                if (oauthData) {
+                    // ask for token
+                    document.getElementById("tbsync.spinner").hidden = true;
+                    let _rv = {};
+                    if (await oauthData.asyncConnect(_rv)) {
+                        password = _rv.tokens;
+                    } else {
+                        error = TbSync.getString("status." + _rv.error, "eas");
+                    }
+                    document.getElementById("tbsync.spinner").hidden = false;
+                    url = v2.server;
+                } else {
+                    error = TbSync.getString("status.404", "eas");
+                }
+            } else {
+                let result = await eas.network.getServerConnectionViaAutodiscover(
+                    accountname,
+                    user,
+                    password,
+                    tbSyncEasNewAccount.maxTimeout * 1000
+                );
+                if (result.server) {
+                    user = result.user;
+                    url = result.server;
+                } else {
+                    error = result.error; // is a localized string
+                }
+            }
+
+            updateTimer.cancel();
+        }
+
+        //now validate the information
+        if (!error) {
+            if (!password) error = TbSync.getString("status.401", "eas");
+        }
+
+        //add if valid
+        if (!error) {
+            await tbSyncEasNewAccount.addAccount(user, password, servertype, accountname, url);
+        }
+
+        //end validation
+        document.getElementById("tbsync.newaccount.name").disabled = false;
+        document.getElementById("tbsync.newaccount.user").disabled = false;
+        document.getElementById("tbsync.newaccount.password").disabled = false;
+        document.getElementById("tbsync.newaccount.servertype").disabled = false;
+        document.getElementById("tbsync.newaccount.wizard").getButton("cancel").disabled = false;
+        document.getElementById("tbsync.newaccount.wizard").getButton("finish").disabled = false;
+        document.getElementById("tbsync.spinner").hidden = true;
+        //document.getElementById("tbsync.newaccount.wizard").canRewind = true;
+
+        this.validating = false;
+
+        //close wizard, if done
+        if (!error) {
+            document.getElementById("tbsync.newaccount.wizard").cancel();
+        } else {
+            document.getElementById("tbsync.error.message").textContent = error;
+            document.getElementById("tbsync.error").hidden = false;
+        }
+        window.sizeToContent();
+    },
+
+    updateAutodiscoverStatus: function () {
+        let offset = Math.round(((Date.now() - tbSyncEasNewAccount.startTime) / 1000));
+        let timeout = (offset > 2) ? " (" + (tbSyncEasNewAccount.maxTimeout - offset) + ")" : "";
+
+        document.getElementById('tbsync.newaccount.autodiscoverstatus').value = TbSync.getString("autodiscover.Querying", "eas") + timeout;
+    },
+
+    async addAccount(user, password, servertype, accountname, url) {
+        let newAccountEntry = this.providerData.getDefaultAccountEntries();
+        newAccountEntry.user = user;
+        newAccountEntry.servertype = servertype;
+
+        if (url) {
+            //if no protocoll is given, prepend "https://"
+            if (url.substring(0, 4) != "http" || url.indexOf("://") == -1) url = "https://" + url.split("://").join("/");
+            newAccountEntry.host = eas.network.stripAutodiscoverUrl(url);
+            newAccountEntry.https = (url.substring(0, 5) == "https");
+        }
+
+        // Add the new account.
+        let newAccountData = this.providerData.addAccount(accountname, newAccountEntry);
+        await eas.network.getAuthData(newAccountData).updateLoginData(user, password);
+
+        window.close();
+    }
+};
diff -Nru eas4tbsync-4.11/content/manager/createAccount.xhtml eas4tbsync-4.17/content/manager/createAccount.xhtml
--- eas4tbsync-4.11/content/manager/createAccount.xhtml	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/manager/createAccount.xhtml	2025-05-15 13:21:20.000000000 +0200
@@ -1,97 +1,97 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
-
-<window
-    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-    xmlns:html="http://www.w3.org/1999/xhtml"
-    onload="tbSyncEasNewAccount.onLoad();"
-    onunload="tbSyncEasNewAccount.onUnload();"
-    onclose="return tbSyncEasNewAccount.onClose()" >
-
-    <linkset>
-        <html:link rel="localization" href="toolkit/global/wizard.ftl"/>
-    </linkset>
-
-    <script type="application/javascript" src="chrome://eas4tbsync/content/manager/createAccount.js"/>
-    <script type="application/javascript" src="chrome://eas4tbsync/content/locales.js"/>
-    
-    <wizard
-        title="__EAS4TBSYNCMSG_add.title__"
-        id="tbsync.newaccount.wizard">
-
-        <wizardpage onFirstPage="true" label="__EAS4TBSYNCMSG_add.shortdescription__">
-            <description style="width: 350px">__EAS4TBSYNCMSG_add.description__</description>
-
-            <richlistbox height="250"  id="tbsync.newaccount.servertype" seltype="single" style="margin-top:1ex" onselect="tbSyncEasNewAccount.onUserDropdown();">
-                <richlistitem value="auto" style="padding: 4px">
-                    <vbox><image src="chrome://eas4tbsync/content/skin/eas32.png" style="margin:1ex" /></vbox>
-                    <vbox flex="1">
-                        <label class="header" value="__EAS4TBSYNCMSG_servertype.auto__" />
-                        <description>__EAS4TBSYNCMSG_servertype.description.auto__</description>
-                    </vbox>
-                </richlistitem>
-                
-                <richlistitem value="custom" style="padding: 4px">
-                    <vbox><image src="chrome://eas4tbsync/content/skin/eas32.png" style="margin:1ex" /></vbox>
-                    <vbox flex="1">
-                        <label class="header" value="__EAS4TBSYNCMSG_servertype.custom__" />
-                        <description>__EAS4TBSYNCMSG_servertype.description.custom__</description>
-                    </vbox>
-                </richlistitem>
-
-                <richlistitem value="office365" style="padding: 4px">
-                    <vbox><image src="chrome://eas4tbsync/content/skin/365_32.png" style="margin:1ex" /></vbox>
-                    <vbox flex="1">
-                        <label class="header" value="__EAS4TBSYNCMSG_servertype.office365__" />
-                        <description>__EAS4TBSYNCMSG_servertype.description.office365__</description>
-                    </vbox>
-                </richlistitem>        
-            </richlistbox>
-
-            <html:table style="margin-top:1em">
-                <html:tr>
-                    <html:td width="33%"><vbox pack="center"><label value="__EAS4TBSYNCMSG_add.name__" /></vbox></html:td>
-                    <html:td width="67%"><html:input id="tbsync.newaccount.name" oninput="tbSyncEasNewAccount.onUserTextInput();"/></html:td>
-                </html:tr>
-                <html:tr id="tbsync.newaccount.user.box">
-                    <html:td><vbox pack="center"><label value="__EAS4TBSYNCMSG_add.user__" /></vbox></html:td>
-                    <html:td><html:input id="tbsync.newaccount.user" oninput="tbSyncEasNewAccount.onUserTextInput();"/></html:td>
-                </html:tr>
-                <html:tr id="tbsync.newaccount.password.box">
-                    <html:td><vbox pack="center"><label value="__EAS4TBSYNCMSG_add.password__" /></vbox></html:td>
-                    <html:td><html:input id="tbsync.newaccount.password" type="password" oninput="tbSyncEasNewAccount.onUserTextInput();"/></html:td>
-                </html:tr>
-                <html:tr id="tbsync.newaccount.url.box">
-                    <html:td><vbox pack="center"><label value="__EAS4TBSYNCMSG_add.url__" /></vbox></html:td>
-                    <html:td><html:input id="tbsync.newaccount.url" oninput="tbSyncEasNewAccount.onUserTextInput();" tooltiptext="__EAS4TBSYNCMSG_add.urldescription__"/></html:td>
-                </html:tr>
-
-                <!--html:tr style="height:40px; margin-top:1ex;margin-bottom:1ex;">
-                    <html:td><vbox pack="center"></vbox></html:td>
-                    <html:td><vbox pack="center"></vbox></html:td>
-                </html:tr-->
-            </html:table>
-
-            <vbox flex="1">
-            </vbox>
-            <hbox id="tbsync.spinner">
-                <image src="chrome://tbsync/content/skin/spinner.gif" style="margin-left:1em" width="16" height="16"/>
-                <label id='tbsync.newaccount.autodiscoverstatus' value="" />
-            </hbox>
-           
-            <vbox id="tbsync.error">
-                <description id="tbsync.error.message" flex="1" style="font-weight: bold;"></description>
-                <vbox>
-                  <button 
-                  id="tbsync.error.link" 
-                  label="__EAS4TBSYNCMSG_manager.ShowEventLog__"
-                  oncommand="TbSync.eventlog.open();"/>
-                </vbox>
-            </vbox>    
-
-
-      </wizardpage>
-        
-    </wizard>
-
-</window>
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+
+<window
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    xmlns:html="http://www.w3.org/1999/xhtml"
+    onload="tbSyncEasNewAccount.onLoad();"
+    onunload="tbSyncEasNewAccount.onUnload();"
+    onclose="return tbSyncEasNewAccount.onClose()" >
+
+    <linkset>
+        <html:link rel="localization" href="toolkit/global/wizard.ftl"/>
+    </linkset>
+
+    <script type="application/javascript" src="chrome://eas4tbsync/content/manager/createAccount.js"/>
+    <script type="application/javascript" src="chrome://eas4tbsync/content/locales.js"/>
+    
+    <wizard
+        title="__EAS4TBSYNCMSG_add.title__"
+        id="tbsync.newaccount.wizard">
+
+        <wizardpage onFirstPage="true" label="__EAS4TBSYNCMSG_add.shortdescription__">
+            <description style="width: 350px">__EAS4TBSYNCMSG_add.description__</description>
+
+            <richlistbox height="250"  id="tbsync.newaccount.servertype" seltype="single" style="margin-top:1ex" onselect="tbSyncEasNewAccount.onUserDropdown();">
+                <richlistitem value="auto" style="padding: 4px">
+                    <vbox><image src="chrome://eas4tbsync/content/skin/eas32.png" style="margin:1ex" /></vbox>
+                    <vbox flex="1">
+                        <label class="header" value="__EAS4TBSYNCMSG_servertype.auto__" />
+                        <description>__EAS4TBSYNCMSG_servertype.description.auto__</description>
+                    </vbox>
+                </richlistitem>
+                
+                <richlistitem value="custom" style="padding: 4px">
+                    <vbox><image src="chrome://eas4tbsync/content/skin/eas32.png" style="margin:1ex" /></vbox>
+                    <vbox flex="1">
+                        <label class="header" value="__EAS4TBSYNCMSG_servertype.custom__" />
+                        <description>__EAS4TBSYNCMSG_servertype.description.custom__</description>
+                    </vbox>
+                </richlistitem>
+
+                <richlistitem value="office365" style="padding: 4px">
+                    <vbox><image src="chrome://eas4tbsync/content/skin/365_32.png" style="margin:1ex" /></vbox>
+                    <vbox flex="1">
+                        <label class="header" value="__EAS4TBSYNCMSG_servertype.office365__" />
+                        <description>__EAS4TBSYNCMSG_servertype.description.office365__</description>
+                    </vbox>
+                </richlistitem>        
+            </richlistbox>
+
+            <html:table style="margin-top:1em">
+                <html:tr>
+                    <html:td width="33%"><vbox pack="center"><label value="__EAS4TBSYNCMSG_add.name__" /></vbox></html:td>
+                    <html:td width="67%"><html:input id="tbsync.newaccount.name" oninput="tbSyncEasNewAccount.onUserTextInput();"/></html:td>
+                </html:tr>
+                <html:tr id="tbsync.newaccount.user.box">
+                    <html:td><vbox pack="center"><label value="__EAS4TBSYNCMSG_add.user__" /></vbox></html:td>
+                    <html:td><html:input id="tbsync.newaccount.user" oninput="tbSyncEasNewAccount.onUserTextInput();"/></html:td>
+                </html:tr>
+                <html:tr id="tbsync.newaccount.password.box">
+                    <html:td><vbox pack="center"><label value="__EAS4TBSYNCMSG_add.password__" /></vbox></html:td>
+                    <html:td><html:input id="tbsync.newaccount.password" type="password" oninput="tbSyncEasNewAccount.onUserTextInput();"/></html:td>
+                </html:tr>
+                <html:tr id="tbsync.newaccount.url.box">
+                    <html:td><vbox pack="center"><label value="__EAS4TBSYNCMSG_add.url__" /></vbox></html:td>
+                    <html:td><html:input id="tbsync.newaccount.url" oninput="tbSyncEasNewAccount.onUserTextInput();" tooltiptext="__EAS4TBSYNCMSG_add.urldescription__"/></html:td>
+                </html:tr>
+
+                <!--html:tr style="height:40px; margin-top:1ex;margin-bottom:1ex;">
+                    <html:td><vbox pack="center"></vbox></html:td>
+                    <html:td><vbox pack="center"></vbox></html:td>
+                </html:tr-->
+            </html:table>
+
+            <vbox flex="1">
+            </vbox>
+            <hbox id="tbsync.spinner">
+                <image src="chrome://tbsync/content/skin/spinner.gif" style="margin-left:1em" width="16" height="16"/>
+                <label id='tbsync.newaccount.autodiscoverstatus' value="" />
+            </hbox>
+           
+            <vbox id="tbsync.error">
+                <description id="tbsync.error.message" flex="1" style="font-weight: bold;"></description>
+                <vbox>
+                  <button 
+                  id="tbsync.error.link" 
+                  label="__EAS4TBSYNCMSG_manager.ShowEventLog__"
+                  oncommand="TbSync.eventlog.open();"/>
+                </vbox>
+            </vbox>    
+
+
+      </wizardpage>
+        
+    </wizard>
+
+</window>
diff -Nru eas4tbsync-4.11/content/manager/editAccountOverlay.js eas4tbsync-4.17/content/manager/editAccountOverlay.js
--- eas4tbsync-4.11/content/manager/editAccountOverlay.js	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/manager/editAccountOverlay.js	2019-08-26 17:50:48.000000000 +0200
@@ -1,56 +1,56 @@
-/*
- * This file is part of EAS-4-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";
-
-const eas = TbSync.providers.eas;
-
-var tbSyncEditAccountOverlay = {
-
-    onload: function (window, accountData) {
-        this.accountData = accountData;
-        
-        // special treatment for configuration label, which is a permanent setting and will not change by switching modes
-        let configlabel = window.document.getElementById("tbsync.accountsettings.label.config");
-        if (configlabel) {
-            configlabel.setAttribute("value", TbSync.getString("config.custom", "eas"));
-        }
-    },
-
-    stripHost: function (document) {
-        let host = document.getElementById('tbsync.AccountPropertys.pref.host').value;
-        if (host.indexOf("https://") == 0) {
-            host = host.replace("https://","");
-            document.getElementById('tbsync.AccountPropertys.pref.https').checked = true;
-            this.accountData.setAccountProperty("https", true);
-        } else if (host.indexOf("http://") == 0) {
-            host = host.replace("http://","");
-            document.getElementById('tbsync.AccountPropertys.pref.https').checked = false;
-           this.accountData.setAccountProperty("https", false);
-        }
-        
-        while (host.endsWith("/")) { host = host.slice(0,-1); }        
-        document.getElementById('tbsync.AccountPropertys.pref.host').value = host
-       this.accountData.setAccountProperty("host", host);
-    },
-    
-    deleteFolder: function() {
-        let folderList = document.getElementById("tbsync.accountsettings.folderlist");
-        if (folderList.selectedItem !== null && !folderList.disabled) {
-            let folderData = folderList.selectedItem.folderData;
-
-            //only trashed folders can be purged (for example O365 does not show deleted folders but also does not allow to purge them)
-            if (!eas.tools.parentIsTrash(folderData)) return;
-            
-            if (folderData.getFolderProperty("selected")) window.alert(TbSync.getString("deletefolder.notallowed::" + folderData.getFolderProperty("foldername"), "eas"));
-            else if (window.confirm(TbSync.getString("deletefolder.confirm::" + folderData.getFolderProperty("foldername"), "eas"))) {
-                folderData.sync({syncList: false, syncJob: "deletefolder"});
-            } 
-        }            
-    }    
-};
+/*
+ * This file is part of EAS-4-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";
+
+const eas = TbSync.providers.eas;
+
+var tbSyncEditAccountOverlay = {
+
+    onload: function (window, accountData) {
+        this.accountData = accountData;
+        
+        // special treatment for configuration label, which is a permanent setting and will not change by switching modes
+        let configlabel = window.document.getElementById("tbsync.accountsettings.label.config");
+        if (configlabel) {
+            configlabel.setAttribute("value", TbSync.getString("config.custom", "eas"));
+        }
+    },
+
+    stripHost: function (document) {
+        let host = document.getElementById('tbsync.AccountPropertys.pref.host').value;
+        if (host.indexOf("https://") == 0) {
+            host = host.replace("https://","");
+            document.getElementById('tbsync.AccountPropertys.pref.https').checked = true;
+            this.accountData.setAccountProperty("https", true);
+        } else if (host.indexOf("http://") == 0) {
+            host = host.replace("http://","");
+            document.getElementById('tbsync.AccountPropertys.pref.https').checked = false;
+           this.accountData.setAccountProperty("https", false);
+        }
+        
+        while (host.endsWith("/")) { host = host.slice(0,-1); }        
+        document.getElementById('tbsync.AccountPropertys.pref.host').value = host
+       this.accountData.setAccountProperty("host", host);
+    },
+    
+    deleteFolder: function() {
+        let folderList = document.getElementById("tbsync.accountsettings.folderlist");
+        if (folderList.selectedItem !== null && !folderList.disabled) {
+            let folderData = folderList.selectedItem.folderData;
+
+            //only trashed folders can be purged (for example O365 does not show deleted folders but also does not allow to purge them)
+            if (!eas.tools.parentIsTrash(folderData)) return;
+            
+            if (folderData.getFolderProperty("selected")) window.alert(TbSync.getString("deletefolder.notallowed::" + folderData.getFolderProperty("foldername"), "eas"));
+            else if (window.confirm(TbSync.getString("deletefolder.confirm::" + folderData.getFolderProperty("foldername"), "eas"))) {
+                folderData.sync({syncList: false, syncJob: "deletefolder"});
+            } 
+        }            
+    }    
+};
diff -Nru eas4tbsync-4.11/content/manager/editAccountOverlay.xhtml eas4tbsync-4.17/content/manager/editAccountOverlay.xhtml
--- eas4tbsync-4.11/content/manager/editAccountOverlay.xhtml	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/manager/editAccountOverlay.xhtml	2025-05-15 13:21:20.000000000 +0200
@@ -1,154 +1,154 @@
-<?xml version="1.0"?>
-<?xml-stylesheet href="chrome://tbsync/content/skin/fix_dropdown_1534697.css" type="text/css"?>
-
-<overlay 
-    id="tbSyncAccountConfig" 
-    xmlns:html="http://www.w3.org/1999/xhtml">
-
-    <script type="application/javascript" src="chrome://eas4tbsync/content/manager/editAccountOverlay.js"/>
-    <script type="application/javascript" src="chrome://eas4tbsync/content/locales.js"/>
-
-    <menuitem 
-        id="TbSync.eas.FolderListContextMenuDelete" 
-        label="__EAS4TBSYNCMSG_pref.ShowTrashedFolders__" 
-        class="menuitem-iconic"
-        image="chrome://tbsync/content/skin/trash16.png"
-        appendto="tbsync.accountsettings.FolderListContextMenu"
-        oncommand="tbSyncEditAccountOverlay.deleteFolder();"/>
-    
-    <tab id="manager.tabs.accountsettings" label="__EAS4TBSYNCMSG_manager.tabs.accountsettings__" appendto="manager.tabs" />
-    <tab id="manager.tabs.syncsettings" label="__EAS4TBSYNCMSG_manager.tabs.syncsettings__" appendto="manager.tabs" />
-
-    <tabpanel id="manager.tabpanels.accountsettings" appendto="manager.tabpanels" flex="1" orient="vertical"><!-- ACCOUNT SETTINGS -->
-          <vbox flex="1">
-                <label class="header lockIfConnected" style="margin-left:0; margin-bottom:1ex;" value="" id="tbsync.accountsettings.label.config" />                
-                <html:table flex="1">
-                    <html:tr>
-                        <html:td style="margin-right:1ex;">
-                            <vbox pack="center">
-                                <label style="text-align:left" control="tbsync.accountsettings.pref.accountname" value="__EAS4TBSYNCMSG_pref.AccountName__" />
-                            </vbox>
-                        </html:td>
-                        <html:td width="100%">
-                            <html:input id="tbsync.accountsettings.pref.accountname" />
-                        </html:td>
-                    </html:tr>
-                    
-                    <html:tr>
-                        <html:td style="margin-right:1ex;" >
-                            <vbox pack="center">
-                                <label class="lockIfConnected" style="text-align:left" control="tbsync.accountsettings.pref.user" value="__EAS4TBSYNCMSG_pref.UserName__" />
-                            </vbox>
-                        </html:td>
-                        <html:td>
-                            <html:input class="lockIfConnected" tooltiptext="__EAS4TBSYNCMSG_pref.UserNameDescription__" id="tbsync.accountsettings.pref.user" />
-                        </html:td>
-                    </html:tr>
-                    
-                    <html:tr>
-                        <html:td style="margin-right:1ex;" >
-                            <vbox pack="center">
-                                <label class="lockIfConnected" style="text-align:left" control="tbsync.accountsettings.pref.host" value="__EAS4TBSYNCMSG_pref.ServerName__" />
-                            </vbox>
-                        </html:td>
-                        <html:td>
-                            <html:input class="lockIfConnected"  tooltiptext="__EAS4TBSYNCMSG_pref.ServerNameDescription__" id="tbsync.accountsettings.pref.host" onblur="tbSyncEditAccountOverlay.stripHost(document);" />
-                        </html:td>
-                    </html:tr>
-
-                    <html:tr>
-                        <html:td style="margin-right:1ex;" >
-                            <hbox/>
-                        </html:td>
-                        <html:td>
-                            <checkbox class="lockIfConnected" style="margin-bottom:1ex" id="tbsync.accountsettings.pref.https" label="__EAS4TBSYNCMSG_pref.usehttps__"  />
-                        </html:td>
-                    </html:tr>
-                    
-                    <html:tr>
-                        <html:td style="margin-right:1ex;" >
-                            <vbox id="asversion.hook" pack="center">
-                                <label class="lockIfConnected"  style="text-align:left" control="tbsync.accountsettings.pref.asversionselected" value="__EAS4TBSYNCMSG_pref.ActiveSyncVersion__" />
-                            </vbox>
-                        </html:td>
-                        <html:td>
-                            <menulist flex="0" id="tbsync.accountsettings.pref.asversionselected" class="lockIfConnected">
-                                <menupopup id="asversion.popup">
-                                    <menuitem label="__EAS4TBSYNCMSG_pref.autodetect__" value="auto" />
-                                    <menuitem label="v2.5" value="2.5" />
-                                    <menuitem label="v14.0" value="14.0" />
-                                </menupopup>
-                            </menulist>
-                        </html:td>
-                    </html:tr>
-
-                    <html:tr>
-                        <html:td style="margin-right:1ex;" >
-                            <label class="lockIfConnected" style="text-align:left" value="__EAS4TBSYNCMSG_pref.DeviceId__" />
-                        </html:td>
-                        <html:td>
-                            <label value="" disabled="true" id="tbsync.accountsettings.pref.deviceId" />
-                        </html:td>
-                    </html:tr>
-                </html:table>
-
-                <vbox flex="1" />
-                <vbox class="showIfConnected">
-                    <hbox>
-                        <vbox pack="center"><image src="chrome://tbsync/content/skin/info16.png" /></vbox>
-                        <description flex="1">__EAS4TBSYNCMSG_manager.lockedsettings.description__</description>
-                    </hbox>
-                </vbox>
-
-        </vbox>
-    </tabpanel>
-
-    <tabpanel id="manager.tabpanels.syncsettings" appendto="manager.tabpanels" flex="1" orient="vertical"><!-- SYNC SETTINGS -->
-          <vbox flex="1">
-                <label style="margin-left:0; margin-bottom: 1ex;" class="header lockIfConnected" value="__EAS4TBSYNCMSG_pref.generaloptions__"/>
-                <vbox>                            
-                    <checkbox class="lockIfConnected" id="tbsync.accountsettings.pref.provision" label="__EAS4TBSYNCMSG_pref.provision__"  />
-                </vbox>                            
-
-                <label style="margin-left:0; margin-bottom: 1ex; margin-top: 3ex" class="header lockIfConnected" value="__EAS4TBSYNCMSG_pref.contactoptions__"/>
-                <vbox>                            
-                    <checkbox class="lockIfConnected" id="tbsync.accountsettings.pref.displayoverride" label="__EAS4TBSYNCMSG_pref.displayoverride__" />
-                    <hbox align="center">
-                        <description id="separator.hook" class="lockIfConnected" flex="0">__EAS4TBSYNCMSG_pref.seperator.description__</description>
-                        <menulist id="tbsync.accountsettings.pref.seperator" class="lockIfConnected">
-                            <menupopup id="separator.popup">
-                                <menuitem label="__EAS4TBSYNCMSG_pref.seperator.linebreak__" value="10" />
-                                <menuitem label="__EAS4TBSYNCMSG_pref.seperator.comma__" value="44" />
-                            </menupopup>
-                        </menulist>                            
-                    </hbox>
-                </vbox>                            
-
-                <label style="margin-left:0; margin-bottom: 1ex; margin-top: 3ex" class="header lockIfConnected" value="__EAS4TBSYNCMSG_pref.calendaroptions__"/>
-                <vbox>                            
-                    <hbox align="center">
-                        <description id="synclimit.hook" class="lockIfConnected" flex="0">__EAS4TBSYNCMSG_pref.synclimit.description__</description>
-                        <menulist id="tbsync.accountsettings.pref.synclimit" class="lockIfConnected">
-                            <menupopup id="synclimit.popup">
-                                <menuitem label="__EAS4TBSYNCMSG_pref.synclimit.all__" value="0" />
-                                <menuitem label="__EAS4TBSYNCMSG_pref.synclimit.2weeks__" value="4" />
-                                <menuitem label="__EAS4TBSYNCMSG_pref.synclimit.1month__" value="5" />
-                                <menuitem label="__EAS4TBSYNCMSG_pref.synclimit.3month__" value="6" />
-                                <menuitem label="__EAS4TBSYNCMSG_pref.synclimit.6month__" value="7" />
-                            </menupopup>
-                        </menulist>                            
-                    </hbox>
-                </vbox>                            
-
-
-                <vbox flex="1" />
-                <vbox class="showIfConnected">
-                    <hbox>
-                        <vbox pack="center"><image src="chrome://tbsync/content/skin/info16.png" /></vbox>
-                        <description flex="1">__EAS4TBSYNCMSG_manager.lockedsettings.description__</description>
-                    </hbox>
-                </vbox>
-            </vbox>
-    </tabpanel>
-
-</overlay>
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://tbsync/content/skin/fix_dropdown_1534697.css" type="text/css"?>
+
+<overlay 
+    id="tbSyncAccountConfig" 
+    xmlns:html="http://www.w3.org/1999/xhtml">
+
+    <script type="application/javascript" src="chrome://eas4tbsync/content/manager/editAccountOverlay.js"/>
+    <script type="application/javascript" src="chrome://eas4tbsync/content/locales.js"/>
+
+    <menuitem 
+        id="TbSync.eas.FolderListContextMenuDelete" 
+        label="__EAS4TBSYNCMSG_pref.ShowTrashedFolders__" 
+        class="menuitem-iconic"
+        image="chrome://tbsync/content/skin/trash16.png"
+        appendto="tbsync.accountsettings.FolderListContextMenu"
+        oncommand="tbSyncEditAccountOverlay.deleteFolder();"/>
+    
+    <tab id="manager.tabs.accountsettings" label="__EAS4TBSYNCMSG_manager.tabs.accountsettings__" appendto="manager.tabs" />
+    <tab id="manager.tabs.syncsettings" label="__EAS4TBSYNCMSG_manager.tabs.syncsettings__" appendto="manager.tabs" />
+
+    <tabpanel id="manager.tabpanels.accountsettings" appendto="manager.tabpanels" flex="1" orient="vertical"><!-- ACCOUNT SETTINGS -->
+          <vbox flex="1">
+                <label class="header lockIfConnected" style="margin-left:0; margin-bottom:1ex;" value="" id="tbsync.accountsettings.label.config" />                
+                <html:table flex="1">
+                    <html:tr>
+                        <html:td style="margin-right:1ex;">
+                            <vbox pack="center">
+                                <label style="text-align:left" control="tbsync.accountsettings.pref.accountname" value="__EAS4TBSYNCMSG_pref.AccountName__" />
+                            </vbox>
+                        </html:td>
+                        <html:td width="100%">
+                            <html:input id="tbsync.accountsettings.pref.accountname" />
+                        </html:td>
+                    </html:tr>
+                    
+                    <html:tr>
+                        <html:td style="margin-right:1ex;" >
+                            <vbox pack="center">
+                                <label class="lockIfConnected" style="text-align:left" control="tbsync.accountsettings.pref.user" value="__EAS4TBSYNCMSG_pref.UserName__" />
+                            </vbox>
+                        </html:td>
+                        <html:td>
+                            <html:input class="lockIfConnected" tooltiptext="__EAS4TBSYNCMSG_pref.UserNameDescription__" id="tbsync.accountsettings.pref.user" />
+                        </html:td>
+                    </html:tr>
+                    
+                    <html:tr>
+                        <html:td style="margin-right:1ex;" >
+                            <vbox pack="center">
+                                <label class="lockIfConnected" style="text-align:left" control="tbsync.accountsettings.pref.host" value="__EAS4TBSYNCMSG_pref.ServerName__" />
+                            </vbox>
+                        </html:td>
+                        <html:td>
+                            <html:input class="lockIfConnected"  tooltiptext="__EAS4TBSYNCMSG_pref.ServerNameDescription__" id="tbsync.accountsettings.pref.host" onblur="tbSyncEditAccountOverlay.stripHost(document);" />
+                        </html:td>
+                    </html:tr>
+
+                    <html:tr>
+                        <html:td style="margin-right:1ex;" >
+                            <hbox/>
+                        </html:td>
+                        <html:td>
+                            <checkbox class="lockIfConnected" style="margin-bottom:1ex" id="tbsync.accountsettings.pref.https" label="__EAS4TBSYNCMSG_pref.usehttps__"  />
+                        </html:td>
+                    </html:tr>
+                    
+                    <html:tr>
+                        <html:td style="margin-right:1ex;" >
+                            <vbox id="asversion.hook" pack="center">
+                                <label class="lockIfConnected"  style="text-align:left" control="tbsync.accountsettings.pref.asversionselected" value="__EAS4TBSYNCMSG_pref.ActiveSyncVersion__" />
+                            </vbox>
+                        </html:td>
+                        <html:td>
+                            <menulist flex="0" id="tbsync.accountsettings.pref.asversionselected" class="lockIfConnected">
+                                <menupopup id="asversion.popup">
+                                    <menuitem label="__EAS4TBSYNCMSG_pref.autodetect__" value="auto" />
+                                    <menuitem label="v2.5" value="2.5" />
+                                    <menuitem label="v14.0" value="14.0" />
+                                </menupopup>
+                            </menulist>
+                        </html:td>
+                    </html:tr>
+
+                    <html:tr>
+                        <html:td style="margin-right:1ex;" >
+                            <label class="lockIfConnected" style="text-align:left" value="__EAS4TBSYNCMSG_pref.DeviceId__" />
+                        </html:td>
+                        <html:td>
+                            <label value="" disabled="true" id="tbsync.accountsettings.pref.deviceId" />
+                        </html:td>
+                    </html:tr>
+                </html:table>
+
+                <vbox flex="1" />
+                <vbox class="showIfConnected">
+                    <hbox>
+                        <vbox pack="center"><image src="chrome://tbsync/content/skin/info16.png" /></vbox>
+                        <description flex="1">__EAS4TBSYNCMSG_manager.lockedsettings.description__</description>
+                    </hbox>
+                </vbox>
+
+        </vbox>
+    </tabpanel>
+
+    <tabpanel id="manager.tabpanels.syncsettings" appendto="manager.tabpanels" flex="1" orient="vertical"><!-- SYNC SETTINGS -->
+          <vbox flex="1">
+                <label style="margin-left:0; margin-bottom: 1ex;" class="header lockIfConnected" value="__EAS4TBSYNCMSG_pref.generaloptions__"/>
+                <vbox>                            
+                    <checkbox class="lockIfConnected" id="tbsync.accountsettings.pref.provision" label="__EAS4TBSYNCMSG_pref.provision__"  />
+                </vbox>                            
+
+                <label style="margin-left:0; margin-bottom: 1ex; margin-top: 3ex" class="header lockIfConnected" value="__EAS4TBSYNCMSG_pref.contactoptions__"/>
+                <vbox>                            
+                    <checkbox class="lockIfConnected" id="tbsync.accountsettings.pref.displayoverride" label="__EAS4TBSYNCMSG_pref.displayoverride__" />
+                    <hbox align="center">
+                        <description id="separator.hook" class="lockIfConnected" flex="0">__EAS4TBSYNCMSG_pref.seperator.description__</description>
+                        <menulist id="tbsync.accountsettings.pref.seperator" class="lockIfConnected">
+                            <menupopup id="separator.popup">
+                                <menuitem label="__EAS4TBSYNCMSG_pref.seperator.linebreak__" value="10" />
+                                <menuitem label="__EAS4TBSYNCMSG_pref.seperator.comma__" value="44" />
+                            </menupopup>
+                        </menulist>                            
+                    </hbox>
+                </vbox>                            
+
+                <label style="margin-left:0; margin-bottom: 1ex; margin-top: 3ex" class="header lockIfConnected" value="__EAS4TBSYNCMSG_pref.calendaroptions__"/>
+                <vbox>                            
+                    <hbox align="center">
+                        <description id="synclimit.hook" class="lockIfConnected" flex="0">__EAS4TBSYNCMSG_pref.synclimit.description__</description>
+                        <menulist id="tbsync.accountsettings.pref.synclimit" class="lockIfConnected">
+                            <menupopup id="synclimit.popup">
+                                <menuitem label="__EAS4TBSYNCMSG_pref.synclimit.all__" value="0" />
+                                <menuitem label="__EAS4TBSYNCMSG_pref.synclimit.2weeks__" value="4" />
+                                <menuitem label="__EAS4TBSYNCMSG_pref.synclimit.1month__" value="5" />
+                                <menuitem label="__EAS4TBSYNCMSG_pref.synclimit.3month__" value="6" />
+                                <menuitem label="__EAS4TBSYNCMSG_pref.synclimit.6month__" value="7" />
+                            </menupopup>
+                        </menulist>                            
+                    </hbox>
+                </vbox>                            
+
+
+                <vbox flex="1" />
+                <vbox class="showIfConnected">
+                    <hbox>
+                        <vbox pack="center"><image src="chrome://tbsync/content/skin/info16.png" /></vbox>
+                        <description flex="1">__EAS4TBSYNCMSG_manager.lockedsettings.description__</description>
+                    </hbox>
+                </vbox>
+            </vbox>
+    </tabpanel>
+
+</overlay>
diff -Nru eas4tbsync-4.11/content/provider.js eas4tbsync-4.17/content/provider.js
--- eas4tbsync-4.11/content/provider.js	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/provider.js	2025-05-15 13:21:20.000000000 +0200
@@ -1,733 +1,744 @@
-/*
- * This file is part of EAS-4-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 { MailServices } = ChromeUtils.import("resource:///modules/MailServices.jsm");
-
-// Every object in here will be loaded into TbSync.providers.<providername>.
-const eas = TbSync.providers.eas;
-
-eas.prefs = Services.prefs.getBranch("extensions.eas4tbsync.");
-
-//use flags instead of strings to avoid errors due to spelling errors
-eas.flags = Object.freeze({
-    allowEmptyResponse: true, 
-});
-
-eas.windowsToIanaTimezoneMap = {};
-eas.ianaToWindowsTimezoneMap = {};
-eas.cachedTimezoneData = null;
-eas.defaultTimezoneInfo = null;
-eas.defaultTimezone = null;
-eas.utcTimezone = null;
-
-
-/**
- * Implementing the TbSync interface for external provider extensions.
- */
-var Base = class {
-    /**
-     * Called during load of external provider extension to init provider.
-     */
-    static async load() {
-        // Set default prefs
-        let branch = Services.prefs.getDefaultBranch("extensions.eas4tbsync.");
-        branch.setIntPref("timeout", 90000);
-        branch.setIntPref("maxitems", 50);
-        branch.setBoolPref("msTodoCompat", false);
-        branch.setCharPref("clientID.type", "TbSync");
-        branch.setCharPref("clientID.useragent", "Thunderbird ActiveSync");    
-        branch.setCharPref("oauth.clientID", "");
-
-        eas.defaultTimezone = null;
-        eas.utcTimezone = null;
-        eas.defaultTimezoneInfo = null;
-        eas.windowsToIanaTimezoneMap = {};
-        eas.openWindows = {};
-
-        try {
-            // Create a basic error info (no accountname or foldername, just the provider)
-            let eventLogInfo = new TbSync.EventLogInfo("eas");
-                            
-            //get timezone info of default timezone (old cal. without dtz are depricated)
-            eas.defaultTimezone = (TbSync.lightning.cal.dtz && TbSync.lightning.cal.dtz.defaultTimezone) ? TbSync.lightning.cal.dtz.defaultTimezone : TbSync.lightning.cal.calendarDefaultTimezone();
-            eas.utcTimezone = (TbSync.lightning.cal.dtz && TbSync.lightning.cal.dtz.UTC) ? TbSync.lightning.cal.dtz.UTC : TbSync.lightning.cal.UTC();
-            if (eas.defaultTimezone && eas.defaultTimezone.icalComponent) {
-                TbSync.eventlog.add("info", eventLogInfo, "Default timezone has been found.");                    
-            } else {
-                TbSync.eventlog.add("info", eventLogInfo, "Default timezone is not defined, using UTC!");
-                eas.defaultTimezone = eas.utcTimezone;
-            }
-
-            eas.defaultTimezoneInfo = eas.tools.getTimezoneInfo(eas.defaultTimezone);
-            if (!eas.defaultTimezoneInfo) {
-                TbSync.eventlog.add("info", eventLogInfo, "Could not create defaultTimezoneInfo");
-            }
-            
-            //get windows timezone data from CSV
-            let aliasData = await eas.tools.fetchFile("chrome://eas4tbsync/content/timezonedata/Aliases.csv");
-            let aliasNames = {};
-            for (let i = 0; i<aliasData.length; i++) {
-                let lData = aliasData[i].split(",");
-                if (lData.length<2) continue;
-                aliasNames[lData[0].toString().trim()] = lData[1].toString().trim().split(" ");
-            }
-
-            let csvData = await eas.tools.fetchFile("chrome://eas4tbsync/content/timezonedata/WindowsTimezone.csv");
-            for (let i = 0; i<csvData.length; i++) {
-                let lData = csvData[i].split(",");
-                if (lData.length<3) continue;
-                
-                let windowsZoneName = lData[0].toString().trim();
-                let zoneType = lData[1].toString().trim();
-                let ianaZoneName = lData[2].toString().trim();
-                
-                if (zoneType == "001") eas.windowsToIanaTimezoneMap[windowsZoneName] = ianaZoneName;
-                if (ianaZoneName == eas.defaultTimezoneInfo.std.id) eas.defaultTimezoneInfo.std.windowsZoneName = windowsZoneName;
-                                    
-                // build the revers map as well, which is many-to-one, grap iana aliases from the csvData and from the aliasData
-                // 1. multiple iana zones map to the same windows zone
-                let ianaZones = ianaZoneName.split(" "); 
-                for (let ianaZone of ianaZones) {
-                    eas.ianaToWindowsTimezoneMap[ianaZone] = windowsZoneName;
-                    if (aliasNames.hasOwnProperty(ianaZone)) {
-                        for (let aliasName of aliasNames[ianaZone]) {
-                            // 2. multiple iana zonescan be an alias to a main iana zone
-                            eas.ianaToWindowsTimezoneMap[aliasName] = windowsZoneName;
-                        }
-                    }
-                }
-            }
-
-            let tzService = TbSync.lightning.cal.timezoneService;
-            for (let timezoneId of tzService.timezoneIds) {
-                if (!eas.ianaToWindowsTimezoneMap[timezoneId]) {
-                    TbSync.eventlog.add("info", eventLogInfo, "The IANA timezone <"+timezoneId+"> cannot be mapped to any Exchange timezone.");
-                }
-            }
-            
-            //If an EAS calendar is currently NOT associated with an email identity, try to associate, 
-            //but do not change any explicitly set association
-            // - A) find email identity and associate (which sets organizer to that user identity)
-            // - B) overwrite default organizer with current best guess
-            //TODO: Do this after email accounts changed, not only on restart? 
-            let providerData = new TbSync.ProviderData("eas");
-            let folders = providerData.getFolders({"selected": true, "type": ["8","13"]});
-            for (let folder of folders) {
-                let manager = TbSync.lightning.cal.manager;
-                let calendar = manager.getCalendarById(folder.getFolderProperty("target"));
-                if (calendar && calendar.getProperty("imip.identity.key") == "") {
-                    //is there an email identity for this eas account?
-                    let authData = eas.network.getAuthData(folder.accountData);
-
-                    let key = eas.tools.getIdentityKey(authData.user);
-                    if (key === "") { //TODO: Do this even after manually switching to NONE, not only on restart?
-                        //set transient calendar organizer settings based on current best guess and 
-                        calendar.setProperty("organizerId", TbSync.lightning.cal.email.prependMailTo(authData.user));
-                        calendar.setProperty("organizerCN",  calendar.getProperty("fallbackOrganizerName"));
-                    } else {
-                        //force switch to found identity
-                        calendar.setProperty("imip.identity.key", key);
-                    }
-                }
-            }
-        } catch(e) {
-            Components.utils.reportError(e);
-        }
-    }
-
-
-    /**
-     * Called during unload of external provider extension to unload provider.
-     */
-    static async unload() {
-        // Close all open windows of this provider.
-        for (let id in eas.openWindows) {
-          if (eas.openWindows.hasOwnProperty(id)) {
-            try {
-                eas.openWindows[id].close();
-            } catch(e) {
-                //NOOP
-            }
-          }
-        }
-    }
-
-
-    /**
-     * Returns string for the name of provider for the add account menu.
-     */
-    static getProviderName() {
-        return "Exchange ActiveSync";
-    }
-
-
-    /**
-     * Returns version of the TbSync API this provider is using
-     */
-    static getApiVersion() { return "2.5"; }
-
-
-    /**
-     * Returns location of a provider icon.
-     */
-    static getProviderIcon(size, accountData = null) {
-        let base = (accountData && accountData.getAccountProperty("servertype") == "office365") ? "365_" : "eas";
-        
-        switch (size) {
-            case 16:
-                return "chrome://eas4tbsync/content/skin/" + base + "16.png";
-            case 32:
-                return "chrome://eas4tbsync/content/skin/" + base + "32.png";
-            default :
-                return "chrome://eas4tbsync/content/skin/" + base + "64.png";
-        }
-    }
-
-
-    /**
-     * Returns a list of sponsors, they will be sorted by the index
-     */
-    static getSponsors() {
-        return {
-            "Schiessl, Michael 1" : {name: "Michael Schiessl", description: "Tine 2.0", icon: "", link: "" },
-            "Schiessl, Michael 2" : {name: "Michael Schiessl", description: " Exchange 2007", icon: "", link: "" },
-            "netcup GmbH" : {name: "netcup GmbH", description : "SOGo", icon: "chrome://eas4tbsync/content/skin/sponsors/netcup.png", link: "http://www.netcup.de/" },
-            "nethinks GmbH" : {name: "nethinks GmbH", description : "Zarafa", icon: "chrome://eas4tbsync/content/skin/sponsors/nethinks.png", link: "http://www.nethinks.com/" },
-            "Jau, Stephan" : {name: "Stephan Jau", description: "Horde", icon: "", link: "" },
-            "Zavar " : {name: "Zavar", description: "Zoho", icon: "", link: "" },
-        };
-    }
-
-
-    /**
-     * Returns the url of a page with details about contributors (used in the manager UI)
-     */
-    static getContributorsUrl() {
-        return "https://github.com/jobisoft/EAS-4-TbSync/blob/master/CONTRIBUTORS.md";
-    }
-
-
-    /**
-     * Returns the email address of the maintainer (used for bug reports).
-     */
-    static getMaintainerEmail() {
-        return "john.bieling at gmx.de";
-    }
-
-
-    /**
-     * Returns URL of the new account window.
-     *
-     * The URL will be opened via openDialog(), when the user wants to create a
-     * new account of this provider.
-     */
-    static getCreateAccountWindowUrl() {
-        return "chrome://eas4tbsync/content/manager/createAccount.xhtml";
-    }
-
-
-    /**
-     * Returns overlay XUL URL of the edit account dialog
-     * (chrome://tbsync/content/manager/editAccount.xhtml)
-     */
-    static getEditAccountOverlayUrl() {
-        return "chrome://eas4tbsync/content/manager/editAccountOverlay.xhtml";
-    }
-
-
-    /**
-     * Return object which contains all possible fields of a row in the
-     * accounts database with the default value if not yet stored in the 
-     * database.
-     */
-    static getDefaultAccountEntries() {
-        let row = {
-            "policykey" : "0", 
-            "foldersynckey" : "0",
-            "deviceId" : eas.tools.getNewDeviceId(),
-            "asversionselected" : "auto",
-            "asversion" : "",
-            "host" : "",
-            "user" : "",
-            "servertype" : "",
-            "seperator" : "10",
-            "https" : true,
-            "provision" : false,
-            "displayoverride" : false, 
-            "lastEasOptionsUpdate":"0",
-            "allowedEasVersions": "",
-            "allowedEasCommands": "",
-            "useragent": eas.prefs.getCharPref("clientID.useragent"),
-            "devicetype": eas.prefs.getCharPref("clientID.type"),
-            "synclimit" : "7",
-            }; 
-        return row;
-    }
-
-
-    /**
-     * Return object which contains all possible fields of a row in the folder 
-     * database with the default value if not yet stored in the database.
-     */
-    static getDefaultFolderEntries() {
-        let folder = {
-            "type" : "",
-            "synckey" : "",
-            "target" : "",
-            "targetColor" : "",
-            "targetName" : "",
-            "parentID" : "0",
-            "serverID" : "",
-            };
-        return folder;
-    }
-
-
-    /**
-     * Is called everytime an account of this provider is enabled in the
-     * manager UI.
-     */
-    static onEnableAccount(accountData) {
-        accountData.resetAccountProperty("policykey");
-        accountData.resetAccountProperty("foldersynckey");
-        accountData.resetAccountProperty("lastEasOptionsUpdate");
-        accountData.resetAccountProperty("lastsynctime");
-    }
-
-
-    /**
-     * Is called everytime an account of this provider is disabled in the
-     * manager UI.
-     *
-     * @param accountData  [in] AccountData
-     */
-    static onDisableAccount(accountData) {
-    }
-
-
-    /**
-     * Is called everytime an account of this provider is deleted in the
-     * manager UI.
-     */
-    static onDeleteAccount(accountData) {
-        eas.network.getAuthData(accountData).removeLoginData();
-    }
-
-
-    /**
-     * Returns all folders of the account, sorted in the desired order.
-     * The most simple implementation is to return accountData.getAllFolders();
-     */
-    static getSortedFolders(accountData) {
-        let allowedTypesOrder = ["9","14","8","13","7","15"];
-        
-        function getIdChain (aServerID) {
-            let serverID = aServerID;
-            let chain = [];
-            let folder;
-            let rootType = "";
-            
-            // create sort string so that child folders are directly below their parent folders
-            do { 
-                folder = accountData.getFolder("serverID", serverID);
-                if (folder) {
-                    chain.unshift(folder.getFolderProperty("foldername"));
-                    serverID = folder.getFolderProperty("parentID");
-                    rootType = folder.getFolderProperty("type");
-                }
-            } while (folder && serverID != "0")
-            
-            // different folder types are grouped and trashed folders at the end
-            let pos = allowedTypesOrder.indexOf(rootType);
-            chain.unshift(pos == -1 ? "ZZZ" : pos.toString().padStart(3,"0"));
-                        
-            return chain.join(".");
-        };
-        
-        let toBeSorted = [];
-        let folders = accountData.getAllFolders();
-        for (let f of folders) {
-            if (!allowedTypesOrder.includes(f.getFolderProperty("type"))) {
-                continue;
-            }
-            toBeSorted.push({"key": getIdChain(f.getFolderProperty("serverID")), "folder": f});
-        }
-        
-        //sort
-        toBeSorted.sort(function(a,b) {
-            return  a.key > b.key;
-        });
-
-        let sortedFolders = [];
-        for (let sortObj of toBeSorted) {
-            sortedFolders.push(sortObj.folder);
-        }
-        return sortedFolders;        
-    }
-
-
-    /**
-     * Return the connection timeout for an active sync, so TbSync can append
-     * a countdown to the connection timeout, while waiting for an answer from
-     * the server. Only syncstates which start with "send." will trigger this.
-     */
-    static getConnectionTimeout(accountData) {
-        return eas.prefs.getIntPref("timeout");
-    }
-    
-
-    /**
-     * Is called if TbSync needs to synchronize the folder list.
-     */
-    static async syncFolderList(syncData, syncJob, syncRunNr) {
-        // Recommendation: Put the actual function call inside a try catch, to
-        // ensure returning a proper StatusData object, regardless of what
-        // happens inside that function. You may also throw custom errors
-        // in that function, which have the StatusData obj attached, which
-        // should be returned.
-        
-        try {
-            await eas.sync.folderList(syncData);
-        } catch (e) {
-            if (e.name == "eas4tbsync") {
-                return e.statusData;
-            } else {
-                Components.utils.reportError(e);
-                // re-throw any other error and let TbSync handle it
-                throw (e);
-            }
-        }
-
-        // Fall through, if there was no error.
-        return new TbSync.StatusData();        
-    }
-
-
-    /**
-     * Is called if TbSync needs to synchronize a folder.
-     */
-    static async syncFolder(syncData, syncJob, syncRunNr) {
-        // Recommendation: Put the actual function call inside a try catch, to
-        // ensure returning a proper StatusData object, regardless of what
-        // happens inside that function. You may also throw custom errors
-        // in that function, which have the StatusData obj attached, which
-        // should be returned.
-        
-        try {
-            switch (syncJob) {
-                case "deletefolder":
-                    await eas.sync.deleteFolder(syncData);
-                    break;
-                default:
-                   await eas.sync.singleFolder(syncData);
-            }
-        } catch (e) {
-            if (e.name == "eas4tbsync") {
-                return e.statusData;
-            } else {
-                Components.utils.reportError(e);
-                // re-throw any other error and let TbSync handle it
-                throw (e);
-            }
-        }
-
-        // Fall through, if there was no error.
-        return new TbSync.StatusData();   
-    }
-
-
-    /**
-     * Return the custom OAuth2 ClientID.
-     */
-    static getCustomeOauthClientID() {
-        return eas.prefs.getCharPref("oauth.clientID");
-    }
-}
-
-
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// * TargetData implementation
-// * Using TbSyncs advanced address book TargetData 
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
-var TargetData_addressbook = class extends TbSync.addressbook.AdvancedTargetData {
-    constructor(folderData) {
-        super(folderData);
-    }
-
-    get primaryKeyField() {
-        return "X-EAS-SERVERID";
-    }
-    
-    generatePrimaryKey() {
-         return TbSync.generateUUID();
-    }
-
-    // enable or disable changelog
-    get logUserChanges() {
-        return  true;
-    }
-
-    directoryObserver(aTopic) {
-        switch (aTopic) {
-            case "addrbook-removed":
-            case "addrbook-updated":
-                //Services.console.logStringMessage("["+ aTopic + "] " + this.folderData.getFolderProperty("foldername"));
-                break;
-        }
-    }
-
-    cardObserver(aTopic, abCardItem) {
-        switch (aTopic) {
-            case "addrbook-contact-updated":
-            case "addrbook-contact-removed":
-                //Services.console.logStringMessage("["+ aTopic + "] " + abCardItem.getProperty("DisplayName"));
-                break;
-
-            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-removed":
-            case "addrbook-list-updated":
-                //Services.console.logStringMessage("["+ aTopic + "] ListName: " + abListItem.getProperty("ListName"));
-                break;
-            
-            case "addrbook-list-created": 
-                //Services.console.logStringMessage("["+ aTopic + "] ListName: "+abListItem.getProperty("ListName")+">");
-                break;
-        }
-    }
-    
-    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);
-        
-        eas.sync.resetFolderSyncInfo(this.folderData);
-        
-        if (directory && directory instanceof Components.interfaces.nsIAbDirectory && directory.dirPrefId == dirPrefId) {
-            directory.setStringValue("tbSyncIcon", "eas" + (this.folderData.accountData.getAccountProperty("servertype") == "office365" ? "_365" : ""));
-            directory.setStringValue("tbSyncRevision", "2");
-            return directory;
-        }
-        return null;
-    }
-}
-
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// * TargetData implementation
-// * Using TbSyncs advanced calendar TargetData 
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
-var TargetData_calendar = class extends TbSync.lightning.AdvancedTargetData {
-    constructor(folderData) {
-        super(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;
-        }
-    }
-
-    async createCalendar(newname) {
-        let calManager = TbSync.lightning.cal.manager;
-
-        //Create the new standard calendar with a unique name
-        let newCalendar = calManager.createCalendar("storage", Services.io.newURI("moz-storage-calendar://"));
-        newCalendar.id = TbSync.lightning.cal.getUUID();
-        newCalendar.name = newname;
-
-        eas.sync.resetFolderSyncInfo(this.folderData);
-
-        newCalendar.setProperty("color", this.folderData.getFolderProperty("targetColor"));
-        newCalendar.setProperty("relaxedMode", true); //sometimes we get "generation too old for modifyItem", check can be disabled with relaxedMode
-        // removed in TB78, as it seems to not fully enable the calendar, if present before registering
-        // https://searchfox.org/comm-central/source/calendar/base/content/calendar-management.js#385
-        //newCalendar.setProperty("calendar-main-in-composite",true);
-        newCalendar.setProperty("readOnly", this.folderData.getFolderProperty("downloadonly"));
-        
-        switch (this.folderData.getFolderProperty("type")) {
-            case "8": //event
-            case "13":
-                newCalendar.setProperty("capabilities.tasks.supported", false);
-                newCalendar.setProperty("capabilities.events.supported", true);
-                break;
-            case "7": //todo
-            case "15":        
-                newCalendar.setProperty("capabilities.tasks.supported", true);
-                newCalendar.setProperty("capabilities.events.supported", false);
-                break;
-            default:
-                newCalendar.setProperty("capabilities.tasks.supported", false);
-                newCalendar.setProperty("capabilities.events.supported", false);
-        }
-        
-        calManager.registerCalendar(newCalendar);
-
-        let authData = eas.network.getAuthData(this.folderData.accountData);
-        
-        //is there an email identity we can associate this calendar to? 
-        //getIdentityKey returns "" if none found, which removes any association
-        let key = eas.tools.getIdentityKey(authData.user);
-        newCalendar.setProperty("fallbackOrganizerName", newCalendar.getProperty("organizerCN"));
-        newCalendar.setProperty("imip.identity.key", key);
-        if (key === "") {
-            //there is no matching email identity - use current default value as best guess and remove association
-            //use current best guess 
-            newCalendar.setProperty("organizerCN", newCalendar.getProperty("fallbackOrganizerName"));
-            newCalendar.setProperty("organizerId", TbSync.lightning.cal.email.prependMailTo(authData.user));
-        }
-        
-        return newCalendar;
-    }
-}
-
-
-
-
-
-/**
- * This provider is implementing the StandardFolderList class instead of
- * the FolderList class.
- */
-var StandardFolderList = class {
-    /**
-     * Is called before the context menu of the folderlist is shown, allows to
-     * show/hide custom menu options based on selected folder. During an active
-     * sync, folderData will be null.
-     */
-    static onContextMenuShowing(window, folderData) {
-        let hideContextMenuDelete = true;
-        if (folderData !== null) {
-            //if a folder in trash is selected, also show ContextMenuDelete (but only if FolderDelete is allowed)
-            if (eas.tools.parentIsTrash(folderData) && folderData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("FolderDelete")) {
-                hideContextMenuDelete = false;
-                window.document.getElementById("TbSync.eas.FolderListContextMenuDelete").label = TbSync.getString("deletefolder.menuentry::" + folderData.getFolderProperty("foldername"), "eas");
-            }                
-        }
-        window.document.getElementById("TbSync.eas.FolderListContextMenuDelete").hidden = hideContextMenuDelete;
-    }
-
-
-    /**
-     * Return the icon used in the folderlist to represent the different folder
-     * types.
-     */
-    static getTypeImage(folderData) {
-        let src = "";
-        switch (folderData.getFolderProperty("type")) {
-            case "9": 
-            case "14": 
-                src = "contacts16.png";
-                break;
-            case "8":
-            case "13":
-                src = "calendar16.png";
-                break;
-            case "7":
-            case "15":
-                src = "todo16.png";
-                break;
-        }
-        return "chrome://tbsync/content/skin/" + src;
-    }
-
-
-    /**
-     * Return the name of the folder shown in the folderlist.
-     */ 
-    static getFolderDisplayName(folderData) {
-        let folderName = folderData.getFolderProperty("foldername");
-        if (eas.tools.parentIsTrash(folderData)) folderName = TbSync.getString("recyclebin", "eas") + " | " + folderName;
-        return folderName;
-    }
-    
-
-    /**
-     * Return the attributes for the ACL RO (readonly menu element per folder.
-     * (label, disabled, hidden, style, ...)
-     *
-     * Return a list of attributes and their values If both (RO+RW) do
-     * not return any attributes, the ACL menu is not displayed at all.
-     */ 
-    static getAttributesRoAcl(folderData) {
-        return {
-            label: TbSync.getString("acl.readonly", "eas"),
-        };
-    }
-    
-
-    /**
-     * Return the attributes for the ACL RW (readwrite) menu element per folder.
-     * (label, disabled, hidden, style, ...)
-     *
-     * Return a list of attributes and their values. If both (RO+RW) do
-     * not return any attributes, the ACL menu is not displayed at all.
-     */ 
-    static getAttributesRwAcl(folderData) {
-        return {
-            label: TbSync.getString("acl.readwrite", "eas"),
-        }             
-    }
-}
-
-Services.scriptloader.loadSubScript("chrome://eas4tbsync/content/includes/network.js", this, "UTF-8");
-Services.scriptloader.loadSubScript("chrome://eas4tbsync/content/includes/wbxmltools.js", this, "UTF-8");
-Services.scriptloader.loadSubScript("chrome://eas4tbsync/content/includes/xmltools.js", this, "UTF-8");
-Services.scriptloader.loadSubScript("chrome://eas4tbsync/content/includes/tools.js", this, "UTF-8");
-Services.scriptloader.loadSubScript("chrome://eas4tbsync/content/includes/sync.js", this, "UTF-8");
-Services.scriptloader.loadSubScript("chrome://eas4tbsync/content/includes/contactsync.js", this.sync, "UTF-8");
-Services.scriptloader.loadSubScript("chrome://eas4tbsync/content/includes/calendarsync.js", this.sync, "UTF-8");
-Services.scriptloader.loadSubScript("chrome://eas4tbsync/content/includes/tasksync.js", this.sync, "UTF-8");
+/*
+ * This file is part of EAS-4-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}`
+);
+
+// Every object in here will be loaded into TbSync.providers.<providername>.
+const eas = TbSync.providers.eas;
+
+eas.prefs = Services.prefs.getBranch("extensions.eas4tbsync.");
+
+//use flags instead of strings to avoid errors due to spelling errors
+eas.flags = Object.freeze({
+    allowEmptyResponse: true,
+});
+
+eas.windowsToIanaTimezoneMap = {};
+eas.ianaToWindowsTimezoneMap = {};
+eas.cachedTimezoneData = null;
+eas.defaultTimezoneInfo = null;
+eas.defaultTimezone = null;
+eas.utcTimezone = null;
+
+
+/**
+ * Implementing the TbSync interface for external provider extensions.
+ */
+var Base = class {
+    /**
+     * Called during load of external provider extension to init provider.
+     */
+    static async load() {
+        // Set default prefs
+        let branch = Services.prefs.getDefaultBranch("extensions.eas4tbsync.");
+        branch.setIntPref("timeout", 90000);
+        branch.setIntPref("maxitems", 50);
+        branch.setBoolPref("msTodoCompat", false);
+        branch.setCharPref("clientID.type", "TbSync");
+        branch.setCharPref("clientID.useragent", "Thunderbird ActiveSync");
+        branch.setCharPref("oauth.clientID", "");
+
+        eas.defaultTimezone = null;
+        eas.utcTimezone = null;
+        eas.defaultTimezoneInfo = null;
+        eas.windowsToIanaTimezoneMap = {};
+        eas.openWindows = {};
+
+        try {
+            // Create a basic error info (no accountname or foldername, just the provider)
+            let eventLogInfo = new TbSync.EventLogInfo("eas");
+
+            //get timezone info of default timezone (old cal. without dtz are depricated)
+            eas.defaultTimezone = (TbSync.lightning.cal.dtz && TbSync.lightning.cal.dtz.defaultTimezone) ? TbSync.lightning.cal.dtz.defaultTimezone : TbSync.lightning.cal.calendarDefaultTimezone();
+            eas.utcTimezone = (TbSync.lightning.cal.dtz && TbSync.lightning.cal.dtz.UTC) ? TbSync.lightning.cal.dtz.UTC : TbSync.lightning.cal.UTC();
+            if (eas.defaultTimezone && eas.defaultTimezone.icalComponent) {
+                TbSync.eventlog.add("info", eventLogInfo, "Default timezone has been found.");
+            } else {
+                TbSync.eventlog.add("info", eventLogInfo, "Default timezone is not defined, using UTC!");
+                eas.defaultTimezone = eas.utcTimezone;
+            }
+
+            eas.defaultTimezoneInfo = eas.tools.getTimezoneInfo(eas.defaultTimezone);
+            if (!eas.defaultTimezoneInfo) {
+                TbSync.eventlog.add("info", eventLogInfo, "Could not create defaultTimezoneInfo");
+            }
+
+            //get windows timezone data from CSV
+            let aliasData = await eas.tools.fetchFile("chrome://eas4tbsync/content/timezonedata/Aliases.csv");
+            let aliasNames = {};
+            for (let i = 0; i < aliasData.length; i++) {
+                let lData = aliasData[i].split(",");
+                if (lData.length < 2) continue;
+                aliasNames[lData[0].toString().trim()] = lData[1].toString().trim().split(" ");
+            }
+
+            let csvData = await eas.tools.fetchFile("chrome://eas4tbsync/content/timezonedata/WindowsTimezone.csv");
+            for (let i = 0; i < csvData.length; i++) {
+                let lData = csvData[i].split(",");
+                if (lData.length < 3) continue;
+
+                let windowsZoneName = lData[0].toString().trim();
+                let zoneType = lData[1].toString().trim();
+                let ianaZoneName = lData[2].toString().trim();
+
+                if (zoneType == "001") eas.windowsToIanaTimezoneMap[windowsZoneName] = ianaZoneName;
+                if (ianaZoneName == eas.defaultTimezoneInfo.std.id) eas.defaultTimezoneInfo.std.windowsZoneName = windowsZoneName;
+
+                // build the revers map as well, which is many-to-one, grap iana aliases from the csvData and from the aliasData
+                // 1. multiple iana zones map to the same windows zone
+                let ianaZones = ianaZoneName.split(" ");
+                for (let ianaZone of ianaZones) {
+                    eas.ianaToWindowsTimezoneMap[ianaZone] = windowsZoneName;
+                    if (aliasNames.hasOwnProperty(ianaZone)) {
+                        for (let aliasName of aliasNames[ianaZone]) {
+                            // 2. multiple iana zonescan be an alias to a main iana zone
+                            eas.ianaToWindowsTimezoneMap[aliasName] = windowsZoneName;
+                        }
+                    }
+                }
+            }
+
+            let tzService = TbSync.lightning.cal.timezoneService;
+            for (let timezoneId of tzService.timezoneIds) {
+                if (!eas.ianaToWindowsTimezoneMap[timezoneId]) {
+                    TbSync.eventlog.add("info", eventLogInfo, "The IANA timezone <" + timezoneId + "> cannot be mapped to any Exchange timezone.");
+                }
+            }
+
+            //If an EAS calendar is currently NOT associated with an email identity, try to associate, 
+            //but do not change any explicitly set association
+            // - A) find email identity and associate (which sets organizer to that user identity)
+            // - B) overwrite default organizer with current best guess
+            //TODO: Do this after email accounts changed, not only on restart? 
+            let providerData = new TbSync.ProviderData("eas");
+            let folders = providerData.getFolders({ "selected": true, "type": ["8", "13"] });
+            for (let folder of folders) {
+                let manager = TbSync.lightning.cal.manager;
+                let calendar = manager.getCalendarById(folder.getFolderProperty("target"));
+                if (calendar && calendar.getProperty("imip.identity.key") == "") {
+                    //is there an email identity for this eas account?
+                    let authData = eas.network.getAuthData(folder.accountData);
+
+                    let key = eas.tools.getIdentityKey(authData.user);
+                    if (key === "") { //TODO: Do this even after manually switching to NONE, not only on restart?
+                        //set transient calendar organizer settings based on current best guess and 
+                        calendar.setProperty("organizerId", TbSync.lightning.cal.email.prependMailTo(authData.user));
+                        calendar.setProperty("organizerCN", calendar.getProperty("fallbackOrganizerName"));
+                    } else {
+                        //force switch to found identity
+                        calendar.setProperty("imip.identity.key", key);
+                    }
+                }
+            }
+        } catch (e) {
+            Components.utils.reportError(e);
+        }
+    }
+
+
+    /**
+     * Called during unload of external provider extension to unload provider.
+     */
+    static async unload() {
+        // Close all open windows of this provider.
+        for (let id in eas.openWindows) {
+            if (eas.openWindows.hasOwnProperty(id)) {
+                try {
+                    eas.openWindows[id].close();
+                } catch (e) {
+                    //NOOP
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Returns string for the name of provider for the add account menu.
+     */
+    static getProviderName() {
+        return "Exchange ActiveSync";
+    }
+
+
+    /**
+     * Returns version of the TbSync API this provider is using
+     */
+    static getApiVersion() { return "2.5"; }
+
+
+    /**
+     * Returns location of a provider icon.
+     */
+    static getProviderIcon(size, accountData = null) {
+        let base = (accountData && accountData.getAccountProperty("servertype") == "office365") ? "365_" : "eas";
+
+        switch (size) {
+            case 16:
+                return "chrome://eas4tbsync/content/skin/" + base + "16.png";
+            case 32:
+                return "chrome://eas4tbsync/content/skin/" + base + "32.png";
+            default:
+                return "chrome://eas4tbsync/content/skin/" + base + "64.png";
+        }
+    }
+
+
+    /**
+     * Returns a list of sponsors, they will be sorted by the index
+     */
+    static getSponsors() {
+        return {
+            "Schiessl, Michael 1": { name: "Michael Schiessl", description: "Tine 2.0", icon: "", link: "" },
+            "Schiessl, Michael 2": { name: "Michael Schiessl", description: " Exchange 2007", icon: "", link: "" },
+            "netcup GmbH": { name: "netcup GmbH", description: "SOGo", icon: "chrome://eas4tbsync/content/skin/sponsors/netcup.png", link: "http://www.netcup.de/" },
+            "nethinks GmbH": { name: "nethinks GmbH", description: "Zarafa", icon: "chrome://eas4tbsync/content/skin/sponsors/nethinks.png", link: "http://www.nethinks.com/" },
+            "Jau, Stephan": { name: "Stephan Jau", description: "Horde", icon: "", link: "" },
+            "Zavar ": { name: "Zavar", description: "Zoho", icon: "", link: "" },
+        };
+    }
+
+
+    /**
+     * Returns the url of a page with details about contributors (used in the manager UI)
+     */
+    static getContributorsUrl() {
+        return "https://github.com/jobisoft/EAS-4-TbSync/blob/master/CONTRIBUTORS.md";
+    }
+
+
+    /**
+     * Returns the email address of the maintainer (used for bug reports).
+     */
+    static getMaintainerEmail() {
+        return "john.bieling at gmx.de";
+    }
+
+
+    /**
+     * Returns URL of the new account window.
+     *
+     * The URL will be opened via openDialog(), when the user wants to create a
+     * new account of this provider.
+     */
+    static getCreateAccountWindowUrl() {
+        return "chrome://eas4tbsync/content/manager/createAccount.xhtml";
+    }
+
+
+    /**
+     * Returns overlay XUL URL of the edit account dialog
+     * (chrome://tbsync/content/manager/editAccount.xhtml)
+     */
+    static getEditAccountOverlayUrl() {
+        return "chrome://eas4tbsync/content/manager/editAccountOverlay.xhtml";
+    }
+
+
+    /**
+     * Return object which contains all possible fields of a row in the
+     * accounts database with the default value if not yet stored in the 
+     * database.
+     */
+    static getDefaultAccountEntries() {
+        let row = {
+            "policykey": "0",
+            "foldersynckey": "0",
+            "deviceId": eas.tools.getNewDeviceId(),
+            "asversionselected": "auto",
+            "asversion": "",
+            "host": "",
+            "user": "",
+            "servertype": "",
+            "seperator": "10",
+            "https": true,
+            "provision": false,
+            "displayoverride": false,
+            "lastEasOptionsUpdate": "0",
+            "allowedEasVersions": "",
+            "allowedEasCommands": "",
+            "useragent": eas.prefs.getCharPref("clientID.useragent"),
+            "devicetype": eas.prefs.getCharPref("clientID.type"),
+            "synclimit": "7",
+        };
+        return row;
+    }
+
+
+    /**
+     * Return object which contains all possible fields of a row in the folder 
+     * database with the default value if not yet stored in the database.
+     */
+    static getDefaultFolderEntries() {
+        let folder = {
+            "type": "",
+            "synckey": "",
+            "target": "",
+            "targetColor": "",
+            "targetName": "",
+            "parentID": "0",
+            "serverID": "",
+        };
+        return folder;
+    }
+
+
+    /**
+     * Is called everytime an account of this provider is enabled in the
+     * manager UI.
+     */
+    static onEnableAccount(accountData) {
+        accountData.resetAccountProperty("policykey");
+        accountData.resetAccountProperty("foldersynckey");
+        accountData.resetAccountProperty("lastEasOptionsUpdate");
+        accountData.resetAccountProperty("lastsynctime");
+    }
+
+
+    /**
+     * Is called everytime an account of this provider is disabled in the
+     * manager UI.
+     *
+     * @param accountData  [in] AccountData
+     */
+    static onDisableAccount(accountData) {
+    }
+
+
+    /**
+     * Is called everytime an account of this provider is deleted in the
+     * manager UI.
+     */
+    static onDeleteAccount(accountData) {
+        eas.network.getAuthData(accountData).removeLoginData();
+    }
+
+
+    /**
+     * Returns all folders of the account, sorted in the desired order.
+     * The most simple implementation is to return accountData.getAllFolders();
+     */
+    static getSortedFolders(accountData) {
+        let allowedTypesOrder = ["9", "14", "8", "13", "7", "15"];
+
+        function getIdChain(aServerID) {
+            let serverID = aServerID;
+            let chain = [];
+            let folder;
+            let rootType = "";
+
+            // create sort string so that child folders are directly below their parent folders
+            do {
+                folder = accountData.getFolder("serverID", serverID);
+                if (folder) {
+                    chain.unshift(folder.getFolderProperty("foldername"));
+                    serverID = folder.getFolderProperty("parentID");
+                    rootType = folder.getFolderProperty("type");
+                }
+            } while (folder && serverID != "0")
+
+            // different folder types are grouped and trashed folders at the end
+            let pos = allowedTypesOrder.indexOf(rootType);
+            chain.unshift(pos == -1 ? "ZZZ" : pos.toString().padStart(3, "0"));
+
+            return chain.join(".");
+        };
+
+        let toBeSorted = [];
+        let folders = accountData.getAllFolders();
+        for (let f of folders) {
+            if (!allowedTypesOrder.includes(f.getFolderProperty("type"))) {
+                continue;
+            }
+            toBeSorted.push({ "key": getIdChain(f.getFolderProperty("serverID")), "folder": f });
+        }
+
+        //sort
+        toBeSorted.sort(function (a, b) {
+            return a.key > b.key;
+        });
+
+        let sortedFolders = [];
+        for (let sortObj of toBeSorted) {
+            sortedFolders.push(sortObj.folder);
+        }
+        return sortedFolders;
+    }
+
+
+    /**
+     * Return the connection timeout for an active sync, so TbSync can append
+     * a countdown to the connection timeout, while waiting for an answer from
+     * the server. Only syncstates which start with "send." will trigger this.
+     */
+    static getConnectionTimeout(accountData) {
+        return eas.prefs.getIntPref("timeout");
+    }
+
+
+    /**
+     * Is called if TbSync needs to synchronize the folder list.
+     */
+    static async syncFolderList(syncData, syncJob, syncRunNr) {
+        // Recommendation: Put the actual function call inside a try catch, to
+        // ensure returning a proper StatusData object, regardless of what
+        // happens inside that function. You may also throw custom errors
+        // in that function, which have the StatusData obj attached, which
+        // should be returned.
+
+        try {
+            await eas.sync.folderList(syncData);
+        } catch (e) {
+            if (e.name == "eas4tbsync") {
+                return e.statusData;
+            } else {
+                Components.utils.reportError(e);
+                // re-throw any other error and let TbSync handle it
+                throw (e);
+            }
+        }
+
+        // Fall through, if there was no error.
+        return new TbSync.StatusData();
+    }
+
+
+    /**
+     * Is called if TbSync needs to synchronize a folder.
+     */
+    static async syncFolder(syncData, syncJob, syncRunNr) {
+        // Recommendation: Put the actual function call inside a try catch, to
+        // ensure returning a proper StatusData object, regardless of what
+        // happens inside that function. You may also throw custom errors
+        // in that function, which have the StatusData obj attached, which
+        // should be returned.
+
+        try {
+            switch (syncJob) {
+                case "deletefolder":
+                    await eas.sync.deleteFolder(syncData);
+                    break;
+                default:
+                    await eas.sync.singleFolder(syncData);
+            }
+        } catch (e) {
+            if (e.name == "eas4tbsync") {
+                return e.statusData;
+            } else {
+                Components.utils.reportError(e);
+                // re-throw any other error and let TbSync handle it
+                throw (e);
+            }
+        }
+
+        // Fall through, if there was no error.
+        return new TbSync.StatusData();
+    }
+
+
+    /**
+     * Return the custom OAuth2 ClientID.
+     */
+    static getCustomeOauthClientID() {
+        return eas.prefs.getCharPref("oauth.clientID");
+    }
+}
+
+
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// * TargetData implementation
+// * Using TbSyncs advanced address book TargetData 
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var TargetData_addressbook = class extends TbSync.addressbook.AdvancedTargetData {
+    constructor(folderData) {
+        super(folderData);
+    }
+
+    get primaryKeyField() {
+        return "X-EAS-SERVERID";
+    }
+
+    generatePrimaryKey() {
+        return TbSync.generateUUID();
+    }
+
+    // enable or disable changelog
+    get logUserChanges() {
+        return true;
+    }
+
+    directoryObserver(aTopic) {
+        switch (aTopic) {
+            case "addrbook-removed":
+            case "addrbook-updated":
+                //Services.console.logStringMessage("["+ aTopic + "] " + this.folderData.getFolderProperty("foldername"));
+                break;
+        }
+    }
+
+    cardObserver(aTopic, abCardItem) {
+        switch (aTopic) {
+            case "addrbook-contact-updated":
+            case "addrbook-contact-removed":
+                //Services.console.logStringMessage("["+ aTopic + "] " + abCardItem.getProperty("DisplayName"));
+                break;
+
+            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-removed":
+            case "addrbook-list-updated":
+                //Services.console.logStringMessage("["+ aTopic + "] ListName: " + abListItem.getProperty("ListName"));
+                break;
+
+            case "addrbook-list-created":
+                //Services.console.logStringMessage("["+ aTopic + "] ListName: "+abListItem.getProperty("ListName")+">");
+                break;
+        }
+    }
+
+    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);
+
+        eas.sync.resetFolderSyncInfo(this.folderData);
+
+        if (directory && directory instanceof Components.interfaces.nsIAbDirectory && directory.dirPrefId == dirPrefId) {
+            directory.setStringValue("tbSyncIcon", "eas" + (this.folderData.accountData.getAccountProperty("servertype") == "office365" ? "_365" : ""));
+            directory.setStringValue("tbSyncRevision", "2");
+            return directory;
+        }
+        return null;
+    }
+}
+
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// * TargetData implementation
+// * Using TbSyncs advanced calendar TargetData 
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var TargetData_calendar = class extends TbSync.lightning.AdvancedTargetData {
+    constructor(folderData) {
+        super(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;
+        }
+    }
+
+    async createCalendar(newname) {
+        let calManager = TbSync.lightning.cal.manager;
+
+        //Create the new standard calendar with a unique name
+        let newCalendar = calManager.createCalendar("storage", Services.io.newURI("moz-storage-calendar://"));
+        newCalendar.id = TbSync.lightning.cal.getUUID();
+        newCalendar.name = newname;
+
+        eas.sync.resetFolderSyncInfo(this.folderData);
+
+        newCalendar.setProperty("color", this.folderData.getFolderProperty("targetColor"));
+        newCalendar.setProperty("relaxedMode", true); //sometimes we get "generation too old for modifyItem", check can be disabled with relaxedMode
+        // removed in TB78, as it seems to not fully enable the calendar, if present before registering
+        // https://searchfox.org/comm-central/source/calendar/base/content/calendar-management.js#385
+        //newCalendar.setProperty("calendar-main-in-composite",true);
+        newCalendar.setProperty("readOnly", this.folderData.getFolderProperty("downloadonly"));
+
+        switch (this.folderData.getFolderProperty("type")) {
+            case "8": //event
+            case "13":
+                newCalendar.setProperty("capabilities.tasks.supported", false);
+                newCalendar.setProperty("capabilities.events.supported", true);
+                break;
+            case "7": //todo
+            case "15":
+                newCalendar.setProperty("capabilities.tasks.supported", true);
+                newCalendar.setProperty("capabilities.events.supported", false);
+                break;
+            default:
+                newCalendar.setProperty("capabilities.tasks.supported", false);
+                newCalendar.setProperty("capabilities.events.supported", false);
+        }
+
+        calManager.registerCalendar(newCalendar);
+
+        let authData = eas.network.getAuthData(this.folderData.accountData);
+
+        //is there an email identity we can associate this calendar to? 
+        //getIdentityKey returns "" if none found, which removes any association
+        let key = eas.tools.getIdentityKey(authData.user);
+        newCalendar.setProperty("fallbackOrganizerName", newCalendar.getProperty("organizerCN"));
+        newCalendar.setProperty("imip.identity.key", key);
+        if (key === "") {
+            //there is no matching email identity - use current default value as best guess and remove association
+            //use current best guess 
+            newCalendar.setProperty("organizerCN", newCalendar.getProperty("fallbackOrganizerName"));
+            newCalendar.setProperty("organizerId", TbSync.lightning.cal.email.prependMailTo(authData.user));
+        }
+
+        return newCalendar;
+    }
+}
+
+
+
+
+
+/**
+ * This provider is implementing the StandardFolderList class instead of
+ * the FolderList class.
+ */
+var StandardFolderList = class {
+    /**
+     * Is called before the context menu of the folderlist is shown, allows to
+     * show/hide custom menu options based on selected folder. During an active
+     * sync, folderData will be null.
+     */
+    static onContextMenuShowing(window, folderData) {
+        let hideContextMenuDelete = true;
+        if (folderData !== null) {
+            //if a folder in trash is selected, also show ContextMenuDelete (but only if FolderDelete is allowed)
+            if (eas.tools.parentIsTrash(folderData) && folderData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("FolderDelete")) {
+                hideContextMenuDelete = false;
+                window.document.getElementById("TbSync.eas.FolderListContextMenuDelete").label = TbSync.getString("deletefolder.menuentry::" + folderData.getFolderProperty("foldername"), "eas");
+            }
+        }
+        window.document.getElementById("TbSync.eas.FolderListContextMenuDelete").hidden = hideContextMenuDelete;
+    }
+
+
+    /**
+     * Return the icon used in the folderlist to represent the different folder
+     * types.
+     */
+    static getTypeImage(folderData) {
+        let src = "";
+        switch (folderData.getFolderProperty("type")) {
+            case "9":
+            case "14":
+                src = "contacts16.png";
+                break;
+            case "8":
+            case "13":
+                src = "calendar16.png";
+                break;
+            case "7":
+            case "15":
+                src = "todo16.png";
+                break;
+        }
+        return "chrome://tbsync/content/skin/" + src;
+    }
+
+
+    /**
+     * Return the name of the folder shown in the folderlist.
+     */
+    static getFolderDisplayName(folderData) {
+        let folderName = folderData.getFolderProperty("foldername");
+        if (eas.tools.parentIsTrash(folderData)) folderName = TbSync.getString("recyclebin", "eas") + " | " + folderName;
+        return folderName;
+    }
+
+
+    /**
+     * Return the attributes for the ACL RO (readonly menu element per folder.
+     * (label, disabled, hidden, style, ...)
+     *
+     * Return a list of attributes and their values If both (RO+RW) do
+     * not return any attributes, the ACL menu is not displayed at all.
+     */
+    static getAttributesRoAcl(folderData) {
+        return {
+            label: TbSync.getString("acl.readonly", "eas"),
+        };
+    }
+
+
+    /**
+     * Return the attributes for the ACL RW (readwrite) menu element per folder.
+     * (label, disabled, hidden, style, ...)
+     *
+     * Return a list of attributes and their values. If both (RO+RW) do
+     * not return any attributes, the ACL menu is not displayed at all.
+     */
+    static getAttributesRwAcl(folderData) {
+        return {
+            label: TbSync.getString("acl.readwrite", "eas"),
+        }
+    }
+}
+
+Services.scriptloader.loadSubScript("chrome://eas4tbsync/content/includes/network.js", this, "UTF-8");
+Services.scriptloader.loadSubScript("chrome://eas4tbsync/content/includes/wbxmltools.js", this, "UTF-8");
+Services.scriptloader.loadSubScript("chrome://eas4tbsync/content/includes/xmltools.js", this, "UTF-8");
+Services.scriptloader.loadSubScript("chrome://eas4tbsync/content/includes/tools.js", this, "UTF-8");
+Services.scriptloader.loadSubScript("chrome://eas4tbsync/content/includes/sync.js", this, "UTF-8");
+Services.scriptloader.loadSubScript("chrome://eas4tbsync/content/includes/contactsync.js", this.sync, "UTF-8");
+Services.scriptloader.loadSubScript("chrome://eas4tbsync/content/includes/calendarsync.js", this.sync, "UTF-8");
+Services.scriptloader.loadSubScript("chrome://eas4tbsync/content/includes/tasksync.js", this.sync, "UTF-8");
diff -Nru eas4tbsync-4.11/content/skin/365.svg eas4tbsync-4.17/content/skin/365.svg
--- eas4tbsync-4.11/content/skin/365.svg	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/skin/365.svg	2019-11-30 13:30:50.000000000 +0100
@@ -1,12 +1,12 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 53.59 64.356" width="53.589577" height="64.356148">
- <g transform="translate(-216.07358,-549.28882)">
-  <g transform="matrix(1.8232952,0,0,1.8232952,-597.71681,-124.12247)">
-   <g transform="translate(0,-91.137241)">
-    <g fill="#eb3c00" transform="matrix(0.74069815,0,0,0.74069815,98.5698,-8.2505871)">
-     <path d="m469.87,671.03,0-28.52,25.229-9.3238,13.711,4.3877,0,38.392-13.711,4.133-25.229-9.0691,25.229,3.0361,0-33.201-16.454,3.8392,0,22.487z"/>
-    </g>
-   </g>
-  </g>
- </g>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 53.59 64.356" width="53.589577" height="64.356148">
+ <g transform="translate(-216.07358,-549.28882)">
+  <g transform="matrix(1.8232952,0,0,1.8232952,-597.71681,-124.12247)">
+   <g transform="translate(0,-91.137241)">
+    <g fill="#eb3c00" transform="matrix(0.74069815,0,0,0.74069815,98.5698,-8.2505871)">
+     <path d="m469.87,671.03,0-28.52,25.229-9.3238,13.711,4.3877,0,38.392-13.711,4.133-25.229-9.0691,25.229,3.0361,0-33.201-16.454,3.8392,0,22.487z"/>
+    </g>
+   </g>
+  </g>
+ </g>
 </svg>
\ Kein Zeilenumbruch am Dateiende.
diff -Nru eas4tbsync-4.11/content/skin/fieldset.css eas4tbsync-4.17/content/skin/fieldset.css
--- eas4tbsync-4.11/content/skin/fieldset.css	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/skin/fieldset.css	2021-08-16 17:44:30.000000000 +0200
@@ -1,6 +1,6 @@
-
-vbox[OS=WINNT] legend.insideTab {
-  padding-right: 5px;
-  padding-left: 5px;
-  margin-bottom:5px;
-}
+
+vbox[OS=WINNT] legend.insideTab {
+  padding-right: 5px;
+  padding-left: 5px;
+  margin-bottom:5px;
+}
diff -Nru eas4tbsync-4.11/content/timezonedata/Aliases.csv eas4tbsync-4.17/content/timezonedata/Aliases.csv
--- eas4tbsync-4.11/content/timezonedata/Aliases.csv	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/timezonedata/Aliases.csv	2025-05-15 13:21:20.000000000 +0200
@@ -1,115 +1,115 @@
-Africa/Abidjan,Iceland Africa/Timbuktu Africa/Accra Africa/Bamako Africa/Banjul Africa/Conakry Africa/Dakar Africa/Freetown Africa/Lome Africa/Nouakchott Africa/Ouagadougou Atlantic/Reykjavik Atlantic/St_Helena
-Africa/Cairo,Egypt
-Africa/Johannesburg,Africa/Maseru Africa/Mbabane
-Africa/Lagos,Africa/Bangui Africa/Brazzaville Africa/Douala Africa/Kinshasa Africa/Libreville Africa/Luanda Africa/Malabo Africa/Niamey Africa/Porto-Novo
-Africa/Maputo,Africa/Blantyre Africa/Bujumbura Africa/Gaborone Africa/Harare Africa/Kigali Africa/Lubumbashi Africa/Lusaka
-Africa/Nairobi,Africa/Asmara Africa/Addis_Ababa Africa/Dar_es_Salaam Africa/Djibouti Africa/Kampala Africa/Mogadishu Indian/Antananarivo Indian/Comoro Indian/Mayotte Africa/Asmera
-Africa/Tripoli,Libya
-America/Adak,America/Atka US/Aleutian
-America/Anchorage,US/Alaska
-America/Argentina/Buenos_Aires,America/Buenos_Aires
-America/Argentina/Catamarca,America/Catamarca America/Argentina/ComodRivadavia
-America/Argentina/Cordoba,America/Cordoba America/Rosario
-America/Argentina/Jujuy,America/Jujuy
-America/Argentina/Mendoza,America/Mendoza
-America/Chicago,US/Central
-America/Denver,America/Shiprock Navajo US/Mountain
-America/Detroit,US/Michigan
-America/Edmonton,Canada/Mountain
-America/Halifax,Canada/Atlantic
-America/Havana,Cuba
-America/Indiana/Indianapolis,America/Fort_Wayne America/Indianapolis US/East-Indiana
-America/Indiana/Knox,America/Knox_IN US/Indiana-Starke
-America/Jamaica,Jamaica
-America/Kentucky/Louisville,America/Louisville
-America/Los_Angeles,US/Pacific US/Pacific-New
-America/Manaus,Brazil/West
-America/Mazatlan,Mexico/BajaSur
-America/Mexico_City,Mexico/General
-America/New_York,US/Eastern
-America/Noronha,Brazil/DeNoronha
-America/Nuuk,America/Godthab
-America/Panama,America/Atikokan America/Coral_Harbour America/Cayman
-America/Phoenix,US/Arizona America/Creston
-America/Puerto_Rico,America/Virgin America/Anguilla America/Antigua America/Aruba America/Curacao America/Blanc-Sablon America/Dominica America/Grenada America/Guadeloupe America/Kralendijk America/Lower_Princes America/Marigot America/Montserrat America/Port_of_Spain America/St_Barthelemy America/St_Kitts America/St_Lucia America/St_Thomas America/St_Vincent America/Tortola
-America/Regina,Canada/East-Saskatchewan Canada/Saskatchewan
-America/Rio_Branco,America/Porto_Acre Brazil/Acre
-America/Santiago,Chile/Continental
-America/Sao_Paulo,Brazil/East
-America/St_Johns,Canada/Newfoundland
-America/Tijuana,America/Ensenada Mexico/BajaNorte America/Santa_Isabel
-America/Toronto,Canada/Eastern America/Montreal America/Nassau
-America/Vancouver,Canada/Pacific
-America/Whitehorse,Canada/Yukon
-America/Winnipeg,Canada/Central
-Asia/Ashgabat,Asia/Ashkhabad
-Asia/Bangkok,Asia/Phnom_Penh Asia/Vientiane Indian/Christmas
-Asia/Dhaka,Asia/Dacca
-Asia/Dubai,Asia/Muscat Indian/Mahe Indian/Reunion
-Asia/Ho_Chi_Minh,Asia/Saigon
-Asia/Hong_Kong,Hongkong
-Asia/Jerusalem,Asia/Tel_Aviv Israel
-Asia/Kathmandu,Asia/Katmandu
-Asia/Kolkata,Asia/Calcutta
-Asia/Kuching,Asia/Brunei
-Asia/Macau,Asia/Macao
-Asia/Makassar,Asia/Ujung_Pandang
-Asia/Nicosia,Europe/Nicosia
-Asia/Qatar,Asia/Bahrain
-Asia/Riyadh,Antarctica/Syowa Asia/Aden Asia/Kuwait
-Asia/Seoul,ROK
-Asia/Shanghai,Asia/Chongqing Asia/Chungking Asia/Harbin PRC
-Asia/Singapore,Singapore Asia/Kuala_Lumpur
-Asia/Taipei,ROC
-Asia/Tehran,Iran
-Asia/Thimphu,Asia/Thimbu
-Asia/Tokyo,Japan
-Asia/Ulaanbaatar,Asia/Ulan_Bator
-Asia/Urumqi,Asia/Kashgar Antarctica/Vostok
-Asia/Yangon,Asia/Rangoon Indian/Cocos
-Atlantic/Canary,WET
-Atlantic/Faroe,Atlantic/Faeroe
-Australia/Adelaide,Australia/South
-Australia/Brisbane,Australia/Queensland
-Australia/Broken_Hill,Australia/Yancowinna
-Australia/Darwin,Australia/North
-Australia/Hobart,Australia/Tasmania Australia/Currie
-Australia/Lord_Howe,Australia/LHI
-Australia/Melbourne,Australia/Victoria
-Australia/Perth,Australia/West
-Australia/Sydney,Australia/ACT Australia/Canberra Australia/NSW
-Etc/GMT+10,HST
-Etc/GMT+5,EST
-Etc/GMT+7,MST
-Etc/UTC,Etc/GMT+0 Etc/GMT-0 Etc/GMT0 Etc/Greenwich GMT GMT+0 GMT-0 GMT0 Greenwich Etc/UCT Etc/Universal Etc/Zulu UCT UTC Universal Zulu Etc/GMT
-Europe/Belgrade,Europe/Ljubljana Europe/Podgorica Europe/Sarajevo Europe/Skopje Europe/Zagreb
-Europe/Berlin,Atlantic/Jan_Mayen Arctic/Longyearbyen Europe/Copenhagen Europe/Oslo Europe/Stockholm
-Europe/Berlin,MET
-Europe/Brussels,Europe/Amsterdam Europe/Luxembourg
-Europe/Bucharest,EET
-Europe/Chisinau,Europe/Tiraspol
-Europe/Dublin,Eire
-Europe/Helsinki,Europe/Mariehamn
-Europe/Istanbul,Asia/Istanbul Turkey
-Europe/Kyiv,Europe/Kiev
-Europe/Lisbon,Portugal
-Europe/London,Europe/Belfast GB GB-Eire Europe/Jersey Europe/Guernsey Europe/Isle_of_Man
-Europe/Moscow,W-SU
-Europe/Paris,CET
-Europe/Paris,Europe/Monaco
-Europe/Prague,Europe/Bratislava
-Europe/Rome,Europe/Vatican Europe/San_Marino
-Europe/Warsaw,Poland
-Europe/Zurich,Europe/Busingen Europe/Vaduz
-Indian/Maldives,Indian/Kerguelen
-Pacific/Auckland,Antarctica/South_Pole NZ Antarctica/McMurdo
-Pacific/Chatham,NZ-CHAT
-Pacific/Easter,Chile/EasterIsland
-Pacific/Guadalcanal,Pacific/Pohnpei Pacific/Ponape
-Pacific/Guam,Pacific/Saipan
-Pacific/Honolulu,US/Hawaii Pacific/Johnston
-Pacific/Kanton,Pacific/Enderbury
-Pacific/Kwajalein,Kwajalein
-Pacific/Pago_Pago,Pacific/Samoa US/Samoa Pacific/Midway
-Pacific/Port_Moresby,Pacific/Chuuk Pacific/Yap Antarctica/DumontDUrville Pacific/Truk
-Pacific/Tarawa,Pacific/Funafuti Pacific/Majuro Pacific/Wake Pacific/Wallis
+Africa/Abidjan,Iceland Africa/Timbuktu Africa/Accra Africa/Bamako Africa/Banjul Africa/Conakry Africa/Dakar Africa/Freetown Africa/Lome Africa/Nouakchott Africa/Ouagadougou Atlantic/Reykjavik Atlantic/St_Helena
+Africa/Cairo,Egypt
+Africa/Johannesburg,Africa/Maseru Africa/Mbabane
+Africa/Lagos,Africa/Bangui Africa/Brazzaville Africa/Douala Africa/Kinshasa Africa/Libreville Africa/Luanda Africa/Malabo Africa/Niamey Africa/Porto-Novo
+Africa/Maputo,Africa/Blantyre Africa/Bujumbura Africa/Gaborone Africa/Harare Africa/Kigali Africa/Lubumbashi Africa/Lusaka
+Africa/Nairobi,Africa/Asmara Africa/Addis_Ababa Africa/Dar_es_Salaam Africa/Djibouti Africa/Kampala Africa/Mogadishu Indian/Antananarivo Indian/Comoro Indian/Mayotte Africa/Asmera
+Africa/Tripoli,Libya
+America/Adak,America/Atka US/Aleutian
+America/Anchorage,US/Alaska
+America/Argentina/Buenos_Aires,America/Buenos_Aires
+America/Argentina/Catamarca,America/Catamarca America/Argentina/ComodRivadavia
+America/Argentina/Cordoba,America/Cordoba America/Rosario
+America/Argentina/Jujuy,America/Jujuy
+America/Argentina/Mendoza,America/Mendoza
+America/Chicago,US/Central
+America/Denver,America/Shiprock Navajo US/Mountain
+America/Detroit,US/Michigan
+America/Edmonton,Canada/Mountain
+America/Halifax,Canada/Atlantic
+America/Havana,Cuba
+America/Indiana/Indianapolis,America/Fort_Wayne America/Indianapolis US/East-Indiana
+America/Indiana/Knox,America/Knox_IN US/Indiana-Starke
+America/Jamaica,Jamaica
+America/Kentucky/Louisville,America/Louisville
+America/Los_Angeles,US/Pacific US/Pacific-New
+America/Manaus,Brazil/West
+America/Mazatlan,Mexico/BajaSur
+America/Mexico_City,Mexico/General
+America/New_York,US/Eastern
+America/Noronha,Brazil/DeNoronha
+America/Nuuk,America/Godthab
+America/Panama,America/Atikokan America/Coral_Harbour America/Cayman
+America/Phoenix,US/Arizona America/Creston
+America/Puerto_Rico,America/Virgin America/Anguilla America/Antigua America/Aruba America/Curacao America/Blanc-Sablon America/Dominica America/Grenada America/Guadeloupe America/Kralendijk America/Lower_Princes America/Marigot America/Montserrat America/Port_of_Spain America/St_Barthelemy America/St_Kitts America/St_Lucia America/St_Thomas America/St_Vincent America/Tortola
+America/Regina,Canada/East-Saskatchewan Canada/Saskatchewan
+America/Rio_Branco,America/Porto_Acre Brazil/Acre
+America/Santiago,Chile/Continental
+America/Sao_Paulo,Brazil/East
+America/St_Johns,Canada/Newfoundland
+America/Tijuana,America/Ensenada Mexico/BajaNorte America/Santa_Isabel
+America/Toronto,Canada/Eastern America/Montreal America/Nassau
+America/Vancouver,Canada/Pacific
+America/Whitehorse,Canada/Yukon
+America/Winnipeg,Canada/Central
+Asia/Ashgabat,Asia/Ashkhabad
+Asia/Bangkok,Asia/Phnom_Penh Asia/Vientiane Indian/Christmas
+Asia/Dhaka,Asia/Dacca
+Asia/Dubai,Asia/Muscat Indian/Mahe Indian/Reunion
+Asia/Ho_Chi_Minh,Asia/Saigon
+Asia/Hong_Kong,Hongkong
+Asia/Jerusalem,Asia/Tel_Aviv Israel
+Asia/Kathmandu,Asia/Katmandu
+Asia/Kolkata,Asia/Calcutta
+Asia/Kuching,Asia/Brunei
+Asia/Macau,Asia/Macao
+Asia/Makassar,Asia/Ujung_Pandang
+Asia/Nicosia,Europe/Nicosia
+Asia/Qatar,Asia/Bahrain
+Asia/Riyadh,Antarctica/Syowa Asia/Aden Asia/Kuwait
+Asia/Seoul,ROK
+Asia/Shanghai,Asia/Chongqing Asia/Chungking Asia/Harbin PRC
+Asia/Singapore,Singapore Asia/Kuala_Lumpur
+Asia/Taipei,ROC
+Asia/Tehran,Iran
+Asia/Thimphu,Asia/Thimbu
+Asia/Tokyo,Japan
+Asia/Ulaanbaatar,Asia/Ulan_Bator
+Asia/Urumqi,Asia/Kashgar Antarctica/Vostok
+Asia/Yangon,Asia/Rangoon Indian/Cocos
+Atlantic/Canary,WET
+Atlantic/Faroe,Atlantic/Faeroe
+Australia/Adelaide,Australia/South
+Australia/Brisbane,Australia/Queensland
+Australia/Broken_Hill,Australia/Yancowinna
+Australia/Darwin,Australia/North
+Australia/Hobart,Australia/Tasmania Australia/Currie
+Australia/Lord_Howe,Australia/LHI
+Australia/Melbourne,Australia/Victoria
+Australia/Perth,Australia/West
+Australia/Sydney,Australia/ACT Australia/Canberra Australia/NSW
+Etc/GMT+10,HST
+Etc/GMT+5,EST
+Etc/GMT+7,MST
+Etc/UTC,Etc/GMT+0 Etc/GMT-0 Etc/GMT0 Etc/Greenwich GMT GMT+0 GMT-0 GMT0 Greenwich Etc/UCT Etc/Universal Etc/Zulu UCT UTC Universal Zulu Etc/GMT
+Europe/Belgrade,Europe/Ljubljana Europe/Podgorica Europe/Sarajevo Europe/Skopje Europe/Zagreb
+Europe/Berlin,Atlantic/Jan_Mayen Arctic/Longyearbyen Europe/Copenhagen Europe/Oslo Europe/Stockholm
+Europe/Berlin,MET
+Europe/Brussels,Europe/Amsterdam Europe/Luxembourg
+Europe/Bucharest,EET
+Europe/Chisinau,Europe/Tiraspol
+Europe/Dublin,Eire
+Europe/Helsinki,Europe/Mariehamn
+Europe/Istanbul,Asia/Istanbul Turkey
+Europe/Kyiv,Europe/Kiev
+Europe/Lisbon,Portugal
+Europe/London,Europe/Belfast GB GB-Eire Europe/Jersey Europe/Guernsey Europe/Isle_of_Man
+Europe/Moscow,W-SU
+Europe/Paris,CET
+Europe/Paris,Europe/Monaco
+Europe/Prague,Europe/Bratislava
+Europe/Rome,Europe/Vatican Europe/San_Marino
+Europe/Warsaw,Poland
+Europe/Zurich,Europe/Busingen Europe/Vaduz
+Indian/Maldives,Indian/Kerguelen
+Pacific/Auckland,Antarctica/South_Pole NZ Antarctica/McMurdo
+Pacific/Chatham,NZ-CHAT
+Pacific/Easter,Chile/EasterIsland
+Pacific/Guadalcanal,Pacific/Pohnpei Pacific/Ponape
+Pacific/Guam,Pacific/Saipan
+Pacific/Honolulu,US/Hawaii Pacific/Johnston
+Pacific/Kanton,Pacific/Enderbury
+Pacific/Kwajalein,Kwajalein
+Pacific/Pago_Pago,Pacific/Samoa US/Samoa Pacific/Midway
+Pacific/Port_Moresby,Pacific/Chuuk Pacific/Yap Antarctica/DumontDUrville Pacific/Truk
+Pacific/Tarawa,Pacific/Funafuti Pacific/Majuro Pacific/Wake Pacific/Wallis
diff -Nru eas4tbsync-4.11/content/timezonedata/README eas4tbsync-4.17/content/timezonedata/README
--- eas4tbsync-4.11/content/timezonedata/README	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/timezonedata/README	2025-05-15 13:21:20.000000000 +0200
@@ -1,4 +1,4 @@
-Taken from TimeZoneConverter:
-https://github.com/mj1856/TimeZoneConverter/blob/master/src/TimeZoneConverter/Data/Mapping.csv.gz
-
- 12 Jan 2022
+Taken from TimeZoneConverter:
+https://github.com/mj1856/TimeZoneConverter/blob/master/src/TimeZoneConverter/Data/Mapping.csv.gz
+
+ 12 Jan 2022
diff -Nru eas4tbsync-4.11/content/timezonedata/WindowsTimezone.csv eas4tbsync-4.17/content/timezonedata/WindowsTimezone.csv
--- eas4tbsync-4.11/content/timezonedata/WindowsTimezone.csv	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/content/timezonedata/WindowsTimezone.csv	2025-05-15 13:21:20.000000000 +0200
@@ -1,514 +1,514 @@
-AUS Central Standard Time,001,Australia/Darwin
-AUS Central Standard Time,AU,Australia/Darwin
-AUS Eastern Standard Time,001,Australia/Sydney
-AUS Eastern Standard Time,AU,Australia/Sydney Australia/Melbourne
-Afghanistan Standard Time,001,Asia/Kabul
-Afghanistan Standard Time,AF,Asia/Kabul
-Alaskan Standard Time,001,America/Anchorage
-Alaskan Standard Time,US,America/Anchorage America/Juneau America/Metlakatla America/Nome America/Sitka America/Yakutat
-Aleutian Standard Time,001,America/Adak
-Aleutian Standard Time,US,America/Adak
-Altai Standard Time,001,Asia/Barnaul
-Altai Standard Time,RU,Asia/Barnaul
-Arab Standard Time,001,Asia/Riyadh
-Arab Standard Time,BH,Asia/Bahrain
-Arab Standard Time,KW,Asia/Kuwait
-Arab Standard Time,QA,Asia/Qatar
-Arab Standard Time,SA,Asia/Riyadh
-Arab Standard Time,YE,Asia/Aden
-Arabian Standard Time,001,Asia/Dubai
-Arabian Standard Time,AE,Asia/Dubai
-Arabian Standard Time,OM,Asia/Muscat
-Arabian Standard Time,ZZ,Etc/GMT-4
-Arabic Standard Time,001,Asia/Baghdad
-Arabic Standard Time,IQ,Asia/Baghdad
-Argentina Standard Time,001,America/Buenos_Aires
-Argentina Standard Time,AR,America/Buenos_Aires America/Argentina/La_Rioja America/Argentina/Rio_Gallegos America/Argentina/Salta America/Argentina/San_Juan America/Argentina/San_Luis America/Argentina/Tucuman America/Argentina/Ushuaia America/Catamarca America/Cordoba America/Jujuy America/Mendoza
-Astrakhan Standard Time,001,Europe/Astrakhan
-Astrakhan Standard Time,RU,Europe/Astrakhan Europe/Ulyanovsk
-Atlantic Standard Time,001,America/Halifax
-Atlantic Standard Time,BM,Atlantic/Bermuda
-Atlantic Standard Time,CA,America/Halifax America/Glace_Bay America/Goose_Bay America/Moncton
-Atlantic Standard Time,GL,America/Thule
-Aus Central W. Standard Time,001,Australia/Eucla
-Aus Central W. Standard Time,AU,Australia/Eucla
-Azerbaijan Standard Time,001,Asia/Baku
-Azerbaijan Standard Time,AZ,Asia/Baku
-Azores Standard Time,001,Atlantic/Azores
-Azores Standard Time,GL,America/Scoresbysund
-Azores Standard Time,PT,Atlantic/Azores
-Bahia Standard Time,001,America/Bahia
-Bahia Standard Time,BR,America/Bahia
-Bangladesh Standard Time,001,Asia/Dhaka
-Bangladesh Standard Time,BD,Asia/Dhaka
-Bangladesh Standard Time,BT,Asia/Thimphu
-Belarus Standard Time,001,Europe/Minsk
-Belarus Standard Time,BY,Europe/Minsk
-Bougainville Standard Time,001,Pacific/Bougainville
-Bougainville Standard Time,PG,Pacific/Bougainville
-Canada Central Standard Time,001,America/Regina
-Canada Central Standard Time,CA,America/Regina America/Swift_Current
-Cape Verde Standard Time,001,Atlantic/Cape_Verde
-Cape Verde Standard Time,CV,Atlantic/Cape_Verde
-Cape Verde Standard Time,ZZ,Etc/GMT+1
-Caucasus Standard Time,001,Asia/Yerevan
-Caucasus Standard Time,AM,Asia/Yerevan
-Cen. Australia Standard Time,001,Australia/Adelaide
-Cen. Australia Standard Time,AU,Australia/Adelaide Australia/Broken_Hill
-Central America Standard Time,001,America/Guatemala
-Central America Standard Time,BZ,America/Belize
-Central America Standard Time,CR,America/Costa_Rica
-Central America Standard Time,EC,Pacific/Galapagos
-Central America Standard Time,GT,America/Guatemala
-Central America Standard Time,HN,America/Tegucigalpa
-Central America Standard Time,NI,America/Managua
-Central America Standard Time,SV,America/El_Salvador
-Central America Standard Time,ZZ,Etc/GMT+6
-Central Asia Standard Time,001,Asia/Almaty
-Central Asia Standard Time,AQ,Antarctica/Vostok
-Central Asia Standard Time,CN,Asia/Urumqi
-Central Asia Standard Time,DG,Indian/Chagos
-Central Asia Standard Time,IO,Indian/Chagos
-Central Asia Standard Time,KG,Asia/Bishkek
-Central Asia Standard Time,KZ,Asia/Almaty Asia/Qostanay
-Central Asia Standard Time,ZZ,Etc/GMT-6
-Central Brazilian Standard Time,001,America/Cuiaba
-Central Brazilian Standard Time,BR,America/Cuiaba America/Campo_Grande
-Central Europe Standard Time,001,Europe/Budapest
-Central Europe Standard Time,AL,Europe/Tirane
-Central Europe Standard Time,CZ,Europe/Prague
-Central Europe Standard Time,HU,Europe/Budapest
-Central Europe Standard Time,ME,Europe/Podgorica
-Central Europe Standard Time,RS,Europe/Belgrade
-Central Europe Standard Time,SI,Europe/Ljubljana
-Central Europe Standard Time,SK,Europe/Bratislava
-Central Europe Standard Time,XK,Europe/Belgrade
-Central European Standard Time,001,Europe/Warsaw
-Central European Standard Time,BA,Europe/Sarajevo
-Central European Standard Time,HR,Europe/Zagreb
-Central European Standard Time,MK,Europe/Skopje
-Central European Standard Time,PL,Europe/Warsaw
-Central Pacific Standard Time,001,Pacific/Guadalcanal
-Central Pacific Standard Time,AQ,Antarctica/Casey
-Central Pacific Standard Time,FM,Pacific/Ponape Pacific/Kosrae
-Central Pacific Standard Time,NC,Pacific/Noumea
-Central Pacific Standard Time,SB,Pacific/Guadalcanal
-Central Pacific Standard Time,VU,Pacific/Efate
-Central Pacific Standard Time,ZZ,Etc/GMT-11
-Central Standard Time (Mexico),001,America/Mexico_City
-Central Standard Time (Mexico),MX,America/Mexico_City America/Bahia_Banderas America/Merida America/Monterrey
-Central Standard Time,001,America/Chicago
-Central Standard Time,CA,America/Winnipeg America/Rainy_River America/Rankin_Inlet America/Resolute
-Central Standard Time,MX,America/Matamoros
-Central Standard Time,US,America/Chicago America/Indiana/Knox America/Indiana/Tell_City America/Menominee America/North_Dakota/Beulah America/North_Dakota/Center America/North_Dakota/New_Salem
-Central Standard Time,ZZ,CST6CDT
-Chatham Islands Standard Time,001,Pacific/Chatham
-Chatham Islands Standard Time,NZ,Pacific/Chatham
-China Standard Time,001,Asia/Shanghai
-China Standard Time,CN,Asia/Shanghai
-China Standard Time,HK,Asia/Hong_Kong
-China Standard Time,MO,Asia/Macau
-Cuba Standard Time,001,America/Havana
-Cuba Standard Time,CU,America/Havana
-Dateline Standard Time,001,Etc/GMT+12
-Dateline Standard Time,ZZ,Etc/GMT+12
-E. Africa Standard Time,001,Africa/Nairobi
-E. Africa Standard Time,AQ,Antarctica/Syowa
-E. Africa Standard Time,DJ,Africa/Djibouti
-E. Africa Standard Time,ER,Africa/Asmera
-E. Africa Standard Time,ET,Africa/Addis_Ababa
-E. Africa Standard Time,KE,Africa/Nairobi
-E. Africa Standard Time,KM,Indian/Comoro
-E. Africa Standard Time,MG,Indian/Antananarivo
-E. Africa Standard Time,SO,Africa/Mogadishu
-E. Africa Standard Time,TZ,Africa/Dar_es_Salaam
-E. Africa Standard Time,UG,Africa/Kampala
-E. Africa Standard Time,YT,Indian/Mayotte
-E. Africa Standard Time,ZZ,Etc/GMT-3
-E. Australia Standard Time,001,Australia/Brisbane
-E. Australia Standard Time,AU,Australia/Brisbane Australia/Lindeman
-E. Europe Standard Time,001,Europe/Chisinau
-E. Europe Standard Time,MD,Europe/Chisinau
-E. South America Standard Time,001,America/Sao_Paulo
-E. South America Standard Time,BR,America/Sao_Paulo
-Easter Island Standard Time,001,Pacific/Easter
-Easter Island Standard Time,CL,Pacific/Easter
-Eastern Standard Time (Mexico),001,America/Cancun
-Eastern Standard Time (Mexico),MX,America/Cancun
-Eastern Standard Time,001,America/New_York
-Eastern Standard Time,BS,America/Nassau
-Eastern Standard Time,CA,America/Toronto America/Iqaluit America/Montreal America/Nipigon America/Pangnirtung America/Thunder_Bay
-Eastern Standard Time,US,America/New_York America/Detroit America/Indiana/Petersburg America/Indiana/Vincennes America/Indiana/Winamac America/Kentucky/Monticello America/Louisville
-Eastern Standard Time,ZZ,EST5EDT
-Egypt Standard Time,001,Africa/Cairo
-Egypt Standard Time,EG,Africa/Cairo
-Ekaterinburg Standard Time,001,Asia/Yekaterinburg
-Ekaterinburg Standard Time,RU,Asia/Yekaterinburg
-FLE Standard Time,001,Europe/Kiev
-FLE Standard Time,AX,Europe/Mariehamn
-FLE Standard Time,BG,Europe/Sofia
-FLE Standard Time,EE,Europe/Tallinn
-FLE Standard Time,FI,Europe/Helsinki
-FLE Standard Time,LT,Europe/Vilnius
-FLE Standard Time,LV,Europe/Riga
-FLE Standard Time,UA,Europe/Kiev Europe/Uzhgorod Europe/Zaporozhye
-Fiji Standard Time,001,Pacific/Fiji
-Fiji Standard Time,FJ,Pacific/Fiji
-GMT Standard Time,001,Europe/London
-GMT Standard Time,ES,Atlantic/Canary
-GMT Standard Time,FO,Atlantic/Faeroe
-GMT Standard Time,GB,Europe/London
-GMT Standard Time,GG,Europe/Guernsey
-GMT Standard Time,IC,Atlantic/Canary
-GMT Standard Time,IE,Europe/Dublin
-GMT Standard Time,IM,Europe/Isle_of_Man
-GMT Standard Time,JE,Europe/Jersey
-GMT Standard Time,PT,Europe/Lisbon Atlantic/Madeira
-GTB Standard Time,001,Europe/Bucharest
-GTB Standard Time,CY,Asia/Nicosia Asia/Famagusta
-GTB Standard Time,GR,Europe/Athens
-GTB Standard Time,RO,Europe/Bucharest
-Georgian Standard Time,001,Asia/Tbilisi
-Georgian Standard Time,GE,Asia/Tbilisi
-Greenland Standard Time,001,America/Godthab
-Greenland Standard Time,GL,America/Godthab
-Greenwich Standard Time,001,Atlantic/Reykjavik
-Greenwich Standard Time,AC,Atlantic/St_Helena
-Greenwich Standard Time,BF,Africa/Ouagadougou
-Greenwich Standard Time,CI,Africa/Abidjan
-Greenwich Standard Time,GH,Africa/Accra
-Greenwich Standard Time,GL,America/Danmarkshavn
-Greenwich Standard Time,GM,Africa/Banjul
-Greenwich Standard Time,GN,Africa/Conakry
-Greenwich Standard Time,GW,Africa/Bissau
-Greenwich Standard Time,IS,Atlantic/Reykjavik
-Greenwich Standard Time,LR,Africa/Monrovia
-Greenwich Standard Time,ML,Africa/Bamako
-Greenwich Standard Time,MR,Africa/Nouakchott
-Greenwich Standard Time,SH,Atlantic/St_Helena
-Greenwich Standard Time,SL,Africa/Freetown
-Greenwich Standard Time,SN,Africa/Dakar
-Greenwich Standard Time,TA,Atlantic/St_Helena
-Greenwich Standard Time,TG,Africa/Lome
-Haiti Standard Time,001,America/Port-au-Prince
-Haiti Standard Time,HT,America/Port-au-Prince
-Hawaiian Standard Time,001,Pacific/Honolulu
-Hawaiian Standard Time,CK,Pacific/Rarotonga
-Hawaiian Standard Time,PF,Pacific/Tahiti
-Hawaiian Standard Time,UM,Pacific/Johnston
-Hawaiian Standard Time,US,Pacific/Honolulu
-Hawaiian Standard Time,ZZ,Etc/GMT+10
-India Standard Time,001,Asia/Calcutta
-India Standard Time,IN,Asia/Calcutta
-Iran Standard Time,001,Asia/Tehran
-Iran Standard Time,IR,Asia/Tehran
-Israel Standard Time,001,Asia/Jerusalem
-Israel Standard Time,IL,Asia/Jerusalem
-Jordan Standard Time,001,Asia/Amman
-Jordan Standard Time,JO,Asia/Amman
-Kaliningrad Standard Time,001,Europe/Kaliningrad
-Kaliningrad Standard Time,RU,Europe/Kaliningrad
-Korea Standard Time,001,Asia/Seoul
-Korea Standard Time,KR,Asia/Seoul
-Libya Standard Time,001,Africa/Tripoli
-Libya Standard Time,LY,Africa/Tripoli
-Line Islands Standard Time,001,Pacific/Kiritimati
-Line Islands Standard Time,KI,Pacific/Kiritimati
-Line Islands Standard Time,ZZ,Etc/GMT-14
-Lord Howe Standard Time,001,Australia/Lord_Howe
-Lord Howe Standard Time,AU,Australia/Lord_Howe
-Magadan Standard Time,001,Asia/Magadan
-Magadan Standard Time,RU,Asia/Magadan
-Magallanes Standard Time,001,America/Punta_Arenas
-Magallanes Standard Time,CL,America/Punta_Arenas
-Marquesas Standard Time,001,Pacific/Marquesas
-Marquesas Standard Time,PF,Pacific/Marquesas
-Mauritius Standard Time,001,Indian/Mauritius
-Mauritius Standard Time,MU,Indian/Mauritius
-Mauritius Standard Time,RE,Indian/Reunion
-Mauritius Standard Time,SC,Indian/Mahe
-Middle East Standard Time,001,Asia/Beirut
-Middle East Standard Time,LB,Asia/Beirut
-Montevideo Standard Time,001,America/Montevideo
-Montevideo Standard Time,UY,America/Montevideo
-Morocco Standard Time,001,Africa/Casablanca
-Morocco Standard Time,EH,Africa/El_Aaiun
-Morocco Standard Time,MA,Africa/Casablanca
-Mountain Standard Time (Mexico),001,America/Chihuahua
-Mountain Standard Time (Mexico),MX,America/Chihuahua America/Mazatlan
-Mountain Standard Time,001,America/Denver
-Mountain Standard Time,CA,America/Edmonton America/Cambridge_Bay America/Inuvik America/Yellowknife
-Mountain Standard Time,MX,America/Ojinaga
-Mountain Standard Time,US,America/Denver America/Boise
-Mountain Standard Time,ZZ,MST7MDT
-Myanmar Standard Time,001,Asia/Rangoon
-Myanmar Standard Time,CC,Indian/Cocos
-Myanmar Standard Time,MM,Asia/Rangoon
-N. Central Asia Standard Time,001,Asia/Novosibirsk
-N. Central Asia Standard Time,RU,Asia/Novosibirsk
-Namibia Standard Time,001,Africa/Windhoek
-Namibia Standard Time,NA,Africa/Windhoek
-Nepal Standard Time,001,Asia/Katmandu
-Nepal Standard Time,NP,Asia/Katmandu
-New Zealand Standard Time,001,Pacific/Auckland
-New Zealand Standard Time,AQ,Antarctica/McMurdo
-New Zealand Standard Time,NZ,Pacific/Auckland
-Newfoundland Standard Time,001,America/St_Johns
-Newfoundland Standard Time,CA,America/St_Johns
-Norfolk Standard Time,001,Pacific/Norfolk
-Norfolk Standard Time,NF,Pacific/Norfolk
-North Asia East Standard Time,001,Asia/Irkutsk
-North Asia East Standard Time,RU,Asia/Irkutsk
-North Asia Standard Time,001,Asia/Krasnoyarsk
-North Asia Standard Time,RU,Asia/Krasnoyarsk Asia/Novokuznetsk
-North Korea Standard Time,001,Asia/Pyongyang
-North Korea Standard Time,KP,Asia/Pyongyang
-Omsk Standard Time,001,Asia/Omsk
-Omsk Standard Time,RU,Asia/Omsk
-Pacific SA Standard Time,001,America/Santiago
-Pacific SA Standard Time,CL,America/Santiago
-Pacific Standard Time (Mexico),001,America/Tijuana
-Pacific Standard Time (Mexico),MX,America/Tijuana America/Santa_Isabel
-Pacific Standard Time,001,America/Los_Angeles
-Pacific Standard Time,CA,America/Vancouver
-Pacific Standard Time,US,America/Los_Angeles
-Pacific Standard Time,ZZ,PST8PDT
-Pakistan Standard Time,001,Asia/Karachi
-Pakistan Standard Time,PK,Asia/Karachi
-Paraguay Standard Time,001,America/Asuncion
-Paraguay Standard Time,PY,America/Asuncion
-Qyzylorda Standard Time,001,Asia/Qyzylorda
-Qyzylorda Standard Time,KZ,Asia/Qyzylorda
-Romance Standard Time,001,Europe/Paris
-Romance Standard Time,BE,Europe/Brussels
-Romance Standard Time,DK,Europe/Copenhagen
-Romance Standard Time,EA,Africa/Ceuta
-Romance Standard Time,ES,Europe/Madrid Africa/Ceuta
-Romance Standard Time,FR,Europe/Paris
-Russia Time Zone 10,001,Asia/Srednekolymsk
-Russia Time Zone 10,RU,Asia/Srednekolymsk
-Russia Time Zone 11,001,Asia/Kamchatka
-Russia Time Zone 11,RU,Asia/Kamchatka Asia/Anadyr
-Russia Time Zone 3,001,Europe/Samara
-Russia Time Zone 3,RU,Europe/Samara
-Russian Standard Time,001,Europe/Moscow
-Russian Standard Time,RU,Europe/Moscow Europe/Kirov
-Russian Standard Time,UA,Europe/Simferopol
-SA Eastern Standard Time,001,America/Cayenne
-SA Eastern Standard Time,AQ,Antarctica/Rothera Antarctica/Palmer
-SA Eastern Standard Time,BR,America/Fortaleza America/Belem America/Maceio America/Recife America/Santarem
-SA Eastern Standard Time,FK,Atlantic/Stanley
-SA Eastern Standard Time,GF,America/Cayenne
-SA Eastern Standard Time,SR,America/Paramaribo
-SA Eastern Standard Time,ZZ,Etc/GMT+3
-SA Pacific Standard Time,001,America/Bogota
-SA Pacific Standard Time,BR,America/Rio_Branco America/Eirunepe
-SA Pacific Standard Time,CA,America/Coral_Harbour
-SA Pacific Standard Time,CO,America/Bogota
-SA Pacific Standard Time,EC,America/Guayaquil
-SA Pacific Standard Time,JM,America/Jamaica
-SA Pacific Standard Time,KY,America/Cayman
-SA Pacific Standard Time,PA,America/Panama
-SA Pacific Standard Time,PE,America/Lima
-SA Pacific Standard Time,ZZ,Etc/GMT+5
-SA Western Standard Time,001,America/La_Paz
-SA Western Standard Time,AG,America/Antigua
-SA Western Standard Time,AI,America/Anguilla
-SA Western Standard Time,AW,America/Aruba
-SA Western Standard Time,BB,America/Barbados
-SA Western Standard Time,BL,America/St_Barthelemy
-SA Western Standard Time,BO,America/La_Paz
-SA Western Standard Time,BQ,America/Kralendijk
-SA Western Standard Time,BR,America/Manaus America/Boa_Vista America/Porto_Velho
-SA Western Standard Time,CA,America/Blanc-Sablon
-SA Western Standard Time,CW,America/Curacao
-SA Western Standard Time,DM,America/Dominica
-SA Western Standard Time,DO,America/Santo_Domingo
-SA Western Standard Time,GD,America/Grenada
-SA Western Standard Time,GP,America/Guadeloupe
-SA Western Standard Time,GY,America/Guyana
-SA Western Standard Time,KN,America/St_Kitts
-SA Western Standard Time,LC,America/St_Lucia
-SA Western Standard Time,MF,America/Marigot
-SA Western Standard Time,MQ,America/Martinique
-SA Western Standard Time,MS,America/Montserrat
-SA Western Standard Time,PR,America/Puerto_Rico
-SA Western Standard Time,SX,America/Lower_Princes
-SA Western Standard Time,TT,America/Port_of_Spain
-SA Western Standard Time,VC,America/St_Vincent
-SA Western Standard Time,VG,America/Tortola
-SA Western Standard Time,VI,America/St_Thomas
-SA Western Standard Time,ZZ,Etc/GMT+4
-SE Asia Standard Time,001,Asia/Bangkok
-SE Asia Standard Time,AQ,Antarctica/Davis
-SE Asia Standard Time,CX,Indian/Christmas
-SE Asia Standard Time,ID,Asia/Jakarta Asia/Pontianak
-SE Asia Standard Time,KH,Asia/Phnom_Penh
-SE Asia Standard Time,LA,Asia/Vientiane
-SE Asia Standard Time,TH,Asia/Bangkok
-SE Asia Standard Time,VN,Asia/Saigon
-SE Asia Standard Time,ZZ,Etc/GMT-7
-Saint Pierre Standard Time,001,America/Miquelon
-Saint Pierre Standard Time,PM,America/Miquelon
-Sakhalin Standard Time,001,Asia/Sakhalin
-Sakhalin Standard Time,RU,Asia/Sakhalin
-Samoa Standard Time,001,Pacific/Apia
-Samoa Standard Time,WS,Pacific/Apia
-Sao Tome Standard Time,001,Africa/Sao_Tome
-Sao Tome Standard Time,ST,Africa/Sao_Tome
-Saratov Standard Time,001,Europe/Saratov
-Saratov Standard Time,RU,Europe/Saratov
-Singapore Standard Time,001,Asia/Singapore
-Singapore Standard Time,BN,Asia/Brunei
-Singapore Standard Time,ID,Asia/Makassar
-Singapore Standard Time,MY,Asia/Kuala_Lumpur Asia/Kuching
-Singapore Standard Time,PH,Asia/Manila
-Singapore Standard Time,SG,Asia/Singapore
-Singapore Standard Time,ZZ,Etc/GMT-8
-South Africa Standard Time,001,Africa/Johannesburg
-South Africa Standard Time,BI,Africa/Bujumbura
-South Africa Standard Time,BW,Africa/Gaborone
-South Africa Standard Time,CD,Africa/Lubumbashi
-South Africa Standard Time,LS,Africa/Maseru
-South Africa Standard Time,MW,Africa/Blantyre
-South Africa Standard Time,MZ,Africa/Maputo
-South Africa Standard Time,RW,Africa/Kigali
-South Africa Standard Time,SZ,Africa/Mbabane
-South Africa Standard Time,ZA,Africa/Johannesburg
-South Africa Standard Time,ZM,Africa/Lusaka
-South Africa Standard Time,ZW,Africa/Harare
-South Africa Standard Time,ZZ,Etc/GMT-2
-South Sudan Standard Time,001,Africa/Juba
-South Sudan Standard Time,SS,Africa/Juba
-Sri Lanka Standard Time,001,Asia/Colombo
-Sri Lanka Standard Time,LK,Asia/Colombo
-Sudan Standard Time,001,Africa/Khartoum
-Sudan Standard Time,SD,Africa/Khartoum
-Syria Standard Time,001,Asia/Damascus
-Syria Standard Time,SY,Asia/Damascus
-Taipei Standard Time,001,Asia/Taipei
-Taipei Standard Time,TW,Asia/Taipei
-Tasmania Standard Time,001,Australia/Hobart
-Tasmania Standard Time,AU,Australia/Hobart Australia/Currie Antarctica/Macquarie
-Tocantins Standard Time,001,America/Araguaina
-Tocantins Standard Time,BR,America/Araguaina
-Tokyo Standard Time,001,Asia/Tokyo
-Tokyo Standard Time,ID,Asia/Jayapura
-Tokyo Standard Time,JP,Asia/Tokyo
-Tokyo Standard Time,PW,Pacific/Palau
-Tokyo Standard Time,TL,Asia/Dili
-Tokyo Standard Time,ZZ,Etc/GMT-9
-Tomsk Standard Time,001,Asia/Tomsk
-Tomsk Standard Time,RU,Asia/Tomsk
-Tonga Standard Time,001,Pacific/Tongatapu
-Tonga Standard Time,TO,Pacific/Tongatapu
-Transbaikal Standard Time,001,Asia/Chita
-Transbaikal Standard Time,RU,Asia/Chita
-Turkey Standard Time,001,Europe/Istanbul
-Turkey Standard Time,TR,Europe/Istanbul
-Turks And Caicos Standard Time,001,America/Grand_Turk
-Turks And Caicos Standard Time,TC,America/Grand_Turk
-US Eastern Standard Time,001,America/Indianapolis
-US Eastern Standard Time,US,America/Indianapolis America/Indiana/Marengo America/Indiana/Vevay
-US Mountain Standard Time,001,America/Phoenix
-US Mountain Standard Time,CA,America/Creston America/Dawson_Creek America/Fort_Nelson
-US Mountain Standard Time,MX,America/Hermosillo
-US Mountain Standard Time,US,America/Phoenix
-US Mountain Standard Time,ZZ,Etc/GMT+7
-UTC+12,001,Etc/GMT-12
-UTC+12,KI,Pacific/Tarawa
-UTC+12,MH,Pacific/Majuro Pacific/Kwajalein
-UTC+12,NR,Pacific/Nauru
-UTC+12,TV,Pacific/Funafuti
-UTC+12,UM,Pacific/Wake
-UTC+12,WF,Pacific/Wallis
-UTC+12,ZZ,Etc/GMT-12
-UTC+13,001,Etc/GMT-13
-UTC+13,KI,Pacific/Enderbury
-UTC+13,TK,Pacific/Fakaofo
-UTC+13,ZZ,Etc/GMT-13
-UTC,001,Etc/UTC
-UTC,ZZ,Etc/UTC Etc/GMT
-UTC-02,001,Etc/GMT+2
-UTC-02,BR,America/Noronha
-UTC-02,GS,Atlantic/South_Georgia
-UTC-02,ZZ,Etc/GMT+2
-UTC-08,001,Etc/GMT+8
-UTC-08,PN,Pacific/Pitcairn
-UTC-08,ZZ,Etc/GMT+8
-UTC-09,001,Etc/GMT+9
-UTC-09,PF,Pacific/Gambier
-UTC-09,ZZ,Etc/GMT+9
-UTC-11,001,Etc/GMT+11
-UTC-11,AS,Pacific/Pago_Pago
-UTC-11,NU,Pacific/Niue
-UTC-11,UM,Pacific/Midway
-UTC-11,ZZ,Etc/GMT+11
-Ulaanbaatar Standard Time,001,Asia/Ulaanbaatar
-Ulaanbaatar Standard Time,MN,Asia/Ulaanbaatar Asia/Choibalsan
-Venezuela Standard Time,001,America/Caracas
-Venezuela Standard Time,VE,America/Caracas
-Vladivostok Standard Time,001,Asia/Vladivostok
-Vladivostok Standard Time,RU,Asia/Vladivostok Asia/Ust-Nera
-Volgograd Standard Time,001,Europe/Volgograd
-Volgograd Standard Time,RU,Europe/Volgograd
-W. Australia Standard Time,001,Australia/Perth
-W. Australia Standard Time,AU,Australia/Perth
-W. Central Africa Standard Time,001,Africa/Lagos
-W. Central Africa Standard Time,AO,Africa/Luanda
-W. Central Africa Standard Time,BJ,Africa/Porto-Novo
-W. Central Africa Standard Time,CD,Africa/Kinshasa
-W. Central Africa Standard Time,CF,Africa/Bangui
-W. Central Africa Standard Time,CG,Africa/Brazzaville
-W. Central Africa Standard Time,CM,Africa/Douala
-W. Central Africa Standard Time,DZ,Africa/Algiers
-W. Central Africa Standard Time,GA,Africa/Libreville
-W. Central Africa Standard Time,GQ,Africa/Malabo
-W. Central Africa Standard Time,NE,Africa/Niamey
-W. Central Africa Standard Time,NG,Africa/Lagos
-W. Central Africa Standard Time,TD,Africa/Ndjamena
-W. Central Africa Standard Time,TN,Africa/Tunis
-W. Central Africa Standard Time,ZZ,Etc/GMT-1
-W. Europe Standard Time,001,Europe/Berlin
-W. Europe Standard Time,AD,Europe/Andorra
-W. Europe Standard Time,AT,Europe/Vienna
-W. Europe Standard Time,CH,Europe/Zurich
-W. Europe Standard Time,DE,Europe/Berlin Europe/Busingen
-W. Europe Standard Time,GI,Europe/Gibraltar
-W. Europe Standard Time,IT,Europe/Rome
-W. Europe Standard Time,LI,Europe/Vaduz
-W. Europe Standard Time,LU,Europe/Luxembourg
-W. Europe Standard Time,MC,Europe/Monaco
-W. Europe Standard Time,MT,Europe/Malta
-W. Europe Standard Time,NL,Europe/Amsterdam
-W. Europe Standard Time,NO,Europe/Oslo
-W. Europe Standard Time,SE,Europe/Stockholm
-W. Europe Standard Time,SJ,Arctic/Longyearbyen
-W. Europe Standard Time,SM,Europe/San_Marino
-W. Europe Standard Time,VA,Europe/Vatican
-W. Mongolia Standard Time,001,Asia/Hovd
-W. Mongolia Standard Time,MN,Asia/Hovd
-West Asia Standard Time,001,Asia/Tashkent
-West Asia Standard Time,AQ,Antarctica/Mawson
-West Asia Standard Time,KZ,Asia/Oral Asia/Aqtau Asia/Aqtobe Asia/Atyrau
-West Asia Standard Time,MV,Indian/Maldives
-West Asia Standard Time,TF,Indian/Kerguelen
-West Asia Standard Time,TJ,Asia/Dushanbe
-West Asia Standard Time,TM,Asia/Ashgabat
-West Asia Standard Time,UZ,Asia/Tashkent Asia/Samarkand
-West Asia Standard Time,ZZ,Etc/GMT-5
-West Bank Standard Time,001,Asia/Hebron
-West Bank Standard Time,PS,Asia/Hebron Asia/Gaza
-West Pacific Standard Time,001,Pacific/Port_Moresby
-West Pacific Standard Time,AQ,Antarctica/DumontDUrville
-West Pacific Standard Time,FM,Pacific/Truk
-West Pacific Standard Time,GU,Pacific/Guam
-West Pacific Standard Time,MP,Pacific/Saipan
-West Pacific Standard Time,PG,Pacific/Port_Moresby
-West Pacific Standard Time,ZZ,Etc/GMT-10
-Yakutsk Standard Time,001,Asia/Yakutsk
-Yakutsk Standard Time,RU,Asia/Yakutsk Asia/Khandyga
-Yukon Standard Time,001,America/Whitehorse
-Yukon Standard Time,CA,America/Whitehorse America/Dawson
-Kamchatka Standard Time,001,Asia/Kamchatka
-Mid-Atlantic Standard Time,001,Etc/GMT+2
+AUS Central Standard Time,001,Australia/Darwin
+AUS Central Standard Time,AU,Australia/Darwin
+AUS Eastern Standard Time,001,Australia/Sydney
+AUS Eastern Standard Time,AU,Australia/Sydney Australia/Melbourne
+Afghanistan Standard Time,001,Asia/Kabul
+Afghanistan Standard Time,AF,Asia/Kabul
+Alaskan Standard Time,001,America/Anchorage
+Alaskan Standard Time,US,America/Anchorage America/Juneau America/Metlakatla America/Nome America/Sitka America/Yakutat
+Aleutian Standard Time,001,America/Adak
+Aleutian Standard Time,US,America/Adak
+Altai Standard Time,001,Asia/Barnaul
+Altai Standard Time,RU,Asia/Barnaul
+Arab Standard Time,001,Asia/Riyadh
+Arab Standard Time,BH,Asia/Bahrain
+Arab Standard Time,KW,Asia/Kuwait
+Arab Standard Time,QA,Asia/Qatar
+Arab Standard Time,SA,Asia/Riyadh
+Arab Standard Time,YE,Asia/Aden
+Arabian Standard Time,001,Asia/Dubai
+Arabian Standard Time,AE,Asia/Dubai
+Arabian Standard Time,OM,Asia/Muscat
+Arabian Standard Time,ZZ,Etc/GMT-4
+Arabic Standard Time,001,Asia/Baghdad
+Arabic Standard Time,IQ,Asia/Baghdad
+Argentina Standard Time,001,America/Buenos_Aires
+Argentina Standard Time,AR,America/Buenos_Aires America/Argentina/La_Rioja America/Argentina/Rio_Gallegos America/Argentina/Salta America/Argentina/San_Juan America/Argentina/San_Luis America/Argentina/Tucuman America/Argentina/Ushuaia America/Catamarca America/Cordoba America/Jujuy America/Mendoza
+Astrakhan Standard Time,001,Europe/Astrakhan
+Astrakhan Standard Time,RU,Europe/Astrakhan Europe/Ulyanovsk
+Atlantic Standard Time,001,America/Halifax
+Atlantic Standard Time,BM,Atlantic/Bermuda
+Atlantic Standard Time,CA,America/Halifax America/Glace_Bay America/Goose_Bay America/Moncton
+Atlantic Standard Time,GL,America/Thule
+Aus Central W. Standard Time,001,Australia/Eucla
+Aus Central W. Standard Time,AU,Australia/Eucla
+Azerbaijan Standard Time,001,Asia/Baku
+Azerbaijan Standard Time,AZ,Asia/Baku
+Azores Standard Time,001,Atlantic/Azores
+Azores Standard Time,GL,America/Scoresbysund
+Azores Standard Time,PT,Atlantic/Azores
+Bahia Standard Time,001,America/Bahia
+Bahia Standard Time,BR,America/Bahia
+Bangladesh Standard Time,001,Asia/Dhaka
+Bangladesh Standard Time,BD,Asia/Dhaka
+Bangladesh Standard Time,BT,Asia/Thimphu
+Belarus Standard Time,001,Europe/Minsk
+Belarus Standard Time,BY,Europe/Minsk
+Bougainville Standard Time,001,Pacific/Bougainville
+Bougainville Standard Time,PG,Pacific/Bougainville
+Canada Central Standard Time,001,America/Regina
+Canada Central Standard Time,CA,America/Regina America/Swift_Current
+Cape Verde Standard Time,001,Atlantic/Cape_Verde
+Cape Verde Standard Time,CV,Atlantic/Cape_Verde
+Cape Verde Standard Time,ZZ,Etc/GMT+1
+Caucasus Standard Time,001,Asia/Yerevan
+Caucasus Standard Time,AM,Asia/Yerevan
+Cen. Australia Standard Time,001,Australia/Adelaide
+Cen. Australia Standard Time,AU,Australia/Adelaide Australia/Broken_Hill
+Central America Standard Time,001,America/Guatemala
+Central America Standard Time,BZ,America/Belize
+Central America Standard Time,CR,America/Costa_Rica
+Central America Standard Time,EC,Pacific/Galapagos
+Central America Standard Time,GT,America/Guatemala
+Central America Standard Time,HN,America/Tegucigalpa
+Central America Standard Time,NI,America/Managua
+Central America Standard Time,SV,America/El_Salvador
+Central America Standard Time,ZZ,Etc/GMT+6
+Central Asia Standard Time,001,Asia/Almaty
+Central Asia Standard Time,AQ,Antarctica/Vostok
+Central Asia Standard Time,CN,Asia/Urumqi
+Central Asia Standard Time,DG,Indian/Chagos
+Central Asia Standard Time,IO,Indian/Chagos
+Central Asia Standard Time,KG,Asia/Bishkek
+Central Asia Standard Time,KZ,Asia/Almaty Asia/Qostanay
+Central Asia Standard Time,ZZ,Etc/GMT-6
+Central Brazilian Standard Time,001,America/Cuiaba
+Central Brazilian Standard Time,BR,America/Cuiaba America/Campo_Grande
+Central Europe Standard Time,001,Europe/Budapest
+Central Europe Standard Time,AL,Europe/Tirane
+Central Europe Standard Time,CZ,Europe/Prague
+Central Europe Standard Time,HU,Europe/Budapest
+Central Europe Standard Time,ME,Europe/Podgorica
+Central Europe Standard Time,RS,Europe/Belgrade
+Central Europe Standard Time,SI,Europe/Ljubljana
+Central Europe Standard Time,SK,Europe/Bratislava
+Central Europe Standard Time,XK,Europe/Belgrade
+Central European Standard Time,001,Europe/Warsaw
+Central European Standard Time,BA,Europe/Sarajevo
+Central European Standard Time,HR,Europe/Zagreb
+Central European Standard Time,MK,Europe/Skopje
+Central European Standard Time,PL,Europe/Warsaw
+Central Pacific Standard Time,001,Pacific/Guadalcanal
+Central Pacific Standard Time,AQ,Antarctica/Casey
+Central Pacific Standard Time,FM,Pacific/Ponape Pacific/Kosrae
+Central Pacific Standard Time,NC,Pacific/Noumea
+Central Pacific Standard Time,SB,Pacific/Guadalcanal
+Central Pacific Standard Time,VU,Pacific/Efate
+Central Pacific Standard Time,ZZ,Etc/GMT-11
+Central Standard Time (Mexico),001,America/Mexico_City
+Central Standard Time (Mexico),MX,America/Mexico_City America/Bahia_Banderas America/Merida America/Monterrey
+Central Standard Time,001,America/Chicago
+Central Standard Time,CA,America/Winnipeg America/Rainy_River America/Rankin_Inlet America/Resolute
+Central Standard Time,MX,America/Matamoros
+Central Standard Time,US,America/Chicago America/Indiana/Knox America/Indiana/Tell_City America/Menominee America/North_Dakota/Beulah America/North_Dakota/Center America/North_Dakota/New_Salem
+Central Standard Time,ZZ,CST6CDT
+Chatham Islands Standard Time,001,Pacific/Chatham
+Chatham Islands Standard Time,NZ,Pacific/Chatham
+China Standard Time,001,Asia/Shanghai
+China Standard Time,CN,Asia/Shanghai
+China Standard Time,HK,Asia/Hong_Kong
+China Standard Time,MO,Asia/Macau
+Cuba Standard Time,001,America/Havana
+Cuba Standard Time,CU,America/Havana
+Dateline Standard Time,001,Etc/GMT+12
+Dateline Standard Time,ZZ,Etc/GMT+12
+E. Africa Standard Time,001,Africa/Nairobi
+E. Africa Standard Time,AQ,Antarctica/Syowa
+E. Africa Standard Time,DJ,Africa/Djibouti
+E. Africa Standard Time,ER,Africa/Asmera
+E. Africa Standard Time,ET,Africa/Addis_Ababa
+E. Africa Standard Time,KE,Africa/Nairobi
+E. Africa Standard Time,KM,Indian/Comoro
+E. Africa Standard Time,MG,Indian/Antananarivo
+E. Africa Standard Time,SO,Africa/Mogadishu
+E. Africa Standard Time,TZ,Africa/Dar_es_Salaam
+E. Africa Standard Time,UG,Africa/Kampala
+E. Africa Standard Time,YT,Indian/Mayotte
+E. Africa Standard Time,ZZ,Etc/GMT-3
+E. Australia Standard Time,001,Australia/Brisbane
+E. Australia Standard Time,AU,Australia/Brisbane Australia/Lindeman
+E. Europe Standard Time,001,Europe/Chisinau
+E. Europe Standard Time,MD,Europe/Chisinau
+E. South America Standard Time,001,America/Sao_Paulo
+E. South America Standard Time,BR,America/Sao_Paulo
+Easter Island Standard Time,001,Pacific/Easter
+Easter Island Standard Time,CL,Pacific/Easter
+Eastern Standard Time (Mexico),001,America/Cancun
+Eastern Standard Time (Mexico),MX,America/Cancun
+Eastern Standard Time,001,America/New_York
+Eastern Standard Time,BS,America/Nassau
+Eastern Standard Time,CA,America/Toronto America/Iqaluit America/Montreal America/Nipigon America/Pangnirtung America/Thunder_Bay
+Eastern Standard Time,US,America/New_York America/Detroit America/Indiana/Petersburg America/Indiana/Vincennes America/Indiana/Winamac America/Kentucky/Monticello America/Louisville
+Eastern Standard Time,ZZ,EST5EDT
+Egypt Standard Time,001,Africa/Cairo
+Egypt Standard Time,EG,Africa/Cairo
+Ekaterinburg Standard Time,001,Asia/Yekaterinburg
+Ekaterinburg Standard Time,RU,Asia/Yekaterinburg
+FLE Standard Time,001,Europe/Kiev
+FLE Standard Time,AX,Europe/Mariehamn
+FLE Standard Time,BG,Europe/Sofia
+FLE Standard Time,EE,Europe/Tallinn
+FLE Standard Time,FI,Europe/Helsinki
+FLE Standard Time,LT,Europe/Vilnius
+FLE Standard Time,LV,Europe/Riga
+FLE Standard Time,UA,Europe/Kiev Europe/Uzhgorod Europe/Zaporozhye
+Fiji Standard Time,001,Pacific/Fiji
+Fiji Standard Time,FJ,Pacific/Fiji
+GMT Standard Time,001,Europe/London
+GMT Standard Time,ES,Atlantic/Canary
+GMT Standard Time,FO,Atlantic/Faeroe
+GMT Standard Time,GB,Europe/London
+GMT Standard Time,GG,Europe/Guernsey
+GMT Standard Time,IC,Atlantic/Canary
+GMT Standard Time,IE,Europe/Dublin
+GMT Standard Time,IM,Europe/Isle_of_Man
+GMT Standard Time,JE,Europe/Jersey
+GMT Standard Time,PT,Europe/Lisbon Atlantic/Madeira
+GTB Standard Time,001,Europe/Bucharest
+GTB Standard Time,CY,Asia/Nicosia Asia/Famagusta
+GTB Standard Time,GR,Europe/Athens
+GTB Standard Time,RO,Europe/Bucharest
+Georgian Standard Time,001,Asia/Tbilisi
+Georgian Standard Time,GE,Asia/Tbilisi
+Greenland Standard Time,001,America/Godthab
+Greenland Standard Time,GL,America/Godthab
+Greenwich Standard Time,001,Atlantic/Reykjavik
+Greenwich Standard Time,AC,Atlantic/St_Helena
+Greenwich Standard Time,BF,Africa/Ouagadougou
+Greenwich Standard Time,CI,Africa/Abidjan
+Greenwich Standard Time,GH,Africa/Accra
+Greenwich Standard Time,GL,America/Danmarkshavn
+Greenwich Standard Time,GM,Africa/Banjul
+Greenwich Standard Time,GN,Africa/Conakry
+Greenwich Standard Time,GW,Africa/Bissau
+Greenwich Standard Time,IS,Atlantic/Reykjavik
+Greenwich Standard Time,LR,Africa/Monrovia
+Greenwich Standard Time,ML,Africa/Bamako
+Greenwich Standard Time,MR,Africa/Nouakchott
+Greenwich Standard Time,SH,Atlantic/St_Helena
+Greenwich Standard Time,SL,Africa/Freetown
+Greenwich Standard Time,SN,Africa/Dakar
+Greenwich Standard Time,TA,Atlantic/St_Helena
+Greenwich Standard Time,TG,Africa/Lome
+Haiti Standard Time,001,America/Port-au-Prince
+Haiti Standard Time,HT,America/Port-au-Prince
+Hawaiian Standard Time,001,Pacific/Honolulu
+Hawaiian Standard Time,CK,Pacific/Rarotonga
+Hawaiian Standard Time,PF,Pacific/Tahiti
+Hawaiian Standard Time,UM,Pacific/Johnston
+Hawaiian Standard Time,US,Pacific/Honolulu
+Hawaiian Standard Time,ZZ,Etc/GMT+10
+India Standard Time,001,Asia/Calcutta
+India Standard Time,IN,Asia/Calcutta
+Iran Standard Time,001,Asia/Tehran
+Iran Standard Time,IR,Asia/Tehran
+Israel Standard Time,001,Asia/Jerusalem
+Israel Standard Time,IL,Asia/Jerusalem
+Jordan Standard Time,001,Asia/Amman
+Jordan Standard Time,JO,Asia/Amman
+Kaliningrad Standard Time,001,Europe/Kaliningrad
+Kaliningrad Standard Time,RU,Europe/Kaliningrad
+Korea Standard Time,001,Asia/Seoul
+Korea Standard Time,KR,Asia/Seoul
+Libya Standard Time,001,Africa/Tripoli
+Libya Standard Time,LY,Africa/Tripoli
+Line Islands Standard Time,001,Pacific/Kiritimati
+Line Islands Standard Time,KI,Pacific/Kiritimati
+Line Islands Standard Time,ZZ,Etc/GMT-14
+Lord Howe Standard Time,001,Australia/Lord_Howe
+Lord Howe Standard Time,AU,Australia/Lord_Howe
+Magadan Standard Time,001,Asia/Magadan
+Magadan Standard Time,RU,Asia/Magadan
+Magallanes Standard Time,001,America/Punta_Arenas
+Magallanes Standard Time,CL,America/Punta_Arenas
+Marquesas Standard Time,001,Pacific/Marquesas
+Marquesas Standard Time,PF,Pacific/Marquesas
+Mauritius Standard Time,001,Indian/Mauritius
+Mauritius Standard Time,MU,Indian/Mauritius
+Mauritius Standard Time,RE,Indian/Reunion
+Mauritius Standard Time,SC,Indian/Mahe
+Middle East Standard Time,001,Asia/Beirut
+Middle East Standard Time,LB,Asia/Beirut
+Montevideo Standard Time,001,America/Montevideo
+Montevideo Standard Time,UY,America/Montevideo
+Morocco Standard Time,001,Africa/Casablanca
+Morocco Standard Time,EH,Africa/El_Aaiun
+Morocco Standard Time,MA,Africa/Casablanca
+Mountain Standard Time (Mexico),001,America/Chihuahua
+Mountain Standard Time (Mexico),MX,America/Chihuahua America/Mazatlan
+Mountain Standard Time,001,America/Denver
+Mountain Standard Time,CA,America/Edmonton America/Cambridge_Bay America/Inuvik America/Yellowknife
+Mountain Standard Time,MX,America/Ojinaga
+Mountain Standard Time,US,America/Denver America/Boise
+Mountain Standard Time,ZZ,MST7MDT
+Myanmar Standard Time,001,Asia/Rangoon
+Myanmar Standard Time,CC,Indian/Cocos
+Myanmar Standard Time,MM,Asia/Rangoon
+N. Central Asia Standard Time,001,Asia/Novosibirsk
+N. Central Asia Standard Time,RU,Asia/Novosibirsk
+Namibia Standard Time,001,Africa/Windhoek
+Namibia Standard Time,NA,Africa/Windhoek
+Nepal Standard Time,001,Asia/Katmandu
+Nepal Standard Time,NP,Asia/Katmandu
+New Zealand Standard Time,001,Pacific/Auckland
+New Zealand Standard Time,AQ,Antarctica/McMurdo
+New Zealand Standard Time,NZ,Pacific/Auckland
+Newfoundland Standard Time,001,America/St_Johns
+Newfoundland Standard Time,CA,America/St_Johns
+Norfolk Standard Time,001,Pacific/Norfolk
+Norfolk Standard Time,NF,Pacific/Norfolk
+North Asia East Standard Time,001,Asia/Irkutsk
+North Asia East Standard Time,RU,Asia/Irkutsk
+North Asia Standard Time,001,Asia/Krasnoyarsk
+North Asia Standard Time,RU,Asia/Krasnoyarsk Asia/Novokuznetsk
+North Korea Standard Time,001,Asia/Pyongyang
+North Korea Standard Time,KP,Asia/Pyongyang
+Omsk Standard Time,001,Asia/Omsk
+Omsk Standard Time,RU,Asia/Omsk
+Pacific SA Standard Time,001,America/Santiago
+Pacific SA Standard Time,CL,America/Santiago
+Pacific Standard Time (Mexico),001,America/Tijuana
+Pacific Standard Time (Mexico),MX,America/Tijuana America/Santa_Isabel
+Pacific Standard Time,001,America/Los_Angeles
+Pacific Standard Time,CA,America/Vancouver
+Pacific Standard Time,US,America/Los_Angeles
+Pacific Standard Time,ZZ,PST8PDT
+Pakistan Standard Time,001,Asia/Karachi
+Pakistan Standard Time,PK,Asia/Karachi
+Paraguay Standard Time,001,America/Asuncion
+Paraguay Standard Time,PY,America/Asuncion
+Qyzylorda Standard Time,001,Asia/Qyzylorda
+Qyzylorda Standard Time,KZ,Asia/Qyzylorda
+Romance Standard Time,001,Europe/Paris
+Romance Standard Time,BE,Europe/Brussels
+Romance Standard Time,DK,Europe/Copenhagen
+Romance Standard Time,EA,Africa/Ceuta
+Romance Standard Time,ES,Europe/Madrid Africa/Ceuta
+Romance Standard Time,FR,Europe/Paris
+Russia Time Zone 10,001,Asia/Srednekolymsk
+Russia Time Zone 10,RU,Asia/Srednekolymsk
+Russia Time Zone 11,001,Asia/Kamchatka
+Russia Time Zone 11,RU,Asia/Kamchatka Asia/Anadyr
+Russia Time Zone 3,001,Europe/Samara
+Russia Time Zone 3,RU,Europe/Samara
+Russian Standard Time,001,Europe/Moscow
+Russian Standard Time,RU,Europe/Moscow Europe/Kirov
+Russian Standard Time,UA,Europe/Simferopol
+SA Eastern Standard Time,001,America/Cayenne
+SA Eastern Standard Time,AQ,Antarctica/Rothera Antarctica/Palmer
+SA Eastern Standard Time,BR,America/Fortaleza America/Belem America/Maceio America/Recife America/Santarem
+SA Eastern Standard Time,FK,Atlantic/Stanley
+SA Eastern Standard Time,GF,America/Cayenne
+SA Eastern Standard Time,SR,America/Paramaribo
+SA Eastern Standard Time,ZZ,Etc/GMT+3
+SA Pacific Standard Time,001,America/Bogota
+SA Pacific Standard Time,BR,America/Rio_Branco America/Eirunepe
+SA Pacific Standard Time,CA,America/Coral_Harbour
+SA Pacific Standard Time,CO,America/Bogota
+SA Pacific Standard Time,EC,America/Guayaquil
+SA Pacific Standard Time,JM,America/Jamaica
+SA Pacific Standard Time,KY,America/Cayman
+SA Pacific Standard Time,PA,America/Panama
+SA Pacific Standard Time,PE,America/Lima
+SA Pacific Standard Time,ZZ,Etc/GMT+5
+SA Western Standard Time,001,America/La_Paz
+SA Western Standard Time,AG,America/Antigua
+SA Western Standard Time,AI,America/Anguilla
+SA Western Standard Time,AW,America/Aruba
+SA Western Standard Time,BB,America/Barbados
+SA Western Standard Time,BL,America/St_Barthelemy
+SA Western Standard Time,BO,America/La_Paz
+SA Western Standard Time,BQ,America/Kralendijk
+SA Western Standard Time,BR,America/Manaus America/Boa_Vista America/Porto_Velho
+SA Western Standard Time,CA,America/Blanc-Sablon
+SA Western Standard Time,CW,America/Curacao
+SA Western Standard Time,DM,America/Dominica
+SA Western Standard Time,DO,America/Santo_Domingo
+SA Western Standard Time,GD,America/Grenada
+SA Western Standard Time,GP,America/Guadeloupe
+SA Western Standard Time,GY,America/Guyana
+SA Western Standard Time,KN,America/St_Kitts
+SA Western Standard Time,LC,America/St_Lucia
+SA Western Standard Time,MF,America/Marigot
+SA Western Standard Time,MQ,America/Martinique
+SA Western Standard Time,MS,America/Montserrat
+SA Western Standard Time,PR,America/Puerto_Rico
+SA Western Standard Time,SX,America/Lower_Princes
+SA Western Standard Time,TT,America/Port_of_Spain
+SA Western Standard Time,VC,America/St_Vincent
+SA Western Standard Time,VG,America/Tortola
+SA Western Standard Time,VI,America/St_Thomas
+SA Western Standard Time,ZZ,Etc/GMT+4
+SE Asia Standard Time,001,Asia/Bangkok
+SE Asia Standard Time,AQ,Antarctica/Davis
+SE Asia Standard Time,CX,Indian/Christmas
+SE Asia Standard Time,ID,Asia/Jakarta Asia/Pontianak
+SE Asia Standard Time,KH,Asia/Phnom_Penh
+SE Asia Standard Time,LA,Asia/Vientiane
+SE Asia Standard Time,TH,Asia/Bangkok
+SE Asia Standard Time,VN,Asia/Saigon
+SE Asia Standard Time,ZZ,Etc/GMT-7
+Saint Pierre Standard Time,001,America/Miquelon
+Saint Pierre Standard Time,PM,America/Miquelon
+Sakhalin Standard Time,001,Asia/Sakhalin
+Sakhalin Standard Time,RU,Asia/Sakhalin
+Samoa Standard Time,001,Pacific/Apia
+Samoa Standard Time,WS,Pacific/Apia
+Sao Tome Standard Time,001,Africa/Sao_Tome
+Sao Tome Standard Time,ST,Africa/Sao_Tome
+Saratov Standard Time,001,Europe/Saratov
+Saratov Standard Time,RU,Europe/Saratov
+Singapore Standard Time,001,Asia/Singapore
+Singapore Standard Time,BN,Asia/Brunei
+Singapore Standard Time,ID,Asia/Makassar
+Singapore Standard Time,MY,Asia/Kuala_Lumpur Asia/Kuching
+Singapore Standard Time,PH,Asia/Manila
+Singapore Standard Time,SG,Asia/Singapore
+Singapore Standard Time,ZZ,Etc/GMT-8
+South Africa Standard Time,001,Africa/Johannesburg
+South Africa Standard Time,BI,Africa/Bujumbura
+South Africa Standard Time,BW,Africa/Gaborone
+South Africa Standard Time,CD,Africa/Lubumbashi
+South Africa Standard Time,LS,Africa/Maseru
+South Africa Standard Time,MW,Africa/Blantyre
+South Africa Standard Time,MZ,Africa/Maputo
+South Africa Standard Time,RW,Africa/Kigali
+South Africa Standard Time,SZ,Africa/Mbabane
+South Africa Standard Time,ZA,Africa/Johannesburg
+South Africa Standard Time,ZM,Africa/Lusaka
+South Africa Standard Time,ZW,Africa/Harare
+South Africa Standard Time,ZZ,Etc/GMT-2
+South Sudan Standard Time,001,Africa/Juba
+South Sudan Standard Time,SS,Africa/Juba
+Sri Lanka Standard Time,001,Asia/Colombo
+Sri Lanka Standard Time,LK,Asia/Colombo
+Sudan Standard Time,001,Africa/Khartoum
+Sudan Standard Time,SD,Africa/Khartoum
+Syria Standard Time,001,Asia/Damascus
+Syria Standard Time,SY,Asia/Damascus
+Taipei Standard Time,001,Asia/Taipei
+Taipei Standard Time,TW,Asia/Taipei
+Tasmania Standard Time,001,Australia/Hobart
+Tasmania Standard Time,AU,Australia/Hobart Australia/Currie Antarctica/Macquarie
+Tocantins Standard Time,001,America/Araguaina
+Tocantins Standard Time,BR,America/Araguaina
+Tokyo Standard Time,001,Asia/Tokyo
+Tokyo Standard Time,ID,Asia/Jayapura
+Tokyo Standard Time,JP,Asia/Tokyo
+Tokyo Standard Time,PW,Pacific/Palau
+Tokyo Standard Time,TL,Asia/Dili
+Tokyo Standard Time,ZZ,Etc/GMT-9
+Tomsk Standard Time,001,Asia/Tomsk
+Tomsk Standard Time,RU,Asia/Tomsk
+Tonga Standard Time,001,Pacific/Tongatapu
+Tonga Standard Time,TO,Pacific/Tongatapu
+Transbaikal Standard Time,001,Asia/Chita
+Transbaikal Standard Time,RU,Asia/Chita
+Turkey Standard Time,001,Europe/Istanbul
+Turkey Standard Time,TR,Europe/Istanbul
+Turks And Caicos Standard Time,001,America/Grand_Turk
+Turks And Caicos Standard Time,TC,America/Grand_Turk
+US Eastern Standard Time,001,America/Indianapolis
+US Eastern Standard Time,US,America/Indianapolis America/Indiana/Marengo America/Indiana/Vevay
+US Mountain Standard Time,001,America/Phoenix
+US Mountain Standard Time,CA,America/Creston America/Dawson_Creek America/Fort_Nelson
+US Mountain Standard Time,MX,America/Hermosillo
+US Mountain Standard Time,US,America/Phoenix
+US Mountain Standard Time,ZZ,Etc/GMT+7
+UTC+12,001,Etc/GMT-12
+UTC+12,KI,Pacific/Tarawa
+UTC+12,MH,Pacific/Majuro Pacific/Kwajalein
+UTC+12,NR,Pacific/Nauru
+UTC+12,TV,Pacific/Funafuti
+UTC+12,UM,Pacific/Wake
+UTC+12,WF,Pacific/Wallis
+UTC+12,ZZ,Etc/GMT-12
+UTC+13,001,Etc/GMT-13
+UTC+13,KI,Pacific/Enderbury
+UTC+13,TK,Pacific/Fakaofo
+UTC+13,ZZ,Etc/GMT-13
+UTC,001,Etc/UTC
+UTC,ZZ,Etc/UTC Etc/GMT
+UTC-02,001,Etc/GMT+2
+UTC-02,BR,America/Noronha
+UTC-02,GS,Atlantic/South_Georgia
+UTC-02,ZZ,Etc/GMT+2
+UTC-08,001,Etc/GMT+8
+UTC-08,PN,Pacific/Pitcairn
+UTC-08,ZZ,Etc/GMT+8
+UTC-09,001,Etc/GMT+9
+UTC-09,PF,Pacific/Gambier
+UTC-09,ZZ,Etc/GMT+9
+UTC-11,001,Etc/GMT+11
+UTC-11,AS,Pacific/Pago_Pago
+UTC-11,NU,Pacific/Niue
+UTC-11,UM,Pacific/Midway
+UTC-11,ZZ,Etc/GMT+11
+Ulaanbaatar Standard Time,001,Asia/Ulaanbaatar
+Ulaanbaatar Standard Time,MN,Asia/Ulaanbaatar Asia/Choibalsan
+Venezuela Standard Time,001,America/Caracas
+Venezuela Standard Time,VE,America/Caracas
+Vladivostok Standard Time,001,Asia/Vladivostok
+Vladivostok Standard Time,RU,Asia/Vladivostok Asia/Ust-Nera
+Volgograd Standard Time,001,Europe/Volgograd
+Volgograd Standard Time,RU,Europe/Volgograd
+W. Australia Standard Time,001,Australia/Perth
+W. Australia Standard Time,AU,Australia/Perth
+W. Central Africa Standard Time,001,Africa/Lagos
+W. Central Africa Standard Time,AO,Africa/Luanda
+W. Central Africa Standard Time,BJ,Africa/Porto-Novo
+W. Central Africa Standard Time,CD,Africa/Kinshasa
+W. Central Africa Standard Time,CF,Africa/Bangui
+W. Central Africa Standard Time,CG,Africa/Brazzaville
+W. Central Africa Standard Time,CM,Africa/Douala
+W. Central Africa Standard Time,DZ,Africa/Algiers
+W. Central Africa Standard Time,GA,Africa/Libreville
+W. Central Africa Standard Time,GQ,Africa/Malabo
+W. Central Africa Standard Time,NE,Africa/Niamey
+W. Central Africa Standard Time,NG,Africa/Lagos
+W. Central Africa Standard Time,TD,Africa/Ndjamena
+W. Central Africa Standard Time,TN,Africa/Tunis
+W. Central Africa Standard Time,ZZ,Etc/GMT-1
+W. Europe Standard Time,001,Europe/Berlin
+W. Europe Standard Time,AD,Europe/Andorra
+W. Europe Standard Time,AT,Europe/Vienna
+W. Europe Standard Time,CH,Europe/Zurich
+W. Europe Standard Time,DE,Europe/Berlin Europe/Busingen
+W. Europe Standard Time,GI,Europe/Gibraltar
+W. Europe Standard Time,IT,Europe/Rome
+W. Europe Standard Time,LI,Europe/Vaduz
+W. Europe Standard Time,LU,Europe/Luxembourg
+W. Europe Standard Time,MC,Europe/Monaco
+W. Europe Standard Time,MT,Europe/Malta
+W. Europe Standard Time,NL,Europe/Amsterdam
+W. Europe Standard Time,NO,Europe/Oslo
+W. Europe Standard Time,SE,Europe/Stockholm
+W. Europe Standard Time,SJ,Arctic/Longyearbyen
+W. Europe Standard Time,SM,Europe/San_Marino
+W. Europe Standard Time,VA,Europe/Vatican
+W. Mongolia Standard Time,001,Asia/Hovd
+W. Mongolia Standard Time,MN,Asia/Hovd
+West Asia Standard Time,001,Asia/Tashkent
+West Asia Standard Time,AQ,Antarctica/Mawson
+West Asia Standard Time,KZ,Asia/Oral Asia/Aqtau Asia/Aqtobe Asia/Atyrau
+West Asia Standard Time,MV,Indian/Maldives
+West Asia Standard Time,TF,Indian/Kerguelen
+West Asia Standard Time,TJ,Asia/Dushanbe
+West Asia Standard Time,TM,Asia/Ashgabat
+West Asia Standard Time,UZ,Asia/Tashkent Asia/Samarkand
+West Asia Standard Time,ZZ,Etc/GMT-5
+West Bank Standard Time,001,Asia/Hebron
+West Bank Standard Time,PS,Asia/Hebron Asia/Gaza
+West Pacific Standard Time,001,Pacific/Port_Moresby
+West Pacific Standard Time,AQ,Antarctica/DumontDUrville
+West Pacific Standard Time,FM,Pacific/Truk
+West Pacific Standard Time,GU,Pacific/Guam
+West Pacific Standard Time,MP,Pacific/Saipan
+West Pacific Standard Time,PG,Pacific/Port_Moresby
+West Pacific Standard Time,ZZ,Etc/GMT-10
+Yakutsk Standard Time,001,Asia/Yakutsk
+Yakutsk Standard Time,RU,Asia/Yakutsk Asia/Khandyga
+Yukon Standard Time,001,America/Whitehorse
+Yukon Standard Time,CA,America/Whitehorse America/Dawson
+Kamchatka Standard Time,001,Asia/Kamchatka
+Mid-Atlantic Standard Time,001,Etc/GMT+2
diff -Nru eas4tbsync-4.11/CONTRIBUTORS.md eas4tbsync-4.17/CONTRIBUTORS.md
--- eas4tbsync-4.11/CONTRIBUTORS.md	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/CONTRIBUTORS.md	2025-07-28 19:36:48.000000000 +0200
@@ -1,19 +1,20 @@
-## Creator
-* John Bieling
-
-## Contributors
-* Chris Allan (recurring events)
-* John Bieling
-* Emil Ljungdahl
-* Mark Nethersole (initial implementation of contact sync)
-* Dzamo Norton
-* Puran2	
-* Tijuca
-
-## 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
+* Chris Allan (recurring events)
+* John Bieling
+* Emil Ljungdahl
+* Mark Nethersole (initial implementation of contact sync)
+* Dzamo Norton
+* Puran2	
+* Tijuca
+* 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 eas4tbsync-4.11/crowdin.yml eas4tbsync-4.17/crowdin.yml
--- eas4tbsync-4.11/crowdin.yml	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/crowdin.yml	1970-01-01 01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-commit_message: https://crowdin.com/project/eas-4-tbsync
-files:
-  - source: /_locales/en-US/*
-    translation: /_locales/%osx_locale%/%original_file_name%
-    escape_special_characters: 0
diff -Nru eas4tbsync-4.11/debian/changelog eas4tbsync-4.17/debian/changelog
--- eas4tbsync-4.11/debian/changelog	2024-09-01 12:49:21.000000000 +0200
+++ eas4tbsync-4.17/debian/changelog	2025-09-23 11:53:37.000000000 +0200
@@ -1,3 +1,31 @@
+eas4tbsync (4.17-1~deb13u1) trixie; urgency=medium
+
+  * Prepared for uploading to trixie proposed update
+    after update of thunderbird in trixie (stable)
+
+ -- Mechtilde Stehmann <mechtilde at debian.org>  Tue, 23 Sep 2025 11:53:37 +0200
+
+eas4tbsync (4.17-1) unstable; urgency=medium
+
+  * Rebuild for unstable after thunderbird_140.3 is uploaded.
+
+ -- Mechtilde Stehmann <mechtilde at debian.org>  Sun, 21 Sep 2025 09:08:07 +0200
+
+eas4tbsync (4.17-1~exp1) experimental; urgency=medium
+
+  * [159fee3] Adapt d/watch to check version in Mozilla repo directly
+  * [0ded151] Fixed entry d/watch to check version in Mozilla repo directly
+  * [a4f69f6] Changed compression to xz to take upstream directly
+              from Mozilla repo
+  * [c9353b1] Fixed double entry in section dch in d/gbp.conf
+  * [221e65b] New upstream version 4.17
+  * [5d5a136] Added d/dpb.conf to be used by debian-packages-scripts
+  * [8ef299d] Bumped years in d/copyright
+  * [4d9b097] Bumped standard version in d/control
+  * [f0db874] Bumped version of dependencies in d/control
+
+ -- Mechtilde Stehmann <mechtilde at debian.org>  Fri, 22 Aug 2025 18:36:01 +0200
+
 eas4tbsync (4.11-1) unstable; urgency=medium
 
   * [6db438f] New upstream version 4.11
diff -Nru eas4tbsync-4.11/debian/control eas4tbsync-4.17/debian/control
--- eas4tbsync-4.11/debian/control	2024-09-01 12:43:53.000000000 +0200
+++ eas4tbsync-4.17/debian/control	2025-08-21 12:31:13.000000000 +0200
@@ -6,7 +6,7 @@
 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/eas4tbsync.git
 Vcs-Browser: https://salsa.debian.org/webext-team/eas4tbsync
@@ -15,9 +15,9 @@
 Package: webext-eas4tbsync
 Architecture: all
 Depends: ${misc:Depends}
- , thunderbird (>= 1:128.0)
- , thunderbird (<= 1:128.x)
- , webext-tbsync (>= 4.12)
+ , thunderbird (>= 1:140.0)
+ , thunderbird (<= 1:140.x)
+ , webext-tbsync (>= 4.16)
 Description: Provide Exchange ActiveSync (EAS v2.5 & v14.0) synchronization capabilities
  The Exchange ActiveSync provider for TbSync to sync contacts, tasks and
  calendars to Thunderbird.
diff -Nru eas4tbsync-4.11/debian/copyright eas4tbsync-4.17/debian/copyright
--- eas4tbsync-4.11/debian/copyright	2024-05-15 12:45:06.000000000 +0200
+++ eas4tbsync-4.17/debian/copyright	2025-08-21 12:28:07.000000000 +0200
@@ -3,7 +3,7 @@
 Source: https://github.com/jobisoft/EAS-4-TbSync
 
 Files: *
-Copyright: 2017-2024 john.bieling at gmx.de
+Copyright: 2017-2025 john.bieling at gmx.de
 License: MPL-2
 
 Files: content/skin/eas16.png
@@ -11,7 +11,7 @@
 License: CC-BY-3.0
 
 Files: debian/*
-Copyright: 2018-2024 Mechtilde Stehmann
+Copyright: 2018-2025 Mechtilde Stehmann
 License: MPL-2
 
 License: MPL-2
diff -Nru eas4tbsync-4.11/debian/dpb.conf eas4tbsync-4.17/debian/dpb.conf
--- eas4tbsync-4.11/debian/dpb.conf	1970-01-01 01:00:00.000000000 +0100
+++ eas4tbsync-4.17/debian/dpb.conf	2025-09-23 11:33:16.000000000 +0200
@@ -0,0 +1,18 @@
+#!/bin/bash
+# debian/dpb.conf
+# ConfigFile for EAS-4-TbSync
+# This file is used by the scripts from
+# debian-package-scripts
+## General parameters
+SourceName=eas4tbsync
+PackName=webext-eas4tbsync
+SalsaName=webext-team/
+RecentBranch=debian/trixie
+RecentUpstreamSuffix=xpi
+## Parameters for Java packages
+JavaFlag=0
+## Parameters for Webext packages
+WebextFlag=1
+## Parameters for Python3 packages
+PythonFlag=0
+RecentBranchD=trixie
diff -Nru eas4tbsync-4.11/debian/gbp.conf eas4tbsync-4.17/debian/gbp.conf
--- eas4tbsync-4.11/debian/gbp.conf	2024-05-15 12:22:36.000000000 +0200
+++ eas4tbsync-4.17/debian/gbp.conf	2025-09-23 11:14:43.000000000 +0200
@@ -4,8 +4,8 @@
 # use pristine-tar:
 pristine-tar = True
 # generate gz compressed orig file
-# compression = xz
-debian-branch = debian/sid
+compression = xz
+debian-branch = debian/trixie
 upstream-branch = upstream
 
 [pq]
@@ -13,7 +13,8 @@
 
 [dch]
 id-length = 7
-debian-branch = debian/sid
+# no double entry
+#debian-branch = debian/trixie
 
 [import-orig]
 # filter out unwanted files/dirs from upstream
diff -Nru eas4tbsync-4.11/debian/watch eas4tbsync-4.17/debian/watch
--- eas4tbsync-4.11/debian/watch	2023-09-12 20:03:43.000000000 +0200
+++ eas4tbsync-4.17/debian/watch	2025-08-20 17:00:08.000000000 +0200
@@ -1,2 +1,6 @@
 version=4
-https://github.com/jobisoft/EAS-4-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/eas-4-tbsync/versions/ (\d[\d\.]+)*
diff -Nru eas4tbsync-4.11/.github/issue_template.md eas4tbsync-4.17/.github/issue_template.md
--- eas4tbsync-4.11/.github/issue_template.md	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/.github/issue_template.md	1970-01-01 01:00:00.000000000 +0100
@@ -1,16 +0,0 @@
-## Your environment
-
-TbSync version:
-EAS-4-TbSync version:
-Thunderbird version:
-
-## Expected behavior
-...
-
-## Actual behavior
-...
-
-## Steps to reproduce
-...
-
-To help resolving your issue, enable debug logging (TbSync Account Manager -> Help) and send me the debug.log via e-mail (use the title of your issue as subject of the email).
diff -Nru eas4tbsync-4.11/LICENSE eas4tbsync-4.17/LICENSE
--- eas4tbsync-4.11/LICENSE	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/LICENSE	2019-05-17 23:11:12.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 eas4tbsync-4.11/_locales/bg/messages.json eas4tbsync-4.17/_locales/bg/messages.json
--- eas4tbsync-4.11/_locales/bg/messages.json	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/_locales/bg/messages.json	2025-05-15 13:21:18.000000000 +0200
@@ -1,566 +1,566 @@
-{
-    "abCard.Anniversary": {
-        "message": "Anniversary:"
-    },
-    "abCard.AssistantName": {
-        "message": "Assistant:"
-    },
-    "abCard.AssistantPhoneNumber": {
-        "message": "Assistant Phone:"
-    },
-    "abCard.Business2PhoneNumber": {
-        "message": "Work Alternative Phone:"
-    },
-    "abCard.BusinessFaxNumber": {
-        "message": "Work Fax:"
-    },
-    "abCard.CarPhoneNumber": {
-        "message": "Car Phone:"
-    },
-    "abCard.CompanyMainPhone": {
-        "message": "Work Main Phone:"
-    },
-    "abCard.Email3Address": {
-        "message": "Alternative Email:"
-    },
-    "abCard.Home2PhoneNumber": {
-        "message": "Home Alternative Phone:"
-    },
-    "abCard.ManagerName": {
-        "message": "Manager:"
-    },
-    "abCard.MiddleName": {
-        "message": "Middle name:"
-    },
-    "abCard.OtherAddress": {
-        "message": "Address:"
-    },
-    "abCard.OtherCity": {
-        "message": "City:"
-    },
-    "abCard.OtherCountry": {
-        "message": "Country:"
-    },
-    "abCard.OtherState": {
-        "message": "State:"
-    },
-    "abCard.OtherZip": {
-        "message": "ZIP Code:"
-    },
-    "abCard.RadioPhoneNumber": {
-        "message": "Radio Phone:"
-    },
-    "abCard.Spouse": {
-        "message": "Spouse:"
-    },
-    "abCard.header.eas": {
-        "message": "Other Fields (EAS)"
-    },
-    "abCard.header.homenumbers": {
-        "message": "Additional home numbers:"
-    },
-    "abCard.header.messaging": {
-        "message": "Messaging:"
-    },
-    "abCard.header.otheraddress": {
-        "message": "Other Address (EAS)"
-    },
-    "abCard.header.othernumbers": {
-        "message": "Additional numbers:"
-    },
-    "abCard.header.people": {
-        "message": "People:"
-    },
-    "abCard.header.worknumbers": {
-        "message": "Additional work numbers:"
-    },
-    "acl.readonly": {
-        "message": "Read-only server access (revert local changes)"
-    },
-    "acl.readwrite": {
-        "message": "Read from and write to server"
-    },
-    "add.description": {
-        "message": "Please select one of the available server configuration options and enter the requested details. "
-    },
-    "add.name": {
-        "message": "Account name:"
-    },
-    "add.ok": {
-        "message": "Add account"
-    },
-    "add.password": {
-        "message": "Password:"
-    },
-    "add.server": {
-        "message": "Server configuration:"
-    },
-    "add.shortdescription": {
-        "message": "Account information"
-    },
-    "add.title": {
-        "message": "Adding an Exchange ActiveSync account to TbSync"
-    },
-    "add.url": {
-        "message": "Server address:"
-    },
-    "add.urldescription": {
-        "message": "It should be sufficient to provide just the basic server address (e.g.: mail.yourserver.com). However, it is also possible to provide the full URL (e.g.: https://mail.yourserver.com/Microsoft-Server-ActiveSync)."
-    },
-    "add.user": {
-        "message": "User name (email address):"
-    },
-    "autocomplete.serverdirectory": {
-        "message": "global server directory"
-    },
-    "autodiscover.Failed": {
-        "message": "Autodiscover for user <##user##> failed. Either the provided credentials were wrong or your ActiveSync provider has a temporary issue, or does not support Autodiscover."
-    },
-    "autodiscover.NeedEmail": {
-        "message": "Autodiscover needs a valid email address as user name."
-    },
-    "autodiscover.Ok": {
-        "message": "Autodiscover completed successfully, you can now check the optional settings and establish the synchronization connection."
-    },
-    "autodiscover.Querying": {
-        "message": "Searching for settings?"
-    },
-    "config.auto": {
-        "message": "ActiveSync server configuration (Autodiscover)"
-    },
-    "config.custom": {
-        "message": "ActiveSync server configuration"
-    },
-    "deletefolder.confirm": {
-        "message": "Do you really want to PERMANENTLY PURGE folder ?##replace.1##? from trash?"
-    },
-    "deletefolder.menuentry": {
-        "message": "Permanently purge folder ?##replace.1##? from trash"
-    },
-    "deletefolder.notallowed": {
-        "message": "Please unsubscribe folder ?##replace.1##? before trying to purge it from trash."
-    },
-    "extensionDescription": {
-        "message": "Add sync support for Exchange ActiveSync accounts to TbSync (contacts, tasks and calendars)."
-    },
-    "extensionName": {
-        "message": "Provider for Exchange ActiveSync"
-    },
-    "helplink.BadItemSkipped": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
-    },
-    "helplink.global.clientdenied": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "manager.tabs.accountsettings": {
-        "message": "Account settings"
-    },
-    "manager.tabs.outOfOffice": {
-        "message": "Auto responder"
-    },
-    "manager.tabs.syncsettings": {
-        "message": "Options"
-    },
-    "newaccount.add_auto": {
-        "message": "Autodiscover settings and add account"
-    },
-    "newaccount.add_custom": {
-        "message": "Add account"
-    },
-    "pref.AccountName": {
-        "message": "Description"
-    },
-    "pref.ActiveSyncVersion": {
-        "message": "ActiveSync version"
-    },
-    "pref.DeviceId": {
-        "message": "ActiveSync device ID"
-    },
-    "pref.ServerName": {
-        "message": "Server address"
-    },
-    "pref.ServerNameDescription": {
-        "message": "e.g. mail.yourserver.com"
-    },
-    "pref.ShowTrashedFolders": {
-        "message": "Show folders found in trash"
-    },
-    "pref.UserName": {
-        "message": "User name"
-    },
-    "pref.UserNameDescription": {
-        "message": "User name is usually the email address of your account."
-    },
-    "pref.autodetect": {
-        "message": "best available"
-    },
-    "pref.birthday": {
-        "message": "Send birthday information"
-    },
-    "pref.calendaroptions": {
-        "message": "Calendar options"
-    },
-    "pref.contactoptions": {
-        "message": "Contact options"
-    },
-    "pref.displayoverride": {
-        "message": "Override Display Name with ?First Name? + ?Second Name?"
-    },
-    "pref.generaloptions": {
-        "message": "General options"
-    },
-    "pref.provision": {
-        "message": "Enforce provisioning (required by Kerio)"
-    },
-    "pref.seperator.comma": {
-        "message": "Comma"
-    },
-    "pref.seperator.description": {
-        "message": "Separator for multiline address field."
-    },
-    "pref.seperator.linebreak": {
-        "message": "Line break"
-    },
-    "pref.synclimit.1month": {
-        "message": "from 4 weeks ago"
-    },
-    "pref.synclimit.2weeks": {
-        "message": "from 2 weeks ago"
-    },
-    "pref.synclimit.3month": {
-        "message": "from 3 months ago"
-    },
-    "pref.synclimit.6month": {
-        "message": "from 6 months ago"
-    },
-    "pref.synclimit.all": {
-        "message": "everything"
-    },
-    "pref.synclimit.description": {
-        "message": "Synchronization period: "
-    },
-    "pref.usehttps": {
-        "message": "Use secure connection (connect via https)"
-    },
-    "recyclebin": {
-        "message": "Trash"
-    },
-    "servertype.auto": {
-        "message": "Automatic configuration"
-    },
-    "servertype.custom": {
-        "message": "Custom configuration"
-    },
-    "servertype.description.auto": {
-        "message": "The configuration for many ActiveSync servers can be discovered by providing just your email address."
-    },
-    "servertype.description.custom": {
-        "message": "Setup your account by manually providing the address of the server you want to connect."
-    },
-    "servertype.description.office365": {
-        "message": "Accounts connected to Office 365 use a modern authentication process called OAuth 2.0 which also supports Multi-Factor-Authentication (MFA)."
-    },
-    "servertype.office365": {
-        "message": "Microsoft Office 365"
-    },
-    "servertype.unlock": {
-        "message": "Double click to unlock all predefined server settings."
-    },
-    "status.401": {
-        "message": "Could not authenticate, check username and password (HTTP Error 401)."
-    },
-    "status.403": {
-        "message": "Server rejected connection (forbidden) (HTTP Error 403)."
-    },
-    "status.404": {
-        "message": "User not found (HTTP Error 404)."
-    },
-    "status.449": {
-        "message": "Server requests provisioning (HTTP Error 449)."
-    },
-    "status.500": {
-        "message": "Unknown Server Error (HTTP Error 500)."
-    },
-    "status.503": {
-        "message": "Service unavailable (HTTP Error 503)."
-    },
-    "status.BadItemSkipped": {
-        "message": "Bad Item Skipped: ##replace.1##"
-    },
-    "status.FolderDelete.3": {
-        "message": "Cannot delete a system folder (status 3)"
-    },
-    "status.FolderDelete.4": {
-        "message": "Folder does not exist (status 4), resyncing"
-    },
-    "status.FolderDelete.6": {
-        "message": "Command could not be completed, an error occurred on the server (status 6)"
-    },
-    "status.FolderDelete.9": {
-        "message": "Invalid synchronization key (status 9), resyncing"
-    },
-    "status.FolderSync.9": {
-        "message": "Invalid synchronization key (status 9), resyncing"
-    },
-    "status.InvalidServerOptions": {
-        "message": "The server does not provide information about the supported ActiveSync versions. Is EAS blocked for this user or this client (TbSync)? You could try to set the ActiveSync version manually."
-    },
-    "status.OK": {
-        "message": "OK"
-    },
-    "status.ServerRejectedRequest": {
-        "message": "The EAS Server rejected the last request."
-    },
-    "status.ServerRejectedSomeItems": {
-        "message": "The EAS server did not accept ##replace.1## elements."
-    },
-    "status.Sync.12": {
-        "message": "Folder hierarchy changed (status 12), resyncing"
-    },
-    "status.Sync.3": {
-        "message": "Invalid synchronization key (status 3), resyncing"
-    },
-    "status.Sync.4": {
-        "message": "Malformed request (status 4)"
-    },
-    "status.Sync.5": {
-        "message": "Temporary server issues or invalid item (status 5)"
-    },
-    "status.Sync.6": {
-        "message": "Invalid item (status 6)"
-    },
-    "status.Sync.8": {
-        "message": "Object not found (status 8)"
-    },
-    "status.aborted": {
-        "message": "Not synchronized"
-    },
-    "status.disabled": {
-        "message": "Disabled"
-    },
-    "status.empty-response": {
-        "message": "Server sends unexpected empty response."
-    },
-    "status.forbiddenCalendarItemInTasksFolder": {
-        "message": "Forbidden calendar item in a task folder (please resort)"
-    },
-    "status.forbiddenTasksItemInCalendarFolder": {
-        "message": "Forbidden task item in a calendar folder (please resort)"
-    },
-    "status.global.101": {
-        "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 101)."
-    },
-    "status.global.102": {
-        "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 102)."
-    },
-    "status.global.103": {
-        "message": "The XML provided in the request does not follow the protocol requirements (EAS Error 103)."
-    },
-    "status.global.110": {
-        "message": "The server reported an internal error and we should not retry immediately. Automatic periodic sync has been disabled for 30 minutes (EAS Error 110)."
-    },
-    "status.global.clientdenied": {
-        "message": "The EAS server reports <##replace.2##> (status ##replace.1##) and does not allow TbSync to access your account."
-    },
-    "status.httperror": {
-        "message": "Communication error (HTTP status ##replace.1##)."
-    },
-    "status.invalid": {
-        "message": "Invalid server response (junk)."
-    },
-    "status.malformed-xml": {
-        "message": "Could not parse XML. Check event log for details."
-    },
-    "status.modified": {
-        "message": "Local modifications"
-    },
-    "status.network": {
-        "message": "Could not connect to server (##replace.1##)."
-    },
-    "status.networkerror": {
-        "message": "Could not connect to server."
-    },
-    "status.nosupportedeasversion": {
-        "message": "Server does not support ActiveSync v2.5 or v14.0 (only ##replace.1##). TbSync will not work with this ActiveSync server."
-    },
-    "status.notargets": {
-        "message": "Aborting Sync, because sync targets could not be created."
-    },
-    "status.notsupportedeasversion": {
-        "message": "Server does not support selected ActiveSync v##replace.1## (only ##replace.2##)."
-    },
-    "status.notsyncronized": {
-        "message": "Account needs to be synchronized, at least one item is out of sync."
-    },
-    "status.nouserhost": {
-        "message": "Missing username and/or server. Please provide those values."
-    },
-    "status.pending": {
-        "message": "Waiting to be synchronized"
-    },
-    "status.policy.2": {
-        "message": "There is no policy for this client. Contact your server administrator or disable provisioning for this account."
-    },
-    "status.policy.3": {
-        "message": "Unknown PolicyType value. Contact your server administrator or disable provisioning for this account."
-    },
-    "status.policy.4": {
-        "message": "The policy data on the server is corrupted (possibly tampered with). Contact your server administrator or disable provisioning for this account."
-    },
-    "status.policy.5": {
-        "message": "The client is acknowledging the wrong policy key. Contact your server administrator or disable provisioning for this account."
-    },
-    "status.provision": {
-        "message": "Provisioning failed with status <##replace.1##>"
-    },
-    "status.response-contains-no-data": {
-        "message": "Response from the server contains no data."
-    },
-    "status.resync-loop": {
-        "message": "There was an error from which we could not recover by resyncing the account. Please disable the account and try again. (Error: resync loop)"
-    },
-    "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.syncing": {
-        "message": "Synchronizing"
-    },
-    "status.timeout": {
-        "message": "Communication timeout."
-    },
-    "status.wbxml-parse-error": {
-        "message": "Server sends unreadable response."
-    },
-    "status.wbxmlerror": {
-        "message": "Sync failed. Server responded with status <##replace.1##>."
-    },
-    "status.wbxmlmissingfield": {
-        "message": "ActiveSync protocol violation: Mandatory field <##replace.1##> is missing from server response."
-    },
-    "syncstate.accountdone": {
-        "message": "Finished account"
-    },
-    "syncstate.done": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.eval.response.autodiscover": {
-        "message": "Processing updated server settings"
-    },
-    "syncstate.eval.response.deletefolder": {
-        "message": "Folder deleted"
-    },
-    "syncstate.eval.response.estimate": {
-        "message": "Processing change estimate"
-    },
-    "syncstate.eval.response.folders": {
-        "message": "Processing folder list update"
-    },
-    "syncstate.eval.response.localchanges": {
-        "message": "Processing acknowledgment of local changes"
-    },
-    "syncstate.eval.response.localdeletes": {
-        "message": "Processing acknowledgment of local deletes"
-    },
-    "syncstate.eval.response.options": {
-        "message": "Processing server options"
-    },
-    "syncstate.eval.response.provision": {
-        "message": "Processing provision"
-    },
-    "syncstate.eval.response.remotechanges": {
-        "message": "Processing remote changes"
-    },
-    "syncstate.eval.response.revertlocalchanges": {
-        "message": "Reverting local changes"
-    },
-    "syncstate.eval.response.setdeviceinfo": {
-        "message": "Sending device information"
-    },
-    "syncstate.eval.response.synckey": {
-        "message": "Processing SyncKey"
-    },
-    "syncstate.prepare.request.autodiscover": {
-        "message": "Requesting updated server settings"
-    },
-    "syncstate.prepare.request.deletefolder": {
-        "message": "Preparing to delete folder"
-    },
-    "syncstate.prepare.request.estimate": {
-        "message": "Requesting change estimate"
-    },
-    "syncstate.prepare.request.folders": {
-        "message": "Sending folder list update"
-    },
-    "syncstate.prepare.request.localchanges": {
-        "message": "Sending local changes"
-    },
-    "syncstate.prepare.request.localdeletes": {
-        "message": "Sending local deletes"
-    },
-    "syncstate.prepare.request.options": {
-        "message": "Requesting server options"
-    },
-    "syncstate.prepare.request.provision": {
-        "message": "Requesting provision"
-    },
-    "syncstate.prepare.request.remotechanges": {
-        "message": "Requesting remote changes"
-    },
-    "syncstate.prepare.request.revertlocalchanges": {
-        "message": "Collecting local changes"
-    },
-    "syncstate.prepare.request.setdeviceinfo": {
-        "message": "Sending device information"
-    },
-    "syncstate.prepare.request.synckey": {
-        "message": "Requesting SyncKey"
-    },
-    "syncstate.preparing": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.send.request.autodiscover": {
-        "message": "Waiting for updated server settings"
-    },
-    "syncstate.send.request.deletefolder": {
-        "message": "Waiting for folder to be deleted"
-    },
-    "syncstate.send.request.estimate": {
-        "message": "Waiting for change estimate"
-    },
-    "syncstate.send.request.folders": {
-        "message": "Waiting for folder list update"
-    },
-    "syncstate.send.request.localchanges": {
-        "message": "Waiting for acknowledgment of local changes"
-    },
-    "syncstate.send.request.localdeletes": {
-        "message": "Waiting for acknowledgment of local deletes"
-    },
-    "syncstate.send.request.options": {
-        "message": "Waiting for server options"
-    },
-    "syncstate.send.request.provision": {
-        "message": "Waiting for provision"
-    },
-    "syncstate.send.request.remotechanges": {
-        "message": "Waiting for remote changes"
-    },
-    "syncstate.send.request.revertlocalchanges": {
-        "message": "Waiting for most recent versions"
-    },
-    "syncstate.send.request.setdeviceinfo": {
-        "message": "Sending device information"
-    },
-    "syncstate.send.request.synckey": {
-        "message": "Waiting for SyncKey"
-    },
-    "syncstate.syncing": {
-        "message": "Initialize synchronization"
-    }
-}
+{
+    "abCard.Anniversary": {
+        "message": "Anniversary:"
+    },
+    "abCard.AssistantName": {
+        "message": "Assistant:"
+    },
+    "abCard.AssistantPhoneNumber": {
+        "message": "Assistant Phone:"
+    },
+    "abCard.Business2PhoneNumber": {
+        "message": "Work Alternative Phone:"
+    },
+    "abCard.BusinessFaxNumber": {
+        "message": "Work Fax:"
+    },
+    "abCard.CarPhoneNumber": {
+        "message": "Car Phone:"
+    },
+    "abCard.CompanyMainPhone": {
+        "message": "Work Main Phone:"
+    },
+    "abCard.Email3Address": {
+        "message": "Alternative Email:"
+    },
+    "abCard.Home2PhoneNumber": {
+        "message": "Home Alternative Phone:"
+    },
+    "abCard.ManagerName": {
+        "message": "Manager:"
+    },
+    "abCard.MiddleName": {
+        "message": "Middle name:"
+    },
+    "abCard.OtherAddress": {
+        "message": "Address:"
+    },
+    "abCard.OtherCity": {
+        "message": "City:"
+    },
+    "abCard.OtherCountry": {
+        "message": "Country:"
+    },
+    "abCard.OtherState": {
+        "message": "State:"
+    },
+    "abCard.OtherZip": {
+        "message": "ZIP Code:"
+    },
+    "abCard.RadioPhoneNumber": {
+        "message": "Radio Phone:"
+    },
+    "abCard.Spouse": {
+        "message": "Spouse:"
+    },
+    "abCard.header.eas": {
+        "message": "Other Fields (EAS)"
+    },
+    "abCard.header.homenumbers": {
+        "message": "Additional home numbers:"
+    },
+    "abCard.header.messaging": {
+        "message": "Messaging:"
+    },
+    "abCard.header.otheraddress": {
+        "message": "Other Address (EAS)"
+    },
+    "abCard.header.othernumbers": {
+        "message": "Additional numbers:"
+    },
+    "abCard.header.people": {
+        "message": "People:"
+    },
+    "abCard.header.worknumbers": {
+        "message": "Additional work numbers:"
+    },
+    "acl.readonly": {
+        "message": "Read-only server access (revert local changes)"
+    },
+    "acl.readwrite": {
+        "message": "Read from and write to server"
+    },
+    "add.description": {
+        "message": "Please select one of the available server configuration options and enter the requested details. "
+    },
+    "add.name": {
+        "message": "Account name:"
+    },
+    "add.ok": {
+        "message": "Add account"
+    },
+    "add.password": {
+        "message": "Password:"
+    },
+    "add.server": {
+        "message": "Server configuration:"
+    },
+    "add.shortdescription": {
+        "message": "Account information"
+    },
+    "add.title": {
+        "message": "Adding an Exchange ActiveSync account to TbSync"
+    },
+    "add.url": {
+        "message": "Server address:"
+    },
+    "add.urldescription": {
+        "message": "It should be sufficient to provide just the basic server address (e.g.: mail.yourserver.com). However, it is also possible to provide the full URL (e.g.: https://mail.yourserver.com/Microsoft-Server-ActiveSync)."
+    },
+    "add.user": {
+        "message": "User name (email address):"
+    },
+    "autocomplete.serverdirectory": {
+        "message": "global server directory"
+    },
+    "autodiscover.Failed": {
+        "message": "Autodiscover for user <##user##> failed. Either the provided credentials were wrong or your ActiveSync provider has a temporary issue, or does not support Autodiscover."
+    },
+    "autodiscover.NeedEmail": {
+        "message": "Autodiscover needs a valid email address as user name."
+    },
+    "autodiscover.Ok": {
+        "message": "Autodiscover completed successfully, you can now check the optional settings and establish the synchronization connection."
+    },
+    "autodiscover.Querying": {
+        "message": "Searching for settings?"
+    },
+    "config.auto": {
+        "message": "ActiveSync server configuration (Autodiscover)"
+    },
+    "config.custom": {
+        "message": "ActiveSync server configuration"
+    },
+    "deletefolder.confirm": {
+        "message": "Do you really want to PERMANENTLY PURGE folder ?##replace.1##? from trash?"
+    },
+    "deletefolder.menuentry": {
+        "message": "Permanently purge folder ?##replace.1##? from trash"
+    },
+    "deletefolder.notallowed": {
+        "message": "Please unsubscribe folder ?##replace.1##? before trying to purge it from trash."
+    },
+    "extensionDescription": {
+        "message": "Add sync support for Exchange ActiveSync accounts to TbSync (contacts, tasks and calendars)."
+    },
+    "extensionName": {
+        "message": "Provider for Exchange ActiveSync"
+    },
+    "helplink.BadItemSkipped": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
+    },
+    "helplink.global.clientdenied": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "manager.tabs.accountsettings": {
+        "message": "Account settings"
+    },
+    "manager.tabs.outOfOffice": {
+        "message": "Auto responder"
+    },
+    "manager.tabs.syncsettings": {
+        "message": "Options"
+    },
+    "newaccount.add_auto": {
+        "message": "Autodiscover settings and add account"
+    },
+    "newaccount.add_custom": {
+        "message": "Add account"
+    },
+    "pref.AccountName": {
+        "message": "Description"
+    },
+    "pref.ActiveSyncVersion": {
+        "message": "ActiveSync version"
+    },
+    "pref.DeviceId": {
+        "message": "ActiveSync device ID"
+    },
+    "pref.ServerName": {
+        "message": "Server address"
+    },
+    "pref.ServerNameDescription": {
+        "message": "e.g. mail.yourserver.com"
+    },
+    "pref.ShowTrashedFolders": {
+        "message": "Show folders found in trash"
+    },
+    "pref.UserName": {
+        "message": "User name"
+    },
+    "pref.UserNameDescription": {
+        "message": "User name is usually the email address of your account."
+    },
+    "pref.autodetect": {
+        "message": "best available"
+    },
+    "pref.birthday": {
+        "message": "Send birthday information"
+    },
+    "pref.calendaroptions": {
+        "message": "Calendar options"
+    },
+    "pref.contactoptions": {
+        "message": "Contact options"
+    },
+    "pref.displayoverride": {
+        "message": "Override Display Name with ?First Name? + ?Second Name?"
+    },
+    "pref.generaloptions": {
+        "message": "General options"
+    },
+    "pref.provision": {
+        "message": "Enforce provisioning (required by Kerio)"
+    },
+    "pref.seperator.comma": {
+        "message": "Comma"
+    },
+    "pref.seperator.description": {
+        "message": "Separator for multiline address field."
+    },
+    "pref.seperator.linebreak": {
+        "message": "Line break"
+    },
+    "pref.synclimit.1month": {
+        "message": "from 4 weeks ago"
+    },
+    "pref.synclimit.2weeks": {
+        "message": "from 2 weeks ago"
+    },
+    "pref.synclimit.3month": {
+        "message": "from 3 months ago"
+    },
+    "pref.synclimit.6month": {
+        "message": "from 6 months ago"
+    },
+    "pref.synclimit.all": {
+        "message": "everything"
+    },
+    "pref.synclimit.description": {
+        "message": "Synchronization period: "
+    },
+    "pref.usehttps": {
+        "message": "Use secure connection (connect via https)"
+    },
+    "recyclebin": {
+        "message": "Trash"
+    },
+    "servertype.auto": {
+        "message": "Automatic configuration"
+    },
+    "servertype.custom": {
+        "message": "Custom configuration"
+    },
+    "servertype.description.auto": {
+        "message": "The configuration for many ActiveSync servers can be discovered by providing just your email address."
+    },
+    "servertype.description.custom": {
+        "message": "Setup your account by manually providing the address of the server you want to connect."
+    },
+    "servertype.description.office365": {
+        "message": "Accounts connected to Office 365 use a modern authentication process called OAuth 2.0 which also supports Multi-Factor-Authentication (MFA)."
+    },
+    "servertype.office365": {
+        "message": "Microsoft Office 365"
+    },
+    "servertype.unlock": {
+        "message": "Double click to unlock all predefined server settings."
+    },
+    "status.401": {
+        "message": "Could not authenticate, check username and password (HTTP Error 401)."
+    },
+    "status.403": {
+        "message": "Server rejected connection (forbidden) (HTTP Error 403)."
+    },
+    "status.404": {
+        "message": "User not found (HTTP Error 404)."
+    },
+    "status.449": {
+        "message": "Server requests provisioning (HTTP Error 449)."
+    },
+    "status.500": {
+        "message": "Unknown Server Error (HTTP Error 500)."
+    },
+    "status.503": {
+        "message": "Service unavailable (HTTP Error 503)."
+    },
+    "status.BadItemSkipped": {
+        "message": "Bad Item Skipped: ##replace.1##"
+    },
+    "status.FolderDelete.3": {
+        "message": "Cannot delete a system folder (status 3)"
+    },
+    "status.FolderDelete.4": {
+        "message": "Folder does not exist (status 4), resyncing"
+    },
+    "status.FolderDelete.6": {
+        "message": "Command could not be completed, an error occurred on the server (status 6)"
+    },
+    "status.FolderDelete.9": {
+        "message": "Invalid synchronization key (status 9), resyncing"
+    },
+    "status.FolderSync.9": {
+        "message": "Invalid synchronization key (status 9), resyncing"
+    },
+    "status.InvalidServerOptions": {
+        "message": "The server does not provide information about the supported ActiveSync versions. Is EAS blocked for this user or this client (TbSync)? You could try to set the ActiveSync version manually."
+    },
+    "status.OK": {
+        "message": "OK"
+    },
+    "status.ServerRejectedRequest": {
+        "message": "The EAS Server rejected the last request."
+    },
+    "status.ServerRejectedSomeItems": {
+        "message": "The EAS server did not accept ##replace.1## elements."
+    },
+    "status.Sync.12": {
+        "message": "Folder hierarchy changed (status 12), resyncing"
+    },
+    "status.Sync.3": {
+        "message": "Invalid synchronization key (status 3), resyncing"
+    },
+    "status.Sync.4": {
+        "message": "Malformed request (status 4)"
+    },
+    "status.Sync.5": {
+        "message": "Temporary server issues or invalid item (status 5)"
+    },
+    "status.Sync.6": {
+        "message": "Invalid item (status 6)"
+    },
+    "status.Sync.8": {
+        "message": "Object not found (status 8)"
+    },
+    "status.aborted": {
+        "message": "Not synchronized"
+    },
+    "status.disabled": {
+        "message": "Disabled"
+    },
+    "status.empty-response": {
+        "message": "Server sends unexpected empty response."
+    },
+    "status.forbiddenCalendarItemInTasksFolder": {
+        "message": "Forbidden calendar item in a task folder (please resort)"
+    },
+    "status.forbiddenTasksItemInCalendarFolder": {
+        "message": "Forbidden task item in a calendar folder (please resort)"
+    },
+    "status.global.101": {
+        "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 101)."
+    },
+    "status.global.102": {
+        "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 102)."
+    },
+    "status.global.103": {
+        "message": "The XML provided in the request does not follow the protocol requirements (EAS Error 103)."
+    },
+    "status.global.110": {
+        "message": "The server reported an internal error and we should not retry immediately. Automatic periodic sync has been disabled for 30 minutes (EAS Error 110)."
+    },
+    "status.global.clientdenied": {
+        "message": "The EAS server reports <##replace.2##> (status ##replace.1##) and does not allow TbSync to access your account."
+    },
+    "status.httperror": {
+        "message": "Communication error (HTTP status ##replace.1##)."
+    },
+    "status.invalid": {
+        "message": "Invalid server response (junk)."
+    },
+    "status.malformed-xml": {
+        "message": "Could not parse XML. Check event log for details."
+    },
+    "status.modified": {
+        "message": "Local modifications"
+    },
+    "status.network": {
+        "message": "Could not connect to server (##replace.1##)."
+    },
+    "status.networkerror": {
+        "message": "Could not connect to server."
+    },
+    "status.nosupportedeasversion": {
+        "message": "Server does not support ActiveSync v2.5 or v14.0 (only ##replace.1##). TbSync will not work with this ActiveSync server."
+    },
+    "status.notargets": {
+        "message": "Aborting Sync, because sync targets could not be created."
+    },
+    "status.notsupportedeasversion": {
+        "message": "Server does not support selected ActiveSync v##replace.1## (only ##replace.2##)."
+    },
+    "status.notsyncronized": {
+        "message": "Account needs to be synchronized, at least one item is out of sync."
+    },
+    "status.nouserhost": {
+        "message": "Missing username and/or server. Please provide those values."
+    },
+    "status.pending": {
+        "message": "Waiting to be synchronized"
+    },
+    "status.policy.2": {
+        "message": "There is no policy for this client. Contact your server administrator or disable provisioning for this account."
+    },
+    "status.policy.3": {
+        "message": "Unknown PolicyType value. Contact your server administrator or disable provisioning for this account."
+    },
+    "status.policy.4": {
+        "message": "The policy data on the server is corrupted (possibly tampered with). Contact your server administrator or disable provisioning for this account."
+    },
+    "status.policy.5": {
+        "message": "The client is acknowledging the wrong policy key. Contact your server administrator or disable provisioning for this account."
+    },
+    "status.provision": {
+        "message": "Provisioning failed with status <##replace.1##>"
+    },
+    "status.response-contains-no-data": {
+        "message": "Response from the server contains no data."
+    },
+    "status.resync-loop": {
+        "message": "There was an error from which we could not recover by resyncing the account. Please disable the account and try again. (Error: resync loop)"
+    },
+    "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.syncing": {
+        "message": "Synchronizing"
+    },
+    "status.timeout": {
+        "message": "Communication timeout."
+    },
+    "status.wbxml-parse-error": {
+        "message": "Server sends unreadable response."
+    },
+    "status.wbxmlerror": {
+        "message": "Sync failed. Server responded with status <##replace.1##>."
+    },
+    "status.wbxmlmissingfield": {
+        "message": "ActiveSync protocol violation: Mandatory field <##replace.1##> is missing from server response."
+    },
+    "syncstate.accountdone": {
+        "message": "Finished account"
+    },
+    "syncstate.done": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.eval.response.autodiscover": {
+        "message": "Processing updated server settings"
+    },
+    "syncstate.eval.response.deletefolder": {
+        "message": "Folder deleted"
+    },
+    "syncstate.eval.response.estimate": {
+        "message": "Processing change estimate"
+    },
+    "syncstate.eval.response.folders": {
+        "message": "Processing folder list update"
+    },
+    "syncstate.eval.response.localchanges": {
+        "message": "Processing acknowledgment of local changes"
+    },
+    "syncstate.eval.response.localdeletes": {
+        "message": "Processing acknowledgment of local deletes"
+    },
+    "syncstate.eval.response.options": {
+        "message": "Processing server options"
+    },
+    "syncstate.eval.response.provision": {
+        "message": "Processing provision"
+    },
+    "syncstate.eval.response.remotechanges": {
+        "message": "Processing remote changes"
+    },
+    "syncstate.eval.response.revertlocalchanges": {
+        "message": "Reverting local changes"
+    },
+    "syncstate.eval.response.setdeviceinfo": {
+        "message": "Sending device information"
+    },
+    "syncstate.eval.response.synckey": {
+        "message": "Processing SyncKey"
+    },
+    "syncstate.prepare.request.autodiscover": {
+        "message": "Requesting updated server settings"
+    },
+    "syncstate.prepare.request.deletefolder": {
+        "message": "Preparing to delete folder"
+    },
+    "syncstate.prepare.request.estimate": {
+        "message": "Requesting change estimate"
+    },
+    "syncstate.prepare.request.folders": {
+        "message": "Sending folder list update"
+    },
+    "syncstate.prepare.request.localchanges": {
+        "message": "Sending local changes"
+    },
+    "syncstate.prepare.request.localdeletes": {
+        "message": "Sending local deletes"
+    },
+    "syncstate.prepare.request.options": {
+        "message": "Requesting server options"
+    },
+    "syncstate.prepare.request.provision": {
+        "message": "Requesting provision"
+    },
+    "syncstate.prepare.request.remotechanges": {
+        "message": "Requesting remote changes"
+    },
+    "syncstate.prepare.request.revertlocalchanges": {
+        "message": "Collecting local changes"
+    },
+    "syncstate.prepare.request.setdeviceinfo": {
+        "message": "Sending device information"
+    },
+    "syncstate.prepare.request.synckey": {
+        "message": "Requesting SyncKey"
+    },
+    "syncstate.preparing": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.send.request.autodiscover": {
+        "message": "Waiting for updated server settings"
+    },
+    "syncstate.send.request.deletefolder": {
+        "message": "Waiting for folder to be deleted"
+    },
+    "syncstate.send.request.estimate": {
+        "message": "Waiting for change estimate"
+    },
+    "syncstate.send.request.folders": {
+        "message": "Waiting for folder list update"
+    },
+    "syncstate.send.request.localchanges": {
+        "message": "Waiting for acknowledgment of local changes"
+    },
+    "syncstate.send.request.localdeletes": {
+        "message": "Waiting for acknowledgment of local deletes"
+    },
+    "syncstate.send.request.options": {
+        "message": "Waiting for server options"
+    },
+    "syncstate.send.request.provision": {
+        "message": "Waiting for provision"
+    },
+    "syncstate.send.request.remotechanges": {
+        "message": "Waiting for remote changes"
+    },
+    "syncstate.send.request.revertlocalchanges": {
+        "message": "Waiting for most recent versions"
+    },
+    "syncstate.send.request.setdeviceinfo": {
+        "message": "Sending device information"
+    },
+    "syncstate.send.request.synckey": {
+        "message": "Waiting for SyncKey"
+    },
+    "syncstate.syncing": {
+        "message": "Initialize synchronization"
+    }
+}
diff -Nru eas4tbsync-4.11/_locales/cs/messages.json eas4tbsync-4.17/_locales/cs/messages.json
--- eas4tbsync-4.11/_locales/cs/messages.json	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/_locales/cs/messages.json	2025-05-15 13:21:18.000000000 +0200
@@ -1,566 +1,566 @@
-{
-    "abCard.Anniversary": {
-        "message": "V?ro??:"
-    },
-    "abCard.AssistantName": {
-        "message": "Asistent:"
-    },
-    "abCard.AssistantPhoneNumber": {
-        "message": "Telefon asistenta:"
-    },
-    "abCard.Business2PhoneNumber": {
-        "message": "Alternativn? telefon do pr?ce:"
-    },
-    "abCard.BusinessFaxNumber": {
-        "message": "Fax do pr?ce:"
-    },
-    "abCard.CarPhoneNumber": {
-        "message": "Telefon do auta:"
-    },
-    "abCard.CompanyMainPhone": {
-        "message": "Hlavn? pracovn? telefon:"
-    },
-    "abCard.Email3Address": {
-        "message": "Alternativn? e-mail:"
-    },
-    "abCard.Home2PhoneNumber": {
-        "message": "Alternativn? telefon dom?:"
-    },
-    "abCard.ManagerName": {
-        "message": "Mana?er:"
-    },
-    "abCard.MiddleName": {
-        "message": "Prost?edn? jm?no:"
-    },
-    "abCard.OtherAddress": {
-        "message": "Adresa:"
-    },
-    "abCard.OtherCity": {
-        "message": "M?sto:"
-    },
-    "abCard.OtherCountry": {
-        "message": "Zem?:"
-    },
-    "abCard.OtherState": {
-        "message": "St?t:"
-    },
-    "abCard.OtherZip": {
-        "message": "PS?:"
-    },
-    "abCard.RadioPhoneNumber": {
-        "message": "Radiotelefon:"
-    },
-    "abCard.Spouse": {
-        "message": "Man?el(ka):"
-    },
-    "abCard.header.eas": {
-        "message": "Dal?? ?daje (EAS)"
-    },
-    "abCard.header.homenumbers": {
-        "message": "Dal?? ??sla dom?:"
-    },
-    "abCard.header.messaging": {
-        "message": "Zpr?vy:"
-    },
-    "abCard.header.otheraddress": {
-        "message": "Dal?? adresa (EAS)"
-    },
-    "abCard.header.othernumbers": {
-        "message": "Dal?? ??sla:"
-    },
-    "abCard.header.people": {
-        "message": "Lid?:"
-    },
-    "abCard.header.worknumbers": {
-        "message": "Dal?? ??sla do pr?ce:"
-    },
-    "acl.readonly": {
-        "message": "P?istup na server pouze pro ?ten? (odstranit m?stn? zm?ny)"
-    },
-    "acl.readwrite": {
-        "message": "P??stup na server pro ?ten? i z?pis"
-    },
-    "add.description": {
-        "message": "Vyberte pros?m jednu z dostupn?ch mo?nost? konfigurace serveru a zadejte po?adovan? podrobnosti. "
-    },
-    "add.name": {
-        "message": "N?zev ??tu:"
-    },
-    "add.ok": {
-        "message": "P?idat ??et"
-    },
-    "add.password": {
-        "message": "Heslo:"
-    },
-    "add.server": {
-        "message": "Nastaven? serveru:"
-    },
-    "add.shortdescription": {
-        "message": "Informace o ??tu"
-    },
-    "add.title": {
-        "message": "P?id?n? nov?ho ??tu Exchange ActiveSync do TbSync"
-    },
-    "add.url": {
-        "message": "Adresa serveru:"
-    },
-    "add.urldescription": {
-        "message": "M?lo by sta?it zadat pouze adresu serveru (nap?. mail.mujmail.cz). Nicm?n? m??ete zadat i celou URL (nap?. https://mail.mujmail.cz/Microsoft-Server-ActiveSync)."
-    },
-    "add.user": {
-        "message": "U?ivatelsk? jm?no (e-mailov? adresa):"
-    },
-    "autocomplete.serverdirectory": {
-        "message": "glob?ln? adres?? serveru"
-    },
-    "autodiscover.Failed": {
-        "message": "Automatick? nastaven? pro u?ivatele <##user##> selhalo. Bu? nejsou zadan? p?ihla?ovac? ?daje spr?vn?, nebo m? v?? poskytovatel ActiveSync do?asn? probl?m, anebo nepodporuje automatick? nastaven?."
-    },
-    "autodiscover.NeedEmail": {
-        "message": "Funkce automatick?ho nastaven? Autodiscover vy?aduje zad?n? platn? e-mailov? adresy jako u?ivatelsk?ho jm?na."
-    },
-    "autodiscover.Ok": {
-        "message": "Automatick? nastaven? bylo ?sp??n? dokon?eno. Nyn? si m??ete proj?t voliteln? nastaven? a vytvo?it synchroniza?n? p?ipojen?."
-    },
-    "autodiscover.Querying": {
-        "message": "Hled?m nastaven??"
-    },
-    "config.auto": {
-        "message": "Konfigurace serveru ActiveSync (Autodiscover)"
-    },
-    "config.custom": {
-        "message": "Konfigurace serveru ActiveSync"
-    },
-    "deletefolder.confirm": {
-        "message": "Opravdu chcete z ko?e TRVALE vymazat slo?ku ?##replace.1##??"
-    },
-    "deletefolder.menuentry": {
-        "message": "Trvale z ko?e vymazat slo?ku ?##replace.1##?"
-    },
-    "deletefolder.notallowed": {
-        "message": "Pros?m, odhla?te odb?r slo?ky ?##replace.1##? p?edt?m, ne? se ji pokus?te odstranit z ko?e."
-    },
-    "extensionDescription": {
-        "message": "P?id?v? do TbSync podporu synchronizace pro ??ty Exchange ActiveSync (kontakty, ?koly a kalend??e)."
-    },
-    "extensionName": {
-        "message": "Modul poskytovatele pro Exchange ActiveSync"
-    },
-    "helplink.BadItemSkipped": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
-    },
-    "helplink.global.clientdenied": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "manager.tabs.accountsettings": {
-        "message": "Nastaven? ??tu"
-    },
-    "manager.tabs.outOfOffice": {
-        "message": "Automatick? odpov??"
-    },
-    "manager.tabs.syncsettings": {
-        "message": "Volby"
-    },
-    "newaccount.add_auto": {
-        "message": "Vyhledat nastaven? a p?idat ??et"
-    },
-    "newaccount.add_custom": {
-        "message": "P?idat ??et"
-    },
-    "pref.AccountName": {
-        "message": "Pojmenov?n?"
-    },
-    "pref.ActiveSyncVersion": {
-        "message": "Verze ActiveSync"
-    },
-    "pref.DeviceId": {
-        "message": "ID za??zen? ActiveSync"
-    },
-    "pref.ServerName": {
-        "message": "Adresa serveru"
-    },
-    "pref.ServerNameDescription": {
-        "message": "nap?. mail.mujmail.cz"
-    },
-    "pref.ShowTrashedFolders": {
-        "message": "Zobrazit slo?ky nalezen? v ko?i"
-    },
-    "pref.UserName": {
-        "message": "U?ivatelsk? jm?no"
-    },
-    "pref.UserNameDescription": {
-        "message": "U?ivatelsk? jm?no je obvykle e-mailov? adresa va?eho ??tu."
-    },
-    "pref.autodetect": {
-        "message": "nejlep?? mo?n?"
-    },
-    "pref.birthday": {
-        "message": "Odeslat informace o narozenin?ch"
-    },
-    "pref.calendaroptions": {
-        "message": "Nastaven? kalend??e"
-    },
-    "pref.contactoptions": {
-        "message": "Kontakty"
-    },
-    "pref.displayoverride": {
-        "message": "Vynutit zobrazov?n? jm?na jako ?k?estn?? + ?p??jmen??"
-    },
-    "pref.generaloptions": {
-        "message": "Obecn?"
-    },
-    "pref.provision": {
-        "message": "Vynutit provisioning (vy?aduje Kerio)"
-    },
-    "pref.seperator.comma": {
-        "message": "??rka"
-    },
-    "pref.seperator.description": {
-        "message": "Odd?lova? pro v?ce??dkov? pole adres."
-    },
-    "pref.seperator.linebreak": {
-        "message": "Nov? ??dek"
-    },
-    "pref.synclimit.1month": {
-        "message": "posledn? 4 t?dny"
-    },
-    "pref.synclimit.2weeks": {
-        "message": "posledn? 2 t?dny"
-    },
-    "pref.synclimit.3month": {
-        "message": "posledn? 3 m?s?ce"
-    },
-    "pref.synclimit.6month": {
-        "message": "posledn?ch 6 m?s?c?"
-    },
-    "pref.synclimit.all": {
-        "message": "v?e"
-    },
-    "pref.synclimit.description": {
-        "message": "Obdob? pro synchronizaci: "
-    },
-    "pref.usehttps": {
-        "message": "Pou??t zabezpe?en? p?ipojen? (p?es https)"
-    },
-    "recyclebin": {
-        "message": "Ko?"
-    },
-    "servertype.auto": {
-        "message": "Automatick? nastaven? pomoc? ActiveSync Autodiscover"
-    },
-    "servertype.custom": {
-        "message": "Ru?n? nastaven?"
-    },
-    "servertype.description.auto": {
-        "message": "Pro nastaven? v?t?iny ActiveSync server? sta?? zadat pouze e-mailovou adresu."
-    },
-    "servertype.description.custom": {
-        "message": "Nastavte si ??et pomoc? ru?n?ho zad?n? adresy serveru."
-    },
-    "servertype.description.office365": {
-        "message": "??ty Office 365 pou??vaj? modern? proces ov??ov?n? s n?zvem OAuth 2.0, kter? tak? podporuje v?cefaktorov? ov??ov?n? (MFA)."
-    },
-    "servertype.office365": {
-        "message": "Microsoft Office 365"
-    },
-    "servertype.unlock": {
-        "message": "Dvojklikem odemknete v?echna p?eddefinovan? nastaven? serveru."
-    },
-    "status.401": {
-        "message": "Chyba ov??en?, zkontrolujte u?ivatelsk? jm?no a heslo (HTTP chyba 401)."
-    },
-    "status.403": {
-        "message": "Server odm?tl spojen? (HTTP chyba 403)."
-    },
-    "status.404": {
-        "message": "U?ivatel nebyl nalezen (HTTP chyba 404)."
-    },
-    "status.449": {
-        "message": "Server si vy??dal provisioning (HTTP chyba 449)."
-    },
-    "status.500": {
-        "message": "Nezn?m? chyba serveru (HTTP chyba 500)."
-    },
-    "status.503": {
-        "message": "Slu?ba nen? dostupn? (HTTP chyba 503)."
-    },
-    "status.BadItemSkipped": {
-        "message": "Vynech?na chybn? polo?ka: ##replace.1##"
-    },
-    "status.FolderDelete.3": {
-        "message": "Syst?movou slo?ku nelze odstranit (status 3)"
-    },
-    "status.FolderDelete.4": {
-        "message": "Slo?ka neexistuje (status 4), op?tovn? synchronizuji"
-    },
-    "status.FolderDelete.6": {
-        "message": "P??kaz nemohl b?t dokon?en, do?lo k chyb? na serveru (status 6)"
-    },
-    "status.FolderDelete.9": {
-        "message": "Neplatn? synchroniza?n? kl?? (status 9), op?tovn? synchronizuji"
-    },
-    "status.FolderSync.9": {
-        "message": "Neplatn? synchroniza?n? kl?? (status 9), op?tovn? synchronizuji"
-    },
-    "status.InvalidServerOptions": {
-        "message": "Server neposkytuje informaci o podporovan?ch verz?ch ActiveSync. Je pro tohoto u?ivatele nebo tohoto klienta (TbSync) EAS blokov?n? M??ete zkusit nastavit verzi ActiveSync ru?n?."
-    },
-    "status.OK": {
-        "message": "OK"
-    },
-    "status.ServerRejectedRequest": {
-        "message": "EAS Server posledn? po?adavek odm?tl."
-    },
-    "status.ServerRejectedSomeItems": {
-        "message": "Server EAS nep?ijal ##replace.1## polo?ek."
-    },
-    "status.Sync.12": {
-        "message": "Zm?nila se struktura slo?ky (status 12), op?tovn? synchronizuji"
-    },
-    "status.Sync.3": {
-        "message": "Neplatn? synchroniza?n? kl?? (status 3), op?tovn? synchronizuji"
-    },
-    "status.Sync.4": {
-        "message": "Chybn? po?adavek (status 4)"
-    },
-    "status.Sync.5": {
-        "message": "Do?asn? pot??e na serveru nebo neplatn? polo?ka (status 5)"
-    },
-    "status.Sync.6": {
-        "message": "Neplatn? polo?ka (status 6)"
-    },
-    "status.Sync.8": {
-        "message": "Objekt nebyl nalezen (status 8)"
-    },
-    "status.aborted": {
-        "message": "Nen? synchronizov?no"
-    },
-    "status.disabled": {
-        "message": "Zak?z?no"
-    },
-    "status.empty-response": {
-        "message": "Server zaslal odpov?? bez obsahu."
-    },
-    "status.forbiddenCalendarItemInTasksFolder": {
-        "message": "V seznamu ?kol? m?te ulo?en? z?znam, kter? m? pat?it do kalend??e (pros?m, p?esu?te jej)"
-    },
-    "status.forbiddenTasksItemInCalendarFolder": {
-        "message": "V kalend??i m?te ulo?en? z?znam, kter? m? pat?it mezi ?koly (pros?m, p?esu?te jej)"
-    },
-    "status.global.101": {
-        "message": "Po?adavek obsahuje WBXML, ale nemohl b?t dek?dov?n do XML (EAS chyba 101)."
-    },
-    "status.global.102": {
-        "message": "Po?adavek obsahuje WBXML, ale nemohl b?t dek?dov?n do XML (EAS chyba 102)."
-    },
-    "status.global.103": {
-        "message": "Poskytnut? XML data neodpov?daj? po?adavk?m protokolu (EAS chyba 103)."
-    },
-    "status.global.110": {
-        "message": "Server nahl?sil intern? chybu, automatick? synchronizace byla pozastavena na 30 minut (EAS chyba 110)."
-    },
-    "status.global.clientdenied": {
-        "message": "EAS server nahl?sil <##replace.2##> (status ##replace.1##) a nepovolil pro TbSync p??stup k ??tu."
-    },
-    "status.httperror": {
-        "message": "Chyba komunikace (HTTP status ##replace.1##)."
-    },
-    "status.invalid": {
-        "message": "Neplatn? odpov?? serveru."
-    },
-    "status.malformed-xml": {
-        "message": "Nelze zpracovat XML. Podrobnosti naleznete v protokolu ud?lost?."
-    },
-    "status.modified": {
-        "message": "M?stn? zm?ny"
-    },
-    "status.network": {
-        "message": "Nelze se p?ipojit k serveru (##replace.1##)."
-    },
-    "status.networkerror": {
-        "message": "Nelze se p?ipojit k serveru."
-    },
-    "status.nosupportedeasversion": {
-        "message": "Server nepodporuje ActiveSync v2.5 nebo v14.0 (pouze ##replace.1##). TbSync nepodporuje tento typ ActiveSync serveru."
-    },
-    "status.notargets": {
-        "message": "Synchronizace byla p?eru?ena, proto?e nebylo mo?n? vytvo?it c?le pro synchronizaci."
-    },
-    "status.notsupportedeasversion": {
-        "message": "Server nepodporuje vybranou verzi ActiveSync v##replace.1## (pouze ##replace.2##)."
-    },
-    "status.notsyncronized": {
-        "message": "??et mus? b?t synchronizov?n, alespo? jedna polo?ka nen? synchronizov?na."
-    },
-    "status.nouserhost": {
-        "message": "U?ivatel a/nebo server nebyl zad?n. Pros?m, dopl?te chyb?j?c? hodnoty."
-    },
-    "status.pending": {
-        "message": "?ek? se na synchronizaci"
-    },
-    "status.policy.2": {
-        "message": "Chyb? z?sady pro tohoto klienta. Kontaktujte administr?tora nebo zaka?te provisioning pro tento ??et."
-    },
-    "status.policy.3": {
-        "message": "Nezn?m? hodnota PolicyType. Kontaktujte administr?tora nebo zaka?te provisioning pro tento ??et."
-    },
-    "status.policy.4": {
-        "message": "Data z?sad na serveru jsou poru?en?. Kontaktujte administr?tora nebo zaka?te provisioning pro tento ??et."
-    },
-    "status.policy.5": {
-        "message": "Klient p?ijal ?patn? kl?? z?sad. Kontaktujte administr?tora nebo zaka?te provisioning pro tento ??et."
-    },
-    "status.provision": {
-        "message": "Provisioning skon?il chybou <##replace.1##>"
-    },
-    "status.response-contains-no-data": {
-        "message": "Odpov?? serveru neobsahovala data."
-    },
-    "status.resync-loop": {
-        "message": "Nastala chyba, kterou nen? mo?n? napravit pouze op?tovnou synchronizac?. Pros?m, zaka?te tento ??et a zkuste to znovu. (Chyba: zacyklen? synchronizace)"
-    },
-    "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.syncing": {
-        "message": "Prob?h? synchronizace"
-    },
-    "status.timeout": {
-        "message": "?asov? limit komunikace vypr?el."
-    },
-    "status.wbxml-parse-error": {
-        "message": "Odpov?? serveru byla ne?iteln?."
-    },
-    "status.wbxmlerror": {
-        "message": "Chyba synchronizace. Server hl?s? status <##replace.1##>."
-    },
-    "status.wbxmlmissingfield": {
-        "message": "Poru?en? protokolu ActiveSync: Vy?adovan? pole <##replace.1##> v odpov?di serveru chyb?."
-    },
-    "syncstate.accountdone": {
-        "message": "Synchronizace ??tu dokon?ena"
-    },
-    "syncstate.done": {
-        "message": "P??prava dal?? polo?ky na synchronizaci"
-    },
-    "syncstate.eval.response.autodiscover": {
-        "message": "Zpracov?v?m aktualizovan? nastaven? serveru"
-    },
-    "syncstate.eval.response.deletefolder": {
-        "message": "Slo?ka smaz?na"
-    },
-    "syncstate.eval.response.estimate": {
-        "message": "Zpracov?v?m zm?nu odhadu"
-    },
-    "syncstate.eval.response.folders": {
-        "message": "Zpracov?v?m aktualizaci seznamu slo?ek"
-    },
-    "syncstate.eval.response.localchanges": {
-        "message": "Zpracov?v?m potvrzen? m?stn?ch zm?n"
-    },
-    "syncstate.eval.response.localdeletes": {
-        "message": "Zpracov?v?m potvrzen? m?stn?ch v?maz?"
-    },
-    "syncstate.eval.response.options": {
-        "message": "Zpracov?v?m mo?nosti serveru"
-    },
-    "syncstate.eval.response.provision": {
-        "message": "Zpracov?v?m provision"
-    },
-    "syncstate.eval.response.remotechanges": {
-        "message": "Zpracov?v?m zm?ny ze serveru"
-    },
-    "syncstate.eval.response.revertlocalchanges": {
-        "message": "Vrac?m zp?t m?stn? zm?ny"
-    },
-    "syncstate.eval.response.setdeviceinfo": {
-        "message": "Odes?l?m informace o za??zen?"
-    },
-    "syncstate.eval.response.synckey": {
-        "message": "Zpracov?v?m SyncKey"
-    },
-    "syncstate.prepare.request.autodiscover": {
-        "message": "??d?m o aktualizovan? nastaven? serveru"
-    },
-    "syncstate.prepare.request.deletefolder": {
-        "message": "P?ipravuji vymaz?n? slo?ky"
-    },
-    "syncstate.prepare.request.estimate": {
-        "message": "??d?m o zm?nu odhadu"
-    },
-    "syncstate.prepare.request.folders": {
-        "message": "Odes?l?m aktualizaci seznamu slo?ek"
-    },
-    "syncstate.prepare.request.localchanges": {
-        "message": "Odes?l?m m?stn? zm?ny"
-    },
-    "syncstate.prepare.request.localdeletes": {
-        "message": "Odes?l?m m?stn? v?mazy"
-    },
-    "syncstate.prepare.request.options": {
-        "message": "Pos?l?m po?adavek na zasl?n? mo?nost? serveru"
-    },
-    "syncstate.prepare.request.provision": {
-        "message": "??d?m o provision"
-    },
-    "syncstate.prepare.request.remotechanges": {
-        "message": "??d?m o zm?ny na serveru"
-    },
-    "syncstate.prepare.request.revertlocalchanges": {
-        "message": "Shroma??uji m?stn? zm?ny"
-    },
-    "syncstate.prepare.request.setdeviceinfo": {
-        "message": "Odes?l?m informace o za??zen?"
-    },
-    "syncstate.prepare.request.synckey": {
-        "message": "??d?m o SyncKey"
-    },
-    "syncstate.preparing": {
-        "message": "P??prava dal?? polo?ky na synchronizaci"
-    },
-    "syncstate.send.request.autodiscover": {
-        "message": "?ek?m na aktualizovan? nastaven? serveru"
-    },
-    "syncstate.send.request.deletefolder": {
-        "message": "?ek?m na vymaz?n? slo?ky"
-    },
-    "syncstate.send.request.estimate": {
-        "message": "?ek?m na zm?nu odhadu"
-    },
-    "syncstate.send.request.folders": {
-        "message": "?ek?m na aktualizaci seznamu slo?ek"
-    },
-    "syncstate.send.request.localchanges": {
-        "message": "?ek?m na potvrzen? m?stn?ch zm?n"
-    },
-    "syncstate.send.request.localdeletes": {
-        "message": "?ek?m na potvrzen? m?stn?ch v?maz?"
-    },
-    "syncstate.send.request.options": {
-        "message": "?ek?m na mo?nosti serveru"
-    },
-    "syncstate.send.request.provision": {
-        "message": "?ek?m na provision"
-    },
-    "syncstate.send.request.remotechanges": {
-        "message": "?ek?m na zm?ny ze serveru"
-    },
-    "syncstate.send.request.revertlocalchanges": {
-        "message": "?ek?m na nejnov?j?? verze"
-    },
-    "syncstate.send.request.setdeviceinfo": {
-        "message": "Odes?l?m informace o za??zen?"
-    },
-    "syncstate.send.request.synckey": {
-        "message": "?ek?m na SyncKey"
-    },
-    "syncstate.syncing": {
-        "message": "Inicializuji synchronizaci"
-    }
-}
+{
+    "abCard.Anniversary": {
+        "message": "V?ro??:"
+    },
+    "abCard.AssistantName": {
+        "message": "Asistent:"
+    },
+    "abCard.AssistantPhoneNumber": {
+        "message": "Telefon asistenta:"
+    },
+    "abCard.Business2PhoneNumber": {
+        "message": "Alternativn? telefon do pr?ce:"
+    },
+    "abCard.BusinessFaxNumber": {
+        "message": "Fax do pr?ce:"
+    },
+    "abCard.CarPhoneNumber": {
+        "message": "Telefon do auta:"
+    },
+    "abCard.CompanyMainPhone": {
+        "message": "Hlavn? pracovn? telefon:"
+    },
+    "abCard.Email3Address": {
+        "message": "Alternativn? e-mail:"
+    },
+    "abCard.Home2PhoneNumber": {
+        "message": "Alternativn? telefon dom?:"
+    },
+    "abCard.ManagerName": {
+        "message": "Mana?er:"
+    },
+    "abCard.MiddleName": {
+        "message": "Prost?edn? jm?no:"
+    },
+    "abCard.OtherAddress": {
+        "message": "Adresa:"
+    },
+    "abCard.OtherCity": {
+        "message": "M?sto:"
+    },
+    "abCard.OtherCountry": {
+        "message": "Zem?:"
+    },
+    "abCard.OtherState": {
+        "message": "St?t:"
+    },
+    "abCard.OtherZip": {
+        "message": "PS?:"
+    },
+    "abCard.RadioPhoneNumber": {
+        "message": "Radiotelefon:"
+    },
+    "abCard.Spouse": {
+        "message": "Man?el(ka):"
+    },
+    "abCard.header.eas": {
+        "message": "Dal?? ?daje (EAS)"
+    },
+    "abCard.header.homenumbers": {
+        "message": "Dal?? ??sla dom?:"
+    },
+    "abCard.header.messaging": {
+        "message": "Zpr?vy:"
+    },
+    "abCard.header.otheraddress": {
+        "message": "Dal?? adresa (EAS)"
+    },
+    "abCard.header.othernumbers": {
+        "message": "Dal?? ??sla:"
+    },
+    "abCard.header.people": {
+        "message": "Lid?:"
+    },
+    "abCard.header.worknumbers": {
+        "message": "Dal?? ??sla do pr?ce:"
+    },
+    "acl.readonly": {
+        "message": "P?istup na server pouze pro ?ten? (odstranit m?stn? zm?ny)"
+    },
+    "acl.readwrite": {
+        "message": "P??stup na server pro ?ten? i z?pis"
+    },
+    "add.description": {
+        "message": "Vyberte pros?m jednu z dostupn?ch mo?nost? konfigurace serveru a zadejte po?adovan? podrobnosti. "
+    },
+    "add.name": {
+        "message": "N?zev ??tu:"
+    },
+    "add.ok": {
+        "message": "P?idat ??et"
+    },
+    "add.password": {
+        "message": "Heslo:"
+    },
+    "add.server": {
+        "message": "Nastaven? serveru:"
+    },
+    "add.shortdescription": {
+        "message": "Informace o ??tu"
+    },
+    "add.title": {
+        "message": "P?id?n? nov?ho ??tu Exchange ActiveSync do TbSync"
+    },
+    "add.url": {
+        "message": "Adresa serveru:"
+    },
+    "add.urldescription": {
+        "message": "M?lo by sta?it zadat pouze adresu serveru (nap?. mail.mujmail.cz). Nicm?n? m??ete zadat i celou URL (nap?. https://mail.mujmail.cz/Microsoft-Server-ActiveSync)."
+    },
+    "add.user": {
+        "message": "U?ivatelsk? jm?no (e-mailov? adresa):"
+    },
+    "autocomplete.serverdirectory": {
+        "message": "glob?ln? adres?? serveru"
+    },
+    "autodiscover.Failed": {
+        "message": "Automatick? nastaven? pro u?ivatele <##user##> selhalo. Bu? nejsou zadan? p?ihla?ovac? ?daje spr?vn?, nebo m? v?? poskytovatel ActiveSync do?asn? probl?m, anebo nepodporuje automatick? nastaven?."
+    },
+    "autodiscover.NeedEmail": {
+        "message": "Funkce automatick?ho nastaven? Autodiscover vy?aduje zad?n? platn? e-mailov? adresy jako u?ivatelsk?ho jm?na."
+    },
+    "autodiscover.Ok": {
+        "message": "Automatick? nastaven? bylo ?sp??n? dokon?eno. Nyn? si m??ete proj?t voliteln? nastaven? a vytvo?it synchroniza?n? p?ipojen?."
+    },
+    "autodiscover.Querying": {
+        "message": "Hled?m nastaven??"
+    },
+    "config.auto": {
+        "message": "Konfigurace serveru ActiveSync (Autodiscover)"
+    },
+    "config.custom": {
+        "message": "Konfigurace serveru ActiveSync"
+    },
+    "deletefolder.confirm": {
+        "message": "Opravdu chcete z ko?e TRVALE vymazat slo?ku ?##replace.1##??"
+    },
+    "deletefolder.menuentry": {
+        "message": "Trvale z ko?e vymazat slo?ku ?##replace.1##?"
+    },
+    "deletefolder.notallowed": {
+        "message": "Pros?m, odhla?te odb?r slo?ky ?##replace.1##? p?edt?m, ne? se ji pokus?te odstranit z ko?e."
+    },
+    "extensionDescription": {
+        "message": "P?id?v? do TbSync podporu synchronizace pro ??ty Exchange ActiveSync (kontakty, ?koly a kalend??e)."
+    },
+    "extensionName": {
+        "message": "Modul poskytovatele pro Exchange ActiveSync"
+    },
+    "helplink.BadItemSkipped": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
+    },
+    "helplink.global.clientdenied": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "manager.tabs.accountsettings": {
+        "message": "Nastaven? ??tu"
+    },
+    "manager.tabs.outOfOffice": {
+        "message": "Automatick? odpov??"
+    },
+    "manager.tabs.syncsettings": {
+        "message": "Volby"
+    },
+    "newaccount.add_auto": {
+        "message": "Vyhledat nastaven? a p?idat ??et"
+    },
+    "newaccount.add_custom": {
+        "message": "P?idat ??et"
+    },
+    "pref.AccountName": {
+        "message": "Pojmenov?n?"
+    },
+    "pref.ActiveSyncVersion": {
+        "message": "Verze ActiveSync"
+    },
+    "pref.DeviceId": {
+        "message": "ID za??zen? ActiveSync"
+    },
+    "pref.ServerName": {
+        "message": "Adresa serveru"
+    },
+    "pref.ServerNameDescription": {
+        "message": "nap?. mail.mujmail.cz"
+    },
+    "pref.ShowTrashedFolders": {
+        "message": "Zobrazit slo?ky nalezen? v ko?i"
+    },
+    "pref.UserName": {
+        "message": "U?ivatelsk? jm?no"
+    },
+    "pref.UserNameDescription": {
+        "message": "U?ivatelsk? jm?no je obvykle e-mailov? adresa va?eho ??tu."
+    },
+    "pref.autodetect": {
+        "message": "nejlep?? mo?n?"
+    },
+    "pref.birthday": {
+        "message": "Odeslat informace o narozenin?ch"
+    },
+    "pref.calendaroptions": {
+        "message": "Nastaven? kalend??e"
+    },
+    "pref.contactoptions": {
+        "message": "Kontakty"
+    },
+    "pref.displayoverride": {
+        "message": "Vynutit zobrazov?n? jm?na jako ?k?estn?? + ?p??jmen??"
+    },
+    "pref.generaloptions": {
+        "message": "Obecn?"
+    },
+    "pref.provision": {
+        "message": "Vynutit provisioning (vy?aduje Kerio)"
+    },
+    "pref.seperator.comma": {
+        "message": "??rka"
+    },
+    "pref.seperator.description": {
+        "message": "Odd?lova? pro v?ce??dkov? pole adres."
+    },
+    "pref.seperator.linebreak": {
+        "message": "Nov? ??dek"
+    },
+    "pref.synclimit.1month": {
+        "message": "posledn? 4 t?dny"
+    },
+    "pref.synclimit.2weeks": {
+        "message": "posledn? 2 t?dny"
+    },
+    "pref.synclimit.3month": {
+        "message": "posledn? 3 m?s?ce"
+    },
+    "pref.synclimit.6month": {
+        "message": "posledn?ch 6 m?s?c?"
+    },
+    "pref.synclimit.all": {
+        "message": "v?e"
+    },
+    "pref.synclimit.description": {
+        "message": "Obdob? pro synchronizaci: "
+    },
+    "pref.usehttps": {
+        "message": "Pou??t zabezpe?en? p?ipojen? (p?es https)"
+    },
+    "recyclebin": {
+        "message": "Ko?"
+    },
+    "servertype.auto": {
+        "message": "Automatick? nastaven? pomoc? ActiveSync Autodiscover"
+    },
+    "servertype.custom": {
+        "message": "Ru?n? nastaven?"
+    },
+    "servertype.description.auto": {
+        "message": "Pro nastaven? v?t?iny ActiveSync server? sta?? zadat pouze e-mailovou adresu."
+    },
+    "servertype.description.custom": {
+        "message": "Nastavte si ??et pomoc? ru?n?ho zad?n? adresy serveru."
+    },
+    "servertype.description.office365": {
+        "message": "??ty Office 365 pou??vaj? modern? proces ov??ov?n? s n?zvem OAuth 2.0, kter? tak? podporuje v?cefaktorov? ov??ov?n? (MFA)."
+    },
+    "servertype.office365": {
+        "message": "Microsoft Office 365"
+    },
+    "servertype.unlock": {
+        "message": "Dvojklikem odemknete v?echna p?eddefinovan? nastaven? serveru."
+    },
+    "status.401": {
+        "message": "Chyba ov??en?, zkontrolujte u?ivatelsk? jm?no a heslo (HTTP chyba 401)."
+    },
+    "status.403": {
+        "message": "Server odm?tl spojen? (HTTP chyba 403)."
+    },
+    "status.404": {
+        "message": "U?ivatel nebyl nalezen (HTTP chyba 404)."
+    },
+    "status.449": {
+        "message": "Server si vy??dal provisioning (HTTP chyba 449)."
+    },
+    "status.500": {
+        "message": "Nezn?m? chyba serveru (HTTP chyba 500)."
+    },
+    "status.503": {
+        "message": "Slu?ba nen? dostupn? (HTTP chyba 503)."
+    },
+    "status.BadItemSkipped": {
+        "message": "Vynech?na chybn? polo?ka: ##replace.1##"
+    },
+    "status.FolderDelete.3": {
+        "message": "Syst?movou slo?ku nelze odstranit (status 3)"
+    },
+    "status.FolderDelete.4": {
+        "message": "Slo?ka neexistuje (status 4), op?tovn? synchronizuji"
+    },
+    "status.FolderDelete.6": {
+        "message": "P??kaz nemohl b?t dokon?en, do?lo k chyb? na serveru (status 6)"
+    },
+    "status.FolderDelete.9": {
+        "message": "Neplatn? synchroniza?n? kl?? (status 9), op?tovn? synchronizuji"
+    },
+    "status.FolderSync.9": {
+        "message": "Neplatn? synchroniza?n? kl?? (status 9), op?tovn? synchronizuji"
+    },
+    "status.InvalidServerOptions": {
+        "message": "Server neposkytuje informaci o podporovan?ch verz?ch ActiveSync. Je pro tohoto u?ivatele nebo tohoto klienta (TbSync) EAS blokov?n? M??ete zkusit nastavit verzi ActiveSync ru?n?."
+    },
+    "status.OK": {
+        "message": "OK"
+    },
+    "status.ServerRejectedRequest": {
+        "message": "EAS Server posledn? po?adavek odm?tl."
+    },
+    "status.ServerRejectedSomeItems": {
+        "message": "Server EAS nep?ijal ##replace.1## polo?ek."
+    },
+    "status.Sync.12": {
+        "message": "Zm?nila se struktura slo?ky (status 12), op?tovn? synchronizuji"
+    },
+    "status.Sync.3": {
+        "message": "Neplatn? synchroniza?n? kl?? (status 3), op?tovn? synchronizuji"
+    },
+    "status.Sync.4": {
+        "message": "Chybn? po?adavek (status 4)"
+    },
+    "status.Sync.5": {
+        "message": "Do?asn? pot??e na serveru nebo neplatn? polo?ka (status 5)"
+    },
+    "status.Sync.6": {
+        "message": "Neplatn? polo?ka (status 6)"
+    },
+    "status.Sync.8": {
+        "message": "Objekt nebyl nalezen (status 8)"
+    },
+    "status.aborted": {
+        "message": "Nen? synchronizov?no"
+    },
+    "status.disabled": {
+        "message": "Zak?z?no"
+    },
+    "status.empty-response": {
+        "message": "Server zaslal odpov?? bez obsahu."
+    },
+    "status.forbiddenCalendarItemInTasksFolder": {
+        "message": "V seznamu ?kol? m?te ulo?en? z?znam, kter? m? pat?it do kalend??e (pros?m, p?esu?te jej)"
+    },
+    "status.forbiddenTasksItemInCalendarFolder": {
+        "message": "V kalend??i m?te ulo?en? z?znam, kter? m? pat?it mezi ?koly (pros?m, p?esu?te jej)"
+    },
+    "status.global.101": {
+        "message": "Po?adavek obsahuje WBXML, ale nemohl b?t dek?dov?n do XML (EAS chyba 101)."
+    },
+    "status.global.102": {
+        "message": "Po?adavek obsahuje WBXML, ale nemohl b?t dek?dov?n do XML (EAS chyba 102)."
+    },
+    "status.global.103": {
+        "message": "Poskytnut? XML data neodpov?daj? po?adavk?m protokolu (EAS chyba 103)."
+    },
+    "status.global.110": {
+        "message": "Server nahl?sil intern? chybu, automatick? synchronizace byla pozastavena na 30 minut (EAS chyba 110)."
+    },
+    "status.global.clientdenied": {
+        "message": "EAS server nahl?sil <##replace.2##> (status ##replace.1##) a nepovolil pro TbSync p??stup k ??tu."
+    },
+    "status.httperror": {
+        "message": "Chyba komunikace (HTTP status ##replace.1##)."
+    },
+    "status.invalid": {
+        "message": "Neplatn? odpov?? serveru."
+    },
+    "status.malformed-xml": {
+        "message": "Nelze zpracovat XML. Podrobnosti naleznete v protokolu ud?lost?."
+    },
+    "status.modified": {
+        "message": "M?stn? zm?ny"
+    },
+    "status.network": {
+        "message": "Nelze se p?ipojit k serveru (##replace.1##)."
+    },
+    "status.networkerror": {
+        "message": "Nelze se p?ipojit k serveru."
+    },
+    "status.nosupportedeasversion": {
+        "message": "Server nepodporuje ActiveSync v2.5 nebo v14.0 (pouze ##replace.1##). TbSync nepodporuje tento typ ActiveSync serveru."
+    },
+    "status.notargets": {
+        "message": "Synchronizace byla p?eru?ena, proto?e nebylo mo?n? vytvo?it c?le pro synchronizaci."
+    },
+    "status.notsupportedeasversion": {
+        "message": "Server nepodporuje vybranou verzi ActiveSync v##replace.1## (pouze ##replace.2##)."
+    },
+    "status.notsyncronized": {
+        "message": "??et mus? b?t synchronizov?n, alespo? jedna polo?ka nen? synchronizov?na."
+    },
+    "status.nouserhost": {
+        "message": "U?ivatel a/nebo server nebyl zad?n. Pros?m, dopl?te chyb?j?c? hodnoty."
+    },
+    "status.pending": {
+        "message": "?ek? se na synchronizaci"
+    },
+    "status.policy.2": {
+        "message": "Chyb? z?sady pro tohoto klienta. Kontaktujte administr?tora nebo zaka?te provisioning pro tento ??et."
+    },
+    "status.policy.3": {
+        "message": "Nezn?m? hodnota PolicyType. Kontaktujte administr?tora nebo zaka?te provisioning pro tento ??et."
+    },
+    "status.policy.4": {
+        "message": "Data z?sad na serveru jsou poru?en?. Kontaktujte administr?tora nebo zaka?te provisioning pro tento ??et."
+    },
+    "status.policy.5": {
+        "message": "Klient p?ijal ?patn? kl?? z?sad. Kontaktujte administr?tora nebo zaka?te provisioning pro tento ??et."
+    },
+    "status.provision": {
+        "message": "Provisioning skon?il chybou <##replace.1##>"
+    },
+    "status.response-contains-no-data": {
+        "message": "Odpov?? serveru neobsahovala data."
+    },
+    "status.resync-loop": {
+        "message": "Nastala chyba, kterou nen? mo?n? napravit pouze op?tovnou synchronizac?. Pros?m, zaka?te tento ??et a zkuste to znovu. (Chyba: zacyklen? synchronizace)"
+    },
+    "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.syncing": {
+        "message": "Prob?h? synchronizace"
+    },
+    "status.timeout": {
+        "message": "?asov? limit komunikace vypr?el."
+    },
+    "status.wbxml-parse-error": {
+        "message": "Odpov?? serveru byla ne?iteln?."
+    },
+    "status.wbxmlerror": {
+        "message": "Chyba synchronizace. Server hl?s? status <##replace.1##>."
+    },
+    "status.wbxmlmissingfield": {
+        "message": "Poru?en? protokolu ActiveSync: Vy?adovan? pole <##replace.1##> v odpov?di serveru chyb?."
+    },
+    "syncstate.accountdone": {
+        "message": "Synchronizace ??tu dokon?ena"
+    },
+    "syncstate.done": {
+        "message": "P??prava dal?? polo?ky na synchronizaci"
+    },
+    "syncstate.eval.response.autodiscover": {
+        "message": "Zpracov?v?m aktualizovan? nastaven? serveru"
+    },
+    "syncstate.eval.response.deletefolder": {
+        "message": "Slo?ka smaz?na"
+    },
+    "syncstate.eval.response.estimate": {
+        "message": "Zpracov?v?m zm?nu odhadu"
+    },
+    "syncstate.eval.response.folders": {
+        "message": "Zpracov?v?m aktualizaci seznamu slo?ek"
+    },
+    "syncstate.eval.response.localchanges": {
+        "message": "Zpracov?v?m potvrzen? m?stn?ch zm?n"
+    },
+    "syncstate.eval.response.localdeletes": {
+        "message": "Zpracov?v?m potvrzen? m?stn?ch v?maz?"
+    },
+    "syncstate.eval.response.options": {
+        "message": "Zpracov?v?m mo?nosti serveru"
+    },
+    "syncstate.eval.response.provision": {
+        "message": "Zpracov?v?m provision"
+    },
+    "syncstate.eval.response.remotechanges": {
+        "message": "Zpracov?v?m zm?ny ze serveru"
+    },
+    "syncstate.eval.response.revertlocalchanges": {
+        "message": "Vrac?m zp?t m?stn? zm?ny"
+    },
+    "syncstate.eval.response.setdeviceinfo": {
+        "message": "Odes?l?m informace o za??zen?"
+    },
+    "syncstate.eval.response.synckey": {
+        "message": "Zpracov?v?m SyncKey"
+    },
+    "syncstate.prepare.request.autodiscover": {
+        "message": "??d?m o aktualizovan? nastaven? serveru"
+    },
+    "syncstate.prepare.request.deletefolder": {
+        "message": "P?ipravuji vymaz?n? slo?ky"
+    },
+    "syncstate.prepare.request.estimate": {
+        "message": "??d?m o zm?nu odhadu"
+    },
+    "syncstate.prepare.request.folders": {
+        "message": "Odes?l?m aktualizaci seznamu slo?ek"
+    },
+    "syncstate.prepare.request.localchanges": {
+        "message": "Odes?l?m m?stn? zm?ny"
+    },
+    "syncstate.prepare.request.localdeletes": {
+        "message": "Odes?l?m m?stn? v?mazy"
+    },
+    "syncstate.prepare.request.options": {
+        "message": "Pos?l?m po?adavek na zasl?n? mo?nost? serveru"
+    },
+    "syncstate.prepare.request.provision": {
+        "message": "??d?m o provision"
+    },
+    "syncstate.prepare.request.remotechanges": {
+        "message": "??d?m o zm?ny na serveru"
+    },
+    "syncstate.prepare.request.revertlocalchanges": {
+        "message": "Shroma??uji m?stn? zm?ny"
+    },
+    "syncstate.prepare.request.setdeviceinfo": {
+        "message": "Odes?l?m informace o za??zen?"
+    },
+    "syncstate.prepare.request.synckey": {
+        "message": "??d?m o SyncKey"
+    },
+    "syncstate.preparing": {
+        "message": "P??prava dal?? polo?ky na synchronizaci"
+    },
+    "syncstate.send.request.autodiscover": {
+        "message": "?ek?m na aktualizovan? nastaven? serveru"
+    },
+    "syncstate.send.request.deletefolder": {
+        "message": "?ek?m na vymaz?n? slo?ky"
+    },
+    "syncstate.send.request.estimate": {
+        "message": "?ek?m na zm?nu odhadu"
+    },
+    "syncstate.send.request.folders": {
+        "message": "?ek?m na aktualizaci seznamu slo?ek"
+    },
+    "syncstate.send.request.localchanges": {
+        "message": "?ek?m na potvrzen? m?stn?ch zm?n"
+    },
+    "syncstate.send.request.localdeletes": {
+        "message": "?ek?m na potvrzen? m?stn?ch v?maz?"
+    },
+    "syncstate.send.request.options": {
+        "message": "?ek?m na mo?nosti serveru"
+    },
+    "syncstate.send.request.provision": {
+        "message": "?ek?m na provision"
+    },
+    "syncstate.send.request.remotechanges": {
+        "message": "?ek?m na zm?ny ze serveru"
+    },
+    "syncstate.send.request.revertlocalchanges": {
+        "message": "?ek?m na nejnov?j?? verze"
+    },
+    "syncstate.send.request.setdeviceinfo": {
+        "message": "Odes?l?m informace o za??zen?"
+    },
+    "syncstate.send.request.synckey": {
+        "message": "?ek?m na SyncKey"
+    },
+    "syncstate.syncing": {
+        "message": "Inicializuji synchronizaci"
+    }
+}
diff -Nru eas4tbsync-4.11/_locales/de/messages.json eas4tbsync-4.17/_locales/de/messages.json
--- eas4tbsync-4.11/_locales/de/messages.json	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/_locales/de/messages.json	2025-05-15 13:21:18.000000000 +0200
@@ -1,566 +1,566 @@
-{
-    "abCard.Anniversary": {
-        "message": "Jubil?um:"
-    },
-    "abCard.AssistantName": {
-        "message": "Assistent:"
-    },
-    "abCard.AssistantPhoneNumber": {
-        "message": "Assistententelefon:"
-    },
-    "abCard.Business2PhoneNumber": {
-        "message": "Telefon 2 Arbeit:"
-    },
-    "abCard.BusinessFaxNumber": {
-        "message": "Fax Arbeit:"
-    },
-    "abCard.CarPhoneNumber": {
-        "message": "Telefon Auto:"
-    },
-    "abCard.CompanyMainPhone": {
-        "message": "Haupttelefon Arbeit:"
-    },
-    "abCard.Email3Address": {
-        "message": "Alternative E-Mail:"
-    },
-    "abCard.Home2PhoneNumber": {
-        "message": "Telefon 2 zu Hause:"
-    },
-    "abCard.ManagerName": {
-        "message": "Manager:"
-    },
-    "abCard.MiddleName": {
-        "message": "Zweiter Vorname:"
-    },
-    "abCard.OtherAddress": {
-        "message": "Adresse:"
-    },
-    "abCard.OtherCity": {
-        "message": "Stadt:"
-    },
-    "abCard.OtherCountry": {
-        "message": "Land:"
-    },
-    "abCard.OtherState": {
-        "message": "Bundesland:"
-    },
-    "abCard.OtherZip": {
-        "message": "Postleitzahl:"
-    },
-    "abCard.RadioPhoneNumber": {
-        "message": "Funktelefon:"
-    },
-    "abCard.Spouse": {
-        "message": "Ehepartner:"
-    },
-    "abCard.header.eas": {
-        "message": "Weitere Felder (EAS)"
-    },
-    "abCard.header.homenumbers": {
-        "message": "Zus?tzliche Nummern zu Hause:"
-    },
-    "abCard.header.messaging": {
-        "message": "Nachrichten:"
-    },
-    "abCard.header.otheraddress": {
-        "message": "Weitere Adresse (EAS)"
-    },
-    "abCard.header.othernumbers": {
-        "message": "Zus?tzliche Nummern:"
-    },
-    "abCard.header.people": {
-        "message": "Personen:"
-    },
-    "abCard.header.worknumbers": {
-        "message": "Zus?tzliche Nummern Arbeit:"
-    },
-    "acl.readonly": {
-        "message": "Serverzugriff nur lesend (verwerfe lokale ?nderungen)"
-    },
-    "acl.readwrite": {
-        "message": "Serverzugriff lesend und schreibend"
-    },
-    "add.description": {
-        "message": "Bitte w?hlen Sie eine der verf?gbaren Server-Konfigurationen aus und geben Sie die angeforderten Details ein. "
-    },
-    "add.name": {
-        "message": "Kontoname:"
-    },
-    "add.ok": {
-        "message": "Konto hinzuf?gen"
-    },
-    "add.password": {
-        "message": "Passwort:"
-    },
-    "add.server": {
-        "message": "Server Konfiguration:"
-    },
-    "add.shortdescription": {
-        "message": "Kontoinformationen"
-    },
-    "add.title": {
-        "message": "Exchange ActiveSync Konto hinzuf?gen"
-    },
-    "add.url": {
-        "message": "Server Adresse:"
-    },
-    "add.urldescription": {
-        "message": "Meist reicht die Angabe der einfachen Serveradresse (z.B.: mail.meinserver.de), alternativ kann aber auch die komplette URL angegeben werden (z.B.: https://mail.meinserver.de/Microsoft-Server-ActiveSync)."
-    },
-    "add.user": {
-        "message": "Benutzername (E-Mail Adresse):"
-    },
-    "autocomplete.serverdirectory": {
-        "message": "Globales Serververzeichnis"
-    },
-    "autodiscover.Failed": {
-        "message": "Autodiscover f?r den Benutzer <##user##> war nicht erfolgreich. Entweder war das Passwort nicht korrekt, Ihr ActiveSync Server hat ein tempor?res Problem oder unterst?tzt kein Autodiscover."
-    },
-    "autodiscover.NeedEmail": {
-        "message": "Autodiscover ben?tigt eine g?ltige E-Mail Adresse als Benutzername."
-    },
-    "autodiscover.Ok": {
-        "message": "Autodiscover war erfolgreich, Sie k?nnen nun die optionalen Einstellungen ?berpr?fen und die Synchronisationsverbindung aktivieren."
-    },
-    "autodiscover.Querying": {
-        "message": "Einstellungen werden gesucht ..."
-    },
-    "config.auto": {
-        "message": "ActiveSync Server Konfiguration (Autodiscover)"
-    },
-    "config.custom": {
-        "message": "ActiveSync Server Konfiguration"
-    },
-    "deletefolder.confirm": {
-        "message": "M?chten Sie den Ordner '##replace.1##' wirklich ENDG?LTIG aus dem Papierkorb ENTFERNEN?"
-    },
-    "deletefolder.menuentry": {
-        "message": "Den Ordner '##replace.1##' endg?ltig aus dem Papierkorb entfernen"
-    },
-    "deletefolder.notallowed": {
-        "message": "Bitte beenden Sie zun?chst das Abonement des Ordner '##replace.1##', bevor Sie diesen aus dem Papierkorb entfernen."
-    },
-    "extensionDescription": {
-        "message": "Erweitert TbSync und erlaubt die Synchronisation von Exchange ActiveSync Konten (Kontakte, Aufgaben und Kalender)."
-    },
-    "extensionName": {
-        "message": "Provider f?r Exchange ActiveSync"
-    },
-    "helplink.BadItemSkipped": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
-    },
-    "helplink.global.clientdenied": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "manager.tabs.accountsettings": {
-        "message": "Kontoeinstellungen"
-    },
-    "manager.tabs.outOfOffice": {
-        "message": "Autoresponder"
-    },
-    "manager.tabs.syncsettings": {
-        "message": "Optionen"
-    },
-    "newaccount.add_auto": {
-        "message": "Einstellungen suchen und Konto hinzuf?gen"
-    },
-    "newaccount.add_custom": {
-        "message": "Konto hinzuf?gen"
-    },
-    "pref.AccountName": {
-        "message": "Kontoname"
-    },
-    "pref.ActiveSyncVersion": {
-        "message": "ActiveSync Version"
-    },
-    "pref.DeviceId": {
-        "message": "ActiveSync Ger?te ID"
-    },
-    "pref.ServerName": {
-        "message": "Server Adresse"
-    },
-    "pref.ServerNameDescription": {
-        "message": "z.B. mail.meinserver.com"
-    },
-    "pref.ShowTrashedFolders": {
-        "message": "Im Papierkorb gefundene Ordner anzeigen"
-    },
-    "pref.UserName": {
-        "message": "Benutzername"
-    },
-    "pref.UserNameDescription": {
-        "message": "Der Benutzername ist meistens die E-Mail Adresse Ihres Kontos."
-    },
-    "pref.autodetect": {
-        "message": "bestm?glich"
-    },
-    "pref.birthday": {
-        "message": "Sende Geburtstagsinformation"
-    },
-    "pref.calendaroptions": {
-        "message": "Kalender Optionen"
-    },
-    "pref.contactoptions": {
-        "message": "Kontakt Optionen"
-    },
-    "pref.displayoverride": {
-        "message": "?berschreibe Anzeigename mit 'Vorname' + 'Nachname'"
-    },
-    "pref.generaloptions": {
-        "message": "Allgemeine Optionen"
-    },
-    "pref.provision": {
-        "message": "Provisionierung erzwingen (wird von Kerio ben?tigt)"
-    },
-    "pref.seperator.comma": {
-        "message": "Komma"
-    },
-    "pref.seperator.description": {
-        "message": "Separator f?r mehrzeilige Adressfelder: "
-    },
-    "pref.seperator.linebreak": {
-        "message": "Zeilenumbruch"
-    },
-    "pref.synclimit.1month": {
-        "message": "ab vor 4 Wochen"
-    },
-    "pref.synclimit.2weeks": {
-        "message": "ab vor 2 Wochen"
-    },
-    "pref.synclimit.3month": {
-        "message": "ab vor 3 Monaten"
-    },
-    "pref.synclimit.6month": {
-        "message": "ab vor 6 Monaten"
-    },
-    "pref.synclimit.all": {
-        "message": "alles"
-    },
-    "pref.synclimit.description": {
-        "message": "Synchronisationszeitraum: "
-    },
-    "pref.usehttps": {
-        "message": "Sichere Verbindungen verwenden (via https://)"
-    },
-    "recyclebin": {
-        "message": "Papierkorb"
-    },
-    "servertype.auto": {
-        "message": "Automatische Konfiguration"
-    },
-    "servertype.custom": {
-        "message": "Benutzerspezifische Konfiguration"
-    },
-    "servertype.description.auto": {
-        "message": "Die Konfiguration vieler ActiveSync Server kann allein durch die Angabe Ihrer E-Mail-Adresse erfolgen."
-    },
-    "servertype.description.custom": {
-        "message": "Richten Sie Ihr Konto ein, indem Sie die Adresse des Servers angeben, mit dem Sie sich verbinden m?chten."
-    },
-    "servertype.description.office365": {
-        "message": "Konten, die mit Office 365 verbunden sind, verwenden den modernen OAuth 2.0 Authentifizierungsprozess, der auch Multi-Factor-Authentication (MFA) unterst?tzt."
-    },
-    "servertype.office365": {
-        "message": "Microsoft Office 365"
-    },
-    "servertype.unlock": {
-        "message": "Doppelklick um die vordefinierten Servereinstellungen zu entsperren."
-    },
-    "status.401": {
-        "message": "Authentifizierung fehlgeschlagen, ?berpr?fen Sie den Benutzernamen und das Passwort."
-    },
-    "status.403": {
-        "message": "Verbindung vom Server abgelehnt (nicht erlaubt)."
-    },
-    "status.404": {
-        "message": "Unbekanner Benutzer (HTTP Fehler 404)."
-    },
-    "status.449": {
-        "message": "Server erwartet Provisionierung."
-    },
-    "status.500": {
-        "message": "Unbekannter Server Fehler (HTTP Fehler 500)."
-    },
-    "status.503": {
-        "message": "Service nicht erreichbar."
-    },
-    "status.BadItemSkipped": {
-        "message": "Ein Element wurde nicht synchronisiert: ##replace.1##"
-    },
-    "status.FolderDelete.3": {
-        "message": "Systemordner k?nnen nicht gel?scht werden."
-    },
-    "status.FolderDelete.4": {
-        "message": "Ordner existiert nicht,  es wird neu synchronisiert"
-    },
-    "status.FolderDelete.6": {
-        "message": "Das Kommando konnte nicht abgeschlossen werden, auf dem Server ist ein Fehler aufgetreten."
-    },
-    "status.FolderDelete.9": {
-        "message": "Ung?ltiger Synchronisationsschl?ssel, es wird neu synchronisiert"
-    },
-    "status.FolderSync.9": {
-        "message": "Ung?ltiger Synchronisationsschl?ssel, es wird neu synchronisiert"
-    },
-    "status.InvalidServerOptions": {
-        "message": "Der Server sendet keine Informationen zu den unterst?tzten ActiveSync Versionen. Ist EAS f?r diesen Benutzer bzw. f?r dieses Programm (TbSync) freigeschaltet? Sie k?nnen versuchen, die ActiveSync Version manuell festzulegen."
-    },
-    "status.OK": {
-        "message": "Ok"
-    },
-    "status.ServerRejectedRequest": {
-        "message": "Der EAS Server hat die letzte Anforderung zur?ckgewiesen."
-    },
-    "status.ServerRejectedSomeItems": {
-        "message": "Der EAS Server hat ##replace.1## Elemente nicht akzeptiert."
-    },
-    "status.Sync.12": {
-        "message": "Ordnerhierarchie hat sich ge?ndert, es wird neu synchronisiert"
-    },
-    "status.Sync.3": {
-        "message": "Ung?ltiger Synchronisationsschl?ssel, es wird neu synchronisiert"
-    },
-    "status.Sync.4": {
-        "message": "Fehlerhafte Anfrage (Status 4)"
-    },
-    "status.Sync.5": {
-        "message": "Tempor?res Serverproblem oder ung?ltiges Element (Status 5)"
-    },
-    "status.Sync.6": {
-        "message": "Ung?ltiges Element (Status 6)"
-    },
-    "status.Sync.8": {
-        "message": "Objekt nicht gefunden (Status 8)"
-    },
-    "status.aborted": {
-        "message": "Nicht synchronisiert"
-    },
-    "status.disabled": {
-        "message": "Konto ist deaktiviert, Synchronisation ist ausgeschaltet."
-    },
-    "status.empty-response": {
-        "message": "Server sendet unerwartete leere Antwort."
-    },
-    "status.forbiddenCalendarItemInTasksFolder": {
-        "message": "Unerlaubtes Kalender-Element in einem Aufgaben-Objekt (bitte umsortieren)"
-    },
-    "status.forbiddenTasksItemInCalendarFolder": {
-        "message": "Unerlaubtes Aufgaben-Element in einem Kalender-Objekt (bitte umsortieren)"
-    },
-    "status.global.101": {
-        "message": "Das WBXML der Anfrage konnte nicht in g?ltiges XML dekodiert werden (EAS Fehler 101)."
-    },
-    "status.global.102": {
-        "message": "Das WBXML der Anfrage konnte nicht in g?ltiges XML dekodiert werden (EAS Fehler 102)."
-    },
-    "status.global.103": {
-        "message": "Das XML der Anfrage entspricht nicht den Protokollanforderungen (EAS Fehler 103)."
-    },
-    "status.global.110": {
-        "message": "Der Server meldet einen internen Fehler und es soll nicht unmittelbar ein erneuter Verbindungsaufbau durchgef?hrt werden. Die automatische periodische Synchronisation wird f?r 30 Minuten ausgesetzt (EAS Fehler 110)."
-    },
-    "status.global.clientdenied": {
-        "message": "Der EAS Server antwortet mit <##replace.2##> (status ##replace.1##) und verweigert TbSync den Zugriff auf Ihr Konto."
-    },
-    "status.httperror": {
-        "message": "Kommunikationsfehler (HTTP Status ##replace.1##)."
-    },
-    "status.invalid": {
-        "message": "Ung?ltige Serverantwort."
-    },
-    "status.malformed-xml": {
-        "message": "Antwort enth?lt fehlerhaftes XML, Sync angebrochen. Pr?fen Sie bitte das Ereignisprotokoll f?r weitere Details."
-    },
-    "status.modified": {
-        "message": "Lokale ?nderungen"
-    },
-    "status.network": {
-        "message": "Verbindung zum Server fehlgeschlagen (##replace.1##)."
-    },
-    "status.networkerror": {
-        "message": "Verbindung zum Server fehlgeschlagen."
-    },
-    "status.nosupportedeasversion": {
-        "message": "Der Server unterst?tzt kein ActiveSync v2.5 oder v14.0 (nur ##replace.1##). TbSync kann nicht mit diesem Server arbeiten."
-    },
-    "status.notargets": {
-        "message": "Synchronisation abgebrochen da die Elemente zum Synchronisieren nicht erstellt werden konnten."
-    },
-    "status.notsupportedeasversion": {
-        "message": "Der Server unterst?tzt nicht die ausgew?hlte ActiveSync Version v##replace.1## (nur ##replace.2##)."
-    },
-    "status.notsyncronized": {
-        "message": "Konto muss synchronisiert werden."
-    },
-    "status.nouserhost": {
-        "message": "Angabe des Benutzernamens und/oder des Servers fehlt. Bitte die korrekten Informationen eintragen."
-    },
-    "status.pending": {
-        "message": "Warten auf Synchronisation"
-    },
-    "status.policy.2": {
-        "message": "Es gibt keine Regel (policy) f?r diesen Klient. Kontaktieren Sie Ihren Server Administrator oder deaktivieren Sie die Provisionierungsoption f?r dieses Konto in TbSync."
-    },
-    "status.policy.3": {
-        "message": "Unbekannter Wert f?r den Regeltyp (policy type). Kontaktieren Sie Ihren Server Administrator oder deaktivieren Sie die Provisionierungsoption f?r dieses Konto in TbSync."
-    },
-    "status.policy.4": {
-        "message": "Die Daten f?r die Regeln auf dem Server sind besch?digt (m?glicherweise manipuliert). Kontaktieren Sie Ihren Server Administrator oder deaktivieren Sie die Provisionierungsoption f?r dieses Konto in TbSync."
-    },
-    "status.policy.5": {
-        "message": "Der Klient best?tigt einen falschen Richtlinienschl?ssel (policy key). Kontaktieren Sie Ihren Server Administrator oder deaktivieren Sie die Provisionierungsoption f?r dieses Konto in TbSync."
-    },
-    "status.provision": {
-        "message": "Provisionierung fehlerhaft mit folgendem Status <##replace.1##>"
-    },
-    "status.response-contains-no-data": {
-        "message": "Antwort vom Server enth?lt keine Daten."
-    },
-    "status.resync-loop": {
-        "message": "Es ist ein Fehler aufgetreten, der nicht durch wiederholtes Synchronisieren des Kontos behoben werden konnte. Bitte deaktivieren sie das Konto und wiederholen den Vorgang. (Fehler: Synchronisationsschleife)"
-    },
-    "status.security": {
-        "message": "Fehler beim Aufbau einer sicherern Verbindung. Benutzen Sie eventuell ein selbst signiertes Zertifikat oder ein andersartiges nicht vertrauensw?rdiges Zertifikat welches nicht in Thunderbird importiert ist? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "Nicht unterst?tzt"
-    },
-    "status.syncing": {
-        "message": "Synchronisierung"
-    },
-    "status.timeout": {
-        "message": "Kommunikations-Timeout."
-    },
-    "status.wbxml-parse-error": {
-        "message": "Server sendet nicht lesbare Antwort."
-    },
-    "status.wbxmlerror": {
-        "message": "Synchronisation fehlgeschlagen. Der Server antwortete mit dem Status <##replace.1##>."
-    },
-    "status.wbxmlmissingfield": {
-        "message": "Verletzung des ActiveSync Protokolls: Notwendiges Feld <##replace.1##> ist nicht in der Serverantwort enthalten."
-    },
-    "syncstate.accountdone": {
-        "message": "Kontosynchronisation abgeschlossen"
-    },
-    "syncstate.done": {
-        "message": "Bereite das n?chste Element f?r die Synchronisation vor"
-    },
-    "syncstate.eval.response.autodiscover": {
-        "message": "Verarbeite aktualisierte Servereinstellungen"
-    },
-    "syncstate.eval.response.deletefolder": {
-        "message": "Ordner erfolgreich gel?scht"
-    },
-    "syncstate.eval.response.estimate": {
-        "message": "Verarbeite gesch?tzte ?nderungen"
-    },
-    "syncstate.eval.response.folders": {
-        "message": "Verarbeite aktualisierte Ordnerliste"
-    },
-    "syncstate.eval.response.localchanges": {
-        "message": "Verarbeite Best?tigung der lokalen ?nderungen"
-    },
-    "syncstate.eval.response.localdeletes": {
-        "message": "Verarbeite Best?tigung lokal gel?schten Elemente"
-    },
-    "syncstate.eval.response.options": {
-        "message": "Verarbeite aktualisierte Serveroptionen"
-    },
-    "syncstate.eval.response.provision": {
-        "message": "Verarbeite Provisionierung"
-    },
-    "syncstate.eval.response.remotechanges": {
-        "message": "Verarbeite aktualisierte Elemente"
-    },
-    "syncstate.eval.response.revertlocalchanges": {
-        "message": "Lokale ?nderungen werden verworfen"
-    },
-    "syncstate.eval.response.setdeviceinfo": {
-        "message": "Sende Ger?teinformationen"
-    },
-    "syncstate.eval.response.synckey": {
-        "message": "Verarbeite Synchronisationsschl?ssel"
-    },
-    "syncstate.prepare.request.autodiscover": {
-        "message": "Sende Anfrage bzgl. aktualisierter Servereinstellungen"
-    },
-    "syncstate.prepare.request.deletefolder": {
-        "message": "L?schen des Ordners wird vorbereitet"
-    },
-    "syncstate.prepare.request.estimate": {
-        "message": "Sende Anfrage bzgl. gesch?tzter ?nderungen"
-    },
-    "syncstate.prepare.request.folders": {
-        "message": "Sende Anfrage bzgl. aktualisierter Ordnerliste"
-    },
-    "syncstate.prepare.request.localchanges": {
-        "message": "Sende lokale ?nderungen"
-    },
-    "syncstate.prepare.request.localdeletes": {
-        "message": "Sende die lokal gel?schten Elemente"
-    },
-    "syncstate.prepare.request.options": {
-        "message": "Sende Anfrage bzgl. aktualisierter Serveroptionen"
-    },
-    "syncstate.prepare.request.provision": {
-        "message": "Sende Anfrage bzgl. Provisionierung"
-    },
-    "syncstate.prepare.request.remotechanges": {
-        "message": "Sende Anfrage bzgl. ?nderungen"
-    },
-    "syncstate.prepare.request.revertlocalchanges": {
-        "message": "Pr?fe lokale ?nderungen"
-    },
-    "syncstate.prepare.request.setdeviceinfo": {
-        "message": "Sende Ger?teinformationen"
-    },
-    "syncstate.prepare.request.synckey": {
-        "message": "Sende Anfrage bzgl. Synchronisationsschl?ssel"
-    },
-    "syncstate.preparing": {
-        "message": "Bereite das n?chste Element f?r die Synchronisation vor"
-    },
-    "syncstate.send.request.autodiscover": {
-        "message": "Warte auf aktualisierte Servereinstellungen"
-    },
-    "syncstate.send.request.deletefolder": {
-        "message": "Ordner wird gel?scht"
-    },
-    "syncstate.send.request.estimate": {
-        "message": "Warte auf gesch?tzte ?nderungen"
-    },
-    "syncstate.send.request.folders": {
-        "message": "Warte auf aktualisierte Ordnerliste"
-    },
-    "syncstate.send.request.localchanges": {
-        "message": "Warte auf Best?tigung der lokalen ?nderungen"
-    },
-    "syncstate.send.request.localdeletes": {
-        "message": "Warte auf Best?tigung lokal gel?schten Elemente"
-    },
-    "syncstate.send.request.options": {
-        "message": "Warte auf aktualisierte Serveroptionen"
-    },
-    "syncstate.send.request.provision": {
-        "message": "Warte auf Provisionierung"
-    },
-    "syncstate.send.request.remotechanges": {
-        "message": "Warte auf aktualisierte Elemente"
-    },
-    "syncstate.send.request.revertlocalchanges": {
-        "message": "Warte auf aktuelle Versionen"
-    },
-    "syncstate.send.request.setdeviceinfo": {
-        "message": "Sende Ger?teinformationen"
-    },
-    "syncstate.send.request.synckey": {
-        "message": "Warte auf Synchronisationsschl?ssel"
-    },
-    "syncstate.syncing": {
-        "message": "Initiiere Synchronisation"
-    }
-}
+{
+    "abCard.Anniversary": {
+        "message": "Jubil?um:"
+    },
+    "abCard.AssistantName": {
+        "message": "Assistent:"
+    },
+    "abCard.AssistantPhoneNumber": {
+        "message": "Assistententelefon:"
+    },
+    "abCard.Business2PhoneNumber": {
+        "message": "Telefon 2 Arbeit:"
+    },
+    "abCard.BusinessFaxNumber": {
+        "message": "Fax Arbeit:"
+    },
+    "abCard.CarPhoneNumber": {
+        "message": "Telefon Auto:"
+    },
+    "abCard.CompanyMainPhone": {
+        "message": "Haupttelefon Arbeit:"
+    },
+    "abCard.Email3Address": {
+        "message": "Alternative E-Mail:"
+    },
+    "abCard.Home2PhoneNumber": {
+        "message": "Telefon 2 zu Hause:"
+    },
+    "abCard.ManagerName": {
+        "message": "Manager:"
+    },
+    "abCard.MiddleName": {
+        "message": "Zweiter Vorname:"
+    },
+    "abCard.OtherAddress": {
+        "message": "Adresse:"
+    },
+    "abCard.OtherCity": {
+        "message": "Stadt:"
+    },
+    "abCard.OtherCountry": {
+        "message": "Land:"
+    },
+    "abCard.OtherState": {
+        "message": "Bundesland:"
+    },
+    "abCard.OtherZip": {
+        "message": "Postleitzahl:"
+    },
+    "abCard.RadioPhoneNumber": {
+        "message": "Funktelefon:"
+    },
+    "abCard.Spouse": {
+        "message": "Ehepartner:"
+    },
+    "abCard.header.eas": {
+        "message": "Weitere Felder (EAS)"
+    },
+    "abCard.header.homenumbers": {
+        "message": "Zus?tzliche Nummern zu Hause:"
+    },
+    "abCard.header.messaging": {
+        "message": "Nachrichten:"
+    },
+    "abCard.header.otheraddress": {
+        "message": "Weitere Adresse (EAS)"
+    },
+    "abCard.header.othernumbers": {
+        "message": "Zus?tzliche Nummern:"
+    },
+    "abCard.header.people": {
+        "message": "Personen:"
+    },
+    "abCard.header.worknumbers": {
+        "message": "Zus?tzliche Nummern Arbeit:"
+    },
+    "acl.readonly": {
+        "message": "Serverzugriff nur lesend (verwerfe lokale ?nderungen)"
+    },
+    "acl.readwrite": {
+        "message": "Serverzugriff lesend und schreibend"
+    },
+    "add.description": {
+        "message": "Bitte w?hlen Sie eine der verf?gbaren Server-Konfigurationen aus und geben Sie die angeforderten Details ein. "
+    },
+    "add.name": {
+        "message": "Kontoname:"
+    },
+    "add.ok": {
+        "message": "Konto hinzuf?gen"
+    },
+    "add.password": {
+        "message": "Passwort:"
+    },
+    "add.server": {
+        "message": "Server Konfiguration:"
+    },
+    "add.shortdescription": {
+        "message": "Kontoinformationen"
+    },
+    "add.title": {
+        "message": "Exchange ActiveSync Konto hinzuf?gen"
+    },
+    "add.url": {
+        "message": "Server Adresse:"
+    },
+    "add.urldescription": {
+        "message": "Meist reicht die Angabe der einfachen Serveradresse (z.B.: mail.meinserver.de), alternativ kann aber auch die komplette URL angegeben werden (z.B.: https://mail.meinserver.de/Microsoft-Server-ActiveSync)."
+    },
+    "add.user": {
+        "message": "Benutzername (E-Mail Adresse):"
+    },
+    "autocomplete.serverdirectory": {
+        "message": "Globales Serververzeichnis"
+    },
+    "autodiscover.Failed": {
+        "message": "Autodiscover f?r den Benutzer <##user##> war nicht erfolgreich. Entweder war das Passwort nicht korrekt, Ihr ActiveSync Server hat ein tempor?res Problem oder unterst?tzt kein Autodiscover."
+    },
+    "autodiscover.NeedEmail": {
+        "message": "Autodiscover ben?tigt eine g?ltige E-Mail Adresse als Benutzername."
+    },
+    "autodiscover.Ok": {
+        "message": "Autodiscover war erfolgreich, Sie k?nnen nun die optionalen Einstellungen ?berpr?fen und die Synchronisationsverbindung aktivieren."
+    },
+    "autodiscover.Querying": {
+        "message": "Einstellungen werden gesucht ..."
+    },
+    "config.auto": {
+        "message": "ActiveSync Server Konfiguration (Autodiscover)"
+    },
+    "config.custom": {
+        "message": "ActiveSync Server Konfiguration"
+    },
+    "deletefolder.confirm": {
+        "message": "M?chten Sie den Ordner '##replace.1##' wirklich ENDG?LTIG aus dem Papierkorb ENTFERNEN?"
+    },
+    "deletefolder.menuentry": {
+        "message": "Den Ordner '##replace.1##' endg?ltig aus dem Papierkorb entfernen"
+    },
+    "deletefolder.notallowed": {
+        "message": "Bitte beenden Sie zun?chst das Abonement des Ordner '##replace.1##', bevor Sie diesen aus dem Papierkorb entfernen."
+    },
+    "extensionDescription": {
+        "message": "Erweitert TbSync und erlaubt die Synchronisation von Exchange ActiveSync Konten (Kontakte, Aufgaben und Kalender)."
+    },
+    "extensionName": {
+        "message": "Provider f?r Exchange ActiveSync"
+    },
+    "helplink.BadItemSkipped": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
+    },
+    "helplink.global.clientdenied": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "manager.tabs.accountsettings": {
+        "message": "Kontoeinstellungen"
+    },
+    "manager.tabs.outOfOffice": {
+        "message": "Autoresponder"
+    },
+    "manager.tabs.syncsettings": {
+        "message": "Optionen"
+    },
+    "newaccount.add_auto": {
+        "message": "Einstellungen suchen und Konto hinzuf?gen"
+    },
+    "newaccount.add_custom": {
+        "message": "Konto hinzuf?gen"
+    },
+    "pref.AccountName": {
+        "message": "Kontoname"
+    },
+    "pref.ActiveSyncVersion": {
+        "message": "ActiveSync Version"
+    },
+    "pref.DeviceId": {
+        "message": "ActiveSync Ger?te ID"
+    },
+    "pref.ServerName": {
+        "message": "Server Adresse"
+    },
+    "pref.ServerNameDescription": {
+        "message": "z.B. mail.meinserver.com"
+    },
+    "pref.ShowTrashedFolders": {
+        "message": "Im Papierkorb gefundene Ordner anzeigen"
+    },
+    "pref.UserName": {
+        "message": "Benutzername"
+    },
+    "pref.UserNameDescription": {
+        "message": "Der Benutzername ist meistens die E-Mail Adresse Ihres Kontos."
+    },
+    "pref.autodetect": {
+        "message": "bestm?glich"
+    },
+    "pref.birthday": {
+        "message": "Sende Geburtstagsinformation"
+    },
+    "pref.calendaroptions": {
+        "message": "Kalender Optionen"
+    },
+    "pref.contactoptions": {
+        "message": "Kontakt Optionen"
+    },
+    "pref.displayoverride": {
+        "message": "?berschreibe Anzeigename mit 'Vorname' + 'Nachname'"
+    },
+    "pref.generaloptions": {
+        "message": "Allgemeine Optionen"
+    },
+    "pref.provision": {
+        "message": "Provisionierung erzwingen (wird von Kerio ben?tigt)"
+    },
+    "pref.seperator.comma": {
+        "message": "Komma"
+    },
+    "pref.seperator.description": {
+        "message": "Separator f?r mehrzeilige Adressfelder: "
+    },
+    "pref.seperator.linebreak": {
+        "message": "Zeilenumbruch"
+    },
+    "pref.synclimit.1month": {
+        "message": "ab vor 4 Wochen"
+    },
+    "pref.synclimit.2weeks": {
+        "message": "ab vor 2 Wochen"
+    },
+    "pref.synclimit.3month": {
+        "message": "ab vor 3 Monaten"
+    },
+    "pref.synclimit.6month": {
+        "message": "ab vor 6 Monaten"
+    },
+    "pref.synclimit.all": {
+        "message": "alles"
+    },
+    "pref.synclimit.description": {
+        "message": "Synchronisationszeitraum: "
+    },
+    "pref.usehttps": {
+        "message": "Sichere Verbindungen verwenden (via https://)"
+    },
+    "recyclebin": {
+        "message": "Papierkorb"
+    },
+    "servertype.auto": {
+        "message": "Automatische Konfiguration"
+    },
+    "servertype.custom": {
+        "message": "Benutzerspezifische Konfiguration"
+    },
+    "servertype.description.auto": {
+        "message": "Die Konfiguration vieler ActiveSync Server kann allein durch die Angabe Ihrer E-Mail-Adresse erfolgen."
+    },
+    "servertype.description.custom": {
+        "message": "Richten Sie Ihr Konto ein, indem Sie die Adresse des Servers angeben, mit dem Sie sich verbinden m?chten."
+    },
+    "servertype.description.office365": {
+        "message": "Konten, die mit Office 365 verbunden sind, verwenden den modernen OAuth 2.0 Authentifizierungsprozess, der auch Multi-Factor-Authentication (MFA) unterst?tzt."
+    },
+    "servertype.office365": {
+        "message": "Microsoft Office 365"
+    },
+    "servertype.unlock": {
+        "message": "Doppelklick um die vordefinierten Servereinstellungen zu entsperren."
+    },
+    "status.401": {
+        "message": "Authentifizierung fehlgeschlagen, ?berpr?fen Sie den Benutzernamen und das Passwort."
+    },
+    "status.403": {
+        "message": "Verbindung vom Server abgelehnt (nicht erlaubt)."
+    },
+    "status.404": {
+        "message": "Unbekanner Benutzer (HTTP Fehler 404)."
+    },
+    "status.449": {
+        "message": "Server erwartet Provisionierung."
+    },
+    "status.500": {
+        "message": "Unbekannter Server Fehler (HTTP Fehler 500)."
+    },
+    "status.503": {
+        "message": "Service nicht erreichbar."
+    },
+    "status.BadItemSkipped": {
+        "message": "Ein Element wurde nicht synchronisiert: ##replace.1##"
+    },
+    "status.FolderDelete.3": {
+        "message": "Systemordner k?nnen nicht gel?scht werden."
+    },
+    "status.FolderDelete.4": {
+        "message": "Ordner existiert nicht,  es wird neu synchronisiert"
+    },
+    "status.FolderDelete.6": {
+        "message": "Das Kommando konnte nicht abgeschlossen werden, auf dem Server ist ein Fehler aufgetreten."
+    },
+    "status.FolderDelete.9": {
+        "message": "Ung?ltiger Synchronisationsschl?ssel, es wird neu synchronisiert"
+    },
+    "status.FolderSync.9": {
+        "message": "Ung?ltiger Synchronisationsschl?ssel, es wird neu synchronisiert"
+    },
+    "status.InvalidServerOptions": {
+        "message": "Der Server sendet keine Informationen zu den unterst?tzten ActiveSync Versionen. Ist EAS f?r diesen Benutzer bzw. f?r dieses Programm (TbSync) freigeschaltet? Sie k?nnen versuchen, die ActiveSync Version manuell festzulegen."
+    },
+    "status.OK": {
+        "message": "Ok"
+    },
+    "status.ServerRejectedRequest": {
+        "message": "Der EAS Server hat die letzte Anforderung zur?ckgewiesen."
+    },
+    "status.ServerRejectedSomeItems": {
+        "message": "Der EAS Server hat ##replace.1## Elemente nicht akzeptiert."
+    },
+    "status.Sync.12": {
+        "message": "Ordnerhierarchie hat sich ge?ndert, es wird neu synchronisiert"
+    },
+    "status.Sync.3": {
+        "message": "Ung?ltiger Synchronisationsschl?ssel, es wird neu synchronisiert"
+    },
+    "status.Sync.4": {
+        "message": "Fehlerhafte Anfrage (Status 4)"
+    },
+    "status.Sync.5": {
+        "message": "Tempor?res Serverproblem oder ung?ltiges Element (Status 5)"
+    },
+    "status.Sync.6": {
+        "message": "Ung?ltiges Element (Status 6)"
+    },
+    "status.Sync.8": {
+        "message": "Objekt nicht gefunden (Status 8)"
+    },
+    "status.aborted": {
+        "message": "Nicht synchronisiert"
+    },
+    "status.disabled": {
+        "message": "Konto ist deaktiviert, Synchronisation ist ausgeschaltet."
+    },
+    "status.empty-response": {
+        "message": "Server sendet unerwartete leere Antwort."
+    },
+    "status.forbiddenCalendarItemInTasksFolder": {
+        "message": "Unerlaubtes Kalender-Element in einem Aufgaben-Objekt (bitte umsortieren)"
+    },
+    "status.forbiddenTasksItemInCalendarFolder": {
+        "message": "Unerlaubtes Aufgaben-Element in einem Kalender-Objekt (bitte umsortieren)"
+    },
+    "status.global.101": {
+        "message": "Das WBXML der Anfrage konnte nicht in g?ltiges XML dekodiert werden (EAS Fehler 101)."
+    },
+    "status.global.102": {
+        "message": "Das WBXML der Anfrage konnte nicht in g?ltiges XML dekodiert werden (EAS Fehler 102)."
+    },
+    "status.global.103": {
+        "message": "Das XML der Anfrage entspricht nicht den Protokollanforderungen (EAS Fehler 103)."
+    },
+    "status.global.110": {
+        "message": "Der Server meldet einen internen Fehler und es soll nicht unmittelbar ein erneuter Verbindungsaufbau durchgef?hrt werden. Die automatische periodische Synchronisation wird f?r 30 Minuten ausgesetzt (EAS Fehler 110)."
+    },
+    "status.global.clientdenied": {
+        "message": "Der EAS Server antwortet mit <##replace.2##> (status ##replace.1##) und verweigert TbSync den Zugriff auf Ihr Konto."
+    },
+    "status.httperror": {
+        "message": "Kommunikationsfehler (HTTP Status ##replace.1##)."
+    },
+    "status.invalid": {
+        "message": "Ung?ltige Serverantwort."
+    },
+    "status.malformed-xml": {
+        "message": "Antwort enth?lt fehlerhaftes XML, Sync angebrochen. Pr?fen Sie bitte das Ereignisprotokoll f?r weitere Details."
+    },
+    "status.modified": {
+        "message": "Lokale ?nderungen"
+    },
+    "status.network": {
+        "message": "Verbindung zum Server fehlgeschlagen (##replace.1##)."
+    },
+    "status.networkerror": {
+        "message": "Verbindung zum Server fehlgeschlagen."
+    },
+    "status.nosupportedeasversion": {
+        "message": "Der Server unterst?tzt kein ActiveSync v2.5 oder v14.0 (nur ##replace.1##). TbSync kann nicht mit diesem Server arbeiten."
+    },
+    "status.notargets": {
+        "message": "Synchronisation abgebrochen da die Elemente zum Synchronisieren nicht erstellt werden konnten."
+    },
+    "status.notsupportedeasversion": {
+        "message": "Der Server unterst?tzt nicht die ausgew?hlte ActiveSync Version v##replace.1## (nur ##replace.2##)."
+    },
+    "status.notsyncronized": {
+        "message": "Konto muss synchronisiert werden."
+    },
+    "status.nouserhost": {
+        "message": "Angabe des Benutzernamens und/oder des Servers fehlt. Bitte die korrekten Informationen eintragen."
+    },
+    "status.pending": {
+        "message": "Warten auf Synchronisation"
+    },
+    "status.policy.2": {
+        "message": "Es gibt keine Regel (policy) f?r diesen Klient. Kontaktieren Sie Ihren Server Administrator oder deaktivieren Sie die Provisionierungsoption f?r dieses Konto in TbSync."
+    },
+    "status.policy.3": {
+        "message": "Unbekannter Wert f?r den Regeltyp (policy type). Kontaktieren Sie Ihren Server Administrator oder deaktivieren Sie die Provisionierungsoption f?r dieses Konto in TbSync."
+    },
+    "status.policy.4": {
+        "message": "Die Daten f?r die Regeln auf dem Server sind besch?digt (m?glicherweise manipuliert). Kontaktieren Sie Ihren Server Administrator oder deaktivieren Sie die Provisionierungsoption f?r dieses Konto in TbSync."
+    },
+    "status.policy.5": {
+        "message": "Der Klient best?tigt einen falschen Richtlinienschl?ssel (policy key). Kontaktieren Sie Ihren Server Administrator oder deaktivieren Sie die Provisionierungsoption f?r dieses Konto in TbSync."
+    },
+    "status.provision": {
+        "message": "Provisionierung fehlerhaft mit folgendem Status <##replace.1##>"
+    },
+    "status.response-contains-no-data": {
+        "message": "Antwort vom Server enth?lt keine Daten."
+    },
+    "status.resync-loop": {
+        "message": "Es ist ein Fehler aufgetreten, der nicht durch wiederholtes Synchronisieren des Kontos behoben werden konnte. Bitte deaktivieren sie das Konto und wiederholen den Vorgang. (Fehler: Synchronisationsschleife)"
+    },
+    "status.security": {
+        "message": "Fehler beim Aufbau einer sicherern Verbindung. Benutzen Sie eventuell ein selbst signiertes Zertifikat oder ein andersartiges nicht vertrauensw?rdiges Zertifikat welches nicht in Thunderbird importiert ist? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "Nicht unterst?tzt"
+    },
+    "status.syncing": {
+        "message": "Synchronisierung"
+    },
+    "status.timeout": {
+        "message": "Kommunikations-Timeout."
+    },
+    "status.wbxml-parse-error": {
+        "message": "Server sendet nicht lesbare Antwort."
+    },
+    "status.wbxmlerror": {
+        "message": "Synchronisation fehlgeschlagen. Der Server antwortete mit dem Status <##replace.1##>."
+    },
+    "status.wbxmlmissingfield": {
+        "message": "Verletzung des ActiveSync Protokolls: Notwendiges Feld <##replace.1##> ist nicht in der Serverantwort enthalten."
+    },
+    "syncstate.accountdone": {
+        "message": "Kontosynchronisation abgeschlossen"
+    },
+    "syncstate.done": {
+        "message": "Bereite das n?chste Element f?r die Synchronisation vor"
+    },
+    "syncstate.eval.response.autodiscover": {
+        "message": "Verarbeite aktualisierte Servereinstellungen"
+    },
+    "syncstate.eval.response.deletefolder": {
+        "message": "Ordner erfolgreich gel?scht"
+    },
+    "syncstate.eval.response.estimate": {
+        "message": "Verarbeite gesch?tzte ?nderungen"
+    },
+    "syncstate.eval.response.folders": {
+        "message": "Verarbeite aktualisierte Ordnerliste"
+    },
+    "syncstate.eval.response.localchanges": {
+        "message": "Verarbeite Best?tigung der lokalen ?nderungen"
+    },
+    "syncstate.eval.response.localdeletes": {
+        "message": "Verarbeite Best?tigung lokal gel?schten Elemente"
+    },
+    "syncstate.eval.response.options": {
+        "message": "Verarbeite aktualisierte Serveroptionen"
+    },
+    "syncstate.eval.response.provision": {
+        "message": "Verarbeite Provisionierung"
+    },
+    "syncstate.eval.response.remotechanges": {
+        "message": "Verarbeite aktualisierte Elemente"
+    },
+    "syncstate.eval.response.revertlocalchanges": {
+        "message": "Lokale ?nderungen werden verworfen"
+    },
+    "syncstate.eval.response.setdeviceinfo": {
+        "message": "Sende Ger?teinformationen"
+    },
+    "syncstate.eval.response.synckey": {
+        "message": "Verarbeite Synchronisationsschl?ssel"
+    },
+    "syncstate.prepare.request.autodiscover": {
+        "message": "Sende Anfrage bzgl. aktualisierter Servereinstellungen"
+    },
+    "syncstate.prepare.request.deletefolder": {
+        "message": "L?schen des Ordners wird vorbereitet"
+    },
+    "syncstate.prepare.request.estimate": {
+        "message": "Sende Anfrage bzgl. gesch?tzter ?nderungen"
+    },
+    "syncstate.prepare.request.folders": {
+        "message": "Sende Anfrage bzgl. aktualisierter Ordnerliste"
+    },
+    "syncstate.prepare.request.localchanges": {
+        "message": "Sende lokale ?nderungen"
+    },
+    "syncstate.prepare.request.localdeletes": {
+        "message": "Sende die lokal gel?schten Elemente"
+    },
+    "syncstate.prepare.request.options": {
+        "message": "Sende Anfrage bzgl. aktualisierter Serveroptionen"
+    },
+    "syncstate.prepare.request.provision": {
+        "message": "Sende Anfrage bzgl. Provisionierung"
+    },
+    "syncstate.prepare.request.remotechanges": {
+        "message": "Sende Anfrage bzgl. ?nderungen"
+    },
+    "syncstate.prepare.request.revertlocalchanges": {
+        "message": "Pr?fe lokale ?nderungen"
+    },
+    "syncstate.prepare.request.setdeviceinfo": {
+        "message": "Sende Ger?teinformationen"
+    },
+    "syncstate.prepare.request.synckey": {
+        "message": "Sende Anfrage bzgl. Synchronisationsschl?ssel"
+    },
+    "syncstate.preparing": {
+        "message": "Bereite das n?chste Element f?r die Synchronisation vor"
+    },
+    "syncstate.send.request.autodiscover": {
+        "message": "Warte auf aktualisierte Servereinstellungen"
+    },
+    "syncstate.send.request.deletefolder": {
+        "message": "Ordner wird gel?scht"
+    },
+    "syncstate.send.request.estimate": {
+        "message": "Warte auf gesch?tzte ?nderungen"
+    },
+    "syncstate.send.request.folders": {
+        "message": "Warte auf aktualisierte Ordnerliste"
+    },
+    "syncstate.send.request.localchanges": {
+        "message": "Warte auf Best?tigung der lokalen ?nderungen"
+    },
+    "syncstate.send.request.localdeletes": {
+        "message": "Warte auf Best?tigung lokal gel?schten Elemente"
+    },
+    "syncstate.send.request.options": {
+        "message": "Warte auf aktualisierte Serveroptionen"
+    },
+    "syncstate.send.request.provision": {
+        "message": "Warte auf Provisionierung"
+    },
+    "syncstate.send.request.remotechanges": {
+        "message": "Warte auf aktualisierte Elemente"
+    },
+    "syncstate.send.request.revertlocalchanges": {
+        "message": "Warte auf aktuelle Versionen"
+    },
+    "syncstate.send.request.setdeviceinfo": {
+        "message": "Sende Ger?teinformationen"
+    },
+    "syncstate.send.request.synckey": {
+        "message": "Warte auf Synchronisationsschl?ssel"
+    },
+    "syncstate.syncing": {
+        "message": "Initiiere Synchronisation"
+    }
+}
diff -Nru eas4tbsync-4.11/_locales/en-US/messages.json eas4tbsync-4.17/_locales/en-US/messages.json
--- eas4tbsync-4.11/_locales/en-US/messages.json	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/_locales/en-US/messages.json	2025-05-15 13:21:18.000000000 +0200
@@ -1,566 +1,566 @@
-{
-    "abCard.Anniversary": {
-        "message": "Anniversary:"
-    },
-    "abCard.AssistantName": {
-        "message": "Assistant:"
-    },
-    "abCard.AssistantPhoneNumber": {
-        "message": "Assistant Phone:"
-    },
-    "abCard.Business2PhoneNumber": {
-        "message": "Work Alternative Phone:"
-    },
-    "abCard.BusinessFaxNumber": {
-        "message": "Work Fax:"
-    },
-    "abCard.CarPhoneNumber": {
-        "message": "Car Phone:"
-    },
-    "abCard.CompanyMainPhone": {
-        "message": "Work Main Phone:"
-    },
-    "abCard.Email3Address": {
-        "message": "Alternative Email:"
-    },
-    "abCard.Home2PhoneNumber": {
-        "message": "Home Alternative Phone:"
-    },
-    "abCard.ManagerName": {
-        "message": "Manager:"
-    },
-    "abCard.MiddleName": {
-        "message": "Middle name:"
-    },
-    "abCard.OtherAddress": {
-        "message": "Address:"
-    },
-    "abCard.OtherCity": {
-        "message": "City:"
-    },
-    "abCard.OtherCountry": {
-        "message": "Country:"
-    },
-    "abCard.OtherState": {
-        "message": "State:"
-    },
-    "abCard.OtherZip": {
-        "message": "ZIP Code:"
-    },
-    "abCard.RadioPhoneNumber": {
-        "message": "Radio Phone:"
-    },
-    "abCard.Spouse": {
-        "message": "Spouse:"
-    },
-    "abCard.header.eas": {
-        "message": "Other Fields (EAS)"
-    },
-    "abCard.header.homenumbers": {
-        "message": "Additional home numbers:"
-    },
-    "abCard.header.messaging": {
-        "message": "Messaging:"
-    },
-    "abCard.header.otheraddress": {
-        "message": "Other Address (EAS)"
-    },
-    "abCard.header.othernumbers": {
-        "message": "Additional numbers:"
-    },
-    "abCard.header.people": {
-        "message": "People:"
-    },
-    "abCard.header.worknumbers": {
-        "message": "Additional work numbers:"
-    },
-    "acl.readonly": {
-        "message": "Read-only server access (revert local changes)"
-    },
-    "acl.readwrite": {
-        "message": "Read from and write to server"
-    },
-    "add.description": {
-        "message": "Please select one of the available server configuration options and enter the requested details. "
-    },
-    "add.name": {
-        "message": "Account name:"
-    },
-    "add.ok": {
-        "message": "Add account"
-    },
-    "add.password": {
-        "message": "Password:"
-    },
-    "add.server": {
-        "message": "Server configuration:"
-    },
-    "add.shortdescription": {
-        "message": "Account information"
-    },
-    "add.title": {
-        "message": "Adding an Exchange ActiveSync account to TbSync"
-    },
-    "add.url": {
-        "message": "Server address:"
-    },
-    "add.urldescription": {
-        "message": "It should be sufficient to provide just the basic server address (e.g.: mail.yourserver.com). However, it is also possible to provide the full URL (e.g.: https://mail.yourserver.com/Microsoft-Server-ActiveSync)."
-    },
-    "add.user": {
-        "message": "User name (email address):"
-    },
-    "autocomplete.serverdirectory": {
-        "message": "global server directory"
-    },
-    "autodiscover.Failed": {
-        "message": "Autodiscover for user <##user##> failed. Either the provided credentials were wrong or your ActiveSync provider has a temporary issue, or does not support Autodiscover."
-    },
-    "autodiscover.NeedEmail": {
-        "message": "Autodiscover needs a valid email address as user name."
-    },
-    "autodiscover.Ok": {
-        "message": "Autodiscover completed successfully, you can now check the optional settings and establish the synchronization connection."
-    },
-    "autodiscover.Querying": {
-        "message": "Searching for settings?"
-    },
-    "config.auto": {
-        "message": "ActiveSync server configuration (Autodiscover)"
-    },
-    "config.custom": {
-        "message": "ActiveSync server configuration"
-    },
-    "deletefolder.confirm": {
-        "message": "Do you really want to PERMANENTLY PURGE folder ?##replace.1##? from trash?"
-    },
-    "deletefolder.menuentry": {
-        "message": "Permanently purge folder ?##replace.1##? from trash"
-    },
-    "deletefolder.notallowed": {
-        "message": "Please unsubscribe folder ?##replace.1##? before trying to purge it from trash."
-    },
-    "extensionDescription": {
-        "message": "Add sync support for Exchange ActiveSync accounts to TbSync (contacts, tasks and calendars)."
-    },
-    "extensionName": {
-        "message": "Provider for Exchange ActiveSync"
-    },
-    "helplink.BadItemSkipped": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
-    },
-    "helplink.global.clientdenied": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "manager.tabs.accountsettings": {
-        "message": "Account settings"
-    },
-    "manager.tabs.outOfOffice": {
-        "message": "Auto responder"
-    },
-    "manager.tabs.syncsettings": {
-        "message": "Options"
-    },
-    "newaccount.add_auto": {
-        "message": "Autodiscover settings and add account"
-    },
-    "newaccount.add_custom": {
-        "message": "Add account"
-    },
-    "pref.AccountName": {
-        "message": "Description"
-    },
-    "pref.ActiveSyncVersion": {
-        "message": "ActiveSync version"
-    },
-    "pref.DeviceId": {
-        "message": "ActiveSync device ID"
-    },
-    "pref.ServerName": {
-        "message": "Server address"
-    },
-    "pref.ServerNameDescription": {
-        "message": "e.g. mail.yourserver.com"
-    },
-    "pref.ShowTrashedFolders": {
-        "message": "Show folders found in trash"
-    },
-    "pref.UserName": {
-        "message": "User name"
-    },
-    "pref.UserNameDescription": {
-        "message": "User name is usually the email address of your account."
-    },
-    "pref.autodetect": {
-        "message": "best available"
-    },
-    "pref.birthday": {
-        "message": "Send birthday information"
-    },
-    "pref.calendaroptions": {
-        "message": "Calendar options"
-    },
-    "pref.contactoptions": {
-        "message": "Contact options"
-    },
-    "pref.displayoverride": {
-        "message": "Override Display Name with ?First Name? + ?Second Name?"
-    },
-    "pref.generaloptions": {
-        "message": "General options"
-    },
-    "pref.provision": {
-        "message": "Enforce provisioning (required by Kerio)"
-    },
-    "pref.seperator.comma": {
-        "message": "Comma"
-    },
-    "pref.seperator.description": {
-        "message": "Separator for multiline address field."
-    },
-    "pref.seperator.linebreak": {
-        "message": "Line break"
-    },
-    "pref.synclimit.1month": {
-        "message": "from 4 weeks ago"
-    },
-    "pref.synclimit.2weeks": {
-        "message": "from 2 weeks ago"
-    },
-    "pref.synclimit.3month": {
-        "message": "from 3 months ago"
-    },
-    "pref.synclimit.6month": {
-        "message": "from 6 months ago"
-    },
-    "pref.synclimit.all": {
-        "message": "everything"
-    },
-    "pref.synclimit.description": {
-        "message": "Synchronization period: "
-    },
-    "pref.usehttps": {
-        "message": "Use secure connection (connect via https)"
-    },
-    "recyclebin": {
-        "message": "Trash"
-    },
-    "servertype.auto": {
-        "message": "Automatic configuration"
-    },
-    "servertype.custom": {
-        "message": "Custom configuration"
-    },
-    "servertype.description.auto": {
-        "message": "The configuration for many ActiveSync servers can be discovered by providing just your email address."
-    },
-    "servertype.description.custom": {
-        "message": "Setup your account by manually providing the address of the server you want to connect."
-    },
-    "servertype.description.office365": {
-        "message": "Accounts connected to Office 365 use a modern authentication process called OAuth 2.0 which also supports Multi-Factor-Authentication (MFA)."
-    },
-    "servertype.office365": {
-        "message": "Microsoft Office 365"
-    },
-    "servertype.unlock": {
-        "message": "Double click to unlock all predefined server settings."
-    },
-    "status.401": {
-        "message": "Could not authenticate, check username and password (HTTP Error 401)."
-    },
-    "status.403": {
-        "message": "Server rejected connection (forbidden) (HTTP Error 403)."
-    },
-    "status.404": {
-        "message": "User not found (HTTP Error 404)."
-    },
-    "status.449": {
-        "message": "Server requests provisioning (HTTP Error 449)."
-    },
-    "status.500": {
-        "message": "Unknown Server Error (HTTP Error 500)."
-    },
-    "status.503": {
-        "message": "Service unavailable (HTTP Error 503)."
-    },
-    "status.BadItemSkipped": {
-        "message": "Bad Item Skipped: ##replace.1##"
-    },
-    "status.FolderDelete.3": {
-        "message": "Cannot delete a system folder (status 3)"
-    },
-    "status.FolderDelete.4": {
-        "message": "Folder does not exist (status 4), resyncing"
-    },
-    "status.FolderDelete.6": {
-        "message": "Command could not be completed, an error occurred on the server (status 6)"
-    },
-    "status.FolderDelete.9": {
-        "message": "Invalid synchronization key (status 9), resyncing"
-    },
-    "status.FolderSync.9": {
-        "message": "Invalid synchronization key (status 9), resyncing"
-    },
-    "status.InvalidServerOptions": {
-        "message": "The server does not provide information about the supported ActiveSync versions. Is EAS blocked for this user or this client (TbSync)? You could try to set the ActiveSync version manually."
-    },
-    "status.OK": {
-        "message": "OK"
-    },
-    "status.ServerRejectedRequest": {
-        "message": "The EAS Server rejected the last request."
-    },
-    "status.ServerRejectedSomeItems": {
-        "message": "The EAS server did not accept ##replace.1## elements."
-    },
-    "status.Sync.12": {
-        "message": "Folder hierarchy changed (status 12), resyncing"
-    },
-    "status.Sync.3": {
-        "message": "Invalid synchronization key (status 3), resyncing"
-    },
-    "status.Sync.4": {
-        "message": "Malformed request (status 4)"
-    },
-    "status.Sync.5": {
-        "message": "Temporary server issues or invalid item (status 5)"
-    },
-    "status.Sync.6": {
-        "message": "Invalid item (status 6)"
-    },
-    "status.Sync.8": {
-        "message": "Object not found (status 8)"
-    },
-    "status.aborted": {
-        "message": "Not synchronized"
-    },
-    "status.disabled": {
-        "message": "Disabled"
-    },
-    "status.empty-response": {
-        "message": "Server sends unexpected empty response."
-    },
-    "status.forbiddenCalendarItemInTasksFolder": {
-        "message": "Forbidden calendar item in a task folder (please resort)"
-    },
-    "status.forbiddenTasksItemInCalendarFolder": {
-        "message": "Forbidden task item in a calendar folder (please resort)"
-    },
-    "status.global.101": {
-        "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 101)."
-    },
-    "status.global.102": {
-        "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 102)."
-    },
-    "status.global.103": {
-        "message": "The XML provided in the request does not follow the protocol requirements (EAS Error 103)."
-    },
-    "status.global.110": {
-        "message": "The server reported an internal error and we should not retry immediately. Automatic periodic sync has been disabled for 30 minutes (EAS Error 110)."
-    },
-    "status.global.clientdenied": {
-        "message": "The EAS server reports <##replace.2##> (status ##replace.1##) and does not allow TbSync to access your account."
-    },
-    "status.httperror": {
-        "message": "Communication error (HTTP status ##replace.1##)."
-    },
-    "status.invalid": {
-        "message": "Invalid server response (junk)."
-    },
-    "status.malformed-xml": {
-        "message": "Could not parse XML. Check event log for details."
-    },
-    "status.modified": {
-        "message": "Local modifications"
-    },
-    "status.network": {
-        "message": "Could not connect to server (##replace.1##)."
-    },
-    "status.networkerror": {
-        "message": "Could not connect to server."
-    },
-    "status.nosupportedeasversion": {
-        "message": "Server does not support ActiveSync v2.5 or v14.0 (only ##replace.1##). TbSync will not work with this ActiveSync server."
-    },
-    "status.notargets": {
-        "message": "Aborting Sync, because sync targets could not be created."
-    },
-    "status.notsupportedeasversion": {
-        "message": "Server does not support selected ActiveSync v##replace.1## (only ##replace.2##)."
-    },
-    "status.notsyncronized": {
-        "message": "Account needs to be synchronized, at least one item is out of sync."
-    },
-    "status.nouserhost": {
-        "message": "Missing username and/or server. Please provide those values."
-    },
-    "status.pending": {
-        "message": "Waiting to be synchronized"
-    },
-    "status.policy.2": {
-        "message": "There is no policy for this client. Contact your server administrator or disable provisioning for this account."
-    },
-    "status.policy.3": {
-        "message": "Unknown PolicyType value. Contact your server administrator or disable provisioning for this account."
-    },
-    "status.policy.4": {
-        "message": "The policy data on the server is corrupted (possibly tampered with). Contact your server administrator or disable provisioning for this account."
-    },
-    "status.policy.5": {
-        "message": "The client is acknowledging the wrong policy key. Contact your server administrator or disable provisioning for this account."
-    },
-    "status.provision": {
-        "message": "Provisioning failed with status <##replace.1##>"
-    },
-    "status.response-contains-no-data": {
-        "message": "Response from the server contains no data."
-    },
-    "status.resync-loop": {
-        "message": "There was an error from which we could not recover by resyncing the account. Please disable the account and try again. (Error: resync loop)"
-    },
-    "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.syncing": {
-        "message": "Synchronizing"
-    },
-    "status.timeout": {
-        "message": "Communication timeout."
-    },
-    "status.wbxml-parse-error": {
-        "message": "Server sends unreadable response."
-    },
-    "status.wbxmlerror": {
-        "message": "Sync failed. Server responded with status <##replace.1##>."
-    },
-    "status.wbxmlmissingfield": {
-        "message": "ActiveSync protocol violation: Mandatory field <##replace.1##> is missing from server response."
-    },
-    "syncstate.accountdone": {
-        "message": "Finished account"
-    },
-    "syncstate.done": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.eval.response.autodiscover": {
-        "message": "Processing updated server settings"
-    },
-    "syncstate.eval.response.deletefolder": {
-        "message": "Folder deleted"
-    },
-    "syncstate.eval.response.estimate": {
-        "message": "Processing change estimate"
-    },
-    "syncstate.eval.response.folders": {
-        "message": "Processing folder list update"
-    },
-    "syncstate.eval.response.localchanges": {
-        "message": "Processing acknowledgment of local changes"
-    },
-    "syncstate.eval.response.localdeletes": {
-        "message": "Processing acknowledgment of local deletes"
-    },
-    "syncstate.eval.response.options": {
-        "message": "Processing server options"
-    },
-    "syncstate.eval.response.provision": {
-        "message": "Processing provision"
-    },
-    "syncstate.eval.response.remotechanges": {
-        "message": "Processing remote changes"
-    },
-    "syncstate.eval.response.revertlocalchanges": {
-        "message": "Reverting local changes"
-    },
-    "syncstate.eval.response.setdeviceinfo": {
-        "message": "Sending device information"
-    },
-    "syncstate.eval.response.synckey": {
-        "message": "Processing SyncKey"
-    },
-    "syncstate.prepare.request.autodiscover": {
-        "message": "Requesting updated server settings"
-    },
-    "syncstate.prepare.request.deletefolder": {
-        "message": "Preparing to delete folder"
-    },
-    "syncstate.prepare.request.estimate": {
-        "message": "Requesting change estimate"
-    },
-    "syncstate.prepare.request.folders": {
-        "message": "Sending folder list update"
-    },
-    "syncstate.prepare.request.localchanges": {
-        "message": "Sending local changes"
-    },
-    "syncstate.prepare.request.localdeletes": {
-        "message": "Sending local deletes"
-    },
-    "syncstate.prepare.request.options": {
-        "message": "Requesting server options"
-    },
-    "syncstate.prepare.request.provision": {
-        "message": "Requesting provision"
-    },
-    "syncstate.prepare.request.remotechanges": {
-        "message": "Requesting remote changes"
-    },
-    "syncstate.prepare.request.revertlocalchanges": {
-        "message": "Collecting local changes"
-    },
-    "syncstate.prepare.request.setdeviceinfo": {
-        "message": "Sending device information"
-    },
-    "syncstate.prepare.request.synckey": {
-        "message": "Requesting SyncKey"
-    },
-    "syncstate.preparing": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.send.request.autodiscover": {
-        "message": "Waiting for updated server settings"
-    },
-    "syncstate.send.request.deletefolder": {
-        "message": "Waiting for folder to be deleted"
-    },
-    "syncstate.send.request.estimate": {
-        "message": "Waiting for change estimate"
-    },
-    "syncstate.send.request.folders": {
-        "message": "Waiting for folder list update"
-    },
-    "syncstate.send.request.localchanges": {
-        "message": "Waiting for acknowledgment of local changes"
-    },
-    "syncstate.send.request.localdeletes": {
-        "message": "Waiting for acknowledgment of local deletes"
-    },
-    "syncstate.send.request.options": {
-        "message": "Waiting for server options"
-    },
-    "syncstate.send.request.provision": {
-        "message": "Waiting for provision"
-    },
-    "syncstate.send.request.remotechanges": {
-        "message": "Waiting for remote changes"
-    },
-    "syncstate.send.request.revertlocalchanges": {
-        "message": "Waiting for most recent versions"
-    },
-    "syncstate.send.request.setdeviceinfo": {
-        "message": "Sending device information"
-    },
-    "syncstate.send.request.synckey": {
-        "message": "Waiting for SyncKey"
-    },
-    "syncstate.syncing": {
-        "message": "Initialize synchronization"
-    }
-}
+{
+    "abCard.Anniversary": {
+        "message": "Anniversary:"
+    },
+    "abCard.AssistantName": {
+        "message": "Assistant:"
+    },
+    "abCard.AssistantPhoneNumber": {
+        "message": "Assistant Phone:"
+    },
+    "abCard.Business2PhoneNumber": {
+        "message": "Work Alternative Phone:"
+    },
+    "abCard.BusinessFaxNumber": {
+        "message": "Work Fax:"
+    },
+    "abCard.CarPhoneNumber": {
+        "message": "Car Phone:"
+    },
+    "abCard.CompanyMainPhone": {
+        "message": "Work Main Phone:"
+    },
+    "abCard.Email3Address": {
+        "message": "Alternative Email:"
+    },
+    "abCard.Home2PhoneNumber": {
+        "message": "Home Alternative Phone:"
+    },
+    "abCard.ManagerName": {
+        "message": "Manager:"
+    },
+    "abCard.MiddleName": {
+        "message": "Middle name:"
+    },
+    "abCard.OtherAddress": {
+        "message": "Address:"
+    },
+    "abCard.OtherCity": {
+        "message": "City:"
+    },
+    "abCard.OtherCountry": {
+        "message": "Country:"
+    },
+    "abCard.OtherState": {
+        "message": "State:"
+    },
+    "abCard.OtherZip": {
+        "message": "ZIP Code:"
+    },
+    "abCard.RadioPhoneNumber": {
+        "message": "Radio Phone:"
+    },
+    "abCard.Spouse": {
+        "message": "Spouse:"
+    },
+    "abCard.header.eas": {
+        "message": "Other Fields (EAS)"
+    },
+    "abCard.header.homenumbers": {
+        "message": "Additional home numbers:"
+    },
+    "abCard.header.messaging": {
+        "message": "Messaging:"
+    },
+    "abCard.header.otheraddress": {
+        "message": "Other Address (EAS)"
+    },
+    "abCard.header.othernumbers": {
+        "message": "Additional numbers:"
+    },
+    "abCard.header.people": {
+        "message": "People:"
+    },
+    "abCard.header.worknumbers": {
+        "message": "Additional work numbers:"
+    },
+    "acl.readonly": {
+        "message": "Read-only server access (revert local changes)"
+    },
+    "acl.readwrite": {
+        "message": "Read from and write to server"
+    },
+    "add.description": {
+        "message": "Please select one of the available server configuration options and enter the requested details. "
+    },
+    "add.name": {
+        "message": "Account name:"
+    },
+    "add.ok": {
+        "message": "Add account"
+    },
+    "add.password": {
+        "message": "Password:"
+    },
+    "add.server": {
+        "message": "Server configuration:"
+    },
+    "add.shortdescription": {
+        "message": "Account information"
+    },
+    "add.title": {
+        "message": "Adding an Exchange ActiveSync account to TbSync"
+    },
+    "add.url": {
+        "message": "Server address:"
+    },
+    "add.urldescription": {
+        "message": "It should be sufficient to provide just the basic server address (e.g.: mail.yourserver.com). However, it is also possible to provide the full URL (e.g.: https://mail.yourserver.com/Microsoft-Server-ActiveSync)."
+    },
+    "add.user": {
+        "message": "User name (email address):"
+    },
+    "autocomplete.serverdirectory": {
+        "message": "global server directory"
+    },
+    "autodiscover.Failed": {
+        "message": "Autodiscover for user <##user##> failed. Either the provided credentials were wrong or your ActiveSync provider has a temporary issue, or does not support Autodiscover."
+    },
+    "autodiscover.NeedEmail": {
+        "message": "Autodiscover needs a valid email address as user name."
+    },
+    "autodiscover.Ok": {
+        "message": "Autodiscover completed successfully, you can now check the optional settings and establish the synchronization connection."
+    },
+    "autodiscover.Querying": {
+        "message": "Searching for settings?"
+    },
+    "config.auto": {
+        "message": "ActiveSync server configuration (Autodiscover)"
+    },
+    "config.custom": {
+        "message": "ActiveSync server configuration"
+    },
+    "deletefolder.confirm": {
+        "message": "Do you really want to PERMANENTLY PURGE folder ?##replace.1##? from trash?"
+    },
+    "deletefolder.menuentry": {
+        "message": "Permanently purge folder ?##replace.1##? from trash"
+    },
+    "deletefolder.notallowed": {
+        "message": "Please unsubscribe folder ?##replace.1##? before trying to purge it from trash."
+    },
+    "extensionDescription": {
+        "message": "Add sync support for Exchange ActiveSync accounts to TbSync (contacts, tasks and calendars)."
+    },
+    "extensionName": {
+        "message": "Provider for Exchange ActiveSync"
+    },
+    "helplink.BadItemSkipped": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
+    },
+    "helplink.global.clientdenied": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "manager.tabs.accountsettings": {
+        "message": "Account settings"
+    },
+    "manager.tabs.outOfOffice": {
+        "message": "Auto responder"
+    },
+    "manager.tabs.syncsettings": {
+        "message": "Options"
+    },
+    "newaccount.add_auto": {
+        "message": "Autodiscover settings and add account"
+    },
+    "newaccount.add_custom": {
+        "message": "Add account"
+    },
+    "pref.AccountName": {
+        "message": "Description"
+    },
+    "pref.ActiveSyncVersion": {
+        "message": "ActiveSync version"
+    },
+    "pref.DeviceId": {
+        "message": "ActiveSync device ID"
+    },
+    "pref.ServerName": {
+        "message": "Server address"
+    },
+    "pref.ServerNameDescription": {
+        "message": "e.g. mail.yourserver.com"
+    },
+    "pref.ShowTrashedFolders": {
+        "message": "Show folders found in trash"
+    },
+    "pref.UserName": {
+        "message": "User name"
+    },
+    "pref.UserNameDescription": {
+        "message": "User name is usually the email address of your account."
+    },
+    "pref.autodetect": {
+        "message": "best available"
+    },
+    "pref.birthday": {
+        "message": "Send birthday information"
+    },
+    "pref.calendaroptions": {
+        "message": "Calendar options"
+    },
+    "pref.contactoptions": {
+        "message": "Contact options"
+    },
+    "pref.displayoverride": {
+        "message": "Override Display Name with ?First Name? + ?Second Name?"
+    },
+    "pref.generaloptions": {
+        "message": "General options"
+    },
+    "pref.provision": {
+        "message": "Enforce provisioning (required by Kerio)"
+    },
+    "pref.seperator.comma": {
+        "message": "Comma"
+    },
+    "pref.seperator.description": {
+        "message": "Separator for multiline address field."
+    },
+    "pref.seperator.linebreak": {
+        "message": "Line break"
+    },
+    "pref.synclimit.1month": {
+        "message": "from 4 weeks ago"
+    },
+    "pref.synclimit.2weeks": {
+        "message": "from 2 weeks ago"
+    },
+    "pref.synclimit.3month": {
+        "message": "from 3 months ago"
+    },
+    "pref.synclimit.6month": {
+        "message": "from 6 months ago"
+    },
+    "pref.synclimit.all": {
+        "message": "everything"
+    },
+    "pref.synclimit.description": {
+        "message": "Synchronization period: "
+    },
+    "pref.usehttps": {
+        "message": "Use secure connection (connect via https)"
+    },
+    "recyclebin": {
+        "message": "Trash"
+    },
+    "servertype.auto": {
+        "message": "Automatic configuration"
+    },
+    "servertype.custom": {
+        "message": "Custom configuration"
+    },
+    "servertype.description.auto": {
+        "message": "The configuration for many ActiveSync servers can be discovered by providing just your email address."
+    },
+    "servertype.description.custom": {
+        "message": "Setup your account by manually providing the address of the server you want to connect."
+    },
+    "servertype.description.office365": {
+        "message": "Accounts connected to Office 365 use a modern authentication process called OAuth 2.0 which also supports Multi-Factor-Authentication (MFA)."
+    },
+    "servertype.office365": {
+        "message": "Microsoft Office 365"
+    },
+    "servertype.unlock": {
+        "message": "Double click to unlock all predefined server settings."
+    },
+    "status.401": {
+        "message": "Could not authenticate, check username and password (HTTP Error 401)."
+    },
+    "status.403": {
+        "message": "Server rejected connection (forbidden) (HTTP Error 403)."
+    },
+    "status.404": {
+        "message": "User not found (HTTP Error 404)."
+    },
+    "status.449": {
+        "message": "Server requests provisioning (HTTP Error 449)."
+    },
+    "status.500": {
+        "message": "Unknown Server Error (HTTP Error 500)."
+    },
+    "status.503": {
+        "message": "Service unavailable (HTTP Error 503)."
+    },
+    "status.BadItemSkipped": {
+        "message": "Bad Item Skipped: ##replace.1##"
+    },
+    "status.FolderDelete.3": {
+        "message": "Cannot delete a system folder (status 3)"
+    },
+    "status.FolderDelete.4": {
+        "message": "Folder does not exist (status 4), resyncing"
+    },
+    "status.FolderDelete.6": {
+        "message": "Command could not be completed, an error occurred on the server (status 6)"
+    },
+    "status.FolderDelete.9": {
+        "message": "Invalid synchronization key (status 9), resyncing"
+    },
+    "status.FolderSync.9": {
+        "message": "Invalid synchronization key (status 9), resyncing"
+    },
+    "status.InvalidServerOptions": {
+        "message": "The server does not provide information about the supported ActiveSync versions. Is EAS blocked for this user or this client (TbSync)? You could try to set the ActiveSync version manually."
+    },
+    "status.OK": {
+        "message": "OK"
+    },
+    "status.ServerRejectedRequest": {
+        "message": "The EAS Server rejected the last request."
+    },
+    "status.ServerRejectedSomeItems": {
+        "message": "The EAS server did not accept ##replace.1## elements."
+    },
+    "status.Sync.12": {
+        "message": "Folder hierarchy changed (status 12), resyncing"
+    },
+    "status.Sync.3": {
+        "message": "Invalid synchronization key (status 3), resyncing"
+    },
+    "status.Sync.4": {
+        "message": "Malformed request (status 4)"
+    },
+    "status.Sync.5": {
+        "message": "Temporary server issues or invalid item (status 5)"
+    },
+    "status.Sync.6": {
+        "message": "Invalid item (status 6)"
+    },
+    "status.Sync.8": {
+        "message": "Object not found (status 8)"
+    },
+    "status.aborted": {
+        "message": "Not synchronized"
+    },
+    "status.disabled": {
+        "message": "Disabled"
+    },
+    "status.empty-response": {
+        "message": "Server sends unexpected empty response."
+    },
+    "status.forbiddenCalendarItemInTasksFolder": {
+        "message": "Forbidden calendar item in a task folder (please resort)"
+    },
+    "status.forbiddenTasksItemInCalendarFolder": {
+        "message": "Forbidden task item in a calendar folder (please resort)"
+    },
+    "status.global.101": {
+        "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 101)."
+    },
+    "status.global.102": {
+        "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 102)."
+    },
+    "status.global.103": {
+        "message": "The XML provided in the request does not follow the protocol requirements (EAS Error 103)."
+    },
+    "status.global.110": {
+        "message": "The server reported an internal error and we should not retry immediately. Automatic periodic sync has been disabled for 30 minutes (EAS Error 110)."
+    },
+    "status.global.clientdenied": {
+        "message": "The EAS server reports <##replace.2##> (status ##replace.1##) and does not allow TbSync to access your account."
+    },
+    "status.httperror": {
+        "message": "Communication error (HTTP status ##replace.1##)."
+    },
+    "status.invalid": {
+        "message": "Invalid server response (junk)."
+    },
+    "status.malformed-xml": {
+        "message": "Could not parse XML. Check event log for details."
+    },
+    "status.modified": {
+        "message": "Local modifications"
+    },
+    "status.network": {
+        "message": "Could not connect to server (##replace.1##)."
+    },
+    "status.networkerror": {
+        "message": "Could not connect to server."
+    },
+    "status.nosupportedeasversion": {
+        "message": "Server does not support ActiveSync v2.5 or v14.0 (only ##replace.1##). TbSync will not work with this ActiveSync server."
+    },
+    "status.notargets": {
+        "message": "Aborting Sync, because sync targets could not be created."
+    },
+    "status.notsupportedeasversion": {
+        "message": "Server does not support selected ActiveSync v##replace.1## (only ##replace.2##)."
+    },
+    "status.notsyncronized": {
+        "message": "Account needs to be synchronized, at least one item is out of sync."
+    },
+    "status.nouserhost": {
+        "message": "Missing username and/or server. Please provide those values."
+    },
+    "status.pending": {
+        "message": "Waiting to be synchronized"
+    },
+    "status.policy.2": {
+        "message": "There is no policy for this client. Contact your server administrator or disable provisioning for this account."
+    },
+    "status.policy.3": {
+        "message": "Unknown PolicyType value. Contact your server administrator or disable provisioning for this account."
+    },
+    "status.policy.4": {
+        "message": "The policy data on the server is corrupted (possibly tampered with). Contact your server administrator or disable provisioning for this account."
+    },
+    "status.policy.5": {
+        "message": "The client is acknowledging the wrong policy key. Contact your server administrator or disable provisioning for this account."
+    },
+    "status.provision": {
+        "message": "Provisioning failed with status <##replace.1##>"
+    },
+    "status.response-contains-no-data": {
+        "message": "Response from the server contains no data."
+    },
+    "status.resync-loop": {
+        "message": "There was an error from which we could not recover by resyncing the account. Please disable the account and try again. (Error: resync loop)"
+    },
+    "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.syncing": {
+        "message": "Synchronizing"
+    },
+    "status.timeout": {
+        "message": "Communication timeout."
+    },
+    "status.wbxml-parse-error": {
+        "message": "Server sends unreadable response."
+    },
+    "status.wbxmlerror": {
+        "message": "Sync failed. Server responded with status <##replace.1##>."
+    },
+    "status.wbxmlmissingfield": {
+        "message": "ActiveSync protocol violation: Mandatory field <##replace.1##> is missing from server response."
+    },
+    "syncstate.accountdone": {
+        "message": "Finished account"
+    },
+    "syncstate.done": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.eval.response.autodiscover": {
+        "message": "Processing updated server settings"
+    },
+    "syncstate.eval.response.deletefolder": {
+        "message": "Folder deleted"
+    },
+    "syncstate.eval.response.estimate": {
+        "message": "Processing change estimate"
+    },
+    "syncstate.eval.response.folders": {
+        "message": "Processing folder list update"
+    },
+    "syncstate.eval.response.localchanges": {
+        "message": "Processing acknowledgment of local changes"
+    },
+    "syncstate.eval.response.localdeletes": {
+        "message": "Processing acknowledgment of local deletes"
+    },
+    "syncstate.eval.response.options": {
+        "message": "Processing server options"
+    },
+    "syncstate.eval.response.provision": {
+        "message": "Processing provision"
+    },
+    "syncstate.eval.response.remotechanges": {
+        "message": "Processing remote changes"
+    },
+    "syncstate.eval.response.revertlocalchanges": {
+        "message": "Reverting local changes"
+    },
+    "syncstate.eval.response.setdeviceinfo": {
+        "message": "Sending device information"
+    },
+    "syncstate.eval.response.synckey": {
+        "message": "Processing SyncKey"
+    },
+    "syncstate.prepare.request.autodiscover": {
+        "message": "Requesting updated server settings"
+    },
+    "syncstate.prepare.request.deletefolder": {
+        "message": "Preparing to delete folder"
+    },
+    "syncstate.prepare.request.estimate": {
+        "message": "Requesting change estimate"
+    },
+    "syncstate.prepare.request.folders": {
+        "message": "Sending folder list update"
+    },
+    "syncstate.prepare.request.localchanges": {
+        "message": "Sending local changes"
+    },
+    "syncstate.prepare.request.localdeletes": {
+        "message": "Sending local deletes"
+    },
+    "syncstate.prepare.request.options": {
+        "message": "Requesting server options"
+    },
+    "syncstate.prepare.request.provision": {
+        "message": "Requesting provision"
+    },
+    "syncstate.prepare.request.remotechanges": {
+        "message": "Requesting remote changes"
+    },
+    "syncstate.prepare.request.revertlocalchanges": {
+        "message": "Collecting local changes"
+    },
+    "syncstate.prepare.request.setdeviceinfo": {
+        "message": "Sending device information"
+    },
+    "syncstate.prepare.request.synckey": {
+        "message": "Requesting SyncKey"
+    },
+    "syncstate.preparing": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.send.request.autodiscover": {
+        "message": "Waiting for updated server settings"
+    },
+    "syncstate.send.request.deletefolder": {
+        "message": "Waiting for folder to be deleted"
+    },
+    "syncstate.send.request.estimate": {
+        "message": "Waiting for change estimate"
+    },
+    "syncstate.send.request.folders": {
+        "message": "Waiting for folder list update"
+    },
+    "syncstate.send.request.localchanges": {
+        "message": "Waiting for acknowledgment of local changes"
+    },
+    "syncstate.send.request.localdeletes": {
+        "message": "Waiting for acknowledgment of local deletes"
+    },
+    "syncstate.send.request.options": {
+        "message": "Waiting for server options"
+    },
+    "syncstate.send.request.provision": {
+        "message": "Waiting for provision"
+    },
+    "syncstate.send.request.remotechanges": {
+        "message": "Waiting for remote changes"
+    },
+    "syncstate.send.request.revertlocalchanges": {
+        "message": "Waiting for most recent versions"
+    },
+    "syncstate.send.request.setdeviceinfo": {
+        "message": "Sending device information"
+    },
+    "syncstate.send.request.synckey": {
+        "message": "Waiting for SyncKey"
+    },
+    "syncstate.syncing": {
+        "message": "Initialize synchronization"
+    }
+}
diff -Nru eas4tbsync-4.11/_locales/es/messages.json eas4tbsync-4.17/_locales/es/messages.json
--- eas4tbsync-4.11/_locales/es/messages.json	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/_locales/es/messages.json	2025-05-15 13:21:18.000000000 +0200
@@ -1,566 +1,566 @@
-{
-    "abCard.Anniversary": {
-        "message": "Aniversario:"
-    },
-    "abCard.AssistantName": {
-        "message": "Asistente:"
-    },
-    "abCard.AssistantPhoneNumber": {
-        "message": "Tel?fono de asistente:"
-    },
-    "abCard.Business2PhoneNumber": {
-        "message": "Tel?fono de trabajo alternativo:"
-    },
-    "abCard.BusinessFaxNumber": {
-        "message": "Fax de trabajo:"
-    },
-    "abCard.CarPhoneNumber": {
-        "message": "Tel?fono del coche:"
-    },
-    "abCard.CompanyMainPhone": {
-        "message": "Tel?fono del trabajo:"
-    },
-    "abCard.Email3Address": {
-        "message": "Correo electr?nico alternativo:"
-    },
-    "abCard.Home2PhoneNumber": {
-        "message": "Tel?fono de casa alternativo:"
-    },
-    "abCard.ManagerName": {
-        "message": "Jefe:"
-    },
-    "abCard.MiddleName": {
-        "message": "Segundo nombre:"
-    },
-    "abCard.OtherAddress": {
-        "message": "Direcci?n:"
-    },
-    "abCard.OtherCity": {
-        "message": "Ciudad:"
-    },
-    "abCard.OtherCountry": {
-        "message": "Pa?s:"
-    },
-    "abCard.OtherState": {
-        "message": "Estado:"
-    },
-    "abCard.OtherZip": {
-        "message": "C?digo postal:"
-    },
-    "abCard.RadioPhoneNumber": {
-        "message": "Radiotel?fono:"
-    },
-    "abCard.Spouse": {
-        "message": "Pareja:"
-    },
-    "abCard.header.eas": {
-        "message": "Otros campos (EAS)"
-    },
-    "abCard.header.homenumbers": {
-        "message": "N?meros de casa adicionales:"
-    },
-    "abCard.header.messaging": {
-        "message": "Mensajes:"
-    },
-    "abCard.header.otheraddress": {
-        "message": "Otra direcci?n (EAS)"
-    },
-    "abCard.header.othernumbers": {
-        "message": "N?meros adicionales:"
-    },
-    "abCard.header.people": {
-        "message": "Personas:"
-    },
-    "abCard.header.worknumbers": {
-        "message": "N?meros de trabajo adicionales:"
-    },
-    "acl.readonly": {
-        "message": "Acceso de solo lectura al servidor (revertir cambios locales)"
-    },
-    "acl.readwrite": {
-        "message": "Leer y escribir en el servidor"
-    },
-    "add.description": {
-        "message": "Seleccione una de las opciones de configuraci?n del servidor disponibles y escriba los detalles solicitados. "
-    },
-    "add.name": {
-        "message": "Nombre de cuenta:"
-    },
-    "add.ok": {
-        "message": "A?adir cuenta"
-    },
-    "add.password": {
-        "message": "Contrase?a:"
-    },
-    "add.server": {
-        "message": "Configuraci?n del servidor:"
-    },
-    "add.shortdescription": {
-        "message": "Informaci?n de la cuenta"
-    },
-    "add.title": {
-        "message": "A?adir una cuenta de Exchange ActiveSync a TbSync"
-    },
-    "add.url": {
-        "message": "Direcci?n del servidor:"
-    },
-    "add.urldescription": {
-        "message": "La direcci?n b?sica del servidor deber?a ser suficiente (por ejemplo, correo.servidor.com). Sin embargo, tambi?n es posible proporcionar la URL completa (por ejemplo, https://correo.servidor.com/Servidor-Microsoft-ActiveSync)."
-    },
-    "add.user": {
-        "message": "Nombre de usuario (correo electr?nico):"
-    },
-    "autocomplete.serverdirectory": {
-        "message": "servidor de directorio global"
-    },
-    "autodiscover.Failed": {
-        "message": "Ha fallado la detecci?n autom?tica del usuario ?##user##?. Es posible que las credenciales sean incorrectas, que su proveedor de ActiveSync tengo a un problema eventual o que no admita la detecci?n autom?tica."
-    },
-    "autodiscover.NeedEmail": {
-        "message": "La detecci?n autom?tica requiere una direcci?n de correo electr?nico v?lida como nombre de usuario."
-    },
-    "autodiscover.Ok": {
-        "message": "La detecci?n autom?tica ha sido correcta. Ya puede revisar los ajustes opcionales y establecer la conexi?n de sincronizaci?n."
-    },
-    "autodiscover.Querying": {
-        "message": "Buscando ajustes?"
-    },
-    "config.auto": {
-        "message": "Configuraci?n del servidor de ActiveSync (detecci?n autom?tica)"
-    },
-    "config.custom": {
-        "message": "Configuraci?n del servidor de ActiveSync"
-    },
-    "deletefolder.confirm": {
-        "message": "?Realmente quiere ELIMINAR DEFINITIVAMENTE la carpeta ?##replace.1##? de la papelera?"
-    },
-    "deletefolder.menuentry": {
-        "message": "Eliminar definitivamente la carpeta ?##replace.1##? de la papelera"
-    },
-    "deletefolder.notallowed": {
-        "message": "Cancele la suscripci?n a la carpeta ?##replace.1##? para poder eliminarla de la papelera."
-    },
-    "extensionDescription": {
-        "message": "A?ade soporte para sincronizaci?n de cuentas de Exchange ActiveSync a TbSync (contactos, tareas y calendarios)."
-    },
-    "extensionName": {
-        "message": "Proveedor de Exchange ActiveSync"
-    },
-    "helplink.BadItemSkipped": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
-    },
-    "helplink.global.clientdenied": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "manager.tabs.accountsettings": {
-        "message": "Ajustes de la cuenta"
-    },
-    "manager.tabs.outOfOffice": {
-        "message": "Respuesta autom?tica"
-    },
-    "manager.tabs.syncsettings": {
-        "message": "Opciones"
-    },
-    "newaccount.add_auto": {
-        "message": "Detectar ajustes autom?ticamente y a?adir cuenta"
-    },
-    "newaccount.add_custom": {
-        "message": "A?adir cuenta"
-    },
-    "pref.AccountName": {
-        "message": "Descripci?n"
-    },
-    "pref.ActiveSyncVersion": {
-        "message": "Versi?n de ActiveSync"
-    },
-    "pref.DeviceId": {
-        "message": "ID de dispositivo de ActiveSync"
-    },
-    "pref.ServerName": {
-        "message": "Direcci?n del servidor"
-    },
-    "pref.ServerNameDescription": {
-        "message": "por ejemplo, correo.servidor.com"
-    },
-    "pref.ShowTrashedFolders": {
-        "message": "Mostrar carpetas encontradas en la papelera"
-    },
-    "pref.UserName": {
-        "message": "Nombre de usuario"
-    },
-    "pref.UserNameDescription": {
-        "message": "El nombre de usuario suele ser la direcci?n de correo electr?nico de su cuenta."
-    },
-    "pref.autodetect": {
-        "message": "mejor disponible"
-    },
-    "pref.birthday": {
-        "message": "Enviar informaci?n de cumplea?os"
-    },
-    "pref.calendaroptions": {
-        "message": "Opciones de calendario"
-    },
-    "pref.contactoptions": {
-        "message": "Opciones de contactos"
-    },
-    "pref.displayoverride": {
-        "message": "Reemplazar nombre de pantalla con ?Nombre? + ?Segundo nombre?"
-    },
-    "pref.generaloptions": {
-        "message": "Opciones generales"
-    },
-    "pref.provision": {
-        "message": "Forzar aprovisionamiento (requerido por Kerio)"
-    },
-    "pref.seperator.comma": {
-        "message": "Coma"
-    },
-    "pref.seperator.description": {
-        "message": "Separador para campo de direcci?n en varias l?neas."
-    },
-    "pref.seperator.linebreak": {
-        "message": "Salto de l?nea"
-    },
-    "pref.synclimit.1month": {
-        "message": "desde 4 semanas atr?s"
-    },
-    "pref.synclimit.2weeks": {
-        "message": "desde 2 semanas atr?s"
-    },
-    "pref.synclimit.3month": {
-        "message": "desde 3 meses atr?s"
-    },
-    "pref.synclimit.6month": {
-        "message": "desde 6 meses atr?s"
-    },
-    "pref.synclimit.all": {
-        "message": "todo"
-    },
-    "pref.synclimit.description": {
-        "message": "Periodo de sincronizaci?n: "
-    },
-    "pref.usehttps": {
-        "message": "Usar conexi?n segura (conectar mediante https)"
-    },
-    "recyclebin": {
-        "message": "Papelera"
-    },
-    "servertype.auto": {
-        "message": "Configuraci?n autom?tica"
-    },
-    "servertype.custom": {
-        "message": "Configuraci?n personalizada"
-    },
-    "servertype.description.auto": {
-        "message": "Es posible detectar la configuraci?n de muchos servidores de ActiveSync con solo proporcionar su direcci?n de correo electr?nico."
-    },
-    "servertype.description.custom": {
-        "message": "Configure la cuenta proporcionando manualmente la direcci?n del servidor al que desea conectar."
-    },
-    "servertype.description.office365": {
-        "message": "Las cuentas conectadas a Office 365 utilizan un proceso de autenticaci?n avanzado, llamado OAuth 2.0, que tambi?n admite autenticaci?n multifactor (MFA)."
-    },
-    "servertype.office365": {
-        "message": "Microsoft Office 365"
-    },
-    "servertype.unlock": {
-        "message": "Haga doble clic para desbloquear todos los ajustes predefinidos del servidor."
-    },
-    "status.401": {
-        "message": "No ha sido posible autentificar, compruebe el nombre de usuario y contrase?a (error HTTP 401)."
-    },
-    "status.403": {
-        "message": "El servidor rechaz? la conexi?n (prohibida) (error HTTP 403)."
-    },
-    "status.404": {
-        "message": "Usuario no encontrado (error HTTP 404)."
-    },
-    "status.449": {
-        "message": "El servidor solicita aprovisionamiento (error HTTP 449)."
-    },
-    "status.500": {
-        "message": "Error de servidor desconocido (error HTTP 500)."
-    },
-    "status.503": {
-        "message": "Servicio no disponible (error HTTP 503)."
-    },
-    "status.BadItemSkipped": {
-        "message": "Objeto incorrecto omitido: ##replace.1##"
-    },
-    "status.FolderDelete.3": {
-        "message": "No es posible eliminar una carpeta del sistema (estado 3)"
-    },
-    "status.FolderDelete.4": {
-        "message": "La carpeta no existe (estado 4), resincronizando"
-    },
-    "status.FolderDelete.6": {
-        "message": "No ha sido posible completar el comando, se ha producido un error en el servidor (estado 6)"
-    },
-    "status.FolderDelete.9": {
-        "message": "Clave de sincronizaci?n no v?lida (estado 9), resincronizando"
-    },
-    "status.FolderSync.9": {
-        "message": "Clave de sincronizaci?n no v?lida (estado 9), resincronizando"
-    },
-    "status.InvalidServerOptions": {
-        "message": "El servidor no proporciona informaci?n sobre las versiones de ActiveSync compatibles. ?Est? EAS bloqueado para este usuario o este cliente (TbSync)? Puede intentar configurar la versi?n de ActiveSync manualmente."
-    },
-    "status.OK": {
-        "message": "OK"
-    },
-    "status.ServerRejectedRequest": {
-        "message": "El servidor de EAS rechaz? la ?ltima petici?n."
-    },
-    "status.ServerRejectedSomeItems": {
-        "message": "El servidor de EAS no acept? ##replace.1## elementos."
-    },
-    "status.Sync.12": {
-        "message": "Jerarqu?a de carpetas cambiada (estado 12), resincronizando"
-    },
-    "status.Sync.3": {
-        "message": "Clave de sincronizaci?n no v?lida (estado 3), resincronizando"
-    },
-    "status.Sync.4": {
-        "message": "Solicitud mal formada (estado 4)"
-    },
-    "status.Sync.5": {
-        "message": "Problemas temporales del servidor o elemento no v?lido (estado 5)"
-    },
-    "status.Sync.6": {
-        "message": "Elemento no v?lido (estado 6)"
-    },
-    "status.Sync.8": {
-        "message": "Objeto no encontrado (estado 8)"
-    },
-    "status.aborted": {
-        "message": "Sin sincronizar"
-    },
-    "status.disabled": {
-        "message": "Desactivado"
-    },
-    "status.empty-response": {
-        "message": "El servidor env?a una respuesta vac?a inesperada."
-    },
-    "status.forbiddenCalendarItemInTasksFolder": {
-        "message": "Elemento de calendario prohibido en una carpeta de tareas (reorganice, por favor)"
-    },
-    "status.forbiddenTasksItemInCalendarFolder": {
-        "message": "Elemento de tareas prohibido en una carpeta de calendario (reorganice, por favor)"
-    },
-    "status.global.101": {
-        "message": "La solicitud contiene WBXML pero no se pudo decodificar como XML (error EAS 101)."
-    },
-    "status.global.102": {
-        "message": "La solicitud contiene WBXML pero no se pudo decodificar como XML (error EAS 102)."
-    },
-    "status.global.103": {
-        "message": "El XML proporcionado en la solicitud no cumple los requisitos de protocolo (error EAS 103)."
-    },
-    "status.global.110": {
-        "message": "El servidor inform? de un error interno y no deber?amos volver a intentarlo inmediatamente. La sincronizaci?n peri?dica autom?tica se ha desactivado durante 30 minutos (error EAS 110)."
-    },
-    "status.global.clientdenied": {
-        "message": "El servidor de EAS notifica <##replace.2##> (estado ##replace.1##) y no permite a TbSync acceder a tu cuenta."
-    },
-    "status.httperror": {
-        "message": "Error de comunicaci?n (estado HTTP ##replace.1##)."
-    },
-    "status.invalid": {
-        "message": "Respuesta del servidor no v?lida (corrupta)."
-    },
-    "status.malformed-xml": {
-        "message": "No ha sido posible analizar el XML. Compruebe el registro de eventos para m?s detalles."
-    },
-    "status.modified": {
-        "message": "Modificaciones locales"
-    },
-    "status.network": {
-        "message": "No ha sido posible conectar al servidor (##replace.1##)."
-    },
-    "status.networkerror": {
-        "message": "No ha sido posible conectar al servidor."
-    },
-    "status.nosupportedeasversion": {
-        "message": "El servidor no es compatible con las versiones de ActiveSync 2.5 y 14.0 (solo ##replace.1##). TbSync no funcionar? con este servidor de ActiveSync."
-    },
-    "status.notargets": {
-        "message": "Sincronizaci?n interrumpida porque no se han podido crear los destinos de la sincronizaci?n."
-    },
-    "status.notsupportedeasversion": {
-        "message": "El servidor no es compatible con la versi?n seleccionada de ActiveSync, ##replace.1## (solo ##replace.2##)."
-    },
-    "status.notsyncronized": {
-        "message": "Es necesario sincronizar la cuenta: uno o varios elementos est?n sin sincronizar."
-    },
-    "status.nouserhost": {
-        "message": "Falta el nombre de usuario o el servidor. Por favor, proporcione esos datos."
-    },
-    "status.pending": {
-        "message": "Esperando sincronizaci?n"
-    },
-    "status.policy.2": {
-        "message": "No hay ninguna directiva para este cliente. P?ngase en contacto con el administrador del servidor o deshabilite el aprovisionamiento de esta cuenta."
-    },
-    "status.policy.3": {
-        "message": "El valor PolicyType es desconocido. P?ngase en contacto con el administrador del servidor o deshabilite el aprovisionamiento de esta cuenta."
-    },
-    "status.policy.4": {
-        "message": "Los datos de directivas del servidor est?n da?ados (posiblemente manipulados). P?ngase en contacto con el administrador del servidor o deshabilite el aprovisionamiento de esta cuenta."
-    },
-    "status.policy.5": {
-        "message": "El cliente est? reconociendo la clave de directiva incorrecta. P?ngase en contacto con el administrador del servidor o deshabilite el aprovisionamiento de esta cuenta."
-    },
-    "status.provision": {
-        "message": "El aprovisionamiento fall? con el estado <##replace.1##>"
-    },
-    "status.response-contains-no-data": {
-        "message": "La respuesta del servidor no contiene datos."
-    },
-    "status.resync-loop": {
-        "message": "Se ha producido un error que no se pudo corregir volviendo a sincronizar la cuenta. Desactive la cuenta e int?ntelo de nuevo (error: bucle de resincronizaci?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.syncing": {
-        "message": "Sincronizando"
-    },
-    "status.timeout": {
-        "message": "Tiempo de comunicaci?n agotado."
-    },
-    "status.wbxml-parse-error": {
-        "message": "El servidor env?a una respuesta ilegible."
-    },
-    "status.wbxmlerror": {
-        "message": "Error al sincronizar. El servidor respondi? con el estado <##replace.1##>."
-    },
-    "status.wbxmlmissingfield": {
-        "message": "Violaci?n del protocolo de ActiveSync: falta el campo obligatorio <##replace.1##> en la respuesta del servidor."
-    },
-    "syncstate.accountdone": {
-        "message": "Cuenta finalizada"
-    },
-    "syncstate.done": {
-        "message": "Preparando el siguiente elemento para la sincronizaci?n"
-    },
-    "syncstate.eval.response.autodiscover": {
-        "message": "Procesando la configuraci?n actualizada del servidor"
-    },
-    "syncstate.eval.response.deletefolder": {
-        "message": "Carpeta eliminada"
-    },
-    "syncstate.eval.response.estimate": {
-        "message": "Procesando estimaci?n de cambio"
-    },
-    "syncstate.eval.response.folders": {
-        "message": "Procesando la lista de carpetas actualizada"
-    },
-    "syncstate.eval.response.localchanges": {
-        "message": "Procesando el reconocimiento de cambios locales"
-    },
-    "syncstate.eval.response.localdeletes": {
-        "message": "Procesando el reconocimiento de eliminaciones locales"
-    },
-    "syncstate.eval.response.options": {
-        "message": "Procesando opciones del servidor"
-    },
-    "syncstate.eval.response.provision": {
-        "message": "Procesando aprovisionamiento"
-    },
-    "syncstate.eval.response.remotechanges": {
-        "message": "Procesando los cambios remotos"
-    },
-    "syncstate.eval.response.revertlocalchanges": {
-        "message": "Revirtiendo los cambios locales"
-    },
-    "syncstate.eval.response.setdeviceinfo": {
-        "message": "Enviando informaci?n del dispositivo"
-    },
-    "syncstate.eval.response.synckey": {
-        "message": "Procesando SyncKey"
-    },
-    "syncstate.prepare.request.autodiscover": {
-        "message": "Solicitando la configuraci?n actualizada del servidor"
-    },
-    "syncstate.prepare.request.deletefolder": {
-        "message": "Preparando la eliminaci?n de la carpeta"
-    },
-    "syncstate.prepare.request.estimate": {
-        "message": "Solicitando estimaci?n de cambios"
-    },
-    "syncstate.prepare.request.folders": {
-        "message": "Enviando actualizaci?n de lista de carpetas"
-    },
-    "syncstate.prepare.request.localchanges": {
-        "message": "Enviando los cambios locales"
-    },
-    "syncstate.prepare.request.localdeletes": {
-        "message": "Enviando las eliminaciones locales"
-    },
-    "syncstate.prepare.request.options": {
-        "message": "Solicitando opciones de servidor"
-    },
-    "syncstate.prepare.request.provision": {
-        "message": "Solicitud de aprovisionamiento"
-    },
-    "syncstate.prepare.request.remotechanges": {
-        "message": "Procesando los cambios remotos"
-    },
-    "syncstate.prepare.request.revertlocalchanges": {
-        "message": "Recopilando los cambios locales"
-    },
-    "syncstate.prepare.request.setdeviceinfo": {
-        "message": "Enviando informaci?n del dispositivo"
-    },
-    "syncstate.prepare.request.synckey": {
-        "message": "Solicitando SyncKey"
-    },
-    "syncstate.preparing": {
-        "message": "Preparando el siguiente elemento para la sincronizaci?n"
-    },
-    "syncstate.send.request.autodiscover": {
-        "message": "Esperando la configuraci?n actualizada del servidor"
-    },
-    "syncstate.send.request.deletefolder": {
-        "message": "Esperando la eliminaci?n de la carpeta"
-    },
-    "syncstate.send.request.estimate": {
-        "message": "Esperando la estimaci?n de cambios"
-    },
-    "syncstate.send.request.folders": {
-        "message": "Esperando la actualizaci?n de la lista de carpetas"
-    },
-    "syncstate.send.request.localchanges": {
-        "message": "Esperando el reconocimiento de cambios locales"
-    },
-    "syncstate.send.request.localdeletes": {
-        "message": "Esperando el reconocimiento de eliminaciones locales"
-    },
-    "syncstate.send.request.options": {
-        "message": "Esperando las opciones del servidor"
-    },
-    "syncstate.send.request.provision": {
-        "message": "Esperando el aprovisionamiento"
-    },
-    "syncstate.send.request.remotechanges": {
-        "message": "Esperando los cambios remotos"
-    },
-    "syncstate.send.request.revertlocalchanges": {
-        "message": "Esperando las versiones m?s recientes"
-    },
-    "syncstate.send.request.setdeviceinfo": {
-        "message": "Enviando informaci?n del dispositivo"
-    },
-    "syncstate.send.request.synckey": {
-        "message": "Esperando a SyncKey"
-    },
-    "syncstate.syncing": {
-        "message": "Iniciar sincronizaci?n"
-    }
-}
+{
+    "abCard.Anniversary": {
+        "message": "Aniversario:"
+    },
+    "abCard.AssistantName": {
+        "message": "Asistente:"
+    },
+    "abCard.AssistantPhoneNumber": {
+        "message": "Tel?fono de asistente:"
+    },
+    "abCard.Business2PhoneNumber": {
+        "message": "Tel?fono de trabajo alternativo:"
+    },
+    "abCard.BusinessFaxNumber": {
+        "message": "Fax de trabajo:"
+    },
+    "abCard.CarPhoneNumber": {
+        "message": "Tel?fono del coche:"
+    },
+    "abCard.CompanyMainPhone": {
+        "message": "Tel?fono del trabajo:"
+    },
+    "abCard.Email3Address": {
+        "message": "Correo electr?nico alternativo:"
+    },
+    "abCard.Home2PhoneNumber": {
+        "message": "Tel?fono de casa alternativo:"
+    },
+    "abCard.ManagerName": {
+        "message": "Jefe:"
+    },
+    "abCard.MiddleName": {
+        "message": "Segundo nombre:"
+    },
+    "abCard.OtherAddress": {
+        "message": "Direcci?n:"
+    },
+    "abCard.OtherCity": {
+        "message": "Ciudad:"
+    },
+    "abCard.OtherCountry": {
+        "message": "Pa?s:"
+    },
+    "abCard.OtherState": {
+        "message": "Estado:"
+    },
+    "abCard.OtherZip": {
+        "message": "C?digo postal:"
+    },
+    "abCard.RadioPhoneNumber": {
+        "message": "Radiotel?fono:"
+    },
+    "abCard.Spouse": {
+        "message": "Pareja:"
+    },
+    "abCard.header.eas": {
+        "message": "Otros campos (EAS)"
+    },
+    "abCard.header.homenumbers": {
+        "message": "N?meros de casa adicionales:"
+    },
+    "abCard.header.messaging": {
+        "message": "Mensajes:"
+    },
+    "abCard.header.otheraddress": {
+        "message": "Otra direcci?n (EAS)"
+    },
+    "abCard.header.othernumbers": {
+        "message": "N?meros adicionales:"
+    },
+    "abCard.header.people": {
+        "message": "Personas:"
+    },
+    "abCard.header.worknumbers": {
+        "message": "N?meros de trabajo adicionales:"
+    },
+    "acl.readonly": {
+        "message": "Acceso de solo lectura al servidor (revertir cambios locales)"
+    },
+    "acl.readwrite": {
+        "message": "Leer y escribir en el servidor"
+    },
+    "add.description": {
+        "message": "Seleccione una de las opciones de configuraci?n del servidor disponibles y escriba los detalles solicitados. "
+    },
+    "add.name": {
+        "message": "Nombre de cuenta:"
+    },
+    "add.ok": {
+        "message": "A?adir cuenta"
+    },
+    "add.password": {
+        "message": "Contrase?a:"
+    },
+    "add.server": {
+        "message": "Configuraci?n del servidor:"
+    },
+    "add.shortdescription": {
+        "message": "Informaci?n de la cuenta"
+    },
+    "add.title": {
+        "message": "A?adir una cuenta de Exchange ActiveSync a TbSync"
+    },
+    "add.url": {
+        "message": "Direcci?n del servidor:"
+    },
+    "add.urldescription": {
+        "message": "La direcci?n b?sica del servidor deber?a ser suficiente (por ejemplo, correo.servidor.com). Sin embargo, tambi?n es posible proporcionar la URL completa (por ejemplo, https://correo.servidor.com/Servidor-Microsoft-ActiveSync)."
+    },
+    "add.user": {
+        "message": "Nombre de usuario (correo electr?nico):"
+    },
+    "autocomplete.serverdirectory": {
+        "message": "servidor de directorio global"
+    },
+    "autodiscover.Failed": {
+        "message": "Ha fallado la detecci?n autom?tica del usuario ?##user##?. Es posible que las credenciales sean incorrectas, que su proveedor de ActiveSync tengo a un problema eventual o que no admita la detecci?n autom?tica."
+    },
+    "autodiscover.NeedEmail": {
+        "message": "La detecci?n autom?tica requiere una direcci?n de correo electr?nico v?lida como nombre de usuario."
+    },
+    "autodiscover.Ok": {
+        "message": "La detecci?n autom?tica ha sido correcta. Ya puede revisar los ajustes opcionales y establecer la conexi?n de sincronizaci?n."
+    },
+    "autodiscover.Querying": {
+        "message": "Buscando ajustes?"
+    },
+    "config.auto": {
+        "message": "Configuraci?n del servidor de ActiveSync (detecci?n autom?tica)"
+    },
+    "config.custom": {
+        "message": "Configuraci?n del servidor de ActiveSync"
+    },
+    "deletefolder.confirm": {
+        "message": "?Realmente quiere ELIMINAR DEFINITIVAMENTE la carpeta ?##replace.1##? de la papelera?"
+    },
+    "deletefolder.menuentry": {
+        "message": "Eliminar definitivamente la carpeta ?##replace.1##? de la papelera"
+    },
+    "deletefolder.notallowed": {
+        "message": "Cancele la suscripci?n a la carpeta ?##replace.1##? para poder eliminarla de la papelera."
+    },
+    "extensionDescription": {
+        "message": "A?ade soporte para sincronizaci?n de cuentas de Exchange ActiveSync a TbSync (contactos, tareas y calendarios)."
+    },
+    "extensionName": {
+        "message": "Proveedor de Exchange ActiveSync"
+    },
+    "helplink.BadItemSkipped": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
+    },
+    "helplink.global.clientdenied": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "manager.tabs.accountsettings": {
+        "message": "Ajustes de la cuenta"
+    },
+    "manager.tabs.outOfOffice": {
+        "message": "Respuesta autom?tica"
+    },
+    "manager.tabs.syncsettings": {
+        "message": "Opciones"
+    },
+    "newaccount.add_auto": {
+        "message": "Detectar ajustes autom?ticamente y a?adir cuenta"
+    },
+    "newaccount.add_custom": {
+        "message": "A?adir cuenta"
+    },
+    "pref.AccountName": {
+        "message": "Descripci?n"
+    },
+    "pref.ActiveSyncVersion": {
+        "message": "Versi?n de ActiveSync"
+    },
+    "pref.DeviceId": {
+        "message": "ID de dispositivo de ActiveSync"
+    },
+    "pref.ServerName": {
+        "message": "Direcci?n del servidor"
+    },
+    "pref.ServerNameDescription": {
+        "message": "por ejemplo, correo.servidor.com"
+    },
+    "pref.ShowTrashedFolders": {
+        "message": "Mostrar carpetas encontradas en la papelera"
+    },
+    "pref.UserName": {
+        "message": "Nombre de usuario"
+    },
+    "pref.UserNameDescription": {
+        "message": "El nombre de usuario suele ser la direcci?n de correo electr?nico de su cuenta."
+    },
+    "pref.autodetect": {
+        "message": "mejor disponible"
+    },
+    "pref.birthday": {
+        "message": "Enviar informaci?n de cumplea?os"
+    },
+    "pref.calendaroptions": {
+        "message": "Opciones de calendario"
+    },
+    "pref.contactoptions": {
+        "message": "Opciones de contactos"
+    },
+    "pref.displayoverride": {
+        "message": "Reemplazar nombre de pantalla con ?Nombre? + ?Segundo nombre?"
+    },
+    "pref.generaloptions": {
+        "message": "Opciones generales"
+    },
+    "pref.provision": {
+        "message": "Forzar aprovisionamiento (requerido por Kerio)"
+    },
+    "pref.seperator.comma": {
+        "message": "Coma"
+    },
+    "pref.seperator.description": {
+        "message": "Separador para campo de direcci?n en varias l?neas."
+    },
+    "pref.seperator.linebreak": {
+        "message": "Salto de l?nea"
+    },
+    "pref.synclimit.1month": {
+        "message": "desde 4 semanas atr?s"
+    },
+    "pref.synclimit.2weeks": {
+        "message": "desde 2 semanas atr?s"
+    },
+    "pref.synclimit.3month": {
+        "message": "desde 3 meses atr?s"
+    },
+    "pref.synclimit.6month": {
+        "message": "desde 6 meses atr?s"
+    },
+    "pref.synclimit.all": {
+        "message": "todo"
+    },
+    "pref.synclimit.description": {
+        "message": "Periodo de sincronizaci?n: "
+    },
+    "pref.usehttps": {
+        "message": "Usar conexi?n segura (conectar mediante https)"
+    },
+    "recyclebin": {
+        "message": "Papelera"
+    },
+    "servertype.auto": {
+        "message": "Configuraci?n autom?tica"
+    },
+    "servertype.custom": {
+        "message": "Configuraci?n personalizada"
+    },
+    "servertype.description.auto": {
+        "message": "Es posible detectar la configuraci?n de muchos servidores de ActiveSync con solo proporcionar su direcci?n de correo electr?nico."
+    },
+    "servertype.description.custom": {
+        "message": "Configure la cuenta proporcionando manualmente la direcci?n del servidor al que desea conectar."
+    },
+    "servertype.description.office365": {
+        "message": "Las cuentas conectadas a Office 365 utilizan un proceso de autenticaci?n avanzado, llamado OAuth 2.0, que tambi?n admite autenticaci?n multifactor (MFA)."
+    },
+    "servertype.office365": {
+        "message": "Microsoft Office 365"
+    },
+    "servertype.unlock": {
+        "message": "Haga doble clic para desbloquear todos los ajustes predefinidos del servidor."
+    },
+    "status.401": {
+        "message": "No ha sido posible autentificar, compruebe el nombre de usuario y contrase?a (error HTTP 401)."
+    },
+    "status.403": {
+        "message": "El servidor rechaz? la conexi?n (prohibida) (error HTTP 403)."
+    },
+    "status.404": {
+        "message": "Usuario no encontrado (error HTTP 404)."
+    },
+    "status.449": {
+        "message": "El servidor solicita aprovisionamiento (error HTTP 449)."
+    },
+    "status.500": {
+        "message": "Error de servidor desconocido (error HTTP 500)."
+    },
+    "status.503": {
+        "message": "Servicio no disponible (error HTTP 503)."
+    },
+    "status.BadItemSkipped": {
+        "message": "Objeto incorrecto omitido: ##replace.1##"
+    },
+    "status.FolderDelete.3": {
+        "message": "No es posible eliminar una carpeta del sistema (estado 3)"
+    },
+    "status.FolderDelete.4": {
+        "message": "La carpeta no existe (estado 4), resincronizando"
+    },
+    "status.FolderDelete.6": {
+        "message": "No ha sido posible completar el comando, se ha producido un error en el servidor (estado 6)"
+    },
+    "status.FolderDelete.9": {
+        "message": "Clave de sincronizaci?n no v?lida (estado 9), resincronizando"
+    },
+    "status.FolderSync.9": {
+        "message": "Clave de sincronizaci?n no v?lida (estado 9), resincronizando"
+    },
+    "status.InvalidServerOptions": {
+        "message": "El servidor no proporciona informaci?n sobre las versiones de ActiveSync compatibles. ?Est? EAS bloqueado para este usuario o este cliente (TbSync)? Puede intentar configurar la versi?n de ActiveSync manualmente."
+    },
+    "status.OK": {
+        "message": "OK"
+    },
+    "status.ServerRejectedRequest": {
+        "message": "El servidor de EAS rechaz? la ?ltima petici?n."
+    },
+    "status.ServerRejectedSomeItems": {
+        "message": "El servidor de EAS no acept? ##replace.1## elementos."
+    },
+    "status.Sync.12": {
+        "message": "Jerarqu?a de carpetas cambiada (estado 12), resincronizando"
+    },
+    "status.Sync.3": {
+        "message": "Clave de sincronizaci?n no v?lida (estado 3), resincronizando"
+    },
+    "status.Sync.4": {
+        "message": "Solicitud mal formada (estado 4)"
+    },
+    "status.Sync.5": {
+        "message": "Problemas temporales del servidor o elemento no v?lido (estado 5)"
+    },
+    "status.Sync.6": {
+        "message": "Elemento no v?lido (estado 6)"
+    },
+    "status.Sync.8": {
+        "message": "Objeto no encontrado (estado 8)"
+    },
+    "status.aborted": {
+        "message": "Sin sincronizar"
+    },
+    "status.disabled": {
+        "message": "Desactivado"
+    },
+    "status.empty-response": {
+        "message": "El servidor env?a una respuesta vac?a inesperada."
+    },
+    "status.forbiddenCalendarItemInTasksFolder": {
+        "message": "Elemento de calendario prohibido en una carpeta de tareas (reorganice, por favor)"
+    },
+    "status.forbiddenTasksItemInCalendarFolder": {
+        "message": "Elemento de tareas prohibido en una carpeta de calendario (reorganice, por favor)"
+    },
+    "status.global.101": {
+        "message": "La solicitud contiene WBXML pero no se pudo decodificar como XML (error EAS 101)."
+    },
+    "status.global.102": {
+        "message": "La solicitud contiene WBXML pero no se pudo decodificar como XML (error EAS 102)."
+    },
+    "status.global.103": {
+        "message": "El XML proporcionado en la solicitud no cumple los requisitos de protocolo (error EAS 103)."
+    },
+    "status.global.110": {
+        "message": "El servidor inform? de un error interno y no deber?amos volver a intentarlo inmediatamente. La sincronizaci?n peri?dica autom?tica se ha desactivado durante 30 minutos (error EAS 110)."
+    },
+    "status.global.clientdenied": {
+        "message": "El servidor de EAS notifica <##replace.2##> (estado ##replace.1##) y no permite a TbSync acceder a tu cuenta."
+    },
+    "status.httperror": {
+        "message": "Error de comunicaci?n (estado HTTP ##replace.1##)."
+    },
+    "status.invalid": {
+        "message": "Respuesta del servidor no v?lida (corrupta)."
+    },
+    "status.malformed-xml": {
+        "message": "No ha sido posible analizar el XML. Compruebe el registro de eventos para m?s detalles."
+    },
+    "status.modified": {
+        "message": "Modificaciones locales"
+    },
+    "status.network": {
+        "message": "No ha sido posible conectar al servidor (##replace.1##)."
+    },
+    "status.networkerror": {
+        "message": "No ha sido posible conectar al servidor."
+    },
+    "status.nosupportedeasversion": {
+        "message": "El servidor no es compatible con las versiones de ActiveSync 2.5 y 14.0 (solo ##replace.1##). TbSync no funcionar? con este servidor de ActiveSync."
+    },
+    "status.notargets": {
+        "message": "Sincronizaci?n interrumpida porque no se han podido crear los destinos de la sincronizaci?n."
+    },
+    "status.notsupportedeasversion": {
+        "message": "El servidor no es compatible con la versi?n seleccionada de ActiveSync, ##replace.1## (solo ##replace.2##)."
+    },
+    "status.notsyncronized": {
+        "message": "Es necesario sincronizar la cuenta: uno o varios elementos est?n sin sincronizar."
+    },
+    "status.nouserhost": {
+        "message": "Falta el nombre de usuario o el servidor. Por favor, proporcione esos datos."
+    },
+    "status.pending": {
+        "message": "Esperando sincronizaci?n"
+    },
+    "status.policy.2": {
+        "message": "No hay ninguna directiva para este cliente. P?ngase en contacto con el administrador del servidor o deshabilite el aprovisionamiento de esta cuenta."
+    },
+    "status.policy.3": {
+        "message": "El valor PolicyType es desconocido. P?ngase en contacto con el administrador del servidor o deshabilite el aprovisionamiento de esta cuenta."
+    },
+    "status.policy.4": {
+        "message": "Los datos de directivas del servidor est?n da?ados (posiblemente manipulados). P?ngase en contacto con el administrador del servidor o deshabilite el aprovisionamiento de esta cuenta."
+    },
+    "status.policy.5": {
+        "message": "El cliente est? reconociendo la clave de directiva incorrecta. P?ngase en contacto con el administrador del servidor o deshabilite el aprovisionamiento de esta cuenta."
+    },
+    "status.provision": {
+        "message": "El aprovisionamiento fall? con el estado <##replace.1##>"
+    },
+    "status.response-contains-no-data": {
+        "message": "La respuesta del servidor no contiene datos."
+    },
+    "status.resync-loop": {
+        "message": "Se ha producido un error que no se pudo corregir volviendo a sincronizar la cuenta. Desactive la cuenta e int?ntelo de nuevo (error: bucle de resincronizaci?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.syncing": {
+        "message": "Sincronizando"
+    },
+    "status.timeout": {
+        "message": "Tiempo de comunicaci?n agotado."
+    },
+    "status.wbxml-parse-error": {
+        "message": "El servidor env?a una respuesta ilegible."
+    },
+    "status.wbxmlerror": {
+        "message": "Error al sincronizar. El servidor respondi? con el estado <##replace.1##>."
+    },
+    "status.wbxmlmissingfield": {
+        "message": "Violaci?n del protocolo de ActiveSync: falta el campo obligatorio <##replace.1##> en la respuesta del servidor."
+    },
+    "syncstate.accountdone": {
+        "message": "Cuenta finalizada"
+    },
+    "syncstate.done": {
+        "message": "Preparando el siguiente elemento para la sincronizaci?n"
+    },
+    "syncstate.eval.response.autodiscover": {
+        "message": "Procesando la configuraci?n actualizada del servidor"
+    },
+    "syncstate.eval.response.deletefolder": {
+        "message": "Carpeta eliminada"
+    },
+    "syncstate.eval.response.estimate": {
+        "message": "Procesando estimaci?n de cambio"
+    },
+    "syncstate.eval.response.folders": {
+        "message": "Procesando la lista de carpetas actualizada"
+    },
+    "syncstate.eval.response.localchanges": {
+        "message": "Procesando el reconocimiento de cambios locales"
+    },
+    "syncstate.eval.response.localdeletes": {
+        "message": "Procesando el reconocimiento de eliminaciones locales"
+    },
+    "syncstate.eval.response.options": {
+        "message": "Procesando opciones del servidor"
+    },
+    "syncstate.eval.response.provision": {
+        "message": "Procesando aprovisionamiento"
+    },
+    "syncstate.eval.response.remotechanges": {
+        "message": "Procesando los cambios remotos"
+    },
+    "syncstate.eval.response.revertlocalchanges": {
+        "message": "Revirtiendo los cambios locales"
+    },
+    "syncstate.eval.response.setdeviceinfo": {
+        "message": "Enviando informaci?n del dispositivo"
+    },
+    "syncstate.eval.response.synckey": {
+        "message": "Procesando SyncKey"
+    },
+    "syncstate.prepare.request.autodiscover": {
+        "message": "Solicitando la configuraci?n actualizada del servidor"
+    },
+    "syncstate.prepare.request.deletefolder": {
+        "message": "Preparando la eliminaci?n de la carpeta"
+    },
+    "syncstate.prepare.request.estimate": {
+        "message": "Solicitando estimaci?n de cambios"
+    },
+    "syncstate.prepare.request.folders": {
+        "message": "Enviando actualizaci?n de lista de carpetas"
+    },
+    "syncstate.prepare.request.localchanges": {
+        "message": "Enviando los cambios locales"
+    },
+    "syncstate.prepare.request.localdeletes": {
+        "message": "Enviando las eliminaciones locales"
+    },
+    "syncstate.prepare.request.options": {
+        "message": "Solicitando opciones de servidor"
+    },
+    "syncstate.prepare.request.provision": {
+        "message": "Solicitud de aprovisionamiento"
+    },
+    "syncstate.prepare.request.remotechanges": {
+        "message": "Procesando los cambios remotos"
+    },
+    "syncstate.prepare.request.revertlocalchanges": {
+        "message": "Recopilando los cambios locales"
+    },
+    "syncstate.prepare.request.setdeviceinfo": {
+        "message": "Enviando informaci?n del dispositivo"
+    },
+    "syncstate.prepare.request.synckey": {
+        "message": "Solicitando SyncKey"
+    },
+    "syncstate.preparing": {
+        "message": "Preparando el siguiente elemento para la sincronizaci?n"
+    },
+    "syncstate.send.request.autodiscover": {
+        "message": "Esperando la configuraci?n actualizada del servidor"
+    },
+    "syncstate.send.request.deletefolder": {
+        "message": "Esperando la eliminaci?n de la carpeta"
+    },
+    "syncstate.send.request.estimate": {
+        "message": "Esperando la estimaci?n de cambios"
+    },
+    "syncstate.send.request.folders": {
+        "message": "Esperando la actualizaci?n de la lista de carpetas"
+    },
+    "syncstate.send.request.localchanges": {
+        "message": "Esperando el reconocimiento de cambios locales"
+    },
+    "syncstate.send.request.localdeletes": {
+        "message": "Esperando el reconocimiento de eliminaciones locales"
+    },
+    "syncstate.send.request.options": {
+        "message": "Esperando las opciones del servidor"
+    },
+    "syncstate.send.request.provision": {
+        "message": "Esperando el aprovisionamiento"
+    },
+    "syncstate.send.request.remotechanges": {
+        "message": "Esperando los cambios remotos"
+    },
+    "syncstate.send.request.revertlocalchanges": {
+        "message": "Esperando las versiones m?s recientes"
+    },
+    "syncstate.send.request.setdeviceinfo": {
+        "message": "Enviando informaci?n del dispositivo"
+    },
+    "syncstate.send.request.synckey": {
+        "message": "Esperando a SyncKey"
+    },
+    "syncstate.syncing": {
+        "message": "Iniciar sincronizaci?n"
+    }
+}
diff -Nru eas4tbsync-4.11/_locales/fr/messages.json eas4tbsync-4.17/_locales/fr/messages.json
--- eas4tbsync-4.11/_locales/fr/messages.json	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/_locales/fr/messages.json	2025-05-15 13:21:18.000000000 +0200
@@ -1,566 +1,566 @@
-{
-    "abCard.Anniversary": {
-        "message": "Anniversaire :"
-    },
-    "abCard.AssistantName": {
-        "message": "Assistant(e) :"
-    },
-    "abCard.AssistantPhoneNumber": {
-        "message": "T?l?phone Assistant(e) :"
-    },
-    "abCard.Business2PhoneNumber": {
-        "message": "T?l?phone Bureau Alternatif :"
-    },
-    "abCard.BusinessFaxNumber": {
-        "message": "Fax de bureau :"
-    },
-    "abCard.CarPhoneNumber": {
-        "message": "T?l?phone Voiture :"
-    },
-    "abCard.CompanyMainPhone": {
-        "message": "T?l?phone de Bureau Principal :"
-    },
-    "abCard.Email3Address": {
-        "message": "Courriel alternatif :"
-    },
-    "abCard.Home2PhoneNumber": {
-        "message": "T?l?phone Domicile Alternatif :"
-    },
-    "abCard.ManagerName": {
-        "message": "Sup?rieur(e) :"
-    },
-    "abCard.MiddleName": {
-        "message": "Deuxi?me pr?nom :"
-    },
-    "abCard.OtherAddress": {
-        "message": "Adresse :"
-    },
-    "abCard.OtherCity": {
-        "message": "Ville :"
-    },
-    "abCard.OtherCountry": {
-        "message": "Pays :"
-    },
-    "abCard.OtherState": {
-        "message": "?tat :"
-    },
-    "abCard.OtherZip": {
-        "message": "Code postal :"
-    },
-    "abCard.RadioPhoneNumber": {
-        "message": "T?l?phone Radio :"
-    },
-    "abCard.Spouse": {
-        "message": "?pou(x/se) :"
-    },
-    "abCard.header.eas": {
-        "message": "Autres champs (EAS)"
-    },
-    "abCard.header.homenumbers": {
-        "message": "T?l?phones domicile suppl?mentaires :"
-    },
-    "abCard.header.messaging": {
-        "message": "Messagerie :"
-    },
-    "abCard.header.otheraddress": {
-        "message": "Autre Adresse (EAS)"
-    },
-    "abCard.header.othernumbers": {
-        "message": "Num?ros de t?l?phone suppl?mentaires :"
-    },
-    "abCard.header.people": {
-        "message": "Personnes :"
-    },
-    "abCard.header.worknumbers": {
-        "message": "T?l?phones de bureau suppl?mentaires :"
-    },
-    "acl.readonly": {
-        "message": "Acc?s au serveur en lecture seule (annule les modifications locales)"
-    },
-    "acl.readwrite": {
-        "message": "Lecture et ?criture sur le serveur"
-    },
-    "add.description": {
-        "message": "Veuillez s?lectionner une des options de configuration du serveur disponibles et entrer les d?tails demand?s. "
-    },
-    "add.name": {
-        "message": "Nom du compte :"
-    },
-    "add.ok": {
-        "message": "Ajouter un compte"
-    },
-    "add.password": {
-        "message": "Mot de passe :"
-    },
-    "add.server": {
-        "message": "Configuration du serveur :"
-    },
-    "add.shortdescription": {
-        "message": "Informations du compte"
-    },
-    "add.title": {
-        "message": "Ajout d'un compte Exchange ActiveSync ? TbSync"
-    },
-    "add.url": {
-        "message": "Adresse du serveur :"
-    },
-    "add.urldescription": {
-        "message": "Il devrait suffire de fournir uniquement l'adresse de base du serveur (par exemple : mail.votreserveur.com). Cependant, il est ?galement possible de fournir l'URL compl?te (par exemple : https://mail.votreserveur.com/Microsoft-Server-ActiveSync)."
-    },
-    "add.user": {
-        "message": "Nom d'utilisateur (adresse e-mail) :"
-    },
-    "autocomplete.serverdirectory": {
-        "message": "annuaire global du serveur"
-    },
-    "autodiscover.Failed": {
-        "message": "L'Autodiscover pour l'utilisateur <##user##> a ?chou?. Soit les informations d'identification fournies ?taient erron?es, soit votre fournisseur ActiveSync a un probl?me temporaire, soit il ne prend pas en charge l'Autodiscover."
-    },
-    "autodiscover.NeedEmail": {
-        "message": "L'Autodiscover a besoin d'une adresse courriel valide comme nom d'utilisateur."
-    },
-    "autodiscover.Ok": {
-        "message": "L'Autodiscover est termin?e avec succ?s, vous pouvez maintenant v?rifier les param?tres optionnels et ?tablir la connexion de synchronisation."
-    },
-    "autodiscover.Querying": {
-        "message": "Recherche de param?tres?"
-    },
-    "config.auto": {
-        "message": "Configuration du serveur ActiveSync (Autodiscover)"
-    },
-    "config.custom": {
-        "message": "Configuration du serveur ActiveSync"
-    },
-    "deletefolder.confirm": {
-        "message": "Voulez-vous vraiment SUPPRIMER D?FINITIVEMENT le dossier ? ##replace.1##? de la corbeille ?"
-    },
-    "deletefolder.menuentry": {
-        "message": "Supprimer d?finitivement le dossier ? ##replace.1##? de la corbeille"
-    },
-    "deletefolder.notallowed": {
-        "message": "Veuillez vous d?sabonner du dossier ? ##replace.1##? avant d'essayer de le supprimer de la corbeille."
-    },
-    "extensionDescription": {
-        "message": "Ajouter la prise en charge de la synchronisation des comptes Exchange ActiveSync ? TbSync (contacts, t?ches et calendriers)."
-    },
-    "extensionName": {
-        "message": "Fournisseur pour Exchange ActiveSync"
-    },
-    "helplink.BadItemSkipped": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
-    },
-    "helplink.global.clientdenied": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "manager.tabs.accountsettings": {
-        "message": "Param?tres du compte"
-    },
-    "manager.tabs.outOfOffice": {
-        "message": "R?pondeur automatique"
-    },
-    "manager.tabs.syncsettings": {
-        "message": "Param?tres"
-    },
-    "newaccount.add_auto": {
-        "message": "Param?tres Autodiscover et ajout de compte"
-    },
-    "newaccount.add_custom": {
-        "message": "Ajouter un compte"
-    },
-    "pref.AccountName": {
-        "message": "Description"
-    },
-    "pref.ActiveSyncVersion": {
-        "message": "Version d'ActiveSync"
-    },
-    "pref.DeviceId": {
-        "message": "ID de p?riph?rique ActiveSync"
-    },
-    "pref.ServerName": {
-        "message": "Adresse du serveur"
-    },
-    "pref.ServerNameDescription": {
-        "message": "par exemple mail.votreserveur.com"
-    },
-    "pref.ShowTrashedFolders": {
-        "message": "Afficher les dossiers trouv?s dans la corbeille"
-    },
-    "pref.UserName": {
-        "message": "Nom d'utilisateur"
-    },
-    "pref.UserNameDescription": {
-        "message": "Le nom d'utilisateur est g?n?ralement l'adresse e-mail de votre compte."
-    },
-    "pref.autodetect": {
-        "message": "le meilleur disponible"
-    },
-    "pref.birthday": {
-        "message": "Envoyer la date de naissance"
-    },
-    "pref.calendaroptions": {
-        "message": "Options de calendrier"
-    },
-    "pref.contactoptions": {
-        "message": "Options des contacts"
-    },
-    "pref.displayoverride": {
-        "message": "Remplacer le nom affich? par ? Pr?nom ? + ? Nom ?"
-    },
-    "pref.generaloptions": {
-        "message": "Options g?n?rales"
-    },
-    "pref.provision": {
-        "message": "Forcer l'approvisionnement (requis par Kerio)"
-    },
-    "pref.seperator.comma": {
-        "message": "Virgule"
-    },
-    "pref.seperator.description": {
-        "message": "S?parateur pour le champ d'adresse multiligne."
-    },
-    "pref.seperator.linebreak": {
-        "message": "Saut de ligne"
-    },
-    "pref.synclimit.1month": {
-        "message": "les 4 derni?res semaines"
-    },
-    "pref.synclimit.2weeks": {
-        "message": "les 2 derni?res semaines"
-    },
-    "pref.synclimit.3month": {
-        "message": "les 3 derniers mois"
-    },
-    "pref.synclimit.6month": {
-        "message": "les 6 derniers mois"
-    },
-    "pref.synclimit.all": {
-        "message": "tout"
-    },
-    "pref.synclimit.description": {
-        "message": "P?riode de synchronisation : "
-    },
-    "pref.usehttps": {
-        "message": "Utiliser une connexion s?curis?e (se connecter via https)"
-    },
-    "recyclebin": {
-        "message": "Corbeille"
-    },
-    "servertype.auto": {
-        "message": "Configuration automatique"
-    },
-    "servertype.custom": {
-        "message": "Configuration personnalis?e"
-    },
-    "servertype.description.auto": {
-        "message": "La configuration de nombreux serveurs ActiveSync peut ?tre d?couverte en fournissant uniquement votre adresse e-mail."
-    },
-    "servertype.description.custom": {
-        "message": "Configurez votre compte en fournissant manuellement l'adresse du serveur que vous souhaitez connecter."
-    },
-    "servertype.description.office365": {
-        "message": "Les comptes connect?s ? Office 365 utilisent un processus d'authentification moderne appel? OAuth 2.0 qui supporte ?galement l'authentification multi-facteur (MFA)."
-    },
-    "servertype.office365": {
-        "message": "Microsoft Office 365"
-    },
-    "servertype.unlock": {
-        "message": "Double-cliquez pour d?verrouiller tous les param?tres pr?d?finis du serveur."
-    },
-    "status.401": {
-        "message": "L'authentification a ?chou?. Veuillez v?rifier le couple nom d'utilisateur/mot de passe (erreur HTTP 401)."
-    },
-    "status.403": {
-        "message": "Le serveur a rejet? la connexion (interdite) (Erreur HTTP 403)."
-    },
-    "status.404": {
-        "message": "Utilisateur introuvable (Erreur HTTP 404)."
-    },
-    "status.449": {
-        "message": "Le serveur demande le provisionnement (erreur HTTP 449)."
-    },
-    "status.500": {
-        "message": "Erreur serveur inconnue (Erreur HTTP 500)."
-    },
-    "status.503": {
-        "message": "Service indisponible (Erreur HTTP 503)."
-    },
-    "status.BadItemSkipped": {
-        "message": "Mauvais ?l?ment ignor? : ##replace.1##"
-    },
-    "status.FolderDelete.3": {
-        "message": "Impossible de supprimer un dossier syst?me (statut 3)"
-    },
-    "status.FolderDelete.4": {
-        "message": "Le dossier n'existe pas (statut 4), resynchronisation"
-    },
-    "status.FolderDelete.6": {
-        "message": "La commande n'a pas pu ?tre termin?e, une erreur est survenue sur le serveur (statut 6)"
-    },
-    "status.FolderDelete.9": {
-        "message": "Cl? de synchronisation invalide (statut 9), resynchronisation"
-    },
-    "status.FolderSync.9": {
-        "message": "Cl? de synchronisation invalide (statut 9), resynchronisation"
-    },
-    "status.InvalidServerOptions": {
-        "message": "Le serveur ne fournit pas d'informations sur les versions ActiveSync support?es. EAS est-il bloqu? pour cet utilisateur ou ce client (TbSync) ? Vous pouvez essayer de d?finir manuellement la version ActiveSync."
-    },
-    "status.OK": {
-        "message": "OK"
-    },
-    "status.ServerRejectedRequest": {
-        "message": "Le serveur EAS a rejet? la derni?re demande."
-    },
-    "status.ServerRejectedSomeItems": {
-        "message": "Le serveur EAS n'a pas accept? les ?l?ments ##replace.1##."
-    },
-    "status.Sync.12": {
-        "message": "La hi?rarchie des dossiers a chang? (statut 12), resynchronisation"
-    },
-    "status.Sync.3": {
-        "message": "Cl? de synchronisation invalide (statut 3), resynchronisation"
-    },
-    "status.Sync.4": {
-        "message": "Requ?te mal form?e (statut 4)"
-    },
-    "status.Sync.5": {
-        "message": "Probl?mes de serveur temporaires ou ?l?ment invalide (statut 5)"
-    },
-    "status.Sync.6": {
-        "message": "?l?ment invalide (statut 6)"
-    },
-    "status.Sync.8": {
-        "message": "Objet introuvable (statut 8)"
-    },
-    "status.aborted": {
-        "message": "Non synchronis?"
-    },
-    "status.disabled": {
-        "message": "D?sactiv?"
-    },
-    "status.empty-response": {
-        "message": "Le serveur a renvoy? une r?ponse vide inattendue."
-    },
-    "status.forbiddenCalendarItemInTasksFolder": {
-        "message": "?l?ment de calendrier interdit dans un dossier de t?che (veuillez intervenir)"
-    },
-    "status.forbiddenTasksItemInCalendarFolder": {
-        "message": "?l?ment de calendrier interdit dans un dossier de t?che (veuillez intervenir)"
-    },
-    "status.global.101": {
-        "message": "La requ?te contient WBXML mais n'a pas pu ?tre d?cod?e en XML (EAS Error 101)."
-    },
-    "status.global.102": {
-        "message": "La requ?te contient WBXML mais n'a pas pu ?tre d?cod?e en XML (EAS Error 102)."
-    },
-    "status.global.103": {
-        "message": "Le XML fourni dans la requ?te ne respecte pas les exigences du protocole (EAS Error 103)."
-    },
-    "status.global.110": {
-        "message": "Le serveur a signal? une erreur interne et nous ne devrions pas r?essayer imm?diatement. La synchronisation p?riodique automatique a ?t? d?sactiv?e pendant 30 minutes (EAS Error 110)."
-    },
-    "status.global.clientdenied": {
-        "message": "Le serveur EAS signale <##replace.2##> (status ##replace.1##) et n'autorise pas TbSync ? acc?der ? votre compte."
-    },
-    "status.httperror": {
-        "message": "Erreur de communication (statut HTTP ##replace.1##)."
-    },
-    "status.invalid": {
-        "message": "R?ponse du serveur invalide (pourriels)."
-    },
-    "status.malformed-xml": {
-        "message": "Impossible d?analyser le XML. V?rifiez le journal des ?v?nements pour plus de d?tails."
-    },
-    "status.modified": {
-        "message": "Modifications locales pr?sentes"
-    },
-    "status.network": {
-        "message": "Impossible de se connecter au serveur (##replace.1##)."
-    },
-    "status.networkerror": {
-        "message": "La connexion au serveur a ?chou?."
-    },
-    "status.nosupportedeasversion": {
-        "message": "Le serveur ne prend pas en charge ActiveSync v2.5 ou v14.0 (seulement ##replace.1##). TbSync ne fonctionnera pas avec ce serveur ActiveSync."
-    },
-    "status.notargets": {
-        "message": "Annulation de la synchronisation en cours : il est impossible de cr?er les destinations de synchronisation."
-    },
-    "status.notsupportedeasversion": {
-        "message": "Le serveur ne prend pas en charge la s?lection ActiveSync v##replace.1## (seulement ##replace.2##)."
-    },
-    "status.notsyncronized": {
-        "message": "Le compte doit ?tre synchronis? : au moins un ?l?ments n'est pas synchronis?."
-    },
-    "status.nouserhost": {
-        "message": "Nom d'utilisateur et/ou serveur manquant. Veuillez fournir ces valeurs."
-    },
-    "status.pending": {
-        "message": "En attente de synchronisation"
-    },
-    "status.policy.2": {
-        "message": "Il n'y a pas de politique pour ce client. Contactez l'administrateur de votre serveur ou d?sactivez le provisioning pour ce compte."
-    },
-    "status.policy.3": {
-        "message": "Valeur de PolicyType inconnue. Contactez l'administrateur du serveur ou d?sactivez le provisioning pour ce compte."
-    },
-    "status.policy.4": {
-        "message": "Les donn?es de strat?gie sur le serveur sont corrompues (potentiellement alt?r?es). Contactez l'administrateur de votre serveur ou d?sactivez le provisioning pour ce compte."
-    },
-    "status.policy.5": {
-        "message": "Le client reconna?t la mauvaise cl? de strat?gie. Contactez l'administrateur du serveur ou d?sactivez le provisioning pour ce compte."
-    },
-    "status.provision": {
-        "message": "Le provisioning a ?chou? avec le statut <##replace.1##>"
-    },
-    "status.response-contains-no-data": {
-        "message": "La r?ponse du serveur ne contient aucune donn?e."
-    },
-    "status.resync-loop": {
-        "message": "Il y a eu une erreur ? partir de laquelle nous n'avons pas pu r?tablir la situation en resynchronisant le compte. Veuillez d?sactiver le compte et r?essayer. (Erreur : boucle de resynchronisation)"
-    },
-    "status.security": {
-        "message": "Impossible d'?tablir une connexion s?curis?e. Utilisez-vous un certificat auto-sign? ou autrement non fiable sans l'importer dans Thunderbird ? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "Pas encore pris en charge, ignor?"
-    },
-    "status.syncing": {
-        "message": "Synchronisation en cours"
-    },
-    "status.timeout": {
-        "message": "D?lai de communication expir?."
-    },
-    "status.wbxml-parse-error": {
-        "message": "Le serveur envoie une r?ponse illisible."
-    },
-    "status.wbxmlerror": {
-        "message": "La synchronisation a ?chou?. Le serveur a r?pondu avec le statut <##replace.1##>."
-    },
-    "status.wbxmlmissingfield": {
-        "message": "Violation du protocole ActiveSync : le champ obligatoire <##replace.1##> est absent de la r?ponse du serveur."
-    },
-    "syncstate.accountdone": {
-        "message": "Synchronisation du compte termin?e"
-    },
-    "syncstate.done": {
-        "message": "Pr?paration du prochain ?l?ment pour la synchronisation"
-    },
-    "syncstate.eval.response.autodiscover": {
-        "message": "Traitement des param?tres du serveur mis ? jour"
-    },
-    "syncstate.eval.response.deletefolder": {
-        "message": "Dossier supprim?"
-    },
-    "syncstate.eval.response.estimate": {
-        "message": "Traitement de l'estimation des changements"
-    },
-    "syncstate.eval.response.folders": {
-        "message": "Mise ? jour de la liste des dossiers en cours de traitement"
-    },
-    "syncstate.eval.response.localchanges": {
-        "message": "Traitement de la confirmation de r?ception des modifications locales"
-    },
-    "syncstate.eval.response.localdeletes": {
-        "message": "Traitement de la confirmation de r?ception des suppressions locales"
-    },
-    "syncstate.eval.response.options": {
-        "message": "Traitement des options du serveur"
-    },
-    "syncstate.eval.response.provision": {
-        "message": "Traitement de la provision"
-    },
-    "syncstate.eval.response.remotechanges": {
-        "message": "Traitement des modifications ? distance"
-    },
-    "syncstate.eval.response.revertlocalchanges": {
-        "message": "R?tablissement des modification locales"
-    },
-    "syncstate.eval.response.setdeviceinfo": {
-        "message": "Envoi des informations de l'appareil"
-    },
-    "syncstate.eval.response.synckey": {
-        "message": "Traitement de la cl? de synchronisation"
-    },
-    "syncstate.prepare.request.autodiscover": {
-        "message": "Demande de mise ? jour des param?tres du serveur"
-    },
-    "syncstate.prepare.request.deletefolder": {
-        "message": "Pr?paration de la suppression du dossier"
-    },
-    "syncstate.prepare.request.estimate": {
-        "message": "Demande de l'estimation des changements"
-    },
-    "syncstate.prepare.request.folders": {
-        "message": "Envoi de la mise ? jour de la liste de dossiers"
-    },
-    "syncstate.prepare.request.localchanges": {
-        "message": "Envoi des modifications locales"
-    },
-    "syncstate.prepare.request.localdeletes": {
-        "message": "Envoi des suppressions locales"
-    },
-    "syncstate.prepare.request.options": {
-        "message": "Demande des options du serveur"
-    },
-    "syncstate.prepare.request.provision": {
-        "message": "Demande de provision"
-    },
-    "syncstate.prepare.request.remotechanges": {
-        "message": "Traitement des modifications ? distance"
-    },
-    "syncstate.prepare.request.revertlocalchanges": {
-        "message": "Collecte des modifications locales"
-    },
-    "syncstate.prepare.request.setdeviceinfo": {
-        "message": "Envoi des informations de l'appareil"
-    },
-    "syncstate.prepare.request.synckey": {
-        "message": "Demande de cl? de synchronisation"
-    },
-    "syncstate.preparing": {
-        "message": "Pr?paration du prochain ?l?ment pour la synchronisation"
-    },
-    "syncstate.send.request.autodiscover": {
-        "message": "En attente de mise ? jour des param?tres du serveur"
-    },
-    "syncstate.send.request.deletefolder": {
-        "message": "En attente de la suppression du dossier"
-    },
-    "syncstate.send.request.estimate": {
-        "message": "En attente de l'estimation des changements"
-    },
-    "syncstate.send.request.folders": {
-        "message": "En attente de mise ? jour de la liste des dossiers"
-    },
-    "syncstate.send.request.localchanges": {
-        "message": "En attente de la confirmation de r?ception des modifications locales"
-    },
-    "syncstate.send.request.localdeletes": {
-        "message": "En attente de la confirmation de r?ception des suppressions locales"
-    },
-    "syncstate.send.request.options": {
-        "message": "En attente des options du serveur"
-    },
-    "syncstate.send.request.provision": {
-        "message": "En attente de provision"
-    },
-    "syncstate.send.request.remotechanges": {
-        "message": "En attente des modifications ? distance"
-    },
-    "syncstate.send.request.revertlocalchanges": {
-        "message": "En attente des versions les plus r?centes"
-    },
-    "syncstate.send.request.setdeviceinfo": {
-        "message": "Envoi des informations de l'appareil"
-    },
-    "syncstate.send.request.synckey": {
-        "message": "En attente de cl? de synchronisation"
-    },
-    "syncstate.syncing": {
-        "message": "Initialisation de la synchronisation"
-    }
-}
+{
+    "abCard.Anniversary": {
+        "message": "Anniversaire :"
+    },
+    "abCard.AssistantName": {
+        "message": "Assistant(e) :"
+    },
+    "abCard.AssistantPhoneNumber": {
+        "message": "T?l?phone Assistant(e) :"
+    },
+    "abCard.Business2PhoneNumber": {
+        "message": "T?l?phone Bureau Alternatif :"
+    },
+    "abCard.BusinessFaxNumber": {
+        "message": "Fax de bureau :"
+    },
+    "abCard.CarPhoneNumber": {
+        "message": "T?l?phone Voiture :"
+    },
+    "abCard.CompanyMainPhone": {
+        "message": "T?l?phone de Bureau Principal :"
+    },
+    "abCard.Email3Address": {
+        "message": "Courriel alternatif :"
+    },
+    "abCard.Home2PhoneNumber": {
+        "message": "T?l?phone Domicile Alternatif :"
+    },
+    "abCard.ManagerName": {
+        "message": "Sup?rieur(e) :"
+    },
+    "abCard.MiddleName": {
+        "message": "Deuxi?me pr?nom :"
+    },
+    "abCard.OtherAddress": {
+        "message": "Adresse :"
+    },
+    "abCard.OtherCity": {
+        "message": "Ville :"
+    },
+    "abCard.OtherCountry": {
+        "message": "Pays :"
+    },
+    "abCard.OtherState": {
+        "message": "?tat :"
+    },
+    "abCard.OtherZip": {
+        "message": "Code postal :"
+    },
+    "abCard.RadioPhoneNumber": {
+        "message": "T?l?phone Radio :"
+    },
+    "abCard.Spouse": {
+        "message": "?pou(x/se) :"
+    },
+    "abCard.header.eas": {
+        "message": "Autres champs (EAS)"
+    },
+    "abCard.header.homenumbers": {
+        "message": "T?l?phones domicile suppl?mentaires :"
+    },
+    "abCard.header.messaging": {
+        "message": "Messagerie :"
+    },
+    "abCard.header.otheraddress": {
+        "message": "Autre Adresse (EAS)"
+    },
+    "abCard.header.othernumbers": {
+        "message": "Num?ros de t?l?phone suppl?mentaires :"
+    },
+    "abCard.header.people": {
+        "message": "Personnes :"
+    },
+    "abCard.header.worknumbers": {
+        "message": "T?l?phones de bureau suppl?mentaires :"
+    },
+    "acl.readonly": {
+        "message": "Acc?s au serveur en lecture seule (annule les modifications locales)"
+    },
+    "acl.readwrite": {
+        "message": "Lecture et ?criture sur le serveur"
+    },
+    "add.description": {
+        "message": "Veuillez s?lectionner une des options de configuration du serveur disponibles et entrer les d?tails demand?s. "
+    },
+    "add.name": {
+        "message": "Nom du compte :"
+    },
+    "add.ok": {
+        "message": "Ajouter un compte"
+    },
+    "add.password": {
+        "message": "Mot de passe :"
+    },
+    "add.server": {
+        "message": "Configuration du serveur :"
+    },
+    "add.shortdescription": {
+        "message": "Informations du compte"
+    },
+    "add.title": {
+        "message": "Ajout d'un compte Exchange ActiveSync ? TbSync"
+    },
+    "add.url": {
+        "message": "Adresse du serveur :"
+    },
+    "add.urldescription": {
+        "message": "Il devrait suffire de fournir uniquement l'adresse de base du serveur (par exemple : mail.votreserveur.com). Cependant, il est ?galement possible de fournir l'URL compl?te (par exemple : https://mail.votreserveur.com/Microsoft-Server-ActiveSync)."
+    },
+    "add.user": {
+        "message": "Nom d'utilisateur (adresse e-mail) :"
+    },
+    "autocomplete.serverdirectory": {
+        "message": "annuaire global du serveur"
+    },
+    "autodiscover.Failed": {
+        "message": "L'Autodiscover pour l'utilisateur <##user##> a ?chou?. Soit les informations d'identification fournies ?taient erron?es, soit votre fournisseur ActiveSync a un probl?me temporaire, soit il ne prend pas en charge l'Autodiscover."
+    },
+    "autodiscover.NeedEmail": {
+        "message": "L'Autodiscover a besoin d'une adresse courriel valide comme nom d'utilisateur."
+    },
+    "autodiscover.Ok": {
+        "message": "L'Autodiscover est termin?e avec succ?s, vous pouvez maintenant v?rifier les param?tres optionnels et ?tablir la connexion de synchronisation."
+    },
+    "autodiscover.Querying": {
+        "message": "Recherche de param?tres?"
+    },
+    "config.auto": {
+        "message": "Configuration du serveur ActiveSync (Autodiscover)"
+    },
+    "config.custom": {
+        "message": "Configuration du serveur ActiveSync"
+    },
+    "deletefolder.confirm": {
+        "message": "Voulez-vous vraiment SUPPRIMER D?FINITIVEMENT le dossier ? ##replace.1##? de la corbeille ?"
+    },
+    "deletefolder.menuentry": {
+        "message": "Supprimer d?finitivement le dossier ? ##replace.1##? de la corbeille"
+    },
+    "deletefolder.notallowed": {
+        "message": "Veuillez vous d?sabonner du dossier ? ##replace.1##? avant d'essayer de le supprimer de la corbeille."
+    },
+    "extensionDescription": {
+        "message": "Ajouter la prise en charge de la synchronisation des comptes Exchange ActiveSync ? TbSync (contacts, t?ches et calendriers)."
+    },
+    "extensionName": {
+        "message": "Fournisseur pour Exchange ActiveSync"
+    },
+    "helplink.BadItemSkipped": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
+    },
+    "helplink.global.clientdenied": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "manager.tabs.accountsettings": {
+        "message": "Param?tres du compte"
+    },
+    "manager.tabs.outOfOffice": {
+        "message": "R?pondeur automatique"
+    },
+    "manager.tabs.syncsettings": {
+        "message": "Param?tres"
+    },
+    "newaccount.add_auto": {
+        "message": "Param?tres Autodiscover et ajout de compte"
+    },
+    "newaccount.add_custom": {
+        "message": "Ajouter un compte"
+    },
+    "pref.AccountName": {
+        "message": "Description"
+    },
+    "pref.ActiveSyncVersion": {
+        "message": "Version d'ActiveSync"
+    },
+    "pref.DeviceId": {
+        "message": "ID de p?riph?rique ActiveSync"
+    },
+    "pref.ServerName": {
+        "message": "Adresse du serveur"
+    },
+    "pref.ServerNameDescription": {
+        "message": "par exemple mail.votreserveur.com"
+    },
+    "pref.ShowTrashedFolders": {
+        "message": "Afficher les dossiers trouv?s dans la corbeille"
+    },
+    "pref.UserName": {
+        "message": "Nom d'utilisateur"
+    },
+    "pref.UserNameDescription": {
+        "message": "Le nom d'utilisateur est g?n?ralement l'adresse e-mail de votre compte."
+    },
+    "pref.autodetect": {
+        "message": "le meilleur disponible"
+    },
+    "pref.birthday": {
+        "message": "Envoyer la date de naissance"
+    },
+    "pref.calendaroptions": {
+        "message": "Options de calendrier"
+    },
+    "pref.contactoptions": {
+        "message": "Options des contacts"
+    },
+    "pref.displayoverride": {
+        "message": "Remplacer le nom affich? par ? Pr?nom ? + ? Nom ?"
+    },
+    "pref.generaloptions": {
+        "message": "Options g?n?rales"
+    },
+    "pref.provision": {
+        "message": "Forcer l'approvisionnement (requis par Kerio)"
+    },
+    "pref.seperator.comma": {
+        "message": "Virgule"
+    },
+    "pref.seperator.description": {
+        "message": "S?parateur pour le champ d'adresse multiligne."
+    },
+    "pref.seperator.linebreak": {
+        "message": "Saut de ligne"
+    },
+    "pref.synclimit.1month": {
+        "message": "les 4 derni?res semaines"
+    },
+    "pref.synclimit.2weeks": {
+        "message": "les 2 derni?res semaines"
+    },
+    "pref.synclimit.3month": {
+        "message": "les 3 derniers mois"
+    },
+    "pref.synclimit.6month": {
+        "message": "les 6 derniers mois"
+    },
+    "pref.synclimit.all": {
+        "message": "tout"
+    },
+    "pref.synclimit.description": {
+        "message": "P?riode de synchronisation : "
+    },
+    "pref.usehttps": {
+        "message": "Utiliser une connexion s?curis?e (se connecter via https)"
+    },
+    "recyclebin": {
+        "message": "Corbeille"
+    },
+    "servertype.auto": {
+        "message": "Configuration automatique"
+    },
+    "servertype.custom": {
+        "message": "Configuration personnalis?e"
+    },
+    "servertype.description.auto": {
+        "message": "La configuration de nombreux serveurs ActiveSync peut ?tre d?couverte en fournissant uniquement votre adresse e-mail."
+    },
+    "servertype.description.custom": {
+        "message": "Configurez votre compte en fournissant manuellement l'adresse du serveur que vous souhaitez connecter."
+    },
+    "servertype.description.office365": {
+        "message": "Les comptes connect?s ? Office 365 utilisent un processus d'authentification moderne appel? OAuth 2.0 qui supporte ?galement l'authentification multi-facteur (MFA)."
+    },
+    "servertype.office365": {
+        "message": "Microsoft Office 365"
+    },
+    "servertype.unlock": {
+        "message": "Double-cliquez pour d?verrouiller tous les param?tres pr?d?finis du serveur."
+    },
+    "status.401": {
+        "message": "L'authentification a ?chou?. Veuillez v?rifier le couple nom d'utilisateur/mot de passe (erreur HTTP 401)."
+    },
+    "status.403": {
+        "message": "Le serveur a rejet? la connexion (interdite) (Erreur HTTP 403)."
+    },
+    "status.404": {
+        "message": "Utilisateur introuvable (Erreur HTTP 404)."
+    },
+    "status.449": {
+        "message": "Le serveur demande le provisionnement (erreur HTTP 449)."
+    },
+    "status.500": {
+        "message": "Erreur serveur inconnue (Erreur HTTP 500)."
+    },
+    "status.503": {
+        "message": "Service indisponible (Erreur HTTP 503)."
+    },
+    "status.BadItemSkipped": {
+        "message": "Mauvais ?l?ment ignor? : ##replace.1##"
+    },
+    "status.FolderDelete.3": {
+        "message": "Impossible de supprimer un dossier syst?me (statut 3)"
+    },
+    "status.FolderDelete.4": {
+        "message": "Le dossier n'existe pas (statut 4), resynchronisation"
+    },
+    "status.FolderDelete.6": {
+        "message": "La commande n'a pas pu ?tre termin?e, une erreur est survenue sur le serveur (statut 6)"
+    },
+    "status.FolderDelete.9": {
+        "message": "Cl? de synchronisation invalide (statut 9), resynchronisation"
+    },
+    "status.FolderSync.9": {
+        "message": "Cl? de synchronisation invalide (statut 9), resynchronisation"
+    },
+    "status.InvalidServerOptions": {
+        "message": "Le serveur ne fournit pas d'informations sur les versions ActiveSync support?es. EAS est-il bloqu? pour cet utilisateur ou ce client (TbSync) ? Vous pouvez essayer de d?finir manuellement la version ActiveSync."
+    },
+    "status.OK": {
+        "message": "OK"
+    },
+    "status.ServerRejectedRequest": {
+        "message": "Le serveur EAS a rejet? la derni?re demande."
+    },
+    "status.ServerRejectedSomeItems": {
+        "message": "Le serveur EAS n'a pas accept? les ?l?ments ##replace.1##."
+    },
+    "status.Sync.12": {
+        "message": "La hi?rarchie des dossiers a chang? (statut 12), resynchronisation"
+    },
+    "status.Sync.3": {
+        "message": "Cl? de synchronisation invalide (statut 3), resynchronisation"
+    },
+    "status.Sync.4": {
+        "message": "Requ?te mal form?e (statut 4)"
+    },
+    "status.Sync.5": {
+        "message": "Probl?mes de serveur temporaires ou ?l?ment invalide (statut 5)"
+    },
+    "status.Sync.6": {
+        "message": "?l?ment invalide (statut 6)"
+    },
+    "status.Sync.8": {
+        "message": "Objet introuvable (statut 8)"
+    },
+    "status.aborted": {
+        "message": "Non synchronis?"
+    },
+    "status.disabled": {
+        "message": "D?sactiv?"
+    },
+    "status.empty-response": {
+        "message": "Le serveur a renvoy? une r?ponse vide inattendue."
+    },
+    "status.forbiddenCalendarItemInTasksFolder": {
+        "message": "?l?ment de calendrier interdit dans un dossier de t?che (veuillez intervenir)"
+    },
+    "status.forbiddenTasksItemInCalendarFolder": {
+        "message": "?l?ment de calendrier interdit dans un dossier de t?che (veuillez intervenir)"
+    },
+    "status.global.101": {
+        "message": "La requ?te contient WBXML mais n'a pas pu ?tre d?cod?e en XML (EAS Error 101)."
+    },
+    "status.global.102": {
+        "message": "La requ?te contient WBXML mais n'a pas pu ?tre d?cod?e en XML (EAS Error 102)."
+    },
+    "status.global.103": {
+        "message": "Le XML fourni dans la requ?te ne respecte pas les exigences du protocole (EAS Error 103)."
+    },
+    "status.global.110": {
+        "message": "Le serveur a signal? une erreur interne et nous ne devrions pas r?essayer imm?diatement. La synchronisation p?riodique automatique a ?t? d?sactiv?e pendant 30 minutes (EAS Error 110)."
+    },
+    "status.global.clientdenied": {
+        "message": "Le serveur EAS signale <##replace.2##> (status ##replace.1##) et n'autorise pas TbSync ? acc?der ? votre compte."
+    },
+    "status.httperror": {
+        "message": "Erreur de communication (statut HTTP ##replace.1##)."
+    },
+    "status.invalid": {
+        "message": "R?ponse du serveur invalide (pourriels)."
+    },
+    "status.malformed-xml": {
+        "message": "Impossible d?analyser le XML. V?rifiez le journal des ?v?nements pour plus de d?tails."
+    },
+    "status.modified": {
+        "message": "Modifications locales pr?sentes"
+    },
+    "status.network": {
+        "message": "Impossible de se connecter au serveur (##replace.1##)."
+    },
+    "status.networkerror": {
+        "message": "La connexion au serveur a ?chou?."
+    },
+    "status.nosupportedeasversion": {
+        "message": "Le serveur ne prend pas en charge ActiveSync v2.5 ou v14.0 (seulement ##replace.1##). TbSync ne fonctionnera pas avec ce serveur ActiveSync."
+    },
+    "status.notargets": {
+        "message": "Annulation de la synchronisation en cours : il est impossible de cr?er les destinations de synchronisation."
+    },
+    "status.notsupportedeasversion": {
+        "message": "Le serveur ne prend pas en charge la s?lection ActiveSync v##replace.1## (seulement ##replace.2##)."
+    },
+    "status.notsyncronized": {
+        "message": "Le compte doit ?tre synchronis? : au moins un ?l?ments n'est pas synchronis?."
+    },
+    "status.nouserhost": {
+        "message": "Nom d'utilisateur et/ou serveur manquant. Veuillez fournir ces valeurs."
+    },
+    "status.pending": {
+        "message": "En attente de synchronisation"
+    },
+    "status.policy.2": {
+        "message": "Il n'y a pas de politique pour ce client. Contactez l'administrateur de votre serveur ou d?sactivez le provisioning pour ce compte."
+    },
+    "status.policy.3": {
+        "message": "Valeur de PolicyType inconnue. Contactez l'administrateur du serveur ou d?sactivez le provisioning pour ce compte."
+    },
+    "status.policy.4": {
+        "message": "Les donn?es de strat?gie sur le serveur sont corrompues (potentiellement alt?r?es). Contactez l'administrateur de votre serveur ou d?sactivez le provisioning pour ce compte."
+    },
+    "status.policy.5": {
+        "message": "Le client reconna?t la mauvaise cl? de strat?gie. Contactez l'administrateur du serveur ou d?sactivez le provisioning pour ce compte."
+    },
+    "status.provision": {
+        "message": "Le provisioning a ?chou? avec le statut <##replace.1##>"
+    },
+    "status.response-contains-no-data": {
+        "message": "La r?ponse du serveur ne contient aucune donn?e."
+    },
+    "status.resync-loop": {
+        "message": "Il y a eu une erreur ? partir de laquelle nous n'avons pas pu r?tablir la situation en resynchronisant le compte. Veuillez d?sactiver le compte et r?essayer. (Erreur : boucle de resynchronisation)"
+    },
+    "status.security": {
+        "message": "Impossible d'?tablir une connexion s?curis?e. Utilisez-vous un certificat auto-sign? ou autrement non fiable sans l'importer dans Thunderbird ? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "Pas encore pris en charge, ignor?"
+    },
+    "status.syncing": {
+        "message": "Synchronisation en cours"
+    },
+    "status.timeout": {
+        "message": "D?lai de communication expir?."
+    },
+    "status.wbxml-parse-error": {
+        "message": "Le serveur envoie une r?ponse illisible."
+    },
+    "status.wbxmlerror": {
+        "message": "La synchronisation a ?chou?. Le serveur a r?pondu avec le statut <##replace.1##>."
+    },
+    "status.wbxmlmissingfield": {
+        "message": "Violation du protocole ActiveSync : le champ obligatoire <##replace.1##> est absent de la r?ponse du serveur."
+    },
+    "syncstate.accountdone": {
+        "message": "Synchronisation du compte termin?e"
+    },
+    "syncstate.done": {
+        "message": "Pr?paration du prochain ?l?ment pour la synchronisation"
+    },
+    "syncstate.eval.response.autodiscover": {
+        "message": "Traitement des param?tres du serveur mis ? jour"
+    },
+    "syncstate.eval.response.deletefolder": {
+        "message": "Dossier supprim?"
+    },
+    "syncstate.eval.response.estimate": {
+        "message": "Traitement de l'estimation des changements"
+    },
+    "syncstate.eval.response.folders": {
+        "message": "Mise ? jour de la liste des dossiers en cours de traitement"
+    },
+    "syncstate.eval.response.localchanges": {
+        "message": "Traitement de la confirmation de r?ception des modifications locales"
+    },
+    "syncstate.eval.response.localdeletes": {
+        "message": "Traitement de la confirmation de r?ception des suppressions locales"
+    },
+    "syncstate.eval.response.options": {
+        "message": "Traitement des options du serveur"
+    },
+    "syncstate.eval.response.provision": {
+        "message": "Traitement de la provision"
+    },
+    "syncstate.eval.response.remotechanges": {
+        "message": "Traitement des modifications ? distance"
+    },
+    "syncstate.eval.response.revertlocalchanges": {
+        "message": "R?tablissement des modification locales"
+    },
+    "syncstate.eval.response.setdeviceinfo": {
+        "message": "Envoi des informations de l'appareil"
+    },
+    "syncstate.eval.response.synckey": {
+        "message": "Traitement de la cl? de synchronisation"
+    },
+    "syncstate.prepare.request.autodiscover": {
+        "message": "Demande de mise ? jour des param?tres du serveur"
+    },
+    "syncstate.prepare.request.deletefolder": {
+        "message": "Pr?paration de la suppression du dossier"
+    },
+    "syncstate.prepare.request.estimate": {
+        "message": "Demande de l'estimation des changements"
+    },
+    "syncstate.prepare.request.folders": {
+        "message": "Envoi de la mise ? jour de la liste de dossiers"
+    },
+    "syncstate.prepare.request.localchanges": {
+        "message": "Envoi des modifications locales"
+    },
+    "syncstate.prepare.request.localdeletes": {
+        "message": "Envoi des suppressions locales"
+    },
+    "syncstate.prepare.request.options": {
+        "message": "Demande des options du serveur"
+    },
+    "syncstate.prepare.request.provision": {
+        "message": "Demande de provision"
+    },
+    "syncstate.prepare.request.remotechanges": {
+        "message": "Traitement des modifications ? distance"
+    },
+    "syncstate.prepare.request.revertlocalchanges": {
+        "message": "Collecte des modifications locales"
+    },
+    "syncstate.prepare.request.setdeviceinfo": {
+        "message": "Envoi des informations de l'appareil"
+    },
+    "syncstate.prepare.request.synckey": {
+        "message": "Demande de cl? de synchronisation"
+    },
+    "syncstate.preparing": {
+        "message": "Pr?paration du prochain ?l?ment pour la synchronisation"
+    },
+    "syncstate.send.request.autodiscover": {
+        "message": "En attente de mise ? jour des param?tres du serveur"
+    },
+    "syncstate.send.request.deletefolder": {
+        "message": "En attente de la suppression du dossier"
+    },
+    "syncstate.send.request.estimate": {
+        "message": "En attente de l'estimation des changements"
+    },
+    "syncstate.send.request.folders": {
+        "message": "En attente de mise ? jour de la liste des dossiers"
+    },
+    "syncstate.send.request.localchanges": {
+        "message": "En attente de la confirmation de r?ception des modifications locales"
+    },
+    "syncstate.send.request.localdeletes": {
+        "message": "En attente de la confirmation de r?ception des suppressions locales"
+    },
+    "syncstate.send.request.options": {
+        "message": "En attente des options du serveur"
+    },
+    "syncstate.send.request.provision": {
+        "message": "En attente de provision"
+    },
+    "syncstate.send.request.remotechanges": {
+        "message": "En attente des modifications ? distance"
+    },
+    "syncstate.send.request.revertlocalchanges": {
+        "message": "En attente des versions les plus r?centes"
+    },
+    "syncstate.send.request.setdeviceinfo": {
+        "message": "Envoi des informations de l'appareil"
+    },
+    "syncstate.send.request.synckey": {
+        "message": "En attente de cl? de synchronisation"
+    },
+    "syncstate.syncing": {
+        "message": "Initialisation de la synchronisation"
+    }
+}
diff -Nru eas4tbsync-4.11/_locales/gl/messages.json eas4tbsync-4.17/_locales/gl/messages.json
--- eas4tbsync-4.11/_locales/gl/messages.json	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/_locales/gl/messages.json	2025-05-15 13:21:18.000000000 +0200
@@ -1,566 +1,566 @@
-{
-    "abCard.Anniversary": {
-        "message": "Aniversario:"
-    },
-    "abCard.AssistantName": {
-        "message": "Asistente:"
-    },
-    "abCard.AssistantPhoneNumber": {
-        "message": "Tel?fono do asistente:"
-    },
-    "abCard.Business2PhoneNumber": {
-        "message": "Tel?fono alternativo do traballo:"
-    },
-    "abCard.BusinessFaxNumber": {
-        "message": "Fax do traballo:"
-    },
-    "abCard.CarPhoneNumber": {
-        "message": "Tel?fono do coche:"
-    },
-    "abCard.CompanyMainPhone": {
-        "message": "Tel?fono principal do traballo:"
-    },
-    "abCard.Email3Address": {
-        "message": "Correo electr?nico alternativo:"
-    },
-    "abCard.Home2PhoneNumber": {
-        "message": "Tel?fono de casa alternativo:"
-    },
-    "abCard.ManagerName": {
-        "message": "Supervisor:"
-    },
-    "abCard.MiddleName": {
-        "message": "Segundo nome:"
-    },
-    "abCard.OtherAddress": {
-        "message": "Enderezo:"
-    },
-    "abCard.OtherCity": {
-        "message": "Cidade:"
-    },
-    "abCard.OtherCountry": {
-        "message": "Pa?s:"
-    },
-    "abCard.OtherState": {
-        "message": "Estado:"
-    },
-    "abCard.OtherZip": {
-        "message": "C?digo postal:"
-    },
-    "abCard.RadioPhoneNumber": {
-        "message": "Radiotel?f?no:"
-    },
-    "abCard.Spouse": {
-        "message": "C?nxuxe:"
-    },
-    "abCard.header.eas": {
-        "message": "Outros campos (EAS)"
-    },
-    "abCard.header.homenumbers": {
-        "message": "N?meros adicionais de casa:"
-    },
-    "abCard.header.messaging": {
-        "message": "Mensaxer?a:"
-    },
-    "abCard.header.otheraddress": {
-        "message": "Outros enderezos (EAS)"
-    },
-    "abCard.header.othernumbers": {
-        "message": "N?meros adicionais:"
-    },
-    "abCard.header.people": {
-        "message": "Persoas:"
-    },
-    "abCard.header.worknumbers": {
-        "message": "N?meros adicionais do traballo:"
-    },
-    "acl.readonly": {
-        "message": "Acceso s? de lectura ao servidor (reverter cambios locais)"
-    },
-    "acl.readwrite": {
-        "message": "Leer e escribir no servidor"
-    },
-    "add.description": {
-        "message": "Por favor, selecciona unha das opci?ns de configuraci?n do servidor e insire os detalles solicitados. "
-    },
-    "add.name": {
-        "message": "Nome da conta:"
-    },
-    "add.ok": {
-        "message": "Engadir conta"
-    },
-    "add.password": {
-        "message": "Contrasinal:"
-    },
-    "add.server": {
-        "message": "Configuraci?n do servidor:"
-    },
-    "add.shortdescription": {
-        "message": "Informaci?n da conta"
-    },
-    "add.title": {
-        "message": "Engadindo unha conta Exchange ActiveSync a TbSync"
-    },
-    "add.url": {
-        "message": "Enderezo do servidor:"
-    },
-    "add.urldescription": {
-        "message": "Deber?a de ser suficiente con proporcionar s? o enderezo b?sico do servidor (por exemplo, correo.dominio.gal). Con todo, tam?n ? posible facilitar o URL completo (por exemplo, https://correo.dominio.gal/Servidor-Microsoft-ActiveSync)."
-    },
-    "add.user": {
-        "message": "Nome de usuario (enderezo de correo electr?nico):"
-    },
-    "autocomplete.serverdirectory": {
-        "message": "directorio global de servidores"
-    },
-    "autodiscover.Failed": {
-        "message": "Fallou o Autodiscover para o usuario <##user##>. Ou ben proporcionaches unhas credenciais err?neas ou ben o teu provedor de ActiveSync ten un problema temporal, ou ben non admite o Autodiscover."
-    },
-    "autodiscover.NeedEmail": {
-        "message": "Autodiscover precisa dun enderezo de correo elect?nico v?lido como nome de usuario."
-    },
-    "autodiscover.Ok": {
-        "message": "Autodiscover completouse correctamente; agora podes revisar os axustes opcionais e establecer a conexi?n de sincronizaci?n."
-    },
-    "autodiscover.Querying": {
-        "message": "Buscando os axustes?"
-    },
-    "config.auto": {
-        "message": "Configuraci?n do servidor de ActiveSync (Autodiscover)"
-    },
-    "config.custom": {
-        "message": "Configuraci?n do servidor de ActiveSync"
-    },
-    "deletefolder.confirm": {
-        "message": "Queres ELIMINAR DEFINITIVAMENTE o cartafol ?##replace.1##? da papeleira?"
-    },
-    "deletefolder.menuentry": {
-        "message": "Eliminar definitivamente o cartafol ?##replace.1##? da papeleira"
-    },
-    "deletefolder.notallowed": {
-        "message": "Por favor, cancela a subscrici?n ao cartafol ?##replace.1##? antes de intentar eliminalo da papeleira."
-    },
-    "extensionDescription": {
-        "message": "Engade soporte a TbSync para a sincronizaci?n de contas de Exchange ActiveSync (contactos, tarefas e calendarios)."
-    },
-    "extensionName": {
-        "message": "Provedor de Exchange ActiveSync"
-    },
-    "helplink.BadItemSkipped": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
-    },
-    "helplink.global.clientdenied": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "manager.tabs.accountsettings": {
-        "message": "Axustes da conta"
-    },
-    "manager.tabs.outOfOffice": {
-        "message": "Resposta autom?tica"
-    },
-    "manager.tabs.syncsettings": {
-        "message": "Opci?ns"
-    },
-    "newaccount.add_auto": {
-        "message": "Axustes de Autodiscover e engadir conta"
-    },
-    "newaccount.add_custom": {
-        "message": "Engadir conta"
-    },
-    "pref.AccountName": {
-        "message": "Descrici?n"
-    },
-    "pref.ActiveSyncVersion": {
-        "message": "Versi?n de ActiveSync"
-    },
-    "pref.DeviceId": {
-        "message": "ID de dispositivo de ActiveSync"
-    },
-    "pref.ServerName": {
-        "message": "Enderezo do servidor"
-    },
-    "pref.ServerNameDescription": {
-        "message": "por exemplo, correo.dominio.gal"
-    },
-    "pref.ShowTrashedFolders": {
-        "message": "Amosar cartafois atopados na papeleira"
-    },
-    "pref.UserName": {
-        "message": "Nome de usuario"
-    },
-    "pref.UserNameDescription": {
-        "message": "O nome de usuario adoita ser o enderezo de correo electr?nico da t?a conta."
-    },
-    "pref.autodetect": {
-        "message": "mellor dispo?ible"
-    },
-    "pref.birthday": {
-        "message": "Enviar informaci?n do aniversario"
-    },
-    "pref.calendaroptions": {
-        "message": "Opci?ns do calendario"
-    },
-    "pref.contactoptions": {
-        "message": "Opci?ns dos contactos"
-    },
-    "pref.displayoverride": {
-        "message": "Substitu?r o nome amosado por ?Nome? + ?Segundo nome?"
-    },
-    "pref.generaloptions": {
-        "message": "Opci?ns xerais"
-    },
-    "pref.provision": {
-        "message": "Forzar aprovisionamento (requirido por Kerio)"
-    },
-    "pref.seperator.comma": {
-        "message": "Coma"
-    },
-    "pref.seperator.description": {
-        "message": "Separador de campo de enderezo en varias li?as."
-    },
-    "pref.seperator.linebreak": {
-        "message": "Salto de li?a"
-    },
-    "pref.synclimit.1month": {
-        "message": "desde hai 4 semanas"
-    },
-    "pref.synclimit.2weeks": {
-        "message": "desde hai 2 semanas"
-    },
-    "pref.synclimit.3month": {
-        "message": "desde hai 3 meses"
-    },
-    "pref.synclimit.6month": {
-        "message": "desde hai 6 meses"
-    },
-    "pref.synclimit.all": {
-        "message": "todo"
-    },
-    "pref.synclimit.description": {
-        "message": "Per?odo de sincronizaci?n: "
-    },
-    "pref.usehttps": {
-        "message": "Usar conexi?n segura (conectar mediante https)"
-    },
-    "recyclebin": {
-        "message": "Papeleira"
-    },
-    "servertype.auto": {
-        "message": "Configuraci?n autom?tica"
-    },
-    "servertype.custom": {
-        "message": "Configuraci?n personalizada"
-    },
-    "servertype.description.auto": {
-        "message": "? posible detectar a configuraci?n de moitos servidores ActiveSync con s? proporcionar o teu enderezo de correo electr?nico."
-    },
-    "servertype.description.custom": {
-        "message": "Configura a conta proporciando manualmente o enderezo do servidor ao que queres conectar."
-    },
-    "servertype.description.office365": {
-        "message": "As contas conectadas a Office 365 utilizan un proceso de autenticaci?n moderno, chamado OAuth 2.0, que tam?n admite autenticaci?n multifactor (MFA)."
-    },
-    "servertype.office365": {
-        "message": "Microsoft Office 365"
-    },
-    "servertype.unlock": {
-        "message": "Fai dobre clic para desbloquear todos os axustes predefinidos do servidor."
-    },
-    "status.401": {
-        "message": "Non foi posible autenticarse, comproba o nome de usuario e o contrasinal (erro HTTP 401)."
-    },
-    "status.403": {
-        "message": "O servidor rexeitou a conexi?n (prohibida) (erro HTTP 403)."
-    },
-    "status.404": {
-        "message": "Usuario non atopado (erro HTTP 404)."
-    },
-    "status.449": {
-        "message": "O servidor solicita aprovisionamento (erro HTTP 449)."
-    },
-    "status.500": {
-        "message": "Erro desco?ecido do servidor (erro HTTP 500)."
-    },
-    "status.503": {
-        "message": "Servicio non dispo?ible (erro HTTP 503)."
-    },
-    "status.BadItemSkipped": {
-        "message": "Omitido obxecto incorrecto: ##replace.1##"
-    },
-    "status.FolderDelete.3": {
-        "message": "Non ? posible eliminar un cartafol do sistema (estado 3)"
-    },
-    "status.FolderDelete.4": {
-        "message": "O cartafol non existe (estado 4), resincronizando"
-    },
-    "status.FolderDelete.6": {
-        "message": "O comando non se completou, produciuse un erro no servidor (estado 6)"
-    },
-    "status.FolderDelete.9": {
-        "message": "Chave de sincronizaci?n non v?lida (estado 9), resincronizando"
-    },
-    "status.FolderSync.9": {
-        "message": "Chave de sincronizaci?n non v?lida (estado 9), resincronizando"
-    },
-    "status.InvalidServerOptions": {
-        "message": "El servidor non proporciona informaci?n sobre as versi?ns de ActiveSync compatibles. Est? EAS bloqueado para este usuario ou para este cliente (TbSync)? Podes intentar establecer a versi?n de ActiveSync manualmente."
-    },
-    "status.OK": {
-        "message": "OK"
-    },
-    "status.ServerRejectedRequest": {
-        "message": "O servidor de EAS rexeitou a ?ltima petici?n."
-    },
-    "status.ServerRejectedSomeItems": {
-        "message": "O servidor de EAS non aceptou ##replace.1## elementos."
-    },
-    "status.Sync.12": {
-        "message": "Cambiou a xerarqu?a de cartafois (estado 12), resincronizando"
-    },
-    "status.Sync.3": {
-        "message": "Chave de sincronizaci?n non v?lida (estado 3), resincronizando"
-    },
-    "status.Sync.4": {
-        "message": "Solicitude mal formada (estado 4)"
-    },
-    "status.Sync.5": {
-        "message": "Problemas temporais do servidor ou elemento non v?lido (estado 5)"
-    },
-    "status.Sync.6": {
-        "message": "Elemento non v?lido (estado 6)"
-    },
-    "status.Sync.8": {
-        "message": "Obxecto non atopado (estado 8)"
-    },
-    "status.aborted": {
-        "message": "Sen sincronizar"
-    },
-    "status.disabled": {
-        "message": "Desactivado"
-    },
-    "status.empty-response": {
-        "message": "O servidor env?a unha resposta baleira non esperada."
-    },
-    "status.forbiddenCalendarItemInTasksFolder": {
-        "message": "Elemento do calendario prohibido nun cartafol de tarefas (por favor, reorganiza)"
-    },
-    "status.forbiddenTasksItemInCalendarFolder": {
-        "message": "Elemento de tarefas prohibido nun cartafol do calendario (por favor, reorganiza)"
-    },
-    "status.global.101": {
-        "message": "A solicitude cont?n WBXML pero non puido ser descodificado a XML (erro EAS 101)."
-    },
-    "status.global.102": {
-        "message": "A solicitude cont?n WBXML pero non puido ser descodificado a XML (erro EAS 102)."
-    },
-    "status.global.103": {
-        "message": "O XML proporcionado na solicitude non cumple os requirimentos do protocolo (erro EAS 103)."
-    },
-    "status.global.110": {
-        "message": "O servidor informou dun erro interno e non deber?as reconectar de inmediato. Desactivouse a sincronizaci?n peri?dica autom?tica durante 30 minutos (erro EAS 110)."
-    },
-    "status.global.clientdenied": {
-        "message": "O servidor EAS notifica <##replace.2##> (estado ##replace.1##) e non permite que TbSync acceda ? t?a conta."
-    },
-    "status.httperror": {
-        "message": "Erro de comunicaci?n (estado HTTP ##replace.1##)."
-    },
-    "status.invalid": {
-        "message": "Resposta do servidor non v?lida (corrompida)."
-    },
-    "status.malformed-xml": {
-        "message": "Non se puido analizar o XML. 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.networkerror": {
-        "message": "Non se puido conectar ao servidor."
-    },
-    "status.nosupportedeasversion": {
-        "message": "O servidor non ? compatible con ActiveSync v2.5 ou v14.0 (s? ##replace.1##). TbSync non funcionar? con este servidor de ActiveSync."
-    },
-    "status.notargets": {
-        "message": "Sincronizaci?n interrompida porque no se puideron crear os destinos da sincronizaci?n."
-    },
-    "status.notsupportedeasversion": {
-        "message": "O servidor non ? compatible con ActiveSync v##replace.1## (s? ##replace.2##)."
-    },
-    "status.notsyncronized": {
-        "message": "? preciso sincronizar a conta: hai alg?n un elemento sen sincronizar."
-    },
-    "status.nouserhost": {
-        "message": "Falta o nome de usuario ou o servidor. Por favor, proporciona eses datos."
-    },
-    "status.pending": {
-        "message": "Agardando pola sincronizaci?n"
-    },
-    "status.policy.2": {
-        "message": "Non hai ningunha directiva para este cliente. Contacta co administrador do servidor ou desactiva o aprovisionamento desta conta."
-    },
-    "status.policy.3": {
-        "message": "Valor de PolicyType desco?ecido. Contacta co administrador do servidor ou desactiva o aprovisionamento desta conta."
-    },
-    "status.policy.4": {
-        "message": "Os datos de directivas do servidor est?n danados (posiblemente manipulados). Contacta co administrador do servidor ou desactiva o aprovisionamento desta conta."
-    },
-    "status.policy.5": {
-        "message": "O cliente est? a reco?ecer a chave de directiva incorrecta. Contacta co administrador do servidor ou desactiva o aprovisionamento desta conta."
-    },
-    "status.provision": {
-        "message": "O aprovisionamento fallou co estado <##replace.1##>"
-    },
-    "status.response-contains-no-data": {
-        "message": "A resposta do servidor non cont?n datos."
-    },
-    "status.resync-loop": {
-        "message": "Produciuse un erro que non se puido corrixir volvendo a sincronizar a conta. Desactiva a conta e int?ntao outra vez (erro: bucle de resincronizaci?n)"
-    },
-    "status.security": {
-        "message": "No se puido establecer unha conexi?n segura. Est?s a usar un certificado autofirmado, ou que non ? de confianza, sen importarlo a Thunderbird? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "A?nda non soportado, omitido"
-    },
-    "status.syncing": {
-        "message": "Sincronizando"
-    },
-    "status.timeout": {
-        "message": "Tempo de comunicaci?n esgotado."
-    },
-    "status.wbxml-parse-error": {
-        "message": "O servidor env?a unha resposta ilexible."
-    },
-    "status.wbxmlerror": {
-        "message": "Erro ao sincronizar. O servidor respondeu co estado <##replace.1##>."
-    },
-    "status.wbxmlmissingfield": {
-        "message": "Violaci?n do protocolo de ActiveSync: falta o campo obrigatorio <##replace.1##> na respuesta do servidor."
-    },
-    "syncstate.accountdone": {
-        "message": "Conta rematada"
-    },
-    "syncstate.done": {
-        "message": "Preparando o seguinte elemento para a sincronizaci?n"
-    },
-    "syncstate.eval.response.autodiscover": {
-        "message": "Procesando os axustes do servidor actualizados"
-    },
-    "syncstate.eval.response.deletefolder": {
-        "message": "Cartafol eliminado"
-    },
-    "syncstate.eval.response.estimate": {
-        "message": "Procesando a estimaci?n do cambio"
-    },
-    "syncstate.eval.response.folders": {
-        "message": "Procesando a lista de cartafois actualizada"
-    },
-    "syncstate.eval.response.localchanges": {
-        "message": "Procesando o reco?ecemento de cambios locais"
-    },
-    "syncstate.eval.response.localdeletes": {
-        "message": "Procesando o reco?ecemento de eliminaci?ns locais"
-    },
-    "syncstate.eval.response.options": {
-        "message": "Procesando as opci?ns do servidor"
-    },
-    "syncstate.eval.response.provision": {
-        "message": "Procesando o aprovisionamento"
-    },
-    "syncstate.eval.response.remotechanges": {
-        "message": "Procesando os cambios remotos"
-    },
-    "syncstate.eval.response.revertlocalchanges": {
-        "message": "Revertendo os cambios locais"
-    },
-    "syncstate.eval.response.setdeviceinfo": {
-        "message": "Enviando informaci?n do dispositivo"
-    },
-    "syncstate.eval.response.synckey": {
-        "message": "Procesando SyncKey"
-    },
-    "syncstate.prepare.request.autodiscover": {
-        "message": "Solicitando axustes actualizados do servidor"
-    },
-    "syncstate.prepare.request.deletefolder": {
-        "message": "Preparando a elimanci?n do cartafol"
-    },
-    "syncstate.prepare.request.estimate": {
-        "message": "Solicitando a estimaci?n dos cambios"
-    },
-    "syncstate.prepare.request.folders": {
-        "message": "Enviando a actualizaci?n da lista de cartafois"
-    },
-    "syncstate.prepare.request.localchanges": {
-        "message": "Enviando os cambios locais"
-    },
-    "syncstate.prepare.request.localdeletes": {
-        "message": "Enviando as eliminaci?ns locais"
-    },
-    "syncstate.prepare.request.options": {
-        "message": "Solicitando as opci?ns do servidor"
-    },
-    "syncstate.prepare.request.provision": {
-        "message": "Solicitando o aprovisionamento"
-    },
-    "syncstate.prepare.request.remotechanges": {
-        "message": "Solicitando os cambios remotos"
-    },
-    "syncstate.prepare.request.revertlocalchanges": {
-        "message": "Recolectando os cambios locais"
-    },
-    "syncstate.prepare.request.setdeviceinfo": {
-        "message": "Enviando informaci?n do dispositivo"
-    },
-    "syncstate.prepare.request.synckey": {
-        "message": "Solicitando SyncKey"
-    },
-    "syncstate.preparing": {
-        "message": "Preparando o seguinte elemento para a sincronizaci?n"
-    },
-    "syncstate.send.request.autodiscover": {
-        "message": "Agardando polos axustes actualizados do servidor"
-    },
-    "syncstate.send.request.deletefolder": {
-        "message": "Agardando pola eliminaci?n do cartafol"
-    },
-    "syncstate.send.request.estimate": {
-        "message": "Agardando pola estimaci?n de cambios"
-    },
-    "syncstate.send.request.folders": {
-        "message": "Agardando pola actualizaci?n da lista de cartafois"
-    },
-    "syncstate.send.request.localchanges": {
-        "message": "Agardando polo reco?ecemento de cambios locais"
-    },
-    "syncstate.send.request.localdeletes": {
-        "message": "Agardando polo reco?ecemento de eliminaci?ns locais"
-    },
-    "syncstate.send.request.options": {
-        "message": "Agardando polas opci?ns do servidor"
-    },
-    "syncstate.send.request.provision": {
-        "message": "Agardando polo aprovisionamento"
-    },
-    "syncstate.send.request.remotechanges": {
-        "message": "Agardando polos cambios remotos"
-    },
-    "syncstate.send.request.revertlocalchanges": {
-        "message": "Agardando polas versi?ns m?is recentes"
-    },
-    "syncstate.send.request.setdeviceinfo": {
-        "message": "Enviando informaci?n do dispositivo"
-    },
-    "syncstate.send.request.synckey": {
-        "message": "Agardando por SyncKey"
-    },
-    "syncstate.syncing": {
-        "message": "Iniciar sincronizaci?n"
-    }
-}
+{
+    "abCard.Anniversary": {
+        "message": "Aniversario:"
+    },
+    "abCard.AssistantName": {
+        "message": "Asistente:"
+    },
+    "abCard.AssistantPhoneNumber": {
+        "message": "Tel?fono do asistente:"
+    },
+    "abCard.Business2PhoneNumber": {
+        "message": "Tel?fono alternativo do traballo:"
+    },
+    "abCard.BusinessFaxNumber": {
+        "message": "Fax do traballo:"
+    },
+    "abCard.CarPhoneNumber": {
+        "message": "Tel?fono do coche:"
+    },
+    "abCard.CompanyMainPhone": {
+        "message": "Tel?fono principal do traballo:"
+    },
+    "abCard.Email3Address": {
+        "message": "Correo electr?nico alternativo:"
+    },
+    "abCard.Home2PhoneNumber": {
+        "message": "Tel?fono de casa alternativo:"
+    },
+    "abCard.ManagerName": {
+        "message": "Supervisor:"
+    },
+    "abCard.MiddleName": {
+        "message": "Segundo nome:"
+    },
+    "abCard.OtherAddress": {
+        "message": "Enderezo:"
+    },
+    "abCard.OtherCity": {
+        "message": "Cidade:"
+    },
+    "abCard.OtherCountry": {
+        "message": "Pa?s:"
+    },
+    "abCard.OtherState": {
+        "message": "Estado:"
+    },
+    "abCard.OtherZip": {
+        "message": "C?digo postal:"
+    },
+    "abCard.RadioPhoneNumber": {
+        "message": "Radiotel?f?no:"
+    },
+    "abCard.Spouse": {
+        "message": "C?nxuxe:"
+    },
+    "abCard.header.eas": {
+        "message": "Outros campos (EAS)"
+    },
+    "abCard.header.homenumbers": {
+        "message": "N?meros adicionais de casa:"
+    },
+    "abCard.header.messaging": {
+        "message": "Mensaxer?a:"
+    },
+    "abCard.header.otheraddress": {
+        "message": "Outros enderezos (EAS)"
+    },
+    "abCard.header.othernumbers": {
+        "message": "N?meros adicionais:"
+    },
+    "abCard.header.people": {
+        "message": "Persoas:"
+    },
+    "abCard.header.worknumbers": {
+        "message": "N?meros adicionais do traballo:"
+    },
+    "acl.readonly": {
+        "message": "Acceso s? de lectura ao servidor (reverter cambios locais)"
+    },
+    "acl.readwrite": {
+        "message": "Leer e escribir no servidor"
+    },
+    "add.description": {
+        "message": "Por favor, selecciona unha das opci?ns de configuraci?n do servidor e insire os detalles solicitados. "
+    },
+    "add.name": {
+        "message": "Nome da conta:"
+    },
+    "add.ok": {
+        "message": "Engadir conta"
+    },
+    "add.password": {
+        "message": "Contrasinal:"
+    },
+    "add.server": {
+        "message": "Configuraci?n do servidor:"
+    },
+    "add.shortdescription": {
+        "message": "Informaci?n da conta"
+    },
+    "add.title": {
+        "message": "Engadindo unha conta Exchange ActiveSync a TbSync"
+    },
+    "add.url": {
+        "message": "Enderezo do servidor:"
+    },
+    "add.urldescription": {
+        "message": "Deber?a de ser suficiente con proporcionar s? o enderezo b?sico do servidor (por exemplo, correo.dominio.gal). Con todo, tam?n ? posible facilitar o URL completo (por exemplo, https://correo.dominio.gal/Servidor-Microsoft-ActiveSync)."
+    },
+    "add.user": {
+        "message": "Nome de usuario (enderezo de correo electr?nico):"
+    },
+    "autocomplete.serverdirectory": {
+        "message": "directorio global de servidores"
+    },
+    "autodiscover.Failed": {
+        "message": "Fallou o Autodiscover para o usuario <##user##>. Ou ben proporcionaches unhas credenciais err?neas ou ben o teu provedor de ActiveSync ten un problema temporal, ou ben non admite o Autodiscover."
+    },
+    "autodiscover.NeedEmail": {
+        "message": "Autodiscover precisa dun enderezo de correo elect?nico v?lido como nome de usuario."
+    },
+    "autodiscover.Ok": {
+        "message": "Autodiscover completouse correctamente; agora podes revisar os axustes opcionais e establecer a conexi?n de sincronizaci?n."
+    },
+    "autodiscover.Querying": {
+        "message": "Buscando os axustes?"
+    },
+    "config.auto": {
+        "message": "Configuraci?n do servidor de ActiveSync (Autodiscover)"
+    },
+    "config.custom": {
+        "message": "Configuraci?n do servidor de ActiveSync"
+    },
+    "deletefolder.confirm": {
+        "message": "Queres ELIMINAR DEFINITIVAMENTE o cartafol ?##replace.1##? da papeleira?"
+    },
+    "deletefolder.menuentry": {
+        "message": "Eliminar definitivamente o cartafol ?##replace.1##? da papeleira"
+    },
+    "deletefolder.notallowed": {
+        "message": "Por favor, cancela a subscrici?n ao cartafol ?##replace.1##? antes de intentar eliminalo da papeleira."
+    },
+    "extensionDescription": {
+        "message": "Engade soporte a TbSync para a sincronizaci?n de contas de Exchange ActiveSync (contactos, tarefas e calendarios)."
+    },
+    "extensionName": {
+        "message": "Provedor de Exchange ActiveSync"
+    },
+    "helplink.BadItemSkipped": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
+    },
+    "helplink.global.clientdenied": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "manager.tabs.accountsettings": {
+        "message": "Axustes da conta"
+    },
+    "manager.tabs.outOfOffice": {
+        "message": "Resposta autom?tica"
+    },
+    "manager.tabs.syncsettings": {
+        "message": "Opci?ns"
+    },
+    "newaccount.add_auto": {
+        "message": "Axustes de Autodiscover e engadir conta"
+    },
+    "newaccount.add_custom": {
+        "message": "Engadir conta"
+    },
+    "pref.AccountName": {
+        "message": "Descrici?n"
+    },
+    "pref.ActiveSyncVersion": {
+        "message": "Versi?n de ActiveSync"
+    },
+    "pref.DeviceId": {
+        "message": "ID de dispositivo de ActiveSync"
+    },
+    "pref.ServerName": {
+        "message": "Enderezo do servidor"
+    },
+    "pref.ServerNameDescription": {
+        "message": "por exemplo, correo.dominio.gal"
+    },
+    "pref.ShowTrashedFolders": {
+        "message": "Amosar cartafois atopados na papeleira"
+    },
+    "pref.UserName": {
+        "message": "Nome de usuario"
+    },
+    "pref.UserNameDescription": {
+        "message": "O nome de usuario adoita ser o enderezo de correo electr?nico da t?a conta."
+    },
+    "pref.autodetect": {
+        "message": "mellor dispo?ible"
+    },
+    "pref.birthday": {
+        "message": "Enviar informaci?n do aniversario"
+    },
+    "pref.calendaroptions": {
+        "message": "Opci?ns do calendario"
+    },
+    "pref.contactoptions": {
+        "message": "Opci?ns dos contactos"
+    },
+    "pref.displayoverride": {
+        "message": "Substitu?r o nome amosado por ?Nome? + ?Segundo nome?"
+    },
+    "pref.generaloptions": {
+        "message": "Opci?ns xerais"
+    },
+    "pref.provision": {
+        "message": "Forzar aprovisionamento (requirido por Kerio)"
+    },
+    "pref.seperator.comma": {
+        "message": "Coma"
+    },
+    "pref.seperator.description": {
+        "message": "Separador de campo de enderezo en varias li?as."
+    },
+    "pref.seperator.linebreak": {
+        "message": "Salto de li?a"
+    },
+    "pref.synclimit.1month": {
+        "message": "desde hai 4 semanas"
+    },
+    "pref.synclimit.2weeks": {
+        "message": "desde hai 2 semanas"
+    },
+    "pref.synclimit.3month": {
+        "message": "desde hai 3 meses"
+    },
+    "pref.synclimit.6month": {
+        "message": "desde hai 6 meses"
+    },
+    "pref.synclimit.all": {
+        "message": "todo"
+    },
+    "pref.synclimit.description": {
+        "message": "Per?odo de sincronizaci?n: "
+    },
+    "pref.usehttps": {
+        "message": "Usar conexi?n segura (conectar mediante https)"
+    },
+    "recyclebin": {
+        "message": "Papeleira"
+    },
+    "servertype.auto": {
+        "message": "Configuraci?n autom?tica"
+    },
+    "servertype.custom": {
+        "message": "Configuraci?n personalizada"
+    },
+    "servertype.description.auto": {
+        "message": "? posible detectar a configuraci?n de moitos servidores ActiveSync con s? proporcionar o teu enderezo de correo electr?nico."
+    },
+    "servertype.description.custom": {
+        "message": "Configura a conta proporciando manualmente o enderezo do servidor ao que queres conectar."
+    },
+    "servertype.description.office365": {
+        "message": "As contas conectadas a Office 365 utilizan un proceso de autenticaci?n moderno, chamado OAuth 2.0, que tam?n admite autenticaci?n multifactor (MFA)."
+    },
+    "servertype.office365": {
+        "message": "Microsoft Office 365"
+    },
+    "servertype.unlock": {
+        "message": "Fai dobre clic para desbloquear todos os axustes predefinidos do servidor."
+    },
+    "status.401": {
+        "message": "Non foi posible autenticarse, comproba o nome de usuario e o contrasinal (erro HTTP 401)."
+    },
+    "status.403": {
+        "message": "O servidor rexeitou a conexi?n (prohibida) (erro HTTP 403)."
+    },
+    "status.404": {
+        "message": "Usuario non atopado (erro HTTP 404)."
+    },
+    "status.449": {
+        "message": "O servidor solicita aprovisionamento (erro HTTP 449)."
+    },
+    "status.500": {
+        "message": "Erro desco?ecido do servidor (erro HTTP 500)."
+    },
+    "status.503": {
+        "message": "Servicio non dispo?ible (erro HTTP 503)."
+    },
+    "status.BadItemSkipped": {
+        "message": "Omitido obxecto incorrecto: ##replace.1##"
+    },
+    "status.FolderDelete.3": {
+        "message": "Non ? posible eliminar un cartafol do sistema (estado 3)"
+    },
+    "status.FolderDelete.4": {
+        "message": "O cartafol non existe (estado 4), resincronizando"
+    },
+    "status.FolderDelete.6": {
+        "message": "O comando non se completou, produciuse un erro no servidor (estado 6)"
+    },
+    "status.FolderDelete.9": {
+        "message": "Chave de sincronizaci?n non v?lida (estado 9), resincronizando"
+    },
+    "status.FolderSync.9": {
+        "message": "Chave de sincronizaci?n non v?lida (estado 9), resincronizando"
+    },
+    "status.InvalidServerOptions": {
+        "message": "El servidor non proporciona informaci?n sobre as versi?ns de ActiveSync compatibles. Est? EAS bloqueado para este usuario ou para este cliente (TbSync)? Podes intentar establecer a versi?n de ActiveSync manualmente."
+    },
+    "status.OK": {
+        "message": "OK"
+    },
+    "status.ServerRejectedRequest": {
+        "message": "O servidor de EAS rexeitou a ?ltima petici?n."
+    },
+    "status.ServerRejectedSomeItems": {
+        "message": "O servidor de EAS non aceptou ##replace.1## elementos."
+    },
+    "status.Sync.12": {
+        "message": "Cambiou a xerarqu?a de cartafois (estado 12), resincronizando"
+    },
+    "status.Sync.3": {
+        "message": "Chave de sincronizaci?n non v?lida (estado 3), resincronizando"
+    },
+    "status.Sync.4": {
+        "message": "Solicitude mal formada (estado 4)"
+    },
+    "status.Sync.5": {
+        "message": "Problemas temporais do servidor ou elemento non v?lido (estado 5)"
+    },
+    "status.Sync.6": {
+        "message": "Elemento non v?lido (estado 6)"
+    },
+    "status.Sync.8": {
+        "message": "Obxecto non atopado (estado 8)"
+    },
+    "status.aborted": {
+        "message": "Sen sincronizar"
+    },
+    "status.disabled": {
+        "message": "Desactivado"
+    },
+    "status.empty-response": {
+        "message": "O servidor env?a unha resposta baleira non esperada."
+    },
+    "status.forbiddenCalendarItemInTasksFolder": {
+        "message": "Elemento do calendario prohibido nun cartafol de tarefas (por favor, reorganiza)"
+    },
+    "status.forbiddenTasksItemInCalendarFolder": {
+        "message": "Elemento de tarefas prohibido nun cartafol do calendario (por favor, reorganiza)"
+    },
+    "status.global.101": {
+        "message": "A solicitude cont?n WBXML pero non puido ser descodificado a XML (erro EAS 101)."
+    },
+    "status.global.102": {
+        "message": "A solicitude cont?n WBXML pero non puido ser descodificado a XML (erro EAS 102)."
+    },
+    "status.global.103": {
+        "message": "O XML proporcionado na solicitude non cumple os requirimentos do protocolo (erro EAS 103)."
+    },
+    "status.global.110": {
+        "message": "O servidor informou dun erro interno e non deber?as reconectar de inmediato. Desactivouse a sincronizaci?n peri?dica autom?tica durante 30 minutos (erro EAS 110)."
+    },
+    "status.global.clientdenied": {
+        "message": "O servidor EAS notifica <##replace.2##> (estado ##replace.1##) e non permite que TbSync acceda ? t?a conta."
+    },
+    "status.httperror": {
+        "message": "Erro de comunicaci?n (estado HTTP ##replace.1##)."
+    },
+    "status.invalid": {
+        "message": "Resposta do servidor non v?lida (corrompida)."
+    },
+    "status.malformed-xml": {
+        "message": "Non se puido analizar o XML. 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.networkerror": {
+        "message": "Non se puido conectar ao servidor."
+    },
+    "status.nosupportedeasversion": {
+        "message": "O servidor non ? compatible con ActiveSync v2.5 ou v14.0 (s? ##replace.1##). TbSync non funcionar? con este servidor de ActiveSync."
+    },
+    "status.notargets": {
+        "message": "Sincronizaci?n interrompida porque no se puideron crear os destinos da sincronizaci?n."
+    },
+    "status.notsupportedeasversion": {
+        "message": "O servidor non ? compatible con ActiveSync v##replace.1## (s? ##replace.2##)."
+    },
+    "status.notsyncronized": {
+        "message": "? preciso sincronizar a conta: hai alg?n un elemento sen sincronizar."
+    },
+    "status.nouserhost": {
+        "message": "Falta o nome de usuario ou o servidor. Por favor, proporciona eses datos."
+    },
+    "status.pending": {
+        "message": "Agardando pola sincronizaci?n"
+    },
+    "status.policy.2": {
+        "message": "Non hai ningunha directiva para este cliente. Contacta co administrador do servidor ou desactiva o aprovisionamento desta conta."
+    },
+    "status.policy.3": {
+        "message": "Valor de PolicyType desco?ecido. Contacta co administrador do servidor ou desactiva o aprovisionamento desta conta."
+    },
+    "status.policy.4": {
+        "message": "Os datos de directivas do servidor est?n danados (posiblemente manipulados). Contacta co administrador do servidor ou desactiva o aprovisionamento desta conta."
+    },
+    "status.policy.5": {
+        "message": "O cliente est? a reco?ecer a chave de directiva incorrecta. Contacta co administrador do servidor ou desactiva o aprovisionamento desta conta."
+    },
+    "status.provision": {
+        "message": "O aprovisionamento fallou co estado <##replace.1##>"
+    },
+    "status.response-contains-no-data": {
+        "message": "A resposta do servidor non cont?n datos."
+    },
+    "status.resync-loop": {
+        "message": "Produciuse un erro que non se puido corrixir volvendo a sincronizar a conta. Desactiva a conta e int?ntao outra vez (erro: bucle de resincronizaci?n)"
+    },
+    "status.security": {
+        "message": "No se puido establecer unha conexi?n segura. Est?s a usar un certificado autofirmado, ou que non ? de confianza, sen importarlo a Thunderbird? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "A?nda non soportado, omitido"
+    },
+    "status.syncing": {
+        "message": "Sincronizando"
+    },
+    "status.timeout": {
+        "message": "Tempo de comunicaci?n esgotado."
+    },
+    "status.wbxml-parse-error": {
+        "message": "O servidor env?a unha resposta ilexible."
+    },
+    "status.wbxmlerror": {
+        "message": "Erro ao sincronizar. O servidor respondeu co estado <##replace.1##>."
+    },
+    "status.wbxmlmissingfield": {
+        "message": "Violaci?n do protocolo de ActiveSync: falta o campo obrigatorio <##replace.1##> na respuesta do servidor."
+    },
+    "syncstate.accountdone": {
+        "message": "Conta rematada"
+    },
+    "syncstate.done": {
+        "message": "Preparando o seguinte elemento para a sincronizaci?n"
+    },
+    "syncstate.eval.response.autodiscover": {
+        "message": "Procesando os axustes do servidor actualizados"
+    },
+    "syncstate.eval.response.deletefolder": {
+        "message": "Cartafol eliminado"
+    },
+    "syncstate.eval.response.estimate": {
+        "message": "Procesando a estimaci?n do cambio"
+    },
+    "syncstate.eval.response.folders": {
+        "message": "Procesando a lista de cartafois actualizada"
+    },
+    "syncstate.eval.response.localchanges": {
+        "message": "Procesando o reco?ecemento de cambios locais"
+    },
+    "syncstate.eval.response.localdeletes": {
+        "message": "Procesando o reco?ecemento de eliminaci?ns locais"
+    },
+    "syncstate.eval.response.options": {
+        "message": "Procesando as opci?ns do servidor"
+    },
+    "syncstate.eval.response.provision": {
+        "message": "Procesando o aprovisionamento"
+    },
+    "syncstate.eval.response.remotechanges": {
+        "message": "Procesando os cambios remotos"
+    },
+    "syncstate.eval.response.revertlocalchanges": {
+        "message": "Revertendo os cambios locais"
+    },
+    "syncstate.eval.response.setdeviceinfo": {
+        "message": "Enviando informaci?n do dispositivo"
+    },
+    "syncstate.eval.response.synckey": {
+        "message": "Procesando SyncKey"
+    },
+    "syncstate.prepare.request.autodiscover": {
+        "message": "Solicitando axustes actualizados do servidor"
+    },
+    "syncstate.prepare.request.deletefolder": {
+        "message": "Preparando a elimanci?n do cartafol"
+    },
+    "syncstate.prepare.request.estimate": {
+        "message": "Solicitando a estimaci?n dos cambios"
+    },
+    "syncstate.prepare.request.folders": {
+        "message": "Enviando a actualizaci?n da lista de cartafois"
+    },
+    "syncstate.prepare.request.localchanges": {
+        "message": "Enviando os cambios locais"
+    },
+    "syncstate.prepare.request.localdeletes": {
+        "message": "Enviando as eliminaci?ns locais"
+    },
+    "syncstate.prepare.request.options": {
+        "message": "Solicitando as opci?ns do servidor"
+    },
+    "syncstate.prepare.request.provision": {
+        "message": "Solicitando o aprovisionamento"
+    },
+    "syncstate.prepare.request.remotechanges": {
+        "message": "Solicitando os cambios remotos"
+    },
+    "syncstate.prepare.request.revertlocalchanges": {
+        "message": "Recolectando os cambios locais"
+    },
+    "syncstate.prepare.request.setdeviceinfo": {
+        "message": "Enviando informaci?n do dispositivo"
+    },
+    "syncstate.prepare.request.synckey": {
+        "message": "Solicitando SyncKey"
+    },
+    "syncstate.preparing": {
+        "message": "Preparando o seguinte elemento para a sincronizaci?n"
+    },
+    "syncstate.send.request.autodiscover": {
+        "message": "Agardando polos axustes actualizados do servidor"
+    },
+    "syncstate.send.request.deletefolder": {
+        "message": "Agardando pola eliminaci?n do cartafol"
+    },
+    "syncstate.send.request.estimate": {
+        "message": "Agardando pola estimaci?n de cambios"
+    },
+    "syncstate.send.request.folders": {
+        "message": "Agardando pola actualizaci?n da lista de cartafois"
+    },
+    "syncstate.send.request.localchanges": {
+        "message": "Agardando polo reco?ecemento de cambios locais"
+    },
+    "syncstate.send.request.localdeletes": {
+        "message": "Agardando polo reco?ecemento de eliminaci?ns locais"
+    },
+    "syncstate.send.request.options": {
+        "message": "Agardando polas opci?ns do servidor"
+    },
+    "syncstate.send.request.provision": {
+        "message": "Agardando polo aprovisionamento"
+    },
+    "syncstate.send.request.remotechanges": {
+        "message": "Agardando polos cambios remotos"
+    },
+    "syncstate.send.request.revertlocalchanges": {
+        "message": "Agardando polas versi?ns m?is recentes"
+    },
+    "syncstate.send.request.setdeviceinfo": {
+        "message": "Enviando informaci?n do dispositivo"
+    },
+    "syncstate.send.request.synckey": {
+        "message": "Agardando por SyncKey"
+    },
+    "syncstate.syncing": {
+        "message": "Iniciar sincronizaci?n"
+    }
+}
diff -Nru eas4tbsync-4.11/_locales/hu/messages.json eas4tbsync-4.17/_locales/hu/messages.json
--- eas4tbsync-4.11/_locales/hu/messages.json	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/_locales/hu/messages.json	2025-05-15 13:21:18.000000000 +0200
@@ -1,566 +1,566 @@
-{
-    "abCard.Anniversary": {
-        "message": "?vfordul?:"
-    },
-    "abCard.AssistantName": {
-        "message": "Asszisztens:"
-    },
-    "abCard.AssistantPhoneNumber": {
-        "message": "Asszisztensi telefon:"
-    },
-    "abCard.Business2PhoneNumber": {
-        "message": "2. munkahelyi telefon:"
-    },
-    "abCard.BusinessFaxNumber": {
-        "message": "Munkahelyi fax:"
-    },
-    "abCard.CarPhoneNumber": {
-        "message": "Aut?stelefon:"
-    },
-    "abCard.CompanyMainPhone": {
-        "message": "F? munkahelyi telefon:"
-    },
-    "abCard.Email3Address": {
-        "message": "M?sodlagos e-mail:"
-    },
-    "abCard.Home2PhoneNumber": {
-        "message": "2. otthoni telefon:"
-    },
-    "abCard.ManagerName": {
-        "message": "Vezet?:"
-    },
-    "abCard.MiddleName": {
-        "message": "M?sodik keresztn?v:"
-    },
-    "abCard.OtherAddress": {
-        "message": "C?m:"
-    },
-    "abCard.OtherCity": {
-        "message": "V?ros:"
-    },
-    "abCard.OtherCountry": {
-        "message": "Orsz?g:"
-    },
-    "abCard.OtherState": {
-        "message": "?llam/tartom?ny:"
-    },
-    "abCard.OtherZip": {
-        "message": "Ir?ny?t?sz?m:"
-    },
-    "abCard.RadioPhoneNumber": {
-        "message": "R?di?-t?vbesz?l?:"
-    },
-    "abCard.Spouse": {
-        "message": "H?zast?rs:"
-    },
-    "abCard.header.eas": {
-        "message": "Egy?b mez?k (EAS)"
-    },
-    "abCard.header.homenumbers": {
-        "message": "Tov?bbi otthoni sz?mok:"
-    },
-    "abCard.header.messaging": {
-        "message": "?zenetek:"
-    },
-    "abCard.header.otheraddress": {
-        "message": "Egy?b c?m (EAS)"
-    },
-    "abCard.header.othernumbers": {
-        "message": "Tov?bbi sz?mok:"
-    },
-    "abCard.header.people": {
-        "message": "Emberek:"
-    },
-    "abCard.header.worknumbers": {
-        "message": "Tov?bbi munkahelyi sz?mok:"
-    },
-    "acl.readonly": {
-        "message": "Csak olvashat? hozz?f?r?s (helyi v?ltoz?sok visszavon?sa)"
-    },
-    "acl.readwrite": {
-        "message": "Olvas?s ?s ?r?s a kiszolg?l?n"
-    },
-    "add.description": {
-        "message": "V?lasszon az el?rhet? kiszolg?l?be?ll?t?sok k?z?l, ?s adja meg a k?rt r?szleteket. "
-    },
-    "add.name": {
-        "message": "Felhaszn?l?n?v:"
-    },
-    "add.ok": {
-        "message": "Fi?k hozz?ad?sa"
-    },
-    "add.password": {
-        "message": "Jelsz?:"
-    },
-    "add.server": {
-        "message": "Kiszolg?l?be?ll?t?sok:"
-    },
-    "add.shortdescription": {
-        "message": "Fi?kadatok"
-    },
-    "add.title": {
-        "message": "Exchange ActiveSync-fi?k hozz?ad?sa a TbSynchez"
-    },
-    "add.url": {
-        "message": "Kiszolg?l? c?me:"
-    },
-    "add.urldescription": {
-        "message": "El?gs?ges, ha csak az alap kiszolg?l?c?met adja meg (p?ld?ul: posta.kiszolg?l?d.hu). De a teljes URL-t is megadhatja (p?ld?ul: https://posta.kiszolg?l?d.hu/Microsoft-Server-ActiveSync)."
-    },
-    "add.user": {
-        "message": "Felhaszn?l?n?v (e-mail-c?m):"
-    },
-    "autocomplete.serverdirectory": {
-        "message": "glob?lis kiszolg?l?jegyz?k"
-    },
-    "autodiscover.Failed": {
-        "message": "A(z) <##user##> felhaszn?l? automatikus felder?t?se sikertelen. Vagy hib?sak voltak a megadott hiteles?t? adatok, vagy az ActiveSync szolg?ltat? ideiglenes probl?m?kat tapasztal, vagy nem t?mogatja az automatikus felder?t?st."
-    },
-    "autodiscover.NeedEmail": {
-        "message": "Az ?nm?k?d? felismer?snek ?rv?nyes e-mail c?mnek kell lennie felhaszn?l?i n?vk?nt."
-    },
-    "autodiscover.Ok": {
-        "message": "Az ?nm?k?d? felder?t?s sikeresen befejez?d?tt, most ellen?rizheti az v?laszthat? be?ll?t?sokat ?s l?trehozhatja az ?sszehangol?si kapcsolatot."
-    },
-    "autodiscover.Querying": {
-        "message": "Be?ll?t?sok keres?se?"
-    },
-    "config.auto": {
-        "message": "Az ActiveSync kiszolg?l? be?ll?t?sok (?nm?k?d? ?szlel?s)"
-    },
-    "config.custom": {
-        "message": "Az ActiveSync kiszolg?l? be?ll?t?sok"
-    },
-    "deletefolder.confirm": {
-        "message": "T?nyleg azt szeretn?, hogy a(z) ?##replace.1##? mappa v?glegesen t?r?lje a kuk?t?"
-    },
-    "deletefolder.menuentry": {
-        "message": "?##replace.1##? mappa kuka ?r?t?se"
-    },
-    "deletefolder.notallowed": {
-        "message": "K?rj?k, t?r?lje le a(z) ?##replace.1##? mapp?t, miel?tt megpr?b?ln?nk kuka ?r?t?se."
-    },
-    "extensionDescription": {
-        "message": "Az Exchange ActiveSync-fi?kok szinkroniz?l?s?nak t?mogat?sa a TbSyncben (n?vjegyek, feladatok ?s napt?rak)."
-    },
-    "extensionName": {
-        "message": "Exchange ActiveSync-szolg?ltat?"
-    },
-    "helplink.BadItemSkipped": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
-    },
-    "helplink.global.clientdenied": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "manager.tabs.accountsettings": {
-        "message": "Fi?kbe?ll?t?sok"
-    },
-    "manager.tabs.outOfOffice": {
-        "message": "Automatikus v?lasz"
-    },
-    "manager.tabs.syncsettings": {
-        "message": "Be?ll?t?sok"
-    },
-    "newaccount.add_auto": {
-        "message": "Automatikus felfedez?s be?ll?t?sai ?s fi?k hozz?ad?sa"
-    },
-    "newaccount.add_custom": {
-        "message": "Fi?k hozz?ad?sa"
-    },
-    "pref.AccountName": {
-        "message": "Le?r?s"
-    },
-    "pref.ActiveSyncVersion": {
-        "message": "ActiveSync verzi?"
-    },
-    "pref.DeviceId": {
-        "message": "ActiveSync eszk?zazonos?t?"
-    },
-    "pref.ServerName": {
-        "message": "Kiszolg?l? c?me"
-    },
-    "pref.ServerNameDescription": {
-        "message": "p?ld?ul: posta.kiszolg?l?d.hu"
-    },
-    "pref.ShowTrashedFolders": {
-        "message": "A kuk?ban tal?lhat? mapp?k megjelen?t?se"
-    },
-    "pref.UserName": {
-        "message": "Felhaszn?l?n?v"
-    },
-    "pref.UserNameDescription": {
-        "message": "A felhaszn?l?n?v ?ltal?ban a fi?kja e-mail-c?me."
-    },
-    "pref.autodetect": {
-        "message": "az el?rhet? legjobb"
-    },
-    "pref.birthday": {
-        "message": "Sz?let?snapi inform?ci?k k?ld?se"
-    },
-    "pref.calendaroptions": {
-        "message": "Napt?r be?ll?t?sai"
-    },
-    "pref.contactoptions": {
-        "message": "N?vjegyz?k be?ll?t?sai"
-    },
-    "pref.displayoverride": {
-        "message": "Megjelen?t?si n?v fel?lb?r?l?sa ezzel: ?keresztn?v? + ?m?sodik keresztn?v?"
-    },
-    "pref.generaloptions": {
-        "message": "?ltal?nos be?ll?t?sok"
-    },
-    "pref.provision": {
-        "message": "Lek?t?s megk?vetel?se (a Kerio k?vetelm?nye)"
-    },
-    "pref.seperator.comma": {
-        "message": "Vessz?"
-    },
-    "pref.seperator.description": {
-        "message": "A t?bbsoros c?mmez? elv?laszt?ja."
-    },
-    "pref.seperator.linebreak": {
-        "message": "Sort?r?s"
-    },
-    "pref.synclimit.1month": {
-        "message": "4 h?ttel ezel?tt"
-    },
-    "pref.synclimit.2weeks": {
-        "message": "2 h?ttel ezel?tt"
-    },
-    "pref.synclimit.3month": {
-        "message": "3 h?nappal ezel?tt"
-    },
-    "pref.synclimit.6month": {
-        "message": "6 h?nappal ezel?tt"
-    },
-    "pref.synclimit.all": {
-        "message": "mindent"
-    },
-    "pref.synclimit.description": {
-        "message": "Szinkroniz?l?si id?szak: "
-    },
-    "pref.usehttps": {
-        "message": "Biztons?gos kapcsolat haszn?lata (kapcsol?d?s https-n kereszt?l)"
-    },
-    "recyclebin": {
-        "message": "Kuka"
-    },
-    "servertype.auto": {
-        "message": "Automatikus be?ll?t?s"
-    },
-    "servertype.custom": {
-        "message": "Egy?ni be?ll?t?s"
-    },
-    "servertype.description.auto": {
-        "message": "Sz?mos ActiveSync-kiszolg?l? be?ll?t?sa automatikusan felfedezhet? puszt?n az e-mail-c?me megad?s?val."
-    },
-    "servertype.description.custom": {
-        "message": "Fi?k be?ll?t?sa a haszn?land? kiszolg?l? c?m?nek k?zi megad?s?val."
-    },
-    "servertype.description.office365": {
-        "message": "Az Office 365-h?z kapcsol?d? fi?kok az OAuth 2.0 nev? modern hiteles?t?si folyamatot haszn?lj?k, amely t?mogatja a t?bbfaktoros hiteles?t?st (MFA) is."
-    },
-    "servertype.office365": {
-        "message": "Microsoft Office 365"
-    },
-    "servertype.unlock": {
-        "message": "Kattintson dupl?n az ?sszes el?re megadott kiszolg?l?be?ll?t?s felold?s?hoz."
-    },
-    "status.401": {
-        "message": "A hiteles?t?s nem siker?lt, ellen?rizze a felhaszn?l?nevet ?s a jelsz?t (401-es HTTP-hiba)."
-    },
-    "status.403": {
-        "message": "A kiszolg?l? elutas?totta a kapcsolatot (403-as HTTP-hiba)."
-    },
-    "status.404": {
-        "message": "A felhaszn?l? nem tal?lhat? (404-es HTTP-hiba)."
-    },
-    "status.449": {
-        "message": "A kiszolg?l? lek?t?st k?t (449-es HTTP-hiba)."
-    },
-    "status.500": {
-        "message": "Ismeretlen kiszolg?l?hiba (500-as HTTP-hiba)."
-    },
-    "status.503": {
-        "message": "A szolg?ltat?s nem el?rhet? (503-?s HTTP-hiba)."
-    },
-    "status.BadItemSkipped": {
-        "message": "Hib?s elem kihagyva: ##replace.1##"
-    },
-    "status.FolderDelete.3": {
-        "message": "Nem lehet t?r?lni egy rendszermapp?t (3-as ?llapot)"
-    },
-    "status.FolderDelete.4": {
-        "message": "A mappa nem l?tezik (4-es ?llapot), ?jraszinkroniz?l?s"
-    },
-    "status.FolderDelete.6": {
-        "message": "A parancs nem fejezhet? be, hiba t?rt?nt a kiszolg?l?n (6-os ?llapot)"
-    },
-    "status.FolderDelete.9": {
-        "message": "?? Invalid synchronization key (status 9), resyncing ??"
-    },
-    "status.FolderSync.9": {
-        "message": "?? Invalid synchronization key (status 9), resyncing ??"
-    },
-    "status.InvalidServerOptions": {
-        "message": "A kiszolg?l? nem ny?jt felvil?gos?t?st a t?mogatott ActiveSync verzi?kr?l. EAS akad?lyozva van ez a felhaszn?l? vagy az ?gyf?l (Thunderbird-?sszehangol?s) sz?m?ra? Megpr?b?lhatja k?zzel be?ll?tani az ActiveSync verzi?t."
-    },
-    "status.OK": {
-        "message": "OK"
-    },
-    "status.ServerRejectedRequest": {
-        "message": "Az EAS-kiszolg?l? elutas?totta az utols? k?r?st."
-    },
-    "status.ServerRejectedSomeItems": {
-        "message": "Az EAS-kiszolg?l? nem fogadta el a(z) ##replace.1## elemeket."
-    },
-    "status.Sync.12": {
-        "message": "A mappahierarchia megv?ltozott (12-es ?llapot), ?jraszinkroniz?l?s"
-    },
-    "status.Sync.3": {
-        "message": "?rv?nytelen szinkroniz?l?si kulcs (3-as ?llapot), ?jraszinkroniz?l?s"
-    },
-    "status.Sync.4": {
-        "message": "Rosszul form?zott k?r?s (4-es ?llapot)"
-    },
-    "status.Sync.5": {
-        "message": "Ideiglenes kiszolg?l?probl?ma vagy ?rv?nytelen elem (5-?s ?llapot)"
-    },
-    "status.Sync.6": {
-        "message": "?rv?nytelen elem (6-os ?llapot)"
-    },
-    "status.Sync.8": {
-        "message": "Az objektum nem tal?lhat? (8-as ?llapot)"
-    },
-    "status.aborted": {
-        "message": "Nincs szinkroniz?lva"
-    },
-    "status.disabled": {
-        "message": "Letiltva"
-    },
-    "status.empty-response": {
-        "message": "A kiszolg?l? v?ratlan ?res v?laszt k?ld?tt."
-    },
-    "status.forbiddenCalendarItemInTasksFolder": {
-        "message": "Tiltott napt?relem a feladatok mapp?ban (rendezze ?jra)"
-    },
-    "status.forbiddenTasksItemInCalendarFolder": {
-        "message": "Tiltott feladatelem a napt?r mapp?ban (rendezze ?jra)"
-    },
-    "status.global.101": {
-        "message": "A k?r?s WBXML-t tartalmaz, de nem siker?lt XML-be dek?dolni (101-es EAS-hiba)."
-    },
-    "status.global.102": {
-        "message": "A k?r?s WBXML-t tartalmaz, de nem siker?lt XML-be dek?dolni (102-es EAS-hiba)."
-    },
-    "status.global.103": {
-        "message": "A k?r?sben megadott XML nem k?veti a protokoll k?vetelm?nyeit (103-as EAS-hiba)."
-    },
-    "status.global.110": {
-        "message": "A kiszolg?l? bels? hib?t jelentett, ?s nem szabad azonnal ?jrapr?b?lkozni. Az automatikus szinkroniz?l?s 30 percre felf?ggeszt?sre ker?lt (110-es EAS hiba)."
-    },
-    "status.global.clientdenied": {
-        "message": "Az EAS-kiszolg?l? ezt jelenti: <##replace.2##> (?llapot: ##replace.1##), ?s nem enged?lyezi a TbSync sz?m?ra a fi?kja el?r?s?t."
-    },
-    "status.httperror": {
-        "message": "Kommunik?ci?s hiba (HTTP ?llapot: ##replace.1##)."
-    },
-    "status.invalid": {
-        "message": "?rv?nytelen kiszolg?l?v?lasz (szem?t)."
-    },
-    "status.malformed-xml": {
-        "message": "Az XML feldolgoz?sa nem siker?lt. Ellen?rizze az esem?nynapl?t a r?szletek?rt."
-    },
-    "status.modified": {
-        "message": "Helyi m?dos?t?sok"
-    },
-    "status.network": {
-        "message": "Nem siker?lt kapcsol?dni a kiszolg?l?hoz (##replace.1##)."
-    },
-    "status.networkerror": {
-        "message": "Nem siker?lt kapcsol?dni a kiszolg?l?hoz."
-    },
-    "status.nosupportedeasversion": {
-        "message": "A kiszolg?l? nem t?mogatja az ActiveSync v2.5-?t vagy a v14.0-t (csak ezt: ##replace.1##). A TbSync nem fog m?k?dni ezzel az ActiveSync-kiszolg?l?val."
-    },
-    "status.notargets": {
-        "message": "A szinkroniz?l?s megszak?t?sa, mert a szinkroniz?l?si c?lokat nem lehetett l?trehozni."
-    },
-    "status.notsupportedeasversion": {
-        "message": "A kiszolg?l? nem t?mogatja a kiv?lasztott ActiveSync ##replace.1## verzi?t (csak ezt: ##replace.2##)."
-    },
-    "status.notsyncronized": {
-        "message": "A fi?kot szinkroniz?lni kell, legal?bb egy elem nincs szinkroniz?lva."
-    },
-    "status.nouserhost": {
-        "message": "Hi?nyz? felhaszn?l?n?v vagy kiszolg?l?. Adja meg ezeket az ?rt?keket."
-    },
-    "status.pending": {
-        "message": "V?rakoz?s a szinkroniz?l?sra"
-    },
-    "status.policy.2": {
-        "message": "Nincs h?zirend ehhez a klienshez. Vegye fel a kapcsolatot a kiszolg?l? rendszergazd?j?val, vagy tiltsa le a fi?k lek?t?s?t."
-    },
-    "status.policy.3": {
-        "message": "Ismeretlen h?zirendt?pus ?rt?k. Vegye fel a kapcsolatot a kiszolg?l? rendszergazd?j?val, vagy tiltsa le a fi?k lek?t?s?t."
-    },
-    "status.policy.4": {
-        "message": "A kiszolg?l? h?zirendadatai s?r?ltek (esetleg meghamis?tott?k). Vegye fel a kapcsolatot a kiszolg?l? rendszergazd?j?val, vagy tiltsa le a fi?k lek?t?s?t."
-    },
-    "status.policy.5": {
-        "message": "A kliens nyugt?zza a hib?s h?zirendkulcsot. Vegye fel a kapcsolatot a kiszolg?l? rendszergazd?j?val, vagy tiltsa le a fi?k lek?t?s?t."
-    },
-    "status.provision": {
-        "message": "A lek?t?s sikertelen, ?llapot: <##replace.1##>"
-    },
-    "status.response-contains-no-data": {
-        "message": "A kiszolg?l? v?lasza nem tartalmaz adatokat."
-    },
-    "status.resync-loop": {
-        "message": "Hiba t?rt?nt, amelyb?l nem siker?lt helyre?llni a fi?k ?jraszinkroniz?l?s?val. Tiltsa le a fi?kot, ?s pr?b?lja meg ?jra. (Hiba: ?lland? ?jraszinkroniz?l?s)"
-    },
-    "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.syncing": {
-        "message": "Szinkroniz?l?s"
-    },
-    "status.timeout": {
-        "message": "Kommunik?ci?s id?t?ll?p?s."
-    },
-    "status.wbxml-parse-error": {
-        "message": "A kiszolg?l? olvashatatlan v?laszt k?ld."
-    },
-    "status.wbxmlerror": {
-        "message": "A szinkroniz?l?s sikertelen. A kiszolg?l? a k?vetkez? ?llapottal v?laszolt: <##replace.1##>."
-    },
-    "status.wbxmlmissingfield": {
-        "message": "ActiveSync protokolls?rt?s: A(z) <##replace.1##> k?telez? mez? hi?nyzik a kiszolg?l? v?lasz?b?l."
-    },
-    "syncstate.accountdone": {
-        "message": "Fi?k k?sz"
-    },
-    "syncstate.done": {
-        "message": "A k?vetkez? elem el?k?sz?t?se szinkroniz?l?sra"
-    },
-    "syncstate.eval.response.autodiscover": {
-        "message": "Friss?tett kiszolg?l?be?ll?t?sok feldolgoz?sa"
-    },
-    "syncstate.eval.response.deletefolder": {
-        "message": "A mappa t?r?lve"
-    },
-    "syncstate.eval.response.estimate": {
-        "message": "V?ltoz?sbecsl?s feldolgoz?sa"
-    },
-    "syncstate.eval.response.folders": {
-        "message": "A mappalista friss?t?s feldolgoz?sa"
-    },
-    "syncstate.eval.response.localchanges": {
-        "message": "A helyi v?ltoz?sok nyugt?z?s?nak feldolgoz?sa"
-    },
-    "syncstate.eval.response.localdeletes": {
-        "message": "A helyi t?rl?sek nyugt?z?s?nak feldolgoz?sa"
-    },
-    "syncstate.eval.response.options": {
-        "message": "A kiszolg?l? be?ll?t?sainak feldolgoz?sa"
-    },
-    "syncstate.eval.response.provision": {
-        "message": "Lek?t?s feldolgoz?sa"
-    },
-    "syncstate.eval.response.remotechanges": {
-        "message": "A t?voli m?dos?t?sok feldolgoz?sa"
-    },
-    "syncstate.eval.response.revertlocalchanges": {
-        "message": "A helyi v?ltoz?sok vissza?ll?t?sa"
-    },
-    "syncstate.eval.response.setdeviceinfo": {
-        "message": "Eszk?zinform?ci?k k?ld?se"
-    },
-    "syncstate.eval.response.synckey": {
-        "message": "Szinkroniz?l?si kulcs feldolgoz?sa"
-    },
-    "syncstate.prepare.request.autodiscover": {
-        "message": "Friss?tett kiszolg?l?be?ll?t?sok k?r?se"
-    },
-    "syncstate.prepare.request.deletefolder": {
-        "message": "Felk?sz?l?s a mappa t?rl?s?re"
-    },
-    "syncstate.prepare.request.estimate": {
-        "message": "V?ltoz?sbecsl?s k?r?se"
-    },
-    "syncstate.prepare.request.folders": {
-        "message": "Mappalista-friss?t?s elk?ld?se"
-    },
-    "syncstate.prepare.request.localchanges": {
-        "message": "Helyi v?ltoz?sok k?ld?se"
-    },
-    "syncstate.prepare.request.localdeletes": {
-        "message": "Helyi t?rl?sek k?ld?se"
-    },
-    "syncstate.prepare.request.options": {
-        "message": "A kiszolg?l?be?ll?t?sok k?r?se"
-    },
-    "syncstate.prepare.request.provision": {
-        "message": "Lek?t?s k?r?se"
-    },
-    "syncstate.prepare.request.remotechanges": {
-        "message": "T?voli m?dos?t?sok k?r?se"
-    },
-    "syncstate.prepare.request.revertlocalchanges": {
-        "message": "Helyi v?ltoz?sok ?sszegy?jt?se"
-    },
-    "syncstate.prepare.request.setdeviceinfo": {
-        "message": "Eszk?zinform?ci?k k?ld?se"
-    },
-    "syncstate.prepare.request.synckey": {
-        "message": "Szinkroniz?l?si kulcs k?r?se"
-    },
-    "syncstate.preparing": {
-        "message": "A k?vetkez? elem el?k?sz?t?se szinkroniz?l?sra"
-    },
-    "syncstate.send.request.autodiscover": {
-        "message": "V?rakoz?s a friss?tett kiszolg?l?be?ll?t?sokra"
-    },
-    "syncstate.send.request.deletefolder": {
-        "message": "V?rakoz?s a mappa t?rl?s?re"
-    },
-    "syncstate.send.request.estimate": {
-        "message": "V?rakoz?s a v?ltoz?sbecsl?sre"
-    },
-    "syncstate.send.request.folders": {
-        "message": "V?rakoz?s a mappalista-friss?t?sre"
-    },
-    "syncstate.send.request.localchanges": {
-        "message": "V?rakoz?s a helyi v?ltoz?sok elismer?s?re"
-    },
-    "syncstate.send.request.localdeletes": {
-        "message": "V?rakoz?s a helyi t?rl?sek nyugt?z?s?ra"
-    },
-    "syncstate.send.request.options": {
-        "message": "V?rakoz?s a kiszolg?l?be?ll?t?sokra"
-    },
-    "syncstate.send.request.provision": {
-        "message": "V?rakoz?s a lek?t?sre"
-    },
-    "syncstate.send.request.remotechanges": {
-        "message": "V?rakoz?s a t?voli m?dos?t?sokra"
-    },
-    "syncstate.send.request.revertlocalchanges": {
-        "message": "V?rakoz?s a legfrissebb verzi?kra"
-    },
-    "syncstate.send.request.setdeviceinfo": {
-        "message": "Eszk?zinform?ci?k k?ld?se"
-    },
-    "syncstate.send.request.synckey": {
-        "message": "V?rakoz?s a szinkroniz?l?si kulcsra"
-    },
-    "syncstate.syncing": {
-        "message": "Szinkroniz?l?s el?k?sz?t?se"
-    }
-}
+{
+    "abCard.Anniversary": {
+        "message": "?vfordul?:"
+    },
+    "abCard.AssistantName": {
+        "message": "Asszisztens:"
+    },
+    "abCard.AssistantPhoneNumber": {
+        "message": "Asszisztensi telefon:"
+    },
+    "abCard.Business2PhoneNumber": {
+        "message": "2. munkahelyi telefon:"
+    },
+    "abCard.BusinessFaxNumber": {
+        "message": "Munkahelyi fax:"
+    },
+    "abCard.CarPhoneNumber": {
+        "message": "Aut?stelefon:"
+    },
+    "abCard.CompanyMainPhone": {
+        "message": "F? munkahelyi telefon:"
+    },
+    "abCard.Email3Address": {
+        "message": "M?sodlagos e-mail:"
+    },
+    "abCard.Home2PhoneNumber": {
+        "message": "2. otthoni telefon:"
+    },
+    "abCard.ManagerName": {
+        "message": "Vezet?:"
+    },
+    "abCard.MiddleName": {
+        "message": "M?sodik keresztn?v:"
+    },
+    "abCard.OtherAddress": {
+        "message": "C?m:"
+    },
+    "abCard.OtherCity": {
+        "message": "V?ros:"
+    },
+    "abCard.OtherCountry": {
+        "message": "Orsz?g:"
+    },
+    "abCard.OtherState": {
+        "message": "?llam/tartom?ny:"
+    },
+    "abCard.OtherZip": {
+        "message": "Ir?ny?t?sz?m:"
+    },
+    "abCard.RadioPhoneNumber": {
+        "message": "R?di?-t?vbesz?l?:"
+    },
+    "abCard.Spouse": {
+        "message": "H?zast?rs:"
+    },
+    "abCard.header.eas": {
+        "message": "Egy?b mez?k (EAS)"
+    },
+    "abCard.header.homenumbers": {
+        "message": "Tov?bbi otthoni sz?mok:"
+    },
+    "abCard.header.messaging": {
+        "message": "?zenetek:"
+    },
+    "abCard.header.otheraddress": {
+        "message": "Egy?b c?m (EAS)"
+    },
+    "abCard.header.othernumbers": {
+        "message": "Tov?bbi sz?mok:"
+    },
+    "abCard.header.people": {
+        "message": "Emberek:"
+    },
+    "abCard.header.worknumbers": {
+        "message": "Tov?bbi munkahelyi sz?mok:"
+    },
+    "acl.readonly": {
+        "message": "Csak olvashat? hozz?f?r?s (helyi v?ltoz?sok visszavon?sa)"
+    },
+    "acl.readwrite": {
+        "message": "Olvas?s ?s ?r?s a kiszolg?l?n"
+    },
+    "add.description": {
+        "message": "V?lasszon az el?rhet? kiszolg?l?be?ll?t?sok k?z?l, ?s adja meg a k?rt r?szleteket. "
+    },
+    "add.name": {
+        "message": "Felhaszn?l?n?v:"
+    },
+    "add.ok": {
+        "message": "Fi?k hozz?ad?sa"
+    },
+    "add.password": {
+        "message": "Jelsz?:"
+    },
+    "add.server": {
+        "message": "Kiszolg?l?be?ll?t?sok:"
+    },
+    "add.shortdescription": {
+        "message": "Fi?kadatok"
+    },
+    "add.title": {
+        "message": "Exchange ActiveSync-fi?k hozz?ad?sa a TbSynchez"
+    },
+    "add.url": {
+        "message": "Kiszolg?l? c?me:"
+    },
+    "add.urldescription": {
+        "message": "El?gs?ges, ha csak az alap kiszolg?l?c?met adja meg (p?ld?ul: posta.kiszolg?l?d.hu). De a teljes URL-t is megadhatja (p?ld?ul: https://posta.kiszolg?l?d.hu/Microsoft-Server-ActiveSync)."
+    },
+    "add.user": {
+        "message": "Felhaszn?l?n?v (e-mail-c?m):"
+    },
+    "autocomplete.serverdirectory": {
+        "message": "glob?lis kiszolg?l?jegyz?k"
+    },
+    "autodiscover.Failed": {
+        "message": "A(z) <##user##> felhaszn?l? automatikus felder?t?se sikertelen. Vagy hib?sak voltak a megadott hiteles?t? adatok, vagy az ActiveSync szolg?ltat? ideiglenes probl?m?kat tapasztal, vagy nem t?mogatja az automatikus felder?t?st."
+    },
+    "autodiscover.NeedEmail": {
+        "message": "Az ?nm?k?d? felismer?snek ?rv?nyes e-mail c?mnek kell lennie felhaszn?l?i n?vk?nt."
+    },
+    "autodiscover.Ok": {
+        "message": "Az ?nm?k?d? felder?t?s sikeresen befejez?d?tt, most ellen?rizheti az v?laszthat? be?ll?t?sokat ?s l?trehozhatja az ?sszehangol?si kapcsolatot."
+    },
+    "autodiscover.Querying": {
+        "message": "Be?ll?t?sok keres?se?"
+    },
+    "config.auto": {
+        "message": "Az ActiveSync kiszolg?l? be?ll?t?sok (?nm?k?d? ?szlel?s)"
+    },
+    "config.custom": {
+        "message": "Az ActiveSync kiszolg?l? be?ll?t?sok"
+    },
+    "deletefolder.confirm": {
+        "message": "T?nyleg azt szeretn?, hogy a(z) ?##replace.1##? mappa v?glegesen t?r?lje a kuk?t?"
+    },
+    "deletefolder.menuentry": {
+        "message": "?##replace.1##? mappa kuka ?r?t?se"
+    },
+    "deletefolder.notallowed": {
+        "message": "K?rj?k, t?r?lje le a(z) ?##replace.1##? mapp?t, miel?tt megpr?b?ln?nk kuka ?r?t?se."
+    },
+    "extensionDescription": {
+        "message": "Az Exchange ActiveSync-fi?kok szinkroniz?l?s?nak t?mogat?sa a TbSyncben (n?vjegyek, feladatok ?s napt?rak)."
+    },
+    "extensionName": {
+        "message": "Exchange ActiveSync-szolg?ltat?"
+    },
+    "helplink.BadItemSkipped": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
+    },
+    "helplink.global.clientdenied": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "manager.tabs.accountsettings": {
+        "message": "Fi?kbe?ll?t?sok"
+    },
+    "manager.tabs.outOfOffice": {
+        "message": "Automatikus v?lasz"
+    },
+    "manager.tabs.syncsettings": {
+        "message": "Be?ll?t?sok"
+    },
+    "newaccount.add_auto": {
+        "message": "Automatikus felfedez?s be?ll?t?sai ?s fi?k hozz?ad?sa"
+    },
+    "newaccount.add_custom": {
+        "message": "Fi?k hozz?ad?sa"
+    },
+    "pref.AccountName": {
+        "message": "Le?r?s"
+    },
+    "pref.ActiveSyncVersion": {
+        "message": "ActiveSync verzi?"
+    },
+    "pref.DeviceId": {
+        "message": "ActiveSync eszk?zazonos?t?"
+    },
+    "pref.ServerName": {
+        "message": "Kiszolg?l? c?me"
+    },
+    "pref.ServerNameDescription": {
+        "message": "p?ld?ul: posta.kiszolg?l?d.hu"
+    },
+    "pref.ShowTrashedFolders": {
+        "message": "A kuk?ban tal?lhat? mapp?k megjelen?t?se"
+    },
+    "pref.UserName": {
+        "message": "Felhaszn?l?n?v"
+    },
+    "pref.UserNameDescription": {
+        "message": "A felhaszn?l?n?v ?ltal?ban a fi?kja e-mail-c?me."
+    },
+    "pref.autodetect": {
+        "message": "az el?rhet? legjobb"
+    },
+    "pref.birthday": {
+        "message": "Sz?let?snapi inform?ci?k k?ld?se"
+    },
+    "pref.calendaroptions": {
+        "message": "Napt?r be?ll?t?sai"
+    },
+    "pref.contactoptions": {
+        "message": "N?vjegyz?k be?ll?t?sai"
+    },
+    "pref.displayoverride": {
+        "message": "Megjelen?t?si n?v fel?lb?r?l?sa ezzel: ?keresztn?v? + ?m?sodik keresztn?v?"
+    },
+    "pref.generaloptions": {
+        "message": "?ltal?nos be?ll?t?sok"
+    },
+    "pref.provision": {
+        "message": "Lek?t?s megk?vetel?se (a Kerio k?vetelm?nye)"
+    },
+    "pref.seperator.comma": {
+        "message": "Vessz?"
+    },
+    "pref.seperator.description": {
+        "message": "A t?bbsoros c?mmez? elv?laszt?ja."
+    },
+    "pref.seperator.linebreak": {
+        "message": "Sort?r?s"
+    },
+    "pref.synclimit.1month": {
+        "message": "4 h?ttel ezel?tt"
+    },
+    "pref.synclimit.2weeks": {
+        "message": "2 h?ttel ezel?tt"
+    },
+    "pref.synclimit.3month": {
+        "message": "3 h?nappal ezel?tt"
+    },
+    "pref.synclimit.6month": {
+        "message": "6 h?nappal ezel?tt"
+    },
+    "pref.synclimit.all": {
+        "message": "mindent"
+    },
+    "pref.synclimit.description": {
+        "message": "Szinkroniz?l?si id?szak: "
+    },
+    "pref.usehttps": {
+        "message": "Biztons?gos kapcsolat haszn?lata (kapcsol?d?s https-n kereszt?l)"
+    },
+    "recyclebin": {
+        "message": "Kuka"
+    },
+    "servertype.auto": {
+        "message": "Automatikus be?ll?t?s"
+    },
+    "servertype.custom": {
+        "message": "Egy?ni be?ll?t?s"
+    },
+    "servertype.description.auto": {
+        "message": "Sz?mos ActiveSync-kiszolg?l? be?ll?t?sa automatikusan felfedezhet? puszt?n az e-mail-c?me megad?s?val."
+    },
+    "servertype.description.custom": {
+        "message": "Fi?k be?ll?t?sa a haszn?land? kiszolg?l? c?m?nek k?zi megad?s?val."
+    },
+    "servertype.description.office365": {
+        "message": "Az Office 365-h?z kapcsol?d? fi?kok az OAuth 2.0 nev? modern hiteles?t?si folyamatot haszn?lj?k, amely t?mogatja a t?bbfaktoros hiteles?t?st (MFA) is."
+    },
+    "servertype.office365": {
+        "message": "Microsoft Office 365"
+    },
+    "servertype.unlock": {
+        "message": "Kattintson dupl?n az ?sszes el?re megadott kiszolg?l?be?ll?t?s felold?s?hoz."
+    },
+    "status.401": {
+        "message": "A hiteles?t?s nem siker?lt, ellen?rizze a felhaszn?l?nevet ?s a jelsz?t (401-es HTTP-hiba)."
+    },
+    "status.403": {
+        "message": "A kiszolg?l? elutas?totta a kapcsolatot (403-as HTTP-hiba)."
+    },
+    "status.404": {
+        "message": "A felhaszn?l? nem tal?lhat? (404-es HTTP-hiba)."
+    },
+    "status.449": {
+        "message": "A kiszolg?l? lek?t?st k?t (449-es HTTP-hiba)."
+    },
+    "status.500": {
+        "message": "Ismeretlen kiszolg?l?hiba (500-as HTTP-hiba)."
+    },
+    "status.503": {
+        "message": "A szolg?ltat?s nem el?rhet? (503-?s HTTP-hiba)."
+    },
+    "status.BadItemSkipped": {
+        "message": "Hib?s elem kihagyva: ##replace.1##"
+    },
+    "status.FolderDelete.3": {
+        "message": "Nem lehet t?r?lni egy rendszermapp?t (3-as ?llapot)"
+    },
+    "status.FolderDelete.4": {
+        "message": "A mappa nem l?tezik (4-es ?llapot), ?jraszinkroniz?l?s"
+    },
+    "status.FolderDelete.6": {
+        "message": "A parancs nem fejezhet? be, hiba t?rt?nt a kiszolg?l?n (6-os ?llapot)"
+    },
+    "status.FolderDelete.9": {
+        "message": "?? Invalid synchronization key (status 9), resyncing ??"
+    },
+    "status.FolderSync.9": {
+        "message": "?? Invalid synchronization key (status 9), resyncing ??"
+    },
+    "status.InvalidServerOptions": {
+        "message": "A kiszolg?l? nem ny?jt felvil?gos?t?st a t?mogatott ActiveSync verzi?kr?l. EAS akad?lyozva van ez a felhaszn?l? vagy az ?gyf?l (Thunderbird-?sszehangol?s) sz?m?ra? Megpr?b?lhatja k?zzel be?ll?tani az ActiveSync verzi?t."
+    },
+    "status.OK": {
+        "message": "OK"
+    },
+    "status.ServerRejectedRequest": {
+        "message": "Az EAS-kiszolg?l? elutas?totta az utols? k?r?st."
+    },
+    "status.ServerRejectedSomeItems": {
+        "message": "Az EAS-kiszolg?l? nem fogadta el a(z) ##replace.1## elemeket."
+    },
+    "status.Sync.12": {
+        "message": "A mappahierarchia megv?ltozott (12-es ?llapot), ?jraszinkroniz?l?s"
+    },
+    "status.Sync.3": {
+        "message": "?rv?nytelen szinkroniz?l?si kulcs (3-as ?llapot), ?jraszinkroniz?l?s"
+    },
+    "status.Sync.4": {
+        "message": "Rosszul form?zott k?r?s (4-es ?llapot)"
+    },
+    "status.Sync.5": {
+        "message": "Ideiglenes kiszolg?l?probl?ma vagy ?rv?nytelen elem (5-?s ?llapot)"
+    },
+    "status.Sync.6": {
+        "message": "?rv?nytelen elem (6-os ?llapot)"
+    },
+    "status.Sync.8": {
+        "message": "Az objektum nem tal?lhat? (8-as ?llapot)"
+    },
+    "status.aborted": {
+        "message": "Nincs szinkroniz?lva"
+    },
+    "status.disabled": {
+        "message": "Letiltva"
+    },
+    "status.empty-response": {
+        "message": "A kiszolg?l? v?ratlan ?res v?laszt k?ld?tt."
+    },
+    "status.forbiddenCalendarItemInTasksFolder": {
+        "message": "Tiltott napt?relem a feladatok mapp?ban (rendezze ?jra)"
+    },
+    "status.forbiddenTasksItemInCalendarFolder": {
+        "message": "Tiltott feladatelem a napt?r mapp?ban (rendezze ?jra)"
+    },
+    "status.global.101": {
+        "message": "A k?r?s WBXML-t tartalmaz, de nem siker?lt XML-be dek?dolni (101-es EAS-hiba)."
+    },
+    "status.global.102": {
+        "message": "A k?r?s WBXML-t tartalmaz, de nem siker?lt XML-be dek?dolni (102-es EAS-hiba)."
+    },
+    "status.global.103": {
+        "message": "A k?r?sben megadott XML nem k?veti a protokoll k?vetelm?nyeit (103-as EAS-hiba)."
+    },
+    "status.global.110": {
+        "message": "A kiszolg?l? bels? hib?t jelentett, ?s nem szabad azonnal ?jrapr?b?lkozni. Az automatikus szinkroniz?l?s 30 percre felf?ggeszt?sre ker?lt (110-es EAS hiba)."
+    },
+    "status.global.clientdenied": {
+        "message": "Az EAS-kiszolg?l? ezt jelenti: <##replace.2##> (?llapot: ##replace.1##), ?s nem enged?lyezi a TbSync sz?m?ra a fi?kja el?r?s?t."
+    },
+    "status.httperror": {
+        "message": "Kommunik?ci?s hiba (HTTP ?llapot: ##replace.1##)."
+    },
+    "status.invalid": {
+        "message": "?rv?nytelen kiszolg?l?v?lasz (szem?t)."
+    },
+    "status.malformed-xml": {
+        "message": "Az XML feldolgoz?sa nem siker?lt. Ellen?rizze az esem?nynapl?t a r?szletek?rt."
+    },
+    "status.modified": {
+        "message": "Helyi m?dos?t?sok"
+    },
+    "status.network": {
+        "message": "Nem siker?lt kapcsol?dni a kiszolg?l?hoz (##replace.1##)."
+    },
+    "status.networkerror": {
+        "message": "Nem siker?lt kapcsol?dni a kiszolg?l?hoz."
+    },
+    "status.nosupportedeasversion": {
+        "message": "A kiszolg?l? nem t?mogatja az ActiveSync v2.5-?t vagy a v14.0-t (csak ezt: ##replace.1##). A TbSync nem fog m?k?dni ezzel az ActiveSync-kiszolg?l?val."
+    },
+    "status.notargets": {
+        "message": "A szinkroniz?l?s megszak?t?sa, mert a szinkroniz?l?si c?lokat nem lehetett l?trehozni."
+    },
+    "status.notsupportedeasversion": {
+        "message": "A kiszolg?l? nem t?mogatja a kiv?lasztott ActiveSync ##replace.1## verzi?t (csak ezt: ##replace.2##)."
+    },
+    "status.notsyncronized": {
+        "message": "A fi?kot szinkroniz?lni kell, legal?bb egy elem nincs szinkroniz?lva."
+    },
+    "status.nouserhost": {
+        "message": "Hi?nyz? felhaszn?l?n?v vagy kiszolg?l?. Adja meg ezeket az ?rt?keket."
+    },
+    "status.pending": {
+        "message": "V?rakoz?s a szinkroniz?l?sra"
+    },
+    "status.policy.2": {
+        "message": "Nincs h?zirend ehhez a klienshez. Vegye fel a kapcsolatot a kiszolg?l? rendszergazd?j?val, vagy tiltsa le a fi?k lek?t?s?t."
+    },
+    "status.policy.3": {
+        "message": "Ismeretlen h?zirendt?pus ?rt?k. Vegye fel a kapcsolatot a kiszolg?l? rendszergazd?j?val, vagy tiltsa le a fi?k lek?t?s?t."
+    },
+    "status.policy.4": {
+        "message": "A kiszolg?l? h?zirendadatai s?r?ltek (esetleg meghamis?tott?k). Vegye fel a kapcsolatot a kiszolg?l? rendszergazd?j?val, vagy tiltsa le a fi?k lek?t?s?t."
+    },
+    "status.policy.5": {
+        "message": "A kliens nyugt?zza a hib?s h?zirendkulcsot. Vegye fel a kapcsolatot a kiszolg?l? rendszergazd?j?val, vagy tiltsa le a fi?k lek?t?s?t."
+    },
+    "status.provision": {
+        "message": "A lek?t?s sikertelen, ?llapot: <##replace.1##>"
+    },
+    "status.response-contains-no-data": {
+        "message": "A kiszolg?l? v?lasza nem tartalmaz adatokat."
+    },
+    "status.resync-loop": {
+        "message": "Hiba t?rt?nt, amelyb?l nem siker?lt helyre?llni a fi?k ?jraszinkroniz?l?s?val. Tiltsa le a fi?kot, ?s pr?b?lja meg ?jra. (Hiba: ?lland? ?jraszinkroniz?l?s)"
+    },
+    "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.syncing": {
+        "message": "Szinkroniz?l?s"
+    },
+    "status.timeout": {
+        "message": "Kommunik?ci?s id?t?ll?p?s."
+    },
+    "status.wbxml-parse-error": {
+        "message": "A kiszolg?l? olvashatatlan v?laszt k?ld."
+    },
+    "status.wbxmlerror": {
+        "message": "A szinkroniz?l?s sikertelen. A kiszolg?l? a k?vetkez? ?llapottal v?laszolt: <##replace.1##>."
+    },
+    "status.wbxmlmissingfield": {
+        "message": "ActiveSync protokolls?rt?s: A(z) <##replace.1##> k?telez? mez? hi?nyzik a kiszolg?l? v?lasz?b?l."
+    },
+    "syncstate.accountdone": {
+        "message": "Fi?k k?sz"
+    },
+    "syncstate.done": {
+        "message": "A k?vetkez? elem el?k?sz?t?se szinkroniz?l?sra"
+    },
+    "syncstate.eval.response.autodiscover": {
+        "message": "Friss?tett kiszolg?l?be?ll?t?sok feldolgoz?sa"
+    },
+    "syncstate.eval.response.deletefolder": {
+        "message": "A mappa t?r?lve"
+    },
+    "syncstate.eval.response.estimate": {
+        "message": "V?ltoz?sbecsl?s feldolgoz?sa"
+    },
+    "syncstate.eval.response.folders": {
+        "message": "A mappalista friss?t?s feldolgoz?sa"
+    },
+    "syncstate.eval.response.localchanges": {
+        "message": "A helyi v?ltoz?sok nyugt?z?s?nak feldolgoz?sa"
+    },
+    "syncstate.eval.response.localdeletes": {
+        "message": "A helyi t?rl?sek nyugt?z?s?nak feldolgoz?sa"
+    },
+    "syncstate.eval.response.options": {
+        "message": "A kiszolg?l? be?ll?t?sainak feldolgoz?sa"
+    },
+    "syncstate.eval.response.provision": {
+        "message": "Lek?t?s feldolgoz?sa"
+    },
+    "syncstate.eval.response.remotechanges": {
+        "message": "A t?voli m?dos?t?sok feldolgoz?sa"
+    },
+    "syncstate.eval.response.revertlocalchanges": {
+        "message": "A helyi v?ltoz?sok vissza?ll?t?sa"
+    },
+    "syncstate.eval.response.setdeviceinfo": {
+        "message": "Eszk?zinform?ci?k k?ld?se"
+    },
+    "syncstate.eval.response.synckey": {
+        "message": "Szinkroniz?l?si kulcs feldolgoz?sa"
+    },
+    "syncstate.prepare.request.autodiscover": {
+        "message": "Friss?tett kiszolg?l?be?ll?t?sok k?r?se"
+    },
+    "syncstate.prepare.request.deletefolder": {
+        "message": "Felk?sz?l?s a mappa t?rl?s?re"
+    },
+    "syncstate.prepare.request.estimate": {
+        "message": "V?ltoz?sbecsl?s k?r?se"
+    },
+    "syncstate.prepare.request.folders": {
+        "message": "Mappalista-friss?t?s elk?ld?se"
+    },
+    "syncstate.prepare.request.localchanges": {
+        "message": "Helyi v?ltoz?sok k?ld?se"
+    },
+    "syncstate.prepare.request.localdeletes": {
+        "message": "Helyi t?rl?sek k?ld?se"
+    },
+    "syncstate.prepare.request.options": {
+        "message": "A kiszolg?l?be?ll?t?sok k?r?se"
+    },
+    "syncstate.prepare.request.provision": {
+        "message": "Lek?t?s k?r?se"
+    },
+    "syncstate.prepare.request.remotechanges": {
+        "message": "T?voli m?dos?t?sok k?r?se"
+    },
+    "syncstate.prepare.request.revertlocalchanges": {
+        "message": "Helyi v?ltoz?sok ?sszegy?jt?se"
+    },
+    "syncstate.prepare.request.setdeviceinfo": {
+        "message": "Eszk?zinform?ci?k k?ld?se"
+    },
+    "syncstate.prepare.request.synckey": {
+        "message": "Szinkroniz?l?si kulcs k?r?se"
+    },
+    "syncstate.preparing": {
+        "message": "A k?vetkez? elem el?k?sz?t?se szinkroniz?l?sra"
+    },
+    "syncstate.send.request.autodiscover": {
+        "message": "V?rakoz?s a friss?tett kiszolg?l?be?ll?t?sokra"
+    },
+    "syncstate.send.request.deletefolder": {
+        "message": "V?rakoz?s a mappa t?rl?s?re"
+    },
+    "syncstate.send.request.estimate": {
+        "message": "V?rakoz?s a v?ltoz?sbecsl?sre"
+    },
+    "syncstate.send.request.folders": {
+        "message": "V?rakoz?s a mappalista-friss?t?sre"
+    },
+    "syncstate.send.request.localchanges": {
+        "message": "V?rakoz?s a helyi v?ltoz?sok elismer?s?re"
+    },
+    "syncstate.send.request.localdeletes": {
+        "message": "V?rakoz?s a helyi t?rl?sek nyugt?z?s?ra"
+    },
+    "syncstate.send.request.options": {
+        "message": "V?rakoz?s a kiszolg?l?be?ll?t?sokra"
+    },
+    "syncstate.send.request.provision": {
+        "message": "V?rakoz?s a lek?t?sre"
+    },
+    "syncstate.send.request.remotechanges": {
+        "message": "V?rakoz?s a t?voli m?dos?t?sokra"
+    },
+    "syncstate.send.request.revertlocalchanges": {
+        "message": "V?rakoz?s a legfrissebb verzi?kra"
+    },
+    "syncstate.send.request.setdeviceinfo": {
+        "message": "Eszk?zinform?ci?k k?ld?se"
+    },
+    "syncstate.send.request.synckey": {
+        "message": "V?rakoz?s a szinkroniz?l?si kulcsra"
+    },
+    "syncstate.syncing": {
+        "message": "Szinkroniz?l?s el?k?sz?t?se"
+    }
+}
diff -Nru eas4tbsync-4.11/_locales/it/messages.json eas4tbsync-4.17/_locales/it/messages.json
--- eas4tbsync-4.11/_locales/it/messages.json	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/_locales/it/messages.json	2025-05-15 13:21:18.000000000 +0200
@@ -1,566 +1,566 @@
-{
-    "abCard.Anniversary": {
-        "message": "Anniversario:"
-    },
-    "abCard.AssistantName": {
-        "message": "Assistente:"
-    },
-    "abCard.AssistantPhoneNumber": {
-        "message": "Telefono assistente:"
-    },
-    "abCard.Business2PhoneNumber": {
-        "message": "Secondo telefono ufficio:"
-    },
-    "abCard.BusinessFaxNumber": {
-        "message": "Fax ufficio:"
-    },
-    "abCard.CarPhoneNumber": {
-        "message": "Telefono auto:"
-    },
-    "abCard.CompanyMainPhone": {
-        "message": "Telefono lavoro principale:"
-    },
-    "abCard.Email3Address": {
-        "message": "Indirizzo di posta elettronica alternativo:"
-    },
-    "abCard.Home2PhoneNumber": {
-        "message": "Secondo telefono casa:"
-    },
-    "abCard.ManagerName": {
-        "message": "Supervisore:"
-    },
-    "abCard.MiddleName": {
-        "message": "Secondo nome:"
-    },
-    "abCard.OtherAddress": {
-        "message": "Indirizzo:"
-    },
-    "abCard.OtherCity": {
-        "message": "Citt?:"
-    },
-    "abCard.OtherCountry": {
-        "message": "Paese:"
-    },
-    "abCard.OtherState": {
-        "message": "Stato:"
-    },
-    "abCard.OtherZip": {
-        "message": "CAP:"
-    },
-    "abCard.RadioPhoneNumber": {
-        "message": "Telefono radio:"
-    },
-    "abCard.Spouse": {
-        "message": "Coniuge:"
-    },
-    "abCard.header.eas": {
-        "message": "Altri campi (EAS)"
-    },
-    "abCard.header.homenumbers": {
-        "message": "Numeri casa aggiuntivi:"
-    },
-    "abCard.header.messaging": {
-        "message": "Messaggeria:"
-    },
-    "abCard.header.otheraddress": {
-        "message": "Altro indirizzo (EAS)"
-    },
-    "abCard.header.othernumbers": {
-        "message": "Numeri aggiuntivi:"
-    },
-    "abCard.header.people": {
-        "message": "Persone:"
-    },
-    "abCard.header.worknumbers": {
-        "message": "Numeri lavoro aggiuntivi:"
-    },
-    "acl.readonly": {
-        "message": "Accesso al server in sola lettura (ripristina le modifiche locali)"
-    },
-    "acl.readwrite": {
-        "message": "Leggi e scrivi sul server"
-    },
-    "add.description": {
-        "message": "Selezionare una delle opzioni configurazione server disponibili e immettere i dettagli richiesti. "
-    },
-    "add.name": {
-        "message": "Nome account:"
-    },
-    "add.ok": {
-        "message": "Aggiungi account"
-    },
-    "add.password": {
-        "message": "Password:"
-    },
-    "add.server": {
-        "message": "Configurazione server:"
-    },
-    "add.shortdescription": {
-        "message": "Informazioni sul conto"
-    },
-    "add.title": {
-        "message": "Aggiunta account Exchange ActiveSync a TbSync"
-    },
-    "add.url": {
-        "message": "Indirizzo server:"
-    },
-    "add.urldescription": {
-        "message": "Dovrebbe essere sufficiente fornire solo il nome del server (ad es. mail.yourserver.com), ma ? anche possibile fornire l'URL completo (ad es. https://mail.yourserver.com/Microsoft-Server-ActiveSync)."
-    },
-    "add.user": {
-        "message": "Nome utente (indirizzo di posta elettronica):"
-    },
-    "autocomplete.serverdirectory": {
-        "message": "directory globale del server"
-    },
-    "autodiscover.Failed": {
-        "message": "Rilevamento automatico non riuscito per l'utente <##user##>. Le credenziali fornite sono errate o il proprio provider ActiveSync ha un problema temporaneo o non supporta il rilevamento automatico impostazioni."
-    },
-    "autodiscover.NeedEmail": {
-        "message": "Il rilevamento automatico impostazioni richiede che venga specificato un indirizzo di posta elettronica valido come nome utente."
-    },
-    "autodiscover.Ok": {
-        "message": "Rilevamento automatico impostazioni completato con successo, ? ora possibile verificare le impostazioni facoltative e stabilire la connessione per la sincronizzazione."
-    },
-    "autodiscover.Querying": {
-        "message": "Rilevamento impostazioni in corso..."
-    },
-    "config.auto": {
-        "message": "Configurazione server ActiveSync (rilevamento automatico)"
-    },
-    "config.custom": {
-        "message": "Configurazione server ActiveSync"
-    },
-    "deletefolder.confirm": {
-        "message": "ELIMINARE PERMANENTEMENTE la cartella '##replace.1##' dal Cestino?"
-    },
-    "deletefolder.menuentry": {
-        "message": "Elimina permanentemente la cartella '##replace.1##' dal Cestino"
-    },
-    "deletefolder.notallowed": {
-        "message": "Annullare la sottoscrizione alla cartella '##replace.1##' prima di provare a eliminarla dal Cestino."
-    },
-    "extensionDescription": {
-        "message": "Aggiunge il supporto per la sincronizzazione di account Exchange ActiveSync (contatti, attivit? e calendari) a TbSync."
-    },
-    "extensionName": {
-        "message": "Provider Exchange ActiveSync"
-    },
-    "helplink.BadItemSkipped": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
-    },
-    "helplink.global.clientdenied": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "manager.tabs.accountsettings": {
-        "message": "Impostazioni account"
-    },
-    "manager.tabs.outOfOffice": {
-        "message": "Risponditore automatico"
-    },
-    "manager.tabs.syncsettings": {
-        "message": "Opzioni"
-    },
-    "newaccount.add_auto": {
-        "message": "Rileva automaticamente impostazioni e aggiungi account"
-    },
-    "newaccount.add_custom": {
-        "message": "Aggiungi account"
-    },
-    "pref.AccountName": {
-        "message": "Nome account"
-    },
-    "pref.ActiveSyncVersion": {
-        "message": "Versione ActiveSync"
-    },
-    "pref.DeviceId": {
-        "message": "ID dispositivo ActiveSync"
-    },
-    "pref.ServerName": {
-        "message": "Indirizzo server"
-    },
-    "pref.ServerNameDescription": {
-        "message": "ad es. mail.yourserver.com"
-    },
-    "pref.ShowTrashedFolders": {
-        "message": "Visualizza le cartelle trovate nel Cestino"
-    },
-    "pref.UserName": {
-        "message": "Nome utente"
-    },
-    "pref.UserNameDescription": {
-        "message": "Il nome utente ? solitamente l'indirizzo di posta elettronica del proprio account."
-    },
-    "pref.autodetect": {
-        "message": "miglior opzione disponibile"
-    },
-    "pref.birthday": {
-        "message": "Invia informazioni di compleanno"
-    },
-    "pref.calendaroptions": {
-        "message": "Opzioni del calendario"
-    },
-    "pref.contactoptions": {
-        "message": "Opzioni di contatto"
-    },
-    "pref.displayoverride": {
-        "message": "Ignora il Nome visualizzato e mostra Nome + Cognome"
-    },
-    "pref.generaloptions": {
-        "message": "Opzioni generali"
-    },
-    "pref.provision": {
-        "message": "Forza provisioning (opzione richiesta per Kerio)"
-    },
-    "pref.seperator.comma": {
-        "message": "Virgola"
-    },
-    "pref.seperator.description": {
-        "message": "Separatore per i campi indirizzo multiriga."
-    },
-    "pref.seperator.linebreak": {
-        "message": "Separatore riga"
-    },
-    "pref.synclimit.1month": {
-        "message": "di 4 settimane fa"
-    },
-    "pref.synclimit.2weeks": {
-        "message": "di 2 settimane fa"
-    },
-    "pref.synclimit.3month": {
-        "message": "di 3 mesi fa"
-    },
-    "pref.synclimit.6month": {
-        "message": "di 6 mesi fa"
-    },
-    "pref.synclimit.all": {
-        "message": "tutto"
-    },
-    "pref.synclimit.description": {
-        "message": "Periodo di sincronizzazione:"
-    },
-    "pref.usehttps": {
-        "message": "Utilizza connessione sicura (connettiti tramite HTTPS)"
-    },
-    "recyclebin": {
-        "message": "Cestino"
-    },
-    "servertype.auto": {
-        "message": "Configurazione automatica"
-    },
-    "servertype.custom": {
-        "message": "Configurazione personalizzata"
-    },
-    "servertype.description.auto": {
-        "message": "Per molti server ActiveSync la configurazione pu? essere trovata fornendo solo l'indirizzo di posta elettronica."
-    },
-    "servertype.description.custom": {
-        "message": "Imposta l'account fornendo manualmente l'indirizzo del server a cui connettersi."
-    },
-    "servertype.description.office365": {
-        "message": "Gli account connessi a Office 365 utilizzano un processo di autenticazione moderno denominato OAuth 2.0 che supporta anche l'autenticazione a pi? fattori (MFA)."
-    },
-    "servertype.office365": {
-        "message": "Microsoft Office 365"
-    },
-    "servertype.unlock": {
-        "message": "Cliccare due volte per sbloccare tutte le impostazioni server predefinite."
-    },
-    "status.401": {
-        "message": "Impossibile autenticarsi, controllare nome utente e password."
-    },
-    "status.403": {
-        "message": "Il server ha rifiutato la connessione (vietato)."
-    },
-    "status.404": {
-        "message": "Utente non trovato (errore HTTP 404)."
-    },
-    "status.449": {
-        "message": "Il server richiede il provisioning."
-    },
-    "status.500": {
-        "message": "Errore server sconosciuto (errore HTTP 500)."
-    },
-    "status.503": {
-        "message": "Servizio non disponibile."
-    },
-    "status.BadItemSkipped": {
-        "message": "Oggetto errato saltato: ##replace.1##"
-    },
-    "status.FolderDelete.3": {
-        "message": "Impossibile eliminare una cartella di sistema."
-    },
-    "status.FolderDelete.4": {
-        "message": "?? Folder does not exist (status 4), resyncing ??"
-    },
-    "status.FolderDelete.6": {
-        "message": "Impossibile completare il comando, si ? verificato un errore sul server."
-    },
-    "status.FolderDelete.9": {
-        "message": "?? Invalid synchronization key (status 9), resyncing ??"
-    },
-    "status.FolderSync.9": {
-        "message": "?? Invalid synchronization key (status 9), resyncing ??"
-    },
-    "status.InvalidServerOptions": {
-        "message": "Il server non fornisce informazioni sulle versioni di ActiveSync supportate. EAS ? bloccato per questo utente o questo client (TbSync)? ? possibile provare a impostare manualmente la versione di ActiveSync."
-    },
-    "status.OK": {
-        "message": "OK"
-    },
-    "status.ServerRejectedRequest": {
-        "message": "Il server EAS ha rifiutato l'ultima richiesta."
-    },
-    "status.ServerRejectedSomeItems": {
-        "message": "Il server EAS non ha accettato ##replace.1## elementi."
-    },
-    "status.Sync.12": {
-        "message": "?? Folder hierarchy changed (status 12), resyncing ??"
-    },
-    "status.Sync.3": {
-        "message": "?? Invalid synchronization key (status 3), resyncing ??"
-    },
-    "status.Sync.4": {
-        "message": "?? Malformed request (status 4) ??"
-    },
-    "status.Sync.5": {
-        "message": "?? Temporary server issues or invalid item (status 5) ??"
-    },
-    "status.Sync.6": {
-        "message": "?? Invalid item (status 6) ??"
-    },
-    "status.Sync.8": {
-        "message": "?? Object not found (status 8) ??"
-    },
-    "status.aborted": {
-        "message": "Non sincronizzato"
-    },
-    "status.disabled": {
-        "message": "L'account non ? abilitato, la sincronizzazione ? disabilitata."
-    },
-    "status.empty-response": {
-        "message": "Il server invia una risposta vuota inaspettata."
-    },
-    "status.forbiddenCalendarItemInTasksFolder": {
-        "message": "?? Forbidden calendar item in a task folder (please resort) ??"
-    },
-    "status.forbiddenTasksItemInCalendarFolder": {
-        "message": "?? Forbidden task item in a calendar folder (please resort) ??"
-    },
-    "status.global.101": {
-        "message": "La richiesta contiene WBXML ma non ? possibile decodificarlo in XML (errore 101)."
-    },
-    "status.global.102": {
-        "message": "La richiesta contiene WBXML ma non ? possibile decodificarlo in XML (errore 102)."
-    },
-    "status.global.103": {
-        "message": "L'XML fornito nella richiesta non rispetta i requisiti del protocollo (errore 103)."
-    },
-    "status.global.110": {
-        "message": "Il server ha segnalato un errore interno e non dovremmo riprovare immediatamente. La sincronizzazione periodica automatica ? stata disattivata per 30 minuti (errore EAS 110)."
-    },
-    "status.global.clientdenied": {
-        "message": "Il server EAS segnala <##replace.2##> (stato ##replace.1##) e non consente a TbSync l'accesso al proprio account."
-    },
-    "status.httperror": {
-        "message": "Errore di comunicazione (stato HTTP ##replace.1##)."
-    },
-    "status.invalid": {
-        "message": "Risposta del server non valida (inutile)."
-    },
-    "status.malformed-xml": {
-        "message": "Impossibile analizzare XML. Controllare il registro eventi per i dettagli."
-    },
-    "status.modified": {
-        "message": "Modifiche locali presenti"
-    },
-    "status.network": {
-        "message": "Impossibile collegarsi al server (##replace.1##)."
-    },
-    "status.networkerror": {
-        "message": "Impossibile connettersi al server."
-    },
-    "status.nosupportedeasversion": {
-        "message": "Il server non supporta ActiveSync v2.5 o v14.0 (solo ##replace.1##). TbSync non funzioner? con questo server ActiveSync."
-    },
-    "status.notargets": {
-        "message": "Interruzione sincronizzazione in corso: non ? possibile creare le destinazioni sincronizzazione."
-    },
-    "status.notsupportedeasversion": {
-        "message": "Il server non supporta la versione di ActiveSync selezionata ##replace.1## (solo ##replace.2##)."
-    },
-    "status.notsyncronized": {
-        "message": "L'account deve essere sincronizzato, almeno un elemento non ? sincronizzato."
-    },
-    "status.nouserhost": {
-        "message": "Nome utente e/o server mancanti. Fornire tali valori."
-    },
-    "status.pending": {
-        "message": "In attesa di sincronizzazione"
-    },
-    "status.policy.2": {
-        "message": "Non esiste alcuna policy per questo client. Contattare l'amministratore del proprio server o disabilitare il provisioning per questo account."
-    },
-    "status.policy.3": {
-        "message": "Valore PolicyType sconosciuto. Contattare l'amministratore del proprio server o disabilitare il provisioning per questo account."
-    },
-    "status.policy.4": {
-        "message": "I dati di policy sul server sono corrotti (forse alterati). Contattare l'amministratore del proprio server o disabilitare il provisioning per questo account."
-    },
-    "status.policy.5": {
-        "message": "Il client sta riconoscendo una policy con nome errato. Contattare l'amministratore del proprio server o disabilitare il provisioning per questo account."
-    },
-    "status.provision": {
-        "message": "Provisioning non riuscito: stato <##replace.1##>"
-    },
-    "status.response-contains-no-data": {
-        "message": "La risposta dal server non contiene dati."
-    },
-    "status.resync-loop": {
-        "message": "Si ? verificato un errore che non ? stato possibile correggere eseguendo una nuova sincronizzazione dell'account. Disabilitare l'account e riprovare. (Errore: ciclo di risincronizzazione)"
-    },
-    "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.syncing": {
-        "message": "Sincronizzazione in corso"
-    },
-    "status.timeout": {
-        "message": "Timeout durante la comunicazione."
-    },
-    "status.wbxml-parse-error": {
-        "message": "Il server invia una risposta illeggibile."
-    },
-    "status.wbxmlerror": {
-        "message": "Sincronizzazione non riuscita. Il server ha risposto con lo stato <##replace.1##>."
-    },
-    "status.wbxmlmissingfield": {
-        "message": "Violazione protocollo ActiveSync: il campo obbligatorio <##replace.1##> manca dalla risposta del server."
-    },
-    "syncstate.accountdone": {
-        "message": "Sincronizzazione account completata"
-    },
-    "syncstate.done": {
-        "message": "Preparazione prossimo elemento per la sincronizzazione in corso"
-    },
-    "syncstate.eval.response.autodiscover": {
-        "message": "Elaborazione impostazioni server aggiornate in corso"
-    },
-    "syncstate.eval.response.deletefolder": {
-        "message": "Cartella eliminata"
-    },
-    "syncstate.eval.response.estimate": {
-        "message": "Elaborazione stima modifiche in corso"
-    },
-    "syncstate.eval.response.folders": {
-        "message": "Elaborazione aggiornamenti elenco cartelle in corso"
-    },
-    "syncstate.eval.response.localchanges": {
-        "message": "Elaborazione riconoscimento modifiche locali in corso"
-    },
-    "syncstate.eval.response.localdeletes": {
-        "message": "Elaborazione riconoscimento eliminazioni locali in corso"
-    },
-    "syncstate.eval.response.options": {
-        "message": "Elaborazione opzioni server in corso"
-    },
-    "syncstate.eval.response.provision": {
-        "message": "Elaborazione provisioning in corso"
-    },
-    "syncstate.eval.response.remotechanges": {
-        "message": "Elaborazione modifiche remote in corso"
-    },
-    "syncstate.eval.response.revertlocalchanges": {
-        "message": "Annullamento modifiche locali in corso"
-    },
-    "syncstate.eval.response.setdeviceinfo": {
-        "message": "Invio informazioni dispositivo in corso"
-    },
-    "syncstate.eval.response.synckey": {
-        "message": "Elaborazione chiave di sincronizzazione in corso"
-    },
-    "syncstate.prepare.request.autodiscover": {
-        "message": "Richiesta impostazioni server aggiornate in corso"
-    },
-    "syncstate.prepare.request.deletefolder": {
-        "message": "Preparazione eliminazione cartella in corso"
-    },
-    "syncstate.prepare.request.estimate": {
-        "message": "Richiesta stima modifiche in corso"
-    },
-    "syncstate.prepare.request.folders": {
-        "message": "Invio aggiornamenti elenco cartelle in corso"
-    },
-    "syncstate.prepare.request.localchanges": {
-        "message": "Invio modifiche locali in corso"
-    },
-    "syncstate.prepare.request.localdeletes": {
-        "message": "Invio eliminazioni locali in corso"
-    },
-    "syncstate.prepare.request.options": {
-        "message": "Richiesta opzioni server in corso"
-    },
-    "syncstate.prepare.request.provision": {
-        "message": "Richiesta provisioning in corso"
-    },
-    "syncstate.prepare.request.remotechanges": {
-        "message": "Richiesta modifiche remote in corso"
-    },
-    "syncstate.prepare.request.revertlocalchanges": {
-        "message": "Raccolta modifiche locali in corso"
-    },
-    "syncstate.prepare.request.setdeviceinfo": {
-        "message": "Invio informazioni dispositivo in corso"
-    },
-    "syncstate.prepare.request.synckey": {
-        "message": "Richiesta chiave di sincronizzazione in corso"
-    },
-    "syncstate.preparing": {
-        "message": "Preparazione prossimo elemento per la sincronizzazione in corso"
-    },
-    "syncstate.send.request.autodiscover": {
-        "message": "In attesa delle impostazioni server aggiornate"
-    },
-    "syncstate.send.request.deletefolder": {
-        "message": "In attesa dell'eliminazione della cartella"
-    },
-    "syncstate.send.request.estimate": {
-        "message": "In attesa della stima modifiche"
-    },
-    "syncstate.send.request.folders": {
-        "message": "In attesa degli aggiornamenti elenco cartelle"
-    },
-    "syncstate.send.request.localchanges": {
-        "message": "In attesa del riconoscimento delle modifiche locali"
-    },
-    "syncstate.send.request.localdeletes": {
-        "message": "In attesa del riconoscimento delle eliminazioni locali"
-    },
-    "syncstate.send.request.options": {
-        "message": "In attesa delle opzioni server"
-    },
-    "syncstate.send.request.provision": {
-        "message": "In attesa del provisioning"
-    },
-    "syncstate.send.request.remotechanges": {
-        "message": "In attesa delle modifiche remote"
-    },
-    "syncstate.send.request.revertlocalchanges": {
-        "message": "In attesa delle versioni pi? recenti"
-    },
-    "syncstate.send.request.setdeviceinfo": {
-        "message": "Invio informazioni dispositivo in corso"
-    },
-    "syncstate.send.request.synckey": {
-        "message": "In attesa della chiave di sincronizzazione"
-    },
-    "syncstate.syncing": {
-        "message": "Inizializzazione sincronizzazione in corso"
-    }
-}
+{
+    "abCard.Anniversary": {
+        "message": "Anniversario:"
+    },
+    "abCard.AssistantName": {
+        "message": "Assistente:"
+    },
+    "abCard.AssistantPhoneNumber": {
+        "message": "Telefono assistente:"
+    },
+    "abCard.Business2PhoneNumber": {
+        "message": "Secondo telefono ufficio:"
+    },
+    "abCard.BusinessFaxNumber": {
+        "message": "Fax ufficio:"
+    },
+    "abCard.CarPhoneNumber": {
+        "message": "Telefono auto:"
+    },
+    "abCard.CompanyMainPhone": {
+        "message": "Telefono lavoro principale:"
+    },
+    "abCard.Email3Address": {
+        "message": "Indirizzo di posta elettronica alternativo:"
+    },
+    "abCard.Home2PhoneNumber": {
+        "message": "Secondo telefono casa:"
+    },
+    "abCard.ManagerName": {
+        "message": "Supervisore:"
+    },
+    "abCard.MiddleName": {
+        "message": "Secondo nome:"
+    },
+    "abCard.OtherAddress": {
+        "message": "Indirizzo:"
+    },
+    "abCard.OtherCity": {
+        "message": "Citt?:"
+    },
+    "abCard.OtherCountry": {
+        "message": "Paese:"
+    },
+    "abCard.OtherState": {
+        "message": "Stato:"
+    },
+    "abCard.OtherZip": {
+        "message": "CAP:"
+    },
+    "abCard.RadioPhoneNumber": {
+        "message": "Telefono radio:"
+    },
+    "abCard.Spouse": {
+        "message": "Coniuge:"
+    },
+    "abCard.header.eas": {
+        "message": "Altri campi (EAS)"
+    },
+    "abCard.header.homenumbers": {
+        "message": "Numeri casa aggiuntivi:"
+    },
+    "abCard.header.messaging": {
+        "message": "Messaggeria:"
+    },
+    "abCard.header.otheraddress": {
+        "message": "Altro indirizzo (EAS)"
+    },
+    "abCard.header.othernumbers": {
+        "message": "Numeri aggiuntivi:"
+    },
+    "abCard.header.people": {
+        "message": "Persone:"
+    },
+    "abCard.header.worknumbers": {
+        "message": "Numeri lavoro aggiuntivi:"
+    },
+    "acl.readonly": {
+        "message": "Accesso al server in sola lettura (ripristina le modifiche locali)"
+    },
+    "acl.readwrite": {
+        "message": "Leggi e scrivi sul server"
+    },
+    "add.description": {
+        "message": "Selezionare una delle opzioni configurazione server disponibili e immettere i dettagli richiesti. "
+    },
+    "add.name": {
+        "message": "Nome account:"
+    },
+    "add.ok": {
+        "message": "Aggiungi account"
+    },
+    "add.password": {
+        "message": "Password:"
+    },
+    "add.server": {
+        "message": "Configurazione server:"
+    },
+    "add.shortdescription": {
+        "message": "Informazioni sul conto"
+    },
+    "add.title": {
+        "message": "Aggiunta account Exchange ActiveSync a TbSync"
+    },
+    "add.url": {
+        "message": "Indirizzo server:"
+    },
+    "add.urldescription": {
+        "message": "Dovrebbe essere sufficiente fornire solo il nome del server (ad es. mail.yourserver.com), ma ? anche possibile fornire l'URL completo (ad es. https://mail.yourserver.com/Microsoft-Server-ActiveSync)."
+    },
+    "add.user": {
+        "message": "Nome utente (indirizzo di posta elettronica):"
+    },
+    "autocomplete.serverdirectory": {
+        "message": "directory globale del server"
+    },
+    "autodiscover.Failed": {
+        "message": "Rilevamento automatico non riuscito per l'utente <##user##>. Le credenziali fornite sono errate o il proprio provider ActiveSync ha un problema temporaneo o non supporta il rilevamento automatico impostazioni."
+    },
+    "autodiscover.NeedEmail": {
+        "message": "Il rilevamento automatico impostazioni richiede che venga specificato un indirizzo di posta elettronica valido come nome utente."
+    },
+    "autodiscover.Ok": {
+        "message": "Rilevamento automatico impostazioni completato con successo, ? ora possibile verificare le impostazioni facoltative e stabilire la connessione per la sincronizzazione."
+    },
+    "autodiscover.Querying": {
+        "message": "Rilevamento impostazioni in corso..."
+    },
+    "config.auto": {
+        "message": "Configurazione server ActiveSync (rilevamento automatico)"
+    },
+    "config.custom": {
+        "message": "Configurazione server ActiveSync"
+    },
+    "deletefolder.confirm": {
+        "message": "ELIMINARE PERMANENTEMENTE la cartella '##replace.1##' dal Cestino?"
+    },
+    "deletefolder.menuentry": {
+        "message": "Elimina permanentemente la cartella '##replace.1##' dal Cestino"
+    },
+    "deletefolder.notallowed": {
+        "message": "Annullare la sottoscrizione alla cartella '##replace.1##' prima di provare a eliminarla dal Cestino."
+    },
+    "extensionDescription": {
+        "message": "Aggiunge il supporto per la sincronizzazione di account Exchange ActiveSync (contatti, attivit? e calendari) a TbSync."
+    },
+    "extensionName": {
+        "message": "Provider Exchange ActiveSync"
+    },
+    "helplink.BadItemSkipped": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
+    },
+    "helplink.global.clientdenied": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "manager.tabs.accountsettings": {
+        "message": "Impostazioni account"
+    },
+    "manager.tabs.outOfOffice": {
+        "message": "Risponditore automatico"
+    },
+    "manager.tabs.syncsettings": {
+        "message": "Opzioni"
+    },
+    "newaccount.add_auto": {
+        "message": "Rileva automaticamente impostazioni e aggiungi account"
+    },
+    "newaccount.add_custom": {
+        "message": "Aggiungi account"
+    },
+    "pref.AccountName": {
+        "message": "Nome account"
+    },
+    "pref.ActiveSyncVersion": {
+        "message": "Versione ActiveSync"
+    },
+    "pref.DeviceId": {
+        "message": "ID dispositivo ActiveSync"
+    },
+    "pref.ServerName": {
+        "message": "Indirizzo server"
+    },
+    "pref.ServerNameDescription": {
+        "message": "ad es. mail.yourserver.com"
+    },
+    "pref.ShowTrashedFolders": {
+        "message": "Visualizza le cartelle trovate nel Cestino"
+    },
+    "pref.UserName": {
+        "message": "Nome utente"
+    },
+    "pref.UserNameDescription": {
+        "message": "Il nome utente ? solitamente l'indirizzo di posta elettronica del proprio account."
+    },
+    "pref.autodetect": {
+        "message": "miglior opzione disponibile"
+    },
+    "pref.birthday": {
+        "message": "Invia informazioni di compleanno"
+    },
+    "pref.calendaroptions": {
+        "message": "Opzioni del calendario"
+    },
+    "pref.contactoptions": {
+        "message": "Opzioni di contatto"
+    },
+    "pref.displayoverride": {
+        "message": "Ignora il Nome visualizzato e mostra Nome + Cognome"
+    },
+    "pref.generaloptions": {
+        "message": "Opzioni generali"
+    },
+    "pref.provision": {
+        "message": "Forza provisioning (opzione richiesta per Kerio)"
+    },
+    "pref.seperator.comma": {
+        "message": "Virgola"
+    },
+    "pref.seperator.description": {
+        "message": "Separatore per i campi indirizzo multiriga."
+    },
+    "pref.seperator.linebreak": {
+        "message": "Separatore riga"
+    },
+    "pref.synclimit.1month": {
+        "message": "di 4 settimane fa"
+    },
+    "pref.synclimit.2weeks": {
+        "message": "di 2 settimane fa"
+    },
+    "pref.synclimit.3month": {
+        "message": "di 3 mesi fa"
+    },
+    "pref.synclimit.6month": {
+        "message": "di 6 mesi fa"
+    },
+    "pref.synclimit.all": {
+        "message": "tutto"
+    },
+    "pref.synclimit.description": {
+        "message": "Periodo di sincronizzazione:"
+    },
+    "pref.usehttps": {
+        "message": "Utilizza connessione sicura (connettiti tramite HTTPS)"
+    },
+    "recyclebin": {
+        "message": "Cestino"
+    },
+    "servertype.auto": {
+        "message": "Configurazione automatica"
+    },
+    "servertype.custom": {
+        "message": "Configurazione personalizzata"
+    },
+    "servertype.description.auto": {
+        "message": "Per molti server ActiveSync la configurazione pu? essere trovata fornendo solo l'indirizzo di posta elettronica."
+    },
+    "servertype.description.custom": {
+        "message": "Imposta l'account fornendo manualmente l'indirizzo del server a cui connettersi."
+    },
+    "servertype.description.office365": {
+        "message": "Gli account connessi a Office 365 utilizzano un processo di autenticazione moderno denominato OAuth 2.0 che supporta anche l'autenticazione a pi? fattori (MFA)."
+    },
+    "servertype.office365": {
+        "message": "Microsoft Office 365"
+    },
+    "servertype.unlock": {
+        "message": "Cliccare due volte per sbloccare tutte le impostazioni server predefinite."
+    },
+    "status.401": {
+        "message": "Impossibile autenticarsi, controllare nome utente e password."
+    },
+    "status.403": {
+        "message": "Il server ha rifiutato la connessione (vietato)."
+    },
+    "status.404": {
+        "message": "Utente non trovato (errore HTTP 404)."
+    },
+    "status.449": {
+        "message": "Il server richiede il provisioning."
+    },
+    "status.500": {
+        "message": "Errore server sconosciuto (errore HTTP 500)."
+    },
+    "status.503": {
+        "message": "Servizio non disponibile."
+    },
+    "status.BadItemSkipped": {
+        "message": "Oggetto errato saltato: ##replace.1##"
+    },
+    "status.FolderDelete.3": {
+        "message": "Impossibile eliminare una cartella di sistema."
+    },
+    "status.FolderDelete.4": {
+        "message": "?? Folder does not exist (status 4), resyncing ??"
+    },
+    "status.FolderDelete.6": {
+        "message": "Impossibile completare il comando, si ? verificato un errore sul server."
+    },
+    "status.FolderDelete.9": {
+        "message": "?? Invalid synchronization key (status 9), resyncing ??"
+    },
+    "status.FolderSync.9": {
+        "message": "?? Invalid synchronization key (status 9), resyncing ??"
+    },
+    "status.InvalidServerOptions": {
+        "message": "Il server non fornisce informazioni sulle versioni di ActiveSync supportate. EAS ? bloccato per questo utente o questo client (TbSync)? ? possibile provare a impostare manualmente la versione di ActiveSync."
+    },
+    "status.OK": {
+        "message": "OK"
+    },
+    "status.ServerRejectedRequest": {
+        "message": "Il server EAS ha rifiutato l'ultima richiesta."
+    },
+    "status.ServerRejectedSomeItems": {
+        "message": "Il server EAS non ha accettato ##replace.1## elementi."
+    },
+    "status.Sync.12": {
+        "message": "?? Folder hierarchy changed (status 12), resyncing ??"
+    },
+    "status.Sync.3": {
+        "message": "?? Invalid synchronization key (status 3), resyncing ??"
+    },
+    "status.Sync.4": {
+        "message": "?? Malformed request (status 4) ??"
+    },
+    "status.Sync.5": {
+        "message": "?? Temporary server issues or invalid item (status 5) ??"
+    },
+    "status.Sync.6": {
+        "message": "?? Invalid item (status 6) ??"
+    },
+    "status.Sync.8": {
+        "message": "?? Object not found (status 8) ??"
+    },
+    "status.aborted": {
+        "message": "Non sincronizzato"
+    },
+    "status.disabled": {
+        "message": "L'account non ? abilitato, la sincronizzazione ? disabilitata."
+    },
+    "status.empty-response": {
+        "message": "Il server invia una risposta vuota inaspettata."
+    },
+    "status.forbiddenCalendarItemInTasksFolder": {
+        "message": "?? Forbidden calendar item in a task folder (please resort) ??"
+    },
+    "status.forbiddenTasksItemInCalendarFolder": {
+        "message": "?? Forbidden task item in a calendar folder (please resort) ??"
+    },
+    "status.global.101": {
+        "message": "La richiesta contiene WBXML ma non ? possibile decodificarlo in XML (errore 101)."
+    },
+    "status.global.102": {
+        "message": "La richiesta contiene WBXML ma non ? possibile decodificarlo in XML (errore 102)."
+    },
+    "status.global.103": {
+        "message": "L'XML fornito nella richiesta non rispetta i requisiti del protocollo (errore 103)."
+    },
+    "status.global.110": {
+        "message": "Il server ha segnalato un errore interno e non dovremmo riprovare immediatamente. La sincronizzazione periodica automatica ? stata disattivata per 30 minuti (errore EAS 110)."
+    },
+    "status.global.clientdenied": {
+        "message": "Il server EAS segnala <##replace.2##> (stato ##replace.1##) e non consente a TbSync l'accesso al proprio account."
+    },
+    "status.httperror": {
+        "message": "Errore di comunicazione (stato HTTP ##replace.1##)."
+    },
+    "status.invalid": {
+        "message": "Risposta del server non valida (inutile)."
+    },
+    "status.malformed-xml": {
+        "message": "Impossibile analizzare XML. Controllare il registro eventi per i dettagli."
+    },
+    "status.modified": {
+        "message": "Modifiche locali presenti"
+    },
+    "status.network": {
+        "message": "Impossibile collegarsi al server (##replace.1##)."
+    },
+    "status.networkerror": {
+        "message": "Impossibile connettersi al server."
+    },
+    "status.nosupportedeasversion": {
+        "message": "Il server non supporta ActiveSync v2.5 o v14.0 (solo ##replace.1##). TbSync non funzioner? con questo server ActiveSync."
+    },
+    "status.notargets": {
+        "message": "Interruzione sincronizzazione in corso: non ? possibile creare le destinazioni sincronizzazione."
+    },
+    "status.notsupportedeasversion": {
+        "message": "Il server non supporta la versione di ActiveSync selezionata ##replace.1## (solo ##replace.2##)."
+    },
+    "status.notsyncronized": {
+        "message": "L'account deve essere sincronizzato, almeno un elemento non ? sincronizzato."
+    },
+    "status.nouserhost": {
+        "message": "Nome utente e/o server mancanti. Fornire tali valori."
+    },
+    "status.pending": {
+        "message": "In attesa di sincronizzazione"
+    },
+    "status.policy.2": {
+        "message": "Non esiste alcuna policy per questo client. Contattare l'amministratore del proprio server o disabilitare il provisioning per questo account."
+    },
+    "status.policy.3": {
+        "message": "Valore PolicyType sconosciuto. Contattare l'amministratore del proprio server o disabilitare il provisioning per questo account."
+    },
+    "status.policy.4": {
+        "message": "I dati di policy sul server sono corrotti (forse alterati). Contattare l'amministratore del proprio server o disabilitare il provisioning per questo account."
+    },
+    "status.policy.5": {
+        "message": "Il client sta riconoscendo una policy con nome errato. Contattare l'amministratore del proprio server o disabilitare il provisioning per questo account."
+    },
+    "status.provision": {
+        "message": "Provisioning non riuscito: stato <##replace.1##>"
+    },
+    "status.response-contains-no-data": {
+        "message": "La risposta dal server non contiene dati."
+    },
+    "status.resync-loop": {
+        "message": "Si ? verificato un errore che non ? stato possibile correggere eseguendo una nuova sincronizzazione dell'account. Disabilitare l'account e riprovare. (Errore: ciclo di risincronizzazione)"
+    },
+    "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.syncing": {
+        "message": "Sincronizzazione in corso"
+    },
+    "status.timeout": {
+        "message": "Timeout durante la comunicazione."
+    },
+    "status.wbxml-parse-error": {
+        "message": "Il server invia una risposta illeggibile."
+    },
+    "status.wbxmlerror": {
+        "message": "Sincronizzazione non riuscita. Il server ha risposto con lo stato <##replace.1##>."
+    },
+    "status.wbxmlmissingfield": {
+        "message": "Violazione protocollo ActiveSync: il campo obbligatorio <##replace.1##> manca dalla risposta del server."
+    },
+    "syncstate.accountdone": {
+        "message": "Sincronizzazione account completata"
+    },
+    "syncstate.done": {
+        "message": "Preparazione prossimo elemento per la sincronizzazione in corso"
+    },
+    "syncstate.eval.response.autodiscover": {
+        "message": "Elaborazione impostazioni server aggiornate in corso"
+    },
+    "syncstate.eval.response.deletefolder": {
+        "message": "Cartella eliminata"
+    },
+    "syncstate.eval.response.estimate": {
+        "message": "Elaborazione stima modifiche in corso"
+    },
+    "syncstate.eval.response.folders": {
+        "message": "Elaborazione aggiornamenti elenco cartelle in corso"
+    },
+    "syncstate.eval.response.localchanges": {
+        "message": "Elaborazione riconoscimento modifiche locali in corso"
+    },
+    "syncstate.eval.response.localdeletes": {
+        "message": "Elaborazione riconoscimento eliminazioni locali in corso"
+    },
+    "syncstate.eval.response.options": {
+        "message": "Elaborazione opzioni server in corso"
+    },
+    "syncstate.eval.response.provision": {
+        "message": "Elaborazione provisioning in corso"
+    },
+    "syncstate.eval.response.remotechanges": {
+        "message": "Elaborazione modifiche remote in corso"
+    },
+    "syncstate.eval.response.revertlocalchanges": {
+        "message": "Annullamento modifiche locali in corso"
+    },
+    "syncstate.eval.response.setdeviceinfo": {
+        "message": "Invio informazioni dispositivo in corso"
+    },
+    "syncstate.eval.response.synckey": {
+        "message": "Elaborazione chiave di sincronizzazione in corso"
+    },
+    "syncstate.prepare.request.autodiscover": {
+        "message": "Richiesta impostazioni server aggiornate in corso"
+    },
+    "syncstate.prepare.request.deletefolder": {
+        "message": "Preparazione eliminazione cartella in corso"
+    },
+    "syncstate.prepare.request.estimate": {
+        "message": "Richiesta stima modifiche in corso"
+    },
+    "syncstate.prepare.request.folders": {
+        "message": "Invio aggiornamenti elenco cartelle in corso"
+    },
+    "syncstate.prepare.request.localchanges": {
+        "message": "Invio modifiche locali in corso"
+    },
+    "syncstate.prepare.request.localdeletes": {
+        "message": "Invio eliminazioni locali in corso"
+    },
+    "syncstate.prepare.request.options": {
+        "message": "Richiesta opzioni server in corso"
+    },
+    "syncstate.prepare.request.provision": {
+        "message": "Richiesta provisioning in corso"
+    },
+    "syncstate.prepare.request.remotechanges": {
+        "message": "Richiesta modifiche remote in corso"
+    },
+    "syncstate.prepare.request.revertlocalchanges": {
+        "message": "Raccolta modifiche locali in corso"
+    },
+    "syncstate.prepare.request.setdeviceinfo": {
+        "message": "Invio informazioni dispositivo in corso"
+    },
+    "syncstate.prepare.request.synckey": {
+        "message": "Richiesta chiave di sincronizzazione in corso"
+    },
+    "syncstate.preparing": {
+        "message": "Preparazione prossimo elemento per la sincronizzazione in corso"
+    },
+    "syncstate.send.request.autodiscover": {
+        "message": "In attesa delle impostazioni server aggiornate"
+    },
+    "syncstate.send.request.deletefolder": {
+        "message": "In attesa dell'eliminazione della cartella"
+    },
+    "syncstate.send.request.estimate": {
+        "message": "In attesa della stima modifiche"
+    },
+    "syncstate.send.request.folders": {
+        "message": "In attesa degli aggiornamenti elenco cartelle"
+    },
+    "syncstate.send.request.localchanges": {
+        "message": "In attesa del riconoscimento delle modifiche locali"
+    },
+    "syncstate.send.request.localdeletes": {
+        "message": "In attesa del riconoscimento delle eliminazioni locali"
+    },
+    "syncstate.send.request.options": {
+        "message": "In attesa delle opzioni server"
+    },
+    "syncstate.send.request.provision": {
+        "message": "In attesa del provisioning"
+    },
+    "syncstate.send.request.remotechanges": {
+        "message": "In attesa delle modifiche remote"
+    },
+    "syncstate.send.request.revertlocalchanges": {
+        "message": "In attesa delle versioni pi? recenti"
+    },
+    "syncstate.send.request.setdeviceinfo": {
+        "message": "Invio informazioni dispositivo in corso"
+    },
+    "syncstate.send.request.synckey": {
+        "message": "In attesa della chiave di sincronizzazione"
+    },
+    "syncstate.syncing": {
+        "message": "Inizializzazione sincronizzazione in corso"
+    }
+}
diff -Nru eas4tbsync-4.11/_locales/ja/messages.json eas4tbsync-4.17/_locales/ja/messages.json
--- eas4tbsync-4.11/_locales/ja/messages.json	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/_locales/ja/messages.json	2025-05-15 13:21:18.000000000 +0200
@@ -1,566 +1,566 @@
-{
-    "abCard.Anniversary": {
-        "message": "???:"
-    },
-    "abCard.AssistantName": {
-        "message": "??????:"
-    },
-    "abCard.AssistantPhoneNumber": {
-        "message": "???????????:"
-    },
-    "abCard.Business2PhoneNumber": {
-        "message": "??????? 2:"
-    },
-    "abCard.BusinessFaxNumber": {
-        "message": "??? FAX:"
-    },
-    "abCard.CarPhoneNumber": {
-        "message": "???????:"
-    },
-    "abCard.CompanyMainPhone": {
-        "message": "???????:"
-    },
-    "abCard.Email3Address": {
-        "message": "????? 2:"
-    },
-    "abCard.Home2PhoneNumber": {
-        "message": "?????? 2:"
-    },
-    "abCard.ManagerName": {
-        "message": "??????:"
-    },
-    "abCard.MiddleName": {
-        "message": "??????:"
-    },
-    "abCard.OtherAddress": {
-        "message": "??:"
-    },
-    "abCard.OtherCity": {
-        "message": "?:"
-    },
-    "abCard.OtherCountry": {
-        "message": "?:"
-    },
-    "abCard.OtherState": {
-        "message": "????:"
-    },
-    "abCard.OtherZip": {
-        "message": "????:"
-    },
-    "abCard.RadioPhoneNumber": {
-        "message": "???????:"
-    },
-    "abCard.Spouse": {
-        "message": "???/?????:"
-    },
-    "abCard.header.eas": {
-        "message": "?????? (EAS)"
-    },
-    "abCard.header.homenumbers": {
-        "message": "?????? 3:"
-    },
-    "abCard.header.messaging": {
-        "message": "???????:"
-    },
-    "abCard.header.otheraddress": {
-        "message": "???????? (EAS)"
-    },
-    "abCard.header.othernumbers": {
-        "message": "???????:"
-    },
-    "abCard.header.people": {
-        "message": "People:"
-    },
-    "abCard.header.worknumbers": {
-        "message": "??????? 3:"
-    },
-    "acl.readonly": {
-        "message": "Read-only server access (revert local changes)"
-    },
-    "acl.readwrite": {
-        "message": "Read from and write to server"
-    },
-    "add.description": {
-        "message": "??????????????????????????????????????????? "
-    },
-    "add.name": {
-        "message": "??????:"
-    },
-    "add.ok": {
-        "message": "????????"
-    },
-    "add.password": {
-        "message": "?????:"
-    },
-    "add.server": {
-        "message": "??????:"
-    },
-    "add.shortdescription": {
-        "message": "???????"
-    },
-    "add.title": {
-        "message": "Adding an Exchange ActiveSync account to TbSync"
-    },
-    "add.url": {
-        "message": "???? ????:"
-    },
-    "add.urldescription": {
-        "message": "?????????????????????????? (?: mail.yourserver.com)? ??????? URL ???????????? (?: https://mail.yourserver.com/Microsoft-Server-ActiveSync)?"
-    },
-    "add.user": {
-        "message": "????? (?????????):"
-    },
-    "autocomplete.serverdirectory": {
-        "message": "global server directory"
-    },
-    "autodiscover.Failed": {
-        "message": "???? <##user##> ???????????????????????????????ActiveSync?????????????????????????????????"
-    },
-    "autodiscover.NeedEmail": {
-        "message": "??????????????????????????????"
-    },
-    "autodiscover.Ok": {
-        "message": "Autodiscover completed successfully, you can now check the optional settings and establish the synchronization connection."
-    },
-    "autodiscover.Querying": {
-        "message": "???????"
-    },
-    "config.auto": {
-        "message": "ActiveSync ?????? (????)"
-    },
-    "config.custom": {
-        "message": "ActiveSync ??????"
-    },
-    "deletefolder.confirm": {
-        "message": "???????????? '## replace.1 ##' ???????????"
-    },
-    "deletefolder.menuentry": {
-        "message": "????????? '## replace.1 ##' ??????"
-    },
-    "deletefolder.notallowed": {
-        "message": "???????????????? ?##replace.1##? ?????????????"
-    },
-    "extensionDescription": {
-        "message": "TbSync ? Exchange ActiveSync ?????????????????? (?????????????)?"
-    },
-    "extensionName": {
-        "message": "Exchange ActiveSync ??????"
-    },
-    "helplink.BadItemSkipped": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
-    },
-    "helplink.global.clientdenied": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "manager.tabs.accountsettings": {
-        "message": "???????"
-    },
-    "manager.tabs.outOfOffice": {
-        "message": "Auto responder"
-    },
-    "manager.tabs.syncsettings": {
-        "message": "?????"
-    },
-    "newaccount.add_auto": {
-        "message": "?????????????????"
-    },
-    "newaccount.add_custom": {
-        "message": "????????"
-    },
-    "pref.AccountName": {
-        "message": "??"
-    },
-    "pref.ActiveSyncVersion": {
-        "message": "ActiveSync ?????"
-    },
-    "pref.DeviceId": {
-        "message": "ActiveSync ???? ID"
-    },
-    "pref.ServerName": {
-        "message": "???? ????"
-    },
-    "pref.ServerNameDescription": {
-        "message": "?: mail.yourserver.com"
-    },
-    "pref.ShowTrashedFolders": {
-        "message": "Show folders found in trash"
-    },
-    "pref.UserName": {
-        "message": "?????"
-    },
-    "pref.UserNameDescription": {
-        "message": "???????????????????????????????"
-    },
-    "pref.autodetect": {
-        "message": "?????????????"
-    },
-    "pref.birthday": {
-        "message": "Send birthday information"
-    },
-    "pref.calendaroptions": {
-        "message": "???????"
-    },
-    "pref.contactoptions": {
-        "message": "?????"
-    },
-    "pref.displayoverride": {
-        "message": "???????+???????"
-    },
-    "pref.generaloptions": {
-        "message": "????"
-    },
-    "pref.provision": {
-        "message": "??????????? (Kerio ???)"
-    },
-    "pref.seperator.comma": {
-        "message": "???"
-    },
-    "pref.seperator.description": {
-        "message": "Separator for multiline address field."
-    },
-    "pref.seperator.linebreak": {
-        "message": "??"
-    },
-    "pref.synclimit.1month": {
-        "message": "4 ?????"
-    },
-    "pref.synclimit.2weeks": {
-        "message": "2 ?????"
-    },
-    "pref.synclimit.3month": {
-        "message": "3 ?????"
-    },
-    "pref.synclimit.6month": {
-        "message": "6 ?????"
-    },
-    "pref.synclimit.all": {
-        "message": "??"
-    },
-    "pref.synclimit.description": {
-        "message": "??????: "
-    },
-    "pref.usehttps": {
-        "message": "?????????? (https ???????)"
-    },
-    "recyclebin": {
-        "message": "???"
-    },
-    "servertype.auto": {
-        "message": "????"
-    },
-    "servertype.custom": {
-        "message": "??????"
-    },
-    "servertype.description.auto": {
-        "message": "??? ActiveSync ?????????????????????????????????"
-    },
-    "servertype.description.custom": {
-        "message": "???????????????????????????????????????"
-    },
-    "servertype.description.office365": {
-        "message": "Office 365?????????????OAuth 2.0 ?????????????????????????Multi-Factor-Authentication (MFA??????) ???????????"
-    },
-    "servertype.office365": {
-        "message": "Microsoft Office 365"
-    },
-    "servertype.unlock": {
-        "message": "Double click to unlock all predefined server settings."
-    },
-    "status.401": {
-        "message": "???????????????????????????? (HTTP ??? 401)?"
-    },
-    "status.403": {
-        "message": "?????????????? (??) (HTTP ??? 403)?"
-    },
-    "status.404": {
-        "message": "???????????? (HTTP ??? 404)?"
-    },
-    "status.449": {
-        "message": "????????????????????? (HTTP ??? 449)?"
-    },
-    "status.500": {
-        "message": "??????? ??? (HTTP ??? 500)?"
-    },
-    "status.503": {
-        "message": "???????????? (HTTP ??? 503)?"
-    },
-    "status.BadItemSkipped": {
-        "message": "????????????????: ##replace.1##"
-    },
-    "status.FolderDelete.3": {
-        "message": "???????????????? (????? 3)"
-    },
-    "status.FolderDelete.4": {
-        "message": "???????????? (????? 4)?????"
-    },
-    "status.FolderDelete.6": {
-        "message": "???????????????????????????? (????? 6)"
-    },
-    "status.FolderDelete.9": {
-        "message": "Invalid synchronization key (status 9), resyncing"
-    },
-    "status.FolderSync.9": {
-        "message": "Invalid synchronization key (status 9), resyncing"
-    },
-    "status.InvalidServerOptions": {
-        "message": "The server does not provide information about the supported ActiveSync versions. Is EAS blocked for this user or this client (TbSync)? You could try to set the ActiveSync version manually."
-    },
-    "status.OK": {
-        "message": "OK"
-    },
-    "status.ServerRejectedRequest": {
-        "message": "The EAS Server rejected the last request."
-    },
-    "status.ServerRejectedSomeItems": {
-        "message": "The EAS server did not accept ##replace.1## elements."
-    },
-    "status.Sync.12": {
-        "message": "????????????????? (????? 12)?????"
-    },
-    "status.Sync.3": {
-        "message": "Invalid synchronization key (status 3), resyncing"
-    },
-    "status.Sync.4": {
-        "message": "?????????? (????? 4)"
-    },
-    "status.Sync.5": {
-        "message": "???????????????????????? (????? 5)"
-    },
-    "status.Sync.6": {
-        "message": "????????? (????? 6)"
-    },
-    "status.Sync.8": {
-        "message": "?????????????? (????? 8)"
-    },
-    "status.aborted": {
-        "message": "?????????"
-    },
-    "status.disabled": {
-        "message": "??"
-    },
-    "status.empty-response": {
-        "message": "Server sends unexpected empty response."
-    },
-    "status.forbiddenCalendarItemInTasksFolder": {
-        "message": "Forbidden calendar item in a task folder (please resort)"
-    },
-    "status.forbiddenTasksItemInCalendarFolder": {
-        "message": "Forbidden task item in a calendar folder (please resort)"
-    },
-    "status.global.101": {
-        "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 101)."
-    },
-    "status.global.102": {
-        "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 102)."
-    },
-    "status.global.103": {
-        "message": "The XML provided in the request does not follow the protocol requirements (EAS Error 103)."
-    },
-    "status.global.110": {
-        "message": "The server reported an internal error and we should not retry immediately. Automatic periodic sync has been disabled for 30 minutes (EAS Error 110)."
-    },
-    "status.global.clientdenied": {
-        "message": "EAS ????? <## replace.2 ##> (????? ## replace.1 ##) ?????TbSync ??????????????????????????"
-    },
-    "status.httperror": {
-        "message": "????????? ??? (HTTP ????? ##replace.1##)?"
-    },
-    "status.invalid": {
-        "message": "Invalid server response (junk)."
-    },
-    "status.malformed-xml": {
-        "message": "XML ???????????????????????????"
-    },
-    "status.modified": {
-        "message": "???????"
-    },
-    "status.network": {
-        "message": "???????????? (##replace.1##)?"
-    },
-    "status.networkerror": {
-        "message": "?????????????"
-    },
-    "status.nosupportedeasversion": {
-        "message": "????? ActiveSync v2.5 ??? v14.0 ??????????? (##replace.1## ??)?TbSync ???? ActiveSync ?????????????"
-    },
-    "status.notargets": {
-        "message": "Aborting Sync, because sync targets could not be created."
-    },
-    "status.notsupportedeasversion": {
-        "message": "?????????? ActiveSync v##replace.1## ??????????? (##replace.2## ??)?"
-    },
-    "status.notsyncronized": {
-        "message": "Account needs to be synchronized, at least one item is out of sync."
-    },
-    "status.nouserhost": {
-        "message": "Missing username and/or server. Please provide those values."
-    },
-    "status.pending": {
-        "message": "????"
-    },
-    "status.policy.2": {
-        "message": "There is no policy for this client. Contact your server administrator or disable provisioning for this account."
-    },
-    "status.policy.3": {
-        "message": "Unknown PolicyType value. Contact your server administrator or disable provisioning for this account."
-    },
-    "status.policy.4": {
-        "message": "The policy data on the server is corrupted (possibly tampered with). Contact your server administrator or disable provisioning for this account."
-    },
-    "status.policy.5": {
-        "message": "The client is acknowledging the wrong policy key. Contact your server administrator or disable provisioning for this account."
-    },
-    "status.provision": {
-        "message": "Provisioning failed with status <##replace.1##>"
-    },
-    "status.response-contains-no-data": {
-        "message": "Response from the server contains no data."
-    },
-    "status.resync-loop": {
-        "message": "There was an error from which we could not recover by resyncing the account. Please disable the account and try again. (Error: resync loop)"
-    },
-    "status.security": {
-        "message": "?????????????????Thunderbird ??????????????????????????????????????? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "????????????????????"
-    },
-    "status.syncing": {
-        "message": "???"
-    },
-    "status.timeout": {
-        "message": "??????????????"
-    },
-    "status.wbxml-parse-error": {
-        "message": "Server sends unreadable response."
-    },
-    "status.wbxmlerror": {
-        "message": "Sync failed. Server responded with status <##replace.1##>."
-    },
-    "status.wbxmlmissingfield": {
-        "message": "ActiveSync ???????: ??????? <##replace.1##> ?????????????????"
-    },
-    "syncstate.accountdone": {
-        "message": "Finished account"
-    },
-    "syncstate.done": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.eval.response.autodiscover": {
-        "message": "Processing updated server settings"
-    },
-    "syncstate.eval.response.deletefolder": {
-        "message": "Folder deleted"
-    },
-    "syncstate.eval.response.estimate": {
-        "message": "Processing change estimate"
-    },
-    "syncstate.eval.response.folders": {
-        "message": "Processing folder list update"
-    },
-    "syncstate.eval.response.localchanges": {
-        "message": "Processing acknowledgment of local changes"
-    },
-    "syncstate.eval.response.localdeletes": {
-        "message": "Processing acknowledgment of local deletes"
-    },
-    "syncstate.eval.response.options": {
-        "message": "Processing server options"
-    },
-    "syncstate.eval.response.provision": {
-        "message": "Processing provision"
-    },
-    "syncstate.eval.response.remotechanges": {
-        "message": "Processing remote changes"
-    },
-    "syncstate.eval.response.revertlocalchanges": {
-        "message": "Reverting local changes"
-    },
-    "syncstate.eval.response.setdeviceinfo": {
-        "message": "??????????"
-    },
-    "syncstate.eval.response.synckey": {
-        "message": "Processing SyncKey"
-    },
-    "syncstate.prepare.request.autodiscover": {
-        "message": "Requesting updated server settings"
-    },
-    "syncstate.prepare.request.deletefolder": {
-        "message": "??????????"
-    },
-    "syncstate.prepare.request.estimate": {
-        "message": "Requesting change estimate"
-    },
-    "syncstate.prepare.request.folders": {
-        "message": "??????????????"
-    },
-    "syncstate.prepare.request.localchanges": {
-        "message": "???????????"
-    },
-    "syncstate.prepare.request.localdeletes": {
-        "message": "???????????"
-    },
-    "syncstate.prepare.request.options": {
-        "message": "Requesting server options"
-    },
-    "syncstate.prepare.request.provision": {
-        "message": "Requesting provision"
-    },
-    "syncstate.prepare.request.remotechanges": {
-        "message": "Requesting remote changes"
-    },
-    "syncstate.prepare.request.revertlocalchanges": {
-        "message": "???????????"
-    },
-    "syncstate.prepare.request.setdeviceinfo": {
-        "message": "??????????"
-    },
-    "syncstate.prepare.request.synckey": {
-        "message": "???????????"
-    },
-    "syncstate.preparing": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.send.request.autodiscover": {
-        "message": "Waiting for updated server settings"
-    },
-    "syncstate.send.request.deletefolder": {
-        "message": "???????????????"
-    },
-    "syncstate.send.request.estimate": {
-        "message": "Waiting for change estimate"
-    },
-    "syncstate.send.request.folders": {
-        "message": "??????????????"
-    },
-    "syncstate.send.request.localchanges": {
-        "message": "??????????????"
-    },
-    "syncstate.send.request.localdeletes": {
-        "message": "??????????????"
-    },
-    "syncstate.send.request.options": {
-        "message": "Waiting for server options"
-    },
-    "syncstate.send.request.provision": {
-        "message": "Waiting for provision"
-    },
-    "syncstate.send.request.remotechanges": {
-        "message": "???????????"
-    },
-    "syncstate.send.request.revertlocalchanges": {
-        "message": "Waiting for most recent versions"
-    },
-    "syncstate.send.request.setdeviceinfo": {
-        "message": "??????????"
-    },
-    "syncstate.send.request.synckey": {
-        "message": "????????"
-    },
-    "syncstate.syncing": {
-        "message": "???????"
-    }
-}
+{
+    "abCard.Anniversary": {
+        "message": "???:"
+    },
+    "abCard.AssistantName": {
+        "message": "??????:"
+    },
+    "abCard.AssistantPhoneNumber": {
+        "message": "???????????:"
+    },
+    "abCard.Business2PhoneNumber": {
+        "message": "??????? 2:"
+    },
+    "abCard.BusinessFaxNumber": {
+        "message": "??? FAX:"
+    },
+    "abCard.CarPhoneNumber": {
+        "message": "???????:"
+    },
+    "abCard.CompanyMainPhone": {
+        "message": "???????:"
+    },
+    "abCard.Email3Address": {
+        "message": "????? 2:"
+    },
+    "abCard.Home2PhoneNumber": {
+        "message": "?????? 2:"
+    },
+    "abCard.ManagerName": {
+        "message": "??????:"
+    },
+    "abCard.MiddleName": {
+        "message": "??????:"
+    },
+    "abCard.OtherAddress": {
+        "message": "??:"
+    },
+    "abCard.OtherCity": {
+        "message": "?:"
+    },
+    "abCard.OtherCountry": {
+        "message": "?:"
+    },
+    "abCard.OtherState": {
+        "message": "????:"
+    },
+    "abCard.OtherZip": {
+        "message": "????:"
+    },
+    "abCard.RadioPhoneNumber": {
+        "message": "???????:"
+    },
+    "abCard.Spouse": {
+        "message": "???/?????:"
+    },
+    "abCard.header.eas": {
+        "message": "?????? (EAS)"
+    },
+    "abCard.header.homenumbers": {
+        "message": "?????? 3:"
+    },
+    "abCard.header.messaging": {
+        "message": "???????:"
+    },
+    "abCard.header.otheraddress": {
+        "message": "???????? (EAS)"
+    },
+    "abCard.header.othernumbers": {
+        "message": "???????:"
+    },
+    "abCard.header.people": {
+        "message": "People:"
+    },
+    "abCard.header.worknumbers": {
+        "message": "??????? 3:"
+    },
+    "acl.readonly": {
+        "message": "Read-only server access (revert local changes)"
+    },
+    "acl.readwrite": {
+        "message": "Read from and write to server"
+    },
+    "add.description": {
+        "message": "??????????????????????????????????????????? "
+    },
+    "add.name": {
+        "message": "??????:"
+    },
+    "add.ok": {
+        "message": "????????"
+    },
+    "add.password": {
+        "message": "?????:"
+    },
+    "add.server": {
+        "message": "??????:"
+    },
+    "add.shortdescription": {
+        "message": "???????"
+    },
+    "add.title": {
+        "message": "Adding an Exchange ActiveSync account to TbSync"
+    },
+    "add.url": {
+        "message": "???? ????:"
+    },
+    "add.urldescription": {
+        "message": "?????????????????????????? (?: mail.yourserver.com)? ??????? URL ???????????? (?: https://mail.yourserver.com/Microsoft-Server-ActiveSync)?"
+    },
+    "add.user": {
+        "message": "????? (?????????):"
+    },
+    "autocomplete.serverdirectory": {
+        "message": "global server directory"
+    },
+    "autodiscover.Failed": {
+        "message": "???? <##user##> ???????????????????????????????ActiveSync?????????????????????????????????"
+    },
+    "autodiscover.NeedEmail": {
+        "message": "??????????????????????????????"
+    },
+    "autodiscover.Ok": {
+        "message": "Autodiscover completed successfully, you can now check the optional settings and establish the synchronization connection."
+    },
+    "autodiscover.Querying": {
+        "message": "???????"
+    },
+    "config.auto": {
+        "message": "ActiveSync ?????? (????)"
+    },
+    "config.custom": {
+        "message": "ActiveSync ??????"
+    },
+    "deletefolder.confirm": {
+        "message": "???????????? '## replace.1 ##' ???????????"
+    },
+    "deletefolder.menuentry": {
+        "message": "????????? '## replace.1 ##' ??????"
+    },
+    "deletefolder.notallowed": {
+        "message": "???????????????? ?##replace.1##? ?????????????"
+    },
+    "extensionDescription": {
+        "message": "TbSync ? Exchange ActiveSync ?????????????????? (?????????????)?"
+    },
+    "extensionName": {
+        "message": "Exchange ActiveSync ??????"
+    },
+    "helplink.BadItemSkipped": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
+    },
+    "helplink.global.clientdenied": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "manager.tabs.accountsettings": {
+        "message": "???????"
+    },
+    "manager.tabs.outOfOffice": {
+        "message": "Auto responder"
+    },
+    "manager.tabs.syncsettings": {
+        "message": "?????"
+    },
+    "newaccount.add_auto": {
+        "message": "?????????????????"
+    },
+    "newaccount.add_custom": {
+        "message": "????????"
+    },
+    "pref.AccountName": {
+        "message": "??"
+    },
+    "pref.ActiveSyncVersion": {
+        "message": "ActiveSync ?????"
+    },
+    "pref.DeviceId": {
+        "message": "ActiveSync ???? ID"
+    },
+    "pref.ServerName": {
+        "message": "???? ????"
+    },
+    "pref.ServerNameDescription": {
+        "message": "?: mail.yourserver.com"
+    },
+    "pref.ShowTrashedFolders": {
+        "message": "Show folders found in trash"
+    },
+    "pref.UserName": {
+        "message": "?????"
+    },
+    "pref.UserNameDescription": {
+        "message": "???????????????????????????????"
+    },
+    "pref.autodetect": {
+        "message": "?????????????"
+    },
+    "pref.birthday": {
+        "message": "Send birthday information"
+    },
+    "pref.calendaroptions": {
+        "message": "???????"
+    },
+    "pref.contactoptions": {
+        "message": "?????"
+    },
+    "pref.displayoverride": {
+        "message": "???????+???????"
+    },
+    "pref.generaloptions": {
+        "message": "????"
+    },
+    "pref.provision": {
+        "message": "??????????? (Kerio ???)"
+    },
+    "pref.seperator.comma": {
+        "message": "???"
+    },
+    "pref.seperator.description": {
+        "message": "Separator for multiline address field."
+    },
+    "pref.seperator.linebreak": {
+        "message": "??"
+    },
+    "pref.synclimit.1month": {
+        "message": "4 ?????"
+    },
+    "pref.synclimit.2weeks": {
+        "message": "2 ?????"
+    },
+    "pref.synclimit.3month": {
+        "message": "3 ?????"
+    },
+    "pref.synclimit.6month": {
+        "message": "6 ?????"
+    },
+    "pref.synclimit.all": {
+        "message": "??"
+    },
+    "pref.synclimit.description": {
+        "message": "??????: "
+    },
+    "pref.usehttps": {
+        "message": "?????????? (https ???????)"
+    },
+    "recyclebin": {
+        "message": "???"
+    },
+    "servertype.auto": {
+        "message": "????"
+    },
+    "servertype.custom": {
+        "message": "??????"
+    },
+    "servertype.description.auto": {
+        "message": "??? ActiveSync ?????????????????????????????????"
+    },
+    "servertype.description.custom": {
+        "message": "???????????????????????????????????????"
+    },
+    "servertype.description.office365": {
+        "message": "Office 365?????????????OAuth 2.0 ?????????????????????????Multi-Factor-Authentication (MFA??????) ???????????"
+    },
+    "servertype.office365": {
+        "message": "Microsoft Office 365"
+    },
+    "servertype.unlock": {
+        "message": "Double click to unlock all predefined server settings."
+    },
+    "status.401": {
+        "message": "???????????????????????????? (HTTP ??? 401)?"
+    },
+    "status.403": {
+        "message": "?????????????? (??) (HTTP ??? 403)?"
+    },
+    "status.404": {
+        "message": "???????????? (HTTP ??? 404)?"
+    },
+    "status.449": {
+        "message": "????????????????????? (HTTP ??? 449)?"
+    },
+    "status.500": {
+        "message": "??????? ??? (HTTP ??? 500)?"
+    },
+    "status.503": {
+        "message": "???????????? (HTTP ??? 503)?"
+    },
+    "status.BadItemSkipped": {
+        "message": "????????????????: ##replace.1##"
+    },
+    "status.FolderDelete.3": {
+        "message": "???????????????? (????? 3)"
+    },
+    "status.FolderDelete.4": {
+        "message": "???????????? (????? 4)?????"
+    },
+    "status.FolderDelete.6": {
+        "message": "???????????????????????????? (????? 6)"
+    },
+    "status.FolderDelete.9": {
+        "message": "Invalid synchronization key (status 9), resyncing"
+    },
+    "status.FolderSync.9": {
+        "message": "Invalid synchronization key (status 9), resyncing"
+    },
+    "status.InvalidServerOptions": {
+        "message": "The server does not provide information about the supported ActiveSync versions. Is EAS blocked for this user or this client (TbSync)? You could try to set the ActiveSync version manually."
+    },
+    "status.OK": {
+        "message": "OK"
+    },
+    "status.ServerRejectedRequest": {
+        "message": "The EAS Server rejected the last request."
+    },
+    "status.ServerRejectedSomeItems": {
+        "message": "The EAS server did not accept ##replace.1## elements."
+    },
+    "status.Sync.12": {
+        "message": "????????????????? (????? 12)?????"
+    },
+    "status.Sync.3": {
+        "message": "Invalid synchronization key (status 3), resyncing"
+    },
+    "status.Sync.4": {
+        "message": "?????????? (????? 4)"
+    },
+    "status.Sync.5": {
+        "message": "???????????????????????? (????? 5)"
+    },
+    "status.Sync.6": {
+        "message": "????????? (????? 6)"
+    },
+    "status.Sync.8": {
+        "message": "?????????????? (????? 8)"
+    },
+    "status.aborted": {
+        "message": "?????????"
+    },
+    "status.disabled": {
+        "message": "??"
+    },
+    "status.empty-response": {
+        "message": "Server sends unexpected empty response."
+    },
+    "status.forbiddenCalendarItemInTasksFolder": {
+        "message": "Forbidden calendar item in a task folder (please resort)"
+    },
+    "status.forbiddenTasksItemInCalendarFolder": {
+        "message": "Forbidden task item in a calendar folder (please resort)"
+    },
+    "status.global.101": {
+        "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 101)."
+    },
+    "status.global.102": {
+        "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 102)."
+    },
+    "status.global.103": {
+        "message": "The XML provided in the request does not follow the protocol requirements (EAS Error 103)."
+    },
+    "status.global.110": {
+        "message": "The server reported an internal error and we should not retry immediately. Automatic periodic sync has been disabled for 30 minutes (EAS Error 110)."
+    },
+    "status.global.clientdenied": {
+        "message": "EAS ????? <## replace.2 ##> (????? ## replace.1 ##) ?????TbSync ??????????????????????????"
+    },
+    "status.httperror": {
+        "message": "????????? ??? (HTTP ????? ##replace.1##)?"
+    },
+    "status.invalid": {
+        "message": "Invalid server response (junk)."
+    },
+    "status.malformed-xml": {
+        "message": "XML ???????????????????????????"
+    },
+    "status.modified": {
+        "message": "???????"
+    },
+    "status.network": {
+        "message": "???????????? (##replace.1##)?"
+    },
+    "status.networkerror": {
+        "message": "?????????????"
+    },
+    "status.nosupportedeasversion": {
+        "message": "????? ActiveSync v2.5 ??? v14.0 ??????????? (##replace.1## ??)?TbSync ???? ActiveSync ?????????????"
+    },
+    "status.notargets": {
+        "message": "Aborting Sync, because sync targets could not be created."
+    },
+    "status.notsupportedeasversion": {
+        "message": "?????????? ActiveSync v##replace.1## ??????????? (##replace.2## ??)?"
+    },
+    "status.notsyncronized": {
+        "message": "Account needs to be synchronized, at least one item is out of sync."
+    },
+    "status.nouserhost": {
+        "message": "Missing username and/or server. Please provide those values."
+    },
+    "status.pending": {
+        "message": "????"
+    },
+    "status.policy.2": {
+        "message": "There is no policy for this client. Contact your server administrator or disable provisioning for this account."
+    },
+    "status.policy.3": {
+        "message": "Unknown PolicyType value. Contact your server administrator or disable provisioning for this account."
+    },
+    "status.policy.4": {
+        "message": "The policy data on the server is corrupted (possibly tampered with). Contact your server administrator or disable provisioning for this account."
+    },
+    "status.policy.5": {
+        "message": "The client is acknowledging the wrong policy key. Contact your server administrator or disable provisioning for this account."
+    },
+    "status.provision": {
+        "message": "Provisioning failed with status <##replace.1##>"
+    },
+    "status.response-contains-no-data": {
+        "message": "Response from the server contains no data."
+    },
+    "status.resync-loop": {
+        "message": "There was an error from which we could not recover by resyncing the account. Please disable the account and try again. (Error: resync loop)"
+    },
+    "status.security": {
+        "message": "?????????????????Thunderbird ??????????????????????????????????????? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "????????????????????"
+    },
+    "status.syncing": {
+        "message": "???"
+    },
+    "status.timeout": {
+        "message": "??????????????"
+    },
+    "status.wbxml-parse-error": {
+        "message": "Server sends unreadable response."
+    },
+    "status.wbxmlerror": {
+        "message": "Sync failed. Server responded with status <##replace.1##>."
+    },
+    "status.wbxmlmissingfield": {
+        "message": "ActiveSync ???????: ??????? <##replace.1##> ?????????????????"
+    },
+    "syncstate.accountdone": {
+        "message": "Finished account"
+    },
+    "syncstate.done": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.eval.response.autodiscover": {
+        "message": "Processing updated server settings"
+    },
+    "syncstate.eval.response.deletefolder": {
+        "message": "Folder deleted"
+    },
+    "syncstate.eval.response.estimate": {
+        "message": "Processing change estimate"
+    },
+    "syncstate.eval.response.folders": {
+        "message": "Processing folder list update"
+    },
+    "syncstate.eval.response.localchanges": {
+        "message": "Processing acknowledgment of local changes"
+    },
+    "syncstate.eval.response.localdeletes": {
+        "message": "Processing acknowledgment of local deletes"
+    },
+    "syncstate.eval.response.options": {
+        "message": "Processing server options"
+    },
+    "syncstate.eval.response.provision": {
+        "message": "Processing provision"
+    },
+    "syncstate.eval.response.remotechanges": {
+        "message": "Processing remote changes"
+    },
+    "syncstate.eval.response.revertlocalchanges": {
+        "message": "Reverting local changes"
+    },
+    "syncstate.eval.response.setdeviceinfo": {
+        "message": "??????????"
+    },
+    "syncstate.eval.response.synckey": {
+        "message": "Processing SyncKey"
+    },
+    "syncstate.prepare.request.autodiscover": {
+        "message": "Requesting updated server settings"
+    },
+    "syncstate.prepare.request.deletefolder": {
+        "message": "??????????"
+    },
+    "syncstate.prepare.request.estimate": {
+        "message": "Requesting change estimate"
+    },
+    "syncstate.prepare.request.folders": {
+        "message": "??????????????"
+    },
+    "syncstate.prepare.request.localchanges": {
+        "message": "???????????"
+    },
+    "syncstate.prepare.request.localdeletes": {
+        "message": "???????????"
+    },
+    "syncstate.prepare.request.options": {
+        "message": "Requesting server options"
+    },
+    "syncstate.prepare.request.provision": {
+        "message": "Requesting provision"
+    },
+    "syncstate.prepare.request.remotechanges": {
+        "message": "Requesting remote changes"
+    },
+    "syncstate.prepare.request.revertlocalchanges": {
+        "message": "???????????"
+    },
+    "syncstate.prepare.request.setdeviceinfo": {
+        "message": "??????????"
+    },
+    "syncstate.prepare.request.synckey": {
+        "message": "???????????"
+    },
+    "syncstate.preparing": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.send.request.autodiscover": {
+        "message": "Waiting for updated server settings"
+    },
+    "syncstate.send.request.deletefolder": {
+        "message": "???????????????"
+    },
+    "syncstate.send.request.estimate": {
+        "message": "Waiting for change estimate"
+    },
+    "syncstate.send.request.folders": {
+        "message": "??????????????"
+    },
+    "syncstate.send.request.localchanges": {
+        "message": "??????????????"
+    },
+    "syncstate.send.request.localdeletes": {
+        "message": "??????????????"
+    },
+    "syncstate.send.request.options": {
+        "message": "Waiting for server options"
+    },
+    "syncstate.send.request.provision": {
+        "message": "Waiting for provision"
+    },
+    "syncstate.send.request.remotechanges": {
+        "message": "???????????"
+    },
+    "syncstate.send.request.revertlocalchanges": {
+        "message": "Waiting for most recent versions"
+    },
+    "syncstate.send.request.setdeviceinfo": {
+        "message": "??????????"
+    },
+    "syncstate.send.request.synckey": {
+        "message": "????????"
+    },
+    "syncstate.syncing": {
+        "message": "???????"
+    }
+}
diff -Nru eas4tbsync-4.11/_locales/pl/messages.json eas4tbsync-4.17/_locales/pl/messages.json
--- eas4tbsync-4.11/_locales/pl/messages.json	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/_locales/pl/messages.json	2025-05-15 13:21:20.000000000 +0200
@@ -1,566 +1,566 @@
-{
-    "abCard.Anniversary": {
-        "message": "Rocznica:"
-    },
-    "abCard.AssistantName": {
-        "message": "Asystent:"
-    },
-    "abCard.AssistantPhoneNumber": {
-        "message": "Telefon Asystenta:"
-    },
-    "abCard.Business2PhoneNumber": {
-        "message": "Alternatywny Telefon S?u?bowy:"
-    },
-    "abCard.BusinessFaxNumber": {
-        "message": "Faks s?u?bowy:"
-    },
-    "abCard.CarPhoneNumber": {
-        "message": "Telefon w Aucie:"
-    },
-    "abCard.CompanyMainPhone": {
-        "message": "G??wny Telefon S?u?bowy:"
-    },
-    "abCard.Email3Address": {
-        "message": "Alternatywny e-mail:"
-    },
-    "abCard.Home2PhoneNumber": {
-        "message": "Alternatywny Telefon Domowy:"
-    },
-    "abCard.ManagerName": {
-        "message": "Mened?er:"
-    },
-    "abCard.MiddleName": {
-        "message": "Drugie imi?:"
-    },
-    "abCard.OtherAddress": {
-        "message": "Adres:"
-    },
-    "abCard.OtherCity": {
-        "message": "Miasto:"
-    },
-    "abCard.OtherCountry": {
-        "message": "Pa?stwo:"
-    },
-    "abCard.OtherState": {
-        "message": "Wojew?dztwo:"
-    },
-    "abCard.OtherZip": {
-        "message": "Kod pocztowy:"
-    },
-    "abCard.RadioPhoneNumber": {
-        "message": "Radiotelefon:"
-    },
-    "abCard.Spouse": {
-        "message": "Ma??onek:"
-    },
-    "abCard.header.eas": {
-        "message": "Inne Pola (EAS)"
-    },
-    "abCard.header.homenumbers": {
-        "message": "Dodatkowe numery domowe:"
-    },
-    "abCard.header.messaging": {
-        "message": "Komunikatory:"
-    },
-    "abCard.header.otheraddress": {
-        "message": "Inne Adresy (EAS)"
-    },
-    "abCard.header.othernumbers": {
-        "message": "Dodatkowe numery:"
-    },
-    "abCard.header.people": {
-        "message": "Osoby:"
-    },
-    "abCard.header.worknumbers": {
-        "message": "Dodatkowe numery s?u?bowe:"
-    },
-    "acl.readonly": {
-        "message": "Dost?p do serwera tylko do odczytu (cofnij zmiany lokalne)"
-    },
-    "acl.readwrite": {
-        "message": "Odczytuj i zapisuj na serwer"
-    },
-    "add.description": {
-        "message": "Wybierz jedn? z dost?pnych opcji konfiguracji serwera i wprowad? wymagane dane. "
-    },
-    "add.name": {
-        "message": "Nazwa konta:"
-    },
-    "add.ok": {
-        "message": "Dodaj konto"
-    },
-    "add.password": {
-        "message": "Has?o:"
-    },
-    "add.server": {
-        "message": "Konfiguracja serwera:"
-    },
-    "add.shortdescription": {
-        "message": "Informacje o koncie"
-    },
-    "add.title": {
-        "message": "Dodawanie konta Exchange ActiveSync do TbSync"
-    },
-    "add.url": {
-        "message": "Adres serwera:"
-    },
-    "add.urldescription": {
-        "message": "Powinno wystarczy? podanie tylko podstawowego adresu serwera (np.: mail.twojserwer.com). Jednak?e mo?liwe jest r?wnie? podanie pe?nego adresu URL (np.: https://mail.twojserwer.com/Microsoft-Server-ActiveSync)."
-    },
-    "add.user": {
-        "message": "Nazwa u?ytkownika (adres e-mail):"
-    },
-    "autocomplete.serverdirectory": {
-        "message": "globalny katalog serwera"
-    },
-    "autodiscover.Failed": {
-        "message": "Auto-wykrywanie dla u?ytkownika <##user##> nie powiod?o si?. Podane dane uwierzytelniaj?ce by?y nieprawid?owe lub dostawca ActiveSync ma tymczasowy problem lub nie obs?uguje funkcji automatycznego wykrywania."
-    },
-    "autodiscover.NeedEmail": {
-        "message": "Automatyczne wykrywanie potrzebuje prawid?owego adresu e-mail jako nazwy u?ytkownika."
-    },
-    "autodiscover.Ok": {
-        "message": "Automatyczne wykrywanie zako?czy?o si? pomy?lnie, mo?esz teraz sprawdzi? ustawienia opcjonalne i ustanowi? po??czenie synchronizacji."
-    },
-    "autodiscover.Querying": {
-        "message": "Wyszukiwanie ustawie??"
-    },
-    "config.auto": {
-        "message": "Konfiguracja serwera ActiveSync (Auto-wykrywanie)"
-    },
-    "config.custom": {
-        "message": "Konfiguracja serwera ActiveSync"
-    },
-    "deletefolder.confirm": {
-        "message": "Czy naprawd? chcesz TRWALE USUN?? folder ?##replace.1##? z kosza?"
-    },
-    "deletefolder.menuentry": {
-        "message": "Trwale usu? folder ?##replace.1##? z kosza"
-    },
-    "deletefolder.notallowed": {
-        "message": "Anuluj subskrypcj? folderu ?##replace.1##? przed pr?b? usuni?cia go z kosza."
-    },
-    "extensionDescription": {
-        "message": "Dodaj obs?ug? synchronizacji kont Exchange ActiveSync do TbSync (kontakty, zadania i kalendarze)."
-    },
-    "extensionName": {
-        "message": "Dostawca dla Exchange ActiveSync"
-    },
-    "helplink.BadItemSkipped": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
-    },
-    "helplink.global.clientdenied": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "manager.tabs.accountsettings": {
-        "message": "Ustawienia konta"
-    },
-    "manager.tabs.outOfOffice": {
-        "message": "Automatyczna odpowied?"
-    },
-    "manager.tabs.syncsettings": {
-        "message": "Opcje"
-    },
-    "newaccount.add_auto": {
-        "message": "Wykryj automatycznie ustawienia i dodaj konto"
-    },
-    "newaccount.add_custom": {
-        "message": "Dodaj konto"
-    },
-    "pref.AccountName": {
-        "message": "Opis"
-    },
-    "pref.ActiveSyncVersion": {
-        "message": "Wersja ActiveSync"
-    },
-    "pref.DeviceId": {
-        "message": "ID urz?dzenia ActiveSync"
-    },
-    "pref.ServerName": {
-        "message": "Adres serwera"
-    },
-    "pref.ServerNameDescription": {
-        "message": "np. mail.twojserwer.com"
-    },
-    "pref.ShowTrashedFolders": {
-        "message": "Poka? foldery znalezione w koszu"
-    },
-    "pref.UserName": {
-        "message": "Nazwa u?ytkownika"
-    },
-    "pref.UserNameDescription": {
-        "message": "Nazwa u?ytkownika to zazwyczaj adres e-mail Twojego konta."
-    },
-    "pref.autodetect": {
-        "message": "najlepsza dost?pna"
-    },
-    "pref.birthday": {
-        "message": "Wy?lij informacje o urodzinach"
-    },
-    "pref.calendaroptions": {
-        "message": "Opcje kalendarza"
-    },
-    "pref.contactoptions": {
-        "message": "Opcje kontaktu"
-    },
-    "pref.displayoverride": {
-        "message": "Zast?p nazw? wy?wietlan? ci?giem ?Imi?? + ?Drugie imi??"
-    },
-    "pref.generaloptions": {
-        "message": "Opcje og?lne"
-    },
-    "pref.provision": {
-        "message": "Wymu? provisioning (wymagane przez Kerio)"
-    },
-    "pref.seperator.comma": {
-        "message": "Przecinek"
-    },
-    "pref.seperator.description": {
-        "message": "Separator pola adresu wielowierszowego."
-    },
-    "pref.seperator.linebreak": {
-        "message": "Znak ko?ca linii"
-    },
-    "pref.synclimit.1month": {
-        "message": "z 4 tygodni"
-    },
-    "pref.synclimit.2weeks": {
-        "message": "z 2 tygodni"
-    },
-    "pref.synclimit.3month": {
-        "message": "z 3 miesi?cy"
-    },
-    "pref.synclimit.6month": {
-        "message": "z 6 miesi?cy"
-    },
-    "pref.synclimit.all": {
-        "message": "wszystko"
-    },
-    "pref.synclimit.description": {
-        "message": "Okres synchronizacji: "
-    },
-    "pref.usehttps": {
-        "message": "U?yj bezpiecznego po??czenia (po??cz przez https)"
-    },
-    "recyclebin": {
-        "message": "Kosz"
-    },
-    "servertype.auto": {
-        "message": "Automatyczna konfiguracja"
-    },
-    "servertype.custom": {
-        "message": "Konfiguracja niestandardowa"
-    },
-    "servertype.description.auto": {
-        "message": "Konfiguracja dla wielu serwer?w ActiveSync mo?e zosta? odnaleziona poprzez podanie tylko adresu e-mail."
-    },
-    "servertype.description.custom": {
-        "message": "Skonfiguruj konto, podaj?c r?cznie adres serwera, z kt?rym chcesz si? po??czy?."
-    },
-    "servertype.description.office365": {
-        "message": "Konta po??czone z Office 365 korzystaj? z nowoczesnego procesu uwierzytelniania o nazwie OAuth 2.0, kt?ry obs?uguje r?wnie? uwierzytelnianie wielopoziomowe (MFA)."
-    },
-    "servertype.office365": {
-        "message": "Microsoft Office 365"
-    },
-    "servertype.unlock": {
-        "message": "Kliknij dwukrotnie, aby odblokowa? wszystkie predefiniowane ustawienia serwera."
-    },
-    "status.401": {
-        "message": "Nie mo?na uwierzytelni?, sprawd? nazw? u?ytkownika i has?o (HTTP Error 401)."
-    },
-    "status.403": {
-        "message": "Serwer odrzuci? po??czenie (zabronione) (b??d HTTP 403)."
-    },
-    "status.404": {
-        "message": "U?ytkownik nie znaleziony (b??d HTTP 404)."
-    },
-    "status.449": {
-        "message": "Server requests provisioning (HTTP Error 449)."
-    },
-    "status.500": {
-        "message": "Nieznany b??d serwera (b??d HTTP 500)."
-    },
-    "status.503": {
-        "message": "Us?uga niedost?pna (b??d HTTP 503)."
-    },
-    "status.BadItemSkipped": {
-        "message": "B??dny element pomini?to: ##replace.1##"
-    },
-    "status.FolderDelete.3": {
-        "message": "Nie mo?na usun?? folderu systemowego (status 3)"
-    },
-    "status.FolderDelete.4": {
-        "message": "Folder nie istnieje (status 4), ponowna synchronizacja"
-    },
-    "status.FolderDelete.6": {
-        "message": "Nie mo?na wykona? polecenia, wyst?pi? b??d na serwerze (status 6)"
-    },
-    "status.FolderDelete.9": {
-        "message": "Nieprawid?owy klucz synchronizacji (status 9), ponowna synchronizacja"
-    },
-    "status.FolderSync.9": {
-        "message": "Nieprawid?owy klucz synchronizacji (status 9), ponowna synchronizacja"
-    },
-    "status.InvalidServerOptions": {
-        "message": "Serwer nie dostarcza informacji o obs?ugiwanych wersjach ActiveSync. Czy EAS jest zablokowany dla tego u?ytkownika lub tego klienta (TbSync)? Mo?esz spr?bowa? r?cznie ustawi? wersj? ActiveSync."
-    },
-    "status.OK": {
-        "message": "OK"
-    },
-    "status.ServerRejectedRequest": {
-        "message": "Serwer EAS odrzuci? ostatnie ??danie."
-    },
-    "status.ServerRejectedSomeItems": {
-        "message": "Serwer EAS nie zaakceptowa? #replace.1## element?w."
-    },
-    "status.Sync.12": {
-        "message": "Hierarchia folder?w zmieniona (status 12), ponowna synchronizacja"
-    },
-    "status.Sync.3": {
-        "message": "Nieprawid?owy klucz synchronizacji (status 3), ponowna synchronizacja"
-    },
-    "status.Sync.4": {
-        "message": "Zniekszta?cone ??danie (status 4)"
-    },
-    "status.Sync.5": {
-        "message": "Tymczasowe problemy z serwerem lub nieprawid?owy element (status 5)"
-    },
-    "status.Sync.6": {
-        "message": "Nieprawid?owy element (status 6)"
-    },
-    "status.Sync.8": {
-        "message": "Nie znaleziono obiektu (status 8)"
-    },
-    "status.aborted": {
-        "message": "Nie zsynchronizowane"
-    },
-    "status.disabled": {
-        "message": "Wy??czony"
-    },
-    "status.empty-response": {
-        "message": "Serwer wysy?a nieoczekiwan? pust? odpowied?."
-    },
-    "status.forbiddenCalendarItemInTasksFolder": {
-        "message": "Niedozwolony element kalendarza w folderze zada? (please resort)"
-    },
-    "status.forbiddenTasksItemInCalendarFolder": {
-        "message": "Niedozwolony element zadania w folderze kalendarza (please resort)"
-    },
-    "status.global.101": {
-        "message": "??danie zawiera WBXML, ale nie mo?na go zdekodowa? do formatu XML (b??d EAS 101)."
-    },
-    "status.global.102": {
-        "message": "??danie zawiera WBXML, ale nie mo?na go zdekodowa? do formatu XML (b??d EAS 102)."
-    },
-    "status.global.103": {
-        "message": "XML podany w ??daniu nie jest zgodny z wymaganiami protoko?u (b??d EAS 103)."
-    },
-    "status.global.110": {
-        "message": "Serwer zg?osi? b??d wewn?trzny i nie powinni?my natychmiast ponawia? pr?by. Automatyczna synchronizacja okresowa zosta?a wy??czona na 30 minut (b??d EAS 110)."
-    },
-    "status.global.clientdenied": {
-        "message": "Serwer EAS zg?asza <##replace.2##> (status ##replace.1##) i nie zezwala TbSync na dost?p do Twojego konta."
-    },
-    "status.httperror": {
-        "message": "B??d komunikacji (status HTTP ##replace.1##)."
-    },
-    "status.invalid": {
-        "message": "Niepoprawna odpowied? serwera (?mieci)."
-    },
-    "status.malformed-xml": {
-        "message": "Nie mo?na przetworzy? XML. Sprawd? dziennik zdarze?, aby uzyska? szczeg??y."
-    },
-    "status.modified": {
-        "message": "Zmiany lokalne"
-    },
-    "status.network": {
-        "message": "Nie mo?na po??czy? z serwerem (##replace.1##)."
-    },
-    "status.networkerror": {
-        "message": "Nie mo?na po??czy? z serwerem."
-    },
-    "status.nosupportedeasversion": {
-        "message": "Serwer nie obs?uguje ActiveSync v2.5 lub v14.0 (tylko ##replace.1##). TbSync nie b?dzie dzia?a? z tym serwerem ActiveSync."
-    },
-    "status.notargets": {
-        "message": "Przerywam synchronizacj?, poniewa? nie mo?na utworzy? cel?w synchronizacji."
-    },
-    "status.notsupportedeasversion": {
-        "message": "Serwer nie wspiera wybranego ActiveSync v##replace.1## (tylko ##replace.2##)."
-    },
-    "status.notsyncronized": {
-        "message": "Konto musi zosta? zsynchronizowane, co najmniej jeden element nie jest zsynchronizowany."
-    },
-    "status.nouserhost": {
-        "message": "Brak nazwy u?ytkownika i/lub serwera. Prosz? poda? te warto?ci."
-    },
-    "status.pending": {
-        "message": "Oczekiwanie na synchronizacj?"
-    },
-    "status.policy.2": {
-        "message": "Brak zasad dla tego klienta. Skontaktuj si? z administratorem serwera lub wy??cz provisioning dla tego konta."
-    },
-    "status.policy.3": {
-        "message": "Nieznana warto?? PolicyType. Skontaktuj si? z administratorem serwera lub wy??cz provisioning dla tego konta."
-    },
-    "status.policy.4": {
-        "message": "Dane zasad na serwerze s? uszkodzone (prawdopodobnie zmienione/sfa?szowane). Skontaktuj si? z administratorem serwera lub wy??cz provisioning dla tego konta."
-    },
-    "status.policy.5": {
-        "message": "Klient potwierdza z?y klucz zasad. Skontaktuj si? z administratorem serwera lub wy??cz provisioning dla tego konta."
-    },
-    "status.provision": {
-        "message": "Niepowodzenie provisioning ze statusem <##replace.1##>"
-    },
-    "status.response-contains-no-data": {
-        "message": "Odpowied? z serwera nie zawiera danych."
-    },
-    "status.resync-loop": {
-        "message": "Wyst?pi? b??d, kt?rego nie uda?o si? naprawi? poprzez ponowne zsynchronizowanie konta. Wy??cz konto i spr?buj ponownie. (B??d: p?tla resynchronizacji)"
-    },
-    "status.security": {
-        "message": "Nie mo?na nawi?za? bezpiecznego po??czenia. Czy u?ywasz w?asnego podpisu lub w inny spos?b niezaufanego certyfikatu bez importowania go do Thunderbirda? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "Jeszcze nie obs?ugiwane, pomini?to"
-    },
-    "status.syncing": {
-        "message": "Synchronizuj?"
-    },
-    "status.timeout": {
-        "message": "Przekroczony limit czasu po??czenia."
-    },
-    "status.wbxml-parse-error": {
-        "message": "Serwer wysy?a nieczyteln? odpowied?."
-    },
-    "status.wbxmlerror": {
-        "message": "Synchronizacja nie powiod?a si?. Serwer odpowiedzia? statusem <##replace.1##>."
-    },
-    "status.wbxmlmissingfield": {
-        "message": "Naruszenie protoko?u ActiveSync: W odpowiedzi serwera brakuje obowi?zkowego pola <##replace.1##>."
-    },
-    "syncstate.accountdone": {
-        "message": "Konto gotowe"
-    },
-    "syncstate.done": {
-        "message": "Przygotowuj? nast?pny element do synchronizacji"
-    },
-    "syncstate.eval.response.autodiscover": {
-        "message": "Przetwarzanie zaktualizowanych ustawie? serwera"
-    },
-    "syncstate.eval.response.deletefolder": {
-        "message": "Folder usuni?ty"
-    },
-    "syncstate.eval.response.estimate": {
-        "message": "Przetwarzanie oszacowanych zmian"
-    },
-    "syncstate.eval.response.folders": {
-        "message": "Przetwarzanie aktualizacji listy folder?w"
-    },
-    "syncstate.eval.response.localchanges": {
-        "message": "Przetwarzanie potwierdzenia lokalnych zmian"
-    },
-    "syncstate.eval.response.localdeletes": {
-        "message": "Przetwarzanie potwierdzenia usuni?cia lokalnego"
-    },
-    "syncstate.eval.response.options": {
-        "message": "Przetwarzanie opcji serwera"
-    },
-    "syncstate.eval.response.provision": {
-        "message": "Przetwarzanie provision"
-    },
-    "syncstate.eval.response.remotechanges": {
-        "message": "Przetwarzanie zdalnych zmian"
-    },
-    "syncstate.eval.response.revertlocalchanges": {
-        "message": "Wycofywanie zmian lokalnych"
-    },
-    "syncstate.eval.response.setdeviceinfo": {
-        "message": "Wysy?anie informacji o urz?dzeniu"
-    },
-    "syncstate.eval.response.synckey": {
-        "message": "Przetwarzanie SyncKey"
-    },
-    "syncstate.prepare.request.autodiscover": {
-        "message": "??danie zaktualizowanych ustawie? serwera"
-    },
-    "syncstate.prepare.request.deletefolder": {
-        "message": "Przygotowanie do usuni?cia folderu"
-    },
-    "syncstate.prepare.request.estimate": {
-        "message": "??danie oszacowanych zmian"
-    },
-    "syncstate.prepare.request.folders": {
-        "message": "Wysy?anie aktualizacji listy folder?w"
-    },
-    "syncstate.prepare.request.localchanges": {
-        "message": "Wysy?anie zmian lokalnych"
-    },
-    "syncstate.prepare.request.localdeletes": {
-        "message": "Wysy?anie usuni?tych lokalnie"
-    },
-    "syncstate.prepare.request.options": {
-        "message": "??danie opcji serwera"
-    },
-    "syncstate.prepare.request.provision": {
-        "message": "??danie provision"
-    },
-    "syncstate.prepare.request.remotechanges": {
-        "message": "??danie zdalnych zmian"
-    },
-    "syncstate.prepare.request.revertlocalchanges": {
-        "message": "Zbieranie zmian lokalnych"
-    },
-    "syncstate.prepare.request.setdeviceinfo": {
-        "message": "Wysy?anie informacji o urz?dzeniu"
-    },
-    "syncstate.prepare.request.synckey": {
-        "message": "??danie SyncKey"
-    },
-    "syncstate.preparing": {
-        "message": "Przygotowuj? nast?pny element do synchronizacji"
-    },
-    "syncstate.send.request.autodiscover": {
-        "message": "Oczekiwanie na zaktualizowane ustawienia serwera"
-    },
-    "syncstate.send.request.deletefolder": {
-        "message": "Oczekiwanie na usuni?cie folderu"
-    },
-    "syncstate.send.request.estimate": {
-        "message": "Oczekiwanie na oszacowanie zmian"
-    },
-    "syncstate.send.request.folders": {
-        "message": "Oczekiwanie na aktualizacj? listy folder?w"
-    },
-    "syncstate.send.request.localchanges": {
-        "message": "Oczekiwanie na potwierdzenie lokalnych zmian"
-    },
-    "syncstate.send.request.localdeletes": {
-        "message": "Oczekiwanie na potwierdzenie usuni?cia lokalnego"
-    },
-    "syncstate.send.request.options": {
-        "message": "Oczekiwanie na opcje serwera"
-    },
-    "syncstate.send.request.provision": {
-        "message": "Oczekiwanie na provision"
-    },
-    "syncstate.send.request.remotechanges": {
-        "message": "Oczekiwanie na zdalne zmiany"
-    },
-    "syncstate.send.request.revertlocalchanges": {
-        "message": "Oczekiwanie na najnowsze wersje"
-    },
-    "syncstate.send.request.setdeviceinfo": {
-        "message": "Wysy?anie informacji o urz?dzeniu"
-    },
-    "syncstate.send.request.synckey": {
-        "message": "Oczekiwanie na SyncKey"
-    },
-    "syncstate.syncing": {
-        "message": "Zainicjuj synchronizacj?"
-    }
-}
+{
+    "abCard.Anniversary": {
+        "message": "Rocznica:"
+    },
+    "abCard.AssistantName": {
+        "message": "Asystent:"
+    },
+    "abCard.AssistantPhoneNumber": {
+        "message": "Telefon Asystenta:"
+    },
+    "abCard.Business2PhoneNumber": {
+        "message": "Alternatywny Telefon S?u?bowy:"
+    },
+    "abCard.BusinessFaxNumber": {
+        "message": "Faks s?u?bowy:"
+    },
+    "abCard.CarPhoneNumber": {
+        "message": "Telefon w Aucie:"
+    },
+    "abCard.CompanyMainPhone": {
+        "message": "G??wny Telefon S?u?bowy:"
+    },
+    "abCard.Email3Address": {
+        "message": "Alternatywny e-mail:"
+    },
+    "abCard.Home2PhoneNumber": {
+        "message": "Alternatywny Telefon Domowy:"
+    },
+    "abCard.ManagerName": {
+        "message": "Mened?er:"
+    },
+    "abCard.MiddleName": {
+        "message": "Drugie imi?:"
+    },
+    "abCard.OtherAddress": {
+        "message": "Adres:"
+    },
+    "abCard.OtherCity": {
+        "message": "Miasto:"
+    },
+    "abCard.OtherCountry": {
+        "message": "Pa?stwo:"
+    },
+    "abCard.OtherState": {
+        "message": "Wojew?dztwo:"
+    },
+    "abCard.OtherZip": {
+        "message": "Kod pocztowy:"
+    },
+    "abCard.RadioPhoneNumber": {
+        "message": "Radiotelefon:"
+    },
+    "abCard.Spouse": {
+        "message": "Ma??onek:"
+    },
+    "abCard.header.eas": {
+        "message": "Inne Pola (EAS)"
+    },
+    "abCard.header.homenumbers": {
+        "message": "Dodatkowe numery domowe:"
+    },
+    "abCard.header.messaging": {
+        "message": "Komunikatory:"
+    },
+    "abCard.header.otheraddress": {
+        "message": "Inne Adresy (EAS)"
+    },
+    "abCard.header.othernumbers": {
+        "message": "Dodatkowe numery:"
+    },
+    "abCard.header.people": {
+        "message": "Osoby:"
+    },
+    "abCard.header.worknumbers": {
+        "message": "Dodatkowe numery s?u?bowe:"
+    },
+    "acl.readonly": {
+        "message": "Dost?p do serwera tylko do odczytu (cofnij zmiany lokalne)"
+    },
+    "acl.readwrite": {
+        "message": "Odczytuj i zapisuj na serwer"
+    },
+    "add.description": {
+        "message": "Wybierz jedn? z dost?pnych opcji konfiguracji serwera i wprowad? wymagane dane. "
+    },
+    "add.name": {
+        "message": "Nazwa konta:"
+    },
+    "add.ok": {
+        "message": "Dodaj konto"
+    },
+    "add.password": {
+        "message": "Has?o:"
+    },
+    "add.server": {
+        "message": "Konfiguracja serwera:"
+    },
+    "add.shortdescription": {
+        "message": "Informacje o koncie"
+    },
+    "add.title": {
+        "message": "Dodawanie konta Exchange ActiveSync do TbSync"
+    },
+    "add.url": {
+        "message": "Adres serwera:"
+    },
+    "add.urldescription": {
+        "message": "Powinno wystarczy? podanie tylko podstawowego adresu serwera (np.: mail.twojserwer.com). Jednak?e mo?liwe jest r?wnie? podanie pe?nego adresu URL (np.: https://mail.twojserwer.com/Microsoft-Server-ActiveSync)."
+    },
+    "add.user": {
+        "message": "Nazwa u?ytkownika (adres e-mail):"
+    },
+    "autocomplete.serverdirectory": {
+        "message": "globalny katalog serwera"
+    },
+    "autodiscover.Failed": {
+        "message": "Auto-wykrywanie dla u?ytkownika <##user##> nie powiod?o si?. Podane dane uwierzytelniaj?ce by?y nieprawid?owe lub dostawca ActiveSync ma tymczasowy problem lub nie obs?uguje funkcji automatycznego wykrywania."
+    },
+    "autodiscover.NeedEmail": {
+        "message": "Automatyczne wykrywanie potrzebuje prawid?owego adresu e-mail jako nazwy u?ytkownika."
+    },
+    "autodiscover.Ok": {
+        "message": "Automatyczne wykrywanie zako?czy?o si? pomy?lnie, mo?esz teraz sprawdzi? ustawienia opcjonalne i ustanowi? po??czenie synchronizacji."
+    },
+    "autodiscover.Querying": {
+        "message": "Wyszukiwanie ustawie??"
+    },
+    "config.auto": {
+        "message": "Konfiguracja serwera ActiveSync (Auto-wykrywanie)"
+    },
+    "config.custom": {
+        "message": "Konfiguracja serwera ActiveSync"
+    },
+    "deletefolder.confirm": {
+        "message": "Czy naprawd? chcesz TRWALE USUN?? folder ?##replace.1##? z kosza?"
+    },
+    "deletefolder.menuentry": {
+        "message": "Trwale usu? folder ?##replace.1##? z kosza"
+    },
+    "deletefolder.notallowed": {
+        "message": "Anuluj subskrypcj? folderu ?##replace.1##? przed pr?b? usuni?cia go z kosza."
+    },
+    "extensionDescription": {
+        "message": "Dodaj obs?ug? synchronizacji kont Exchange ActiveSync do TbSync (kontakty, zadania i kalendarze)."
+    },
+    "extensionName": {
+        "message": "Dostawca dla Exchange ActiveSync"
+    },
+    "helplink.BadItemSkipped": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
+    },
+    "helplink.global.clientdenied": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "manager.tabs.accountsettings": {
+        "message": "Ustawienia konta"
+    },
+    "manager.tabs.outOfOffice": {
+        "message": "Automatyczna odpowied?"
+    },
+    "manager.tabs.syncsettings": {
+        "message": "Opcje"
+    },
+    "newaccount.add_auto": {
+        "message": "Wykryj automatycznie ustawienia i dodaj konto"
+    },
+    "newaccount.add_custom": {
+        "message": "Dodaj konto"
+    },
+    "pref.AccountName": {
+        "message": "Opis"
+    },
+    "pref.ActiveSyncVersion": {
+        "message": "Wersja ActiveSync"
+    },
+    "pref.DeviceId": {
+        "message": "ID urz?dzenia ActiveSync"
+    },
+    "pref.ServerName": {
+        "message": "Adres serwera"
+    },
+    "pref.ServerNameDescription": {
+        "message": "np. mail.twojserwer.com"
+    },
+    "pref.ShowTrashedFolders": {
+        "message": "Poka? foldery znalezione w koszu"
+    },
+    "pref.UserName": {
+        "message": "Nazwa u?ytkownika"
+    },
+    "pref.UserNameDescription": {
+        "message": "Nazwa u?ytkownika to zazwyczaj adres e-mail Twojego konta."
+    },
+    "pref.autodetect": {
+        "message": "najlepsza dost?pna"
+    },
+    "pref.birthday": {
+        "message": "Wy?lij informacje o urodzinach"
+    },
+    "pref.calendaroptions": {
+        "message": "Opcje kalendarza"
+    },
+    "pref.contactoptions": {
+        "message": "Opcje kontaktu"
+    },
+    "pref.displayoverride": {
+        "message": "Zast?p nazw? wy?wietlan? ci?giem ?Imi?? + ?Drugie imi??"
+    },
+    "pref.generaloptions": {
+        "message": "Opcje og?lne"
+    },
+    "pref.provision": {
+        "message": "Wymu? provisioning (wymagane przez Kerio)"
+    },
+    "pref.seperator.comma": {
+        "message": "Przecinek"
+    },
+    "pref.seperator.description": {
+        "message": "Separator pola adresu wielowierszowego."
+    },
+    "pref.seperator.linebreak": {
+        "message": "Znak ko?ca linii"
+    },
+    "pref.synclimit.1month": {
+        "message": "z 4 tygodni"
+    },
+    "pref.synclimit.2weeks": {
+        "message": "z 2 tygodni"
+    },
+    "pref.synclimit.3month": {
+        "message": "z 3 miesi?cy"
+    },
+    "pref.synclimit.6month": {
+        "message": "z 6 miesi?cy"
+    },
+    "pref.synclimit.all": {
+        "message": "wszystko"
+    },
+    "pref.synclimit.description": {
+        "message": "Okres synchronizacji: "
+    },
+    "pref.usehttps": {
+        "message": "U?yj bezpiecznego po??czenia (po??cz przez https)"
+    },
+    "recyclebin": {
+        "message": "Kosz"
+    },
+    "servertype.auto": {
+        "message": "Automatyczna konfiguracja"
+    },
+    "servertype.custom": {
+        "message": "Konfiguracja niestandardowa"
+    },
+    "servertype.description.auto": {
+        "message": "Konfiguracja dla wielu serwer?w ActiveSync mo?e zosta? odnaleziona poprzez podanie tylko adresu e-mail."
+    },
+    "servertype.description.custom": {
+        "message": "Skonfiguruj konto, podaj?c r?cznie adres serwera, z kt?rym chcesz si? po??czy?."
+    },
+    "servertype.description.office365": {
+        "message": "Konta po??czone z Office 365 korzystaj? z nowoczesnego procesu uwierzytelniania o nazwie OAuth 2.0, kt?ry obs?uguje r?wnie? uwierzytelnianie wielopoziomowe (MFA)."
+    },
+    "servertype.office365": {
+        "message": "Microsoft Office 365"
+    },
+    "servertype.unlock": {
+        "message": "Kliknij dwukrotnie, aby odblokowa? wszystkie predefiniowane ustawienia serwera."
+    },
+    "status.401": {
+        "message": "Nie mo?na uwierzytelni?, sprawd? nazw? u?ytkownika i has?o (HTTP Error 401)."
+    },
+    "status.403": {
+        "message": "Serwer odrzuci? po??czenie (zabronione) (b??d HTTP 403)."
+    },
+    "status.404": {
+        "message": "U?ytkownik nie znaleziony (b??d HTTP 404)."
+    },
+    "status.449": {
+        "message": "Server requests provisioning (HTTP Error 449)."
+    },
+    "status.500": {
+        "message": "Nieznany b??d serwera (b??d HTTP 500)."
+    },
+    "status.503": {
+        "message": "Us?uga niedost?pna (b??d HTTP 503)."
+    },
+    "status.BadItemSkipped": {
+        "message": "B??dny element pomini?to: ##replace.1##"
+    },
+    "status.FolderDelete.3": {
+        "message": "Nie mo?na usun?? folderu systemowego (status 3)"
+    },
+    "status.FolderDelete.4": {
+        "message": "Folder nie istnieje (status 4), ponowna synchronizacja"
+    },
+    "status.FolderDelete.6": {
+        "message": "Nie mo?na wykona? polecenia, wyst?pi? b??d na serwerze (status 6)"
+    },
+    "status.FolderDelete.9": {
+        "message": "Nieprawid?owy klucz synchronizacji (status 9), ponowna synchronizacja"
+    },
+    "status.FolderSync.9": {
+        "message": "Nieprawid?owy klucz synchronizacji (status 9), ponowna synchronizacja"
+    },
+    "status.InvalidServerOptions": {
+        "message": "Serwer nie dostarcza informacji o obs?ugiwanych wersjach ActiveSync. Czy EAS jest zablokowany dla tego u?ytkownika lub tego klienta (TbSync)? Mo?esz spr?bowa? r?cznie ustawi? wersj? ActiveSync."
+    },
+    "status.OK": {
+        "message": "OK"
+    },
+    "status.ServerRejectedRequest": {
+        "message": "Serwer EAS odrzuci? ostatnie ??danie."
+    },
+    "status.ServerRejectedSomeItems": {
+        "message": "Serwer EAS nie zaakceptowa? #replace.1## element?w."
+    },
+    "status.Sync.12": {
+        "message": "Hierarchia folder?w zmieniona (status 12), ponowna synchronizacja"
+    },
+    "status.Sync.3": {
+        "message": "Nieprawid?owy klucz synchronizacji (status 3), ponowna synchronizacja"
+    },
+    "status.Sync.4": {
+        "message": "Zniekszta?cone ??danie (status 4)"
+    },
+    "status.Sync.5": {
+        "message": "Tymczasowe problemy z serwerem lub nieprawid?owy element (status 5)"
+    },
+    "status.Sync.6": {
+        "message": "Nieprawid?owy element (status 6)"
+    },
+    "status.Sync.8": {
+        "message": "Nie znaleziono obiektu (status 8)"
+    },
+    "status.aborted": {
+        "message": "Nie zsynchronizowane"
+    },
+    "status.disabled": {
+        "message": "Wy??czony"
+    },
+    "status.empty-response": {
+        "message": "Serwer wysy?a nieoczekiwan? pust? odpowied?."
+    },
+    "status.forbiddenCalendarItemInTasksFolder": {
+        "message": "Niedozwolony element kalendarza w folderze zada? (please resort)"
+    },
+    "status.forbiddenTasksItemInCalendarFolder": {
+        "message": "Niedozwolony element zadania w folderze kalendarza (please resort)"
+    },
+    "status.global.101": {
+        "message": "??danie zawiera WBXML, ale nie mo?na go zdekodowa? do formatu XML (b??d EAS 101)."
+    },
+    "status.global.102": {
+        "message": "??danie zawiera WBXML, ale nie mo?na go zdekodowa? do formatu XML (b??d EAS 102)."
+    },
+    "status.global.103": {
+        "message": "XML podany w ??daniu nie jest zgodny z wymaganiami protoko?u (b??d EAS 103)."
+    },
+    "status.global.110": {
+        "message": "Serwer zg?osi? b??d wewn?trzny i nie powinni?my natychmiast ponawia? pr?by. Automatyczna synchronizacja okresowa zosta?a wy??czona na 30 minut (b??d EAS 110)."
+    },
+    "status.global.clientdenied": {
+        "message": "Serwer EAS zg?asza <##replace.2##> (status ##replace.1##) i nie zezwala TbSync na dost?p do Twojego konta."
+    },
+    "status.httperror": {
+        "message": "B??d komunikacji (status HTTP ##replace.1##)."
+    },
+    "status.invalid": {
+        "message": "Niepoprawna odpowied? serwera (?mieci)."
+    },
+    "status.malformed-xml": {
+        "message": "Nie mo?na przetworzy? XML. Sprawd? dziennik zdarze?, aby uzyska? szczeg??y."
+    },
+    "status.modified": {
+        "message": "Zmiany lokalne"
+    },
+    "status.network": {
+        "message": "Nie mo?na po??czy? z serwerem (##replace.1##)."
+    },
+    "status.networkerror": {
+        "message": "Nie mo?na po??czy? z serwerem."
+    },
+    "status.nosupportedeasversion": {
+        "message": "Serwer nie obs?uguje ActiveSync v2.5 lub v14.0 (tylko ##replace.1##). TbSync nie b?dzie dzia?a? z tym serwerem ActiveSync."
+    },
+    "status.notargets": {
+        "message": "Przerywam synchronizacj?, poniewa? nie mo?na utworzy? cel?w synchronizacji."
+    },
+    "status.notsupportedeasversion": {
+        "message": "Serwer nie wspiera wybranego ActiveSync v##replace.1## (tylko ##replace.2##)."
+    },
+    "status.notsyncronized": {
+        "message": "Konto musi zosta? zsynchronizowane, co najmniej jeden element nie jest zsynchronizowany."
+    },
+    "status.nouserhost": {
+        "message": "Brak nazwy u?ytkownika i/lub serwera. Prosz? poda? te warto?ci."
+    },
+    "status.pending": {
+        "message": "Oczekiwanie na synchronizacj?"
+    },
+    "status.policy.2": {
+        "message": "Brak zasad dla tego klienta. Skontaktuj si? z administratorem serwera lub wy??cz provisioning dla tego konta."
+    },
+    "status.policy.3": {
+        "message": "Nieznana warto?? PolicyType. Skontaktuj si? z administratorem serwera lub wy??cz provisioning dla tego konta."
+    },
+    "status.policy.4": {
+        "message": "Dane zasad na serwerze s? uszkodzone (prawdopodobnie zmienione/sfa?szowane). Skontaktuj si? z administratorem serwera lub wy??cz provisioning dla tego konta."
+    },
+    "status.policy.5": {
+        "message": "Klient potwierdza z?y klucz zasad. Skontaktuj si? z administratorem serwera lub wy??cz provisioning dla tego konta."
+    },
+    "status.provision": {
+        "message": "Niepowodzenie provisioning ze statusem <##replace.1##>"
+    },
+    "status.response-contains-no-data": {
+        "message": "Odpowied? z serwera nie zawiera danych."
+    },
+    "status.resync-loop": {
+        "message": "Wyst?pi? b??d, kt?rego nie uda?o si? naprawi? poprzez ponowne zsynchronizowanie konta. Wy??cz konto i spr?buj ponownie. (B??d: p?tla resynchronizacji)"
+    },
+    "status.security": {
+        "message": "Nie mo?na nawi?za? bezpiecznego po??czenia. Czy u?ywasz w?asnego podpisu lub w inny spos?b niezaufanego certyfikatu bez importowania go do Thunderbirda? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "Jeszcze nie obs?ugiwane, pomini?to"
+    },
+    "status.syncing": {
+        "message": "Synchronizuj?"
+    },
+    "status.timeout": {
+        "message": "Przekroczony limit czasu po??czenia."
+    },
+    "status.wbxml-parse-error": {
+        "message": "Serwer wysy?a nieczyteln? odpowied?."
+    },
+    "status.wbxmlerror": {
+        "message": "Synchronizacja nie powiod?a si?. Serwer odpowiedzia? statusem <##replace.1##>."
+    },
+    "status.wbxmlmissingfield": {
+        "message": "Naruszenie protoko?u ActiveSync: W odpowiedzi serwera brakuje obowi?zkowego pola <##replace.1##>."
+    },
+    "syncstate.accountdone": {
+        "message": "Konto gotowe"
+    },
+    "syncstate.done": {
+        "message": "Przygotowuj? nast?pny element do synchronizacji"
+    },
+    "syncstate.eval.response.autodiscover": {
+        "message": "Przetwarzanie zaktualizowanych ustawie? serwera"
+    },
+    "syncstate.eval.response.deletefolder": {
+        "message": "Folder usuni?ty"
+    },
+    "syncstate.eval.response.estimate": {
+        "message": "Przetwarzanie oszacowanych zmian"
+    },
+    "syncstate.eval.response.folders": {
+        "message": "Przetwarzanie aktualizacji listy folder?w"
+    },
+    "syncstate.eval.response.localchanges": {
+        "message": "Przetwarzanie potwierdzenia lokalnych zmian"
+    },
+    "syncstate.eval.response.localdeletes": {
+        "message": "Przetwarzanie potwierdzenia usuni?cia lokalnego"
+    },
+    "syncstate.eval.response.options": {
+        "message": "Przetwarzanie opcji serwera"
+    },
+    "syncstate.eval.response.provision": {
+        "message": "Przetwarzanie provision"
+    },
+    "syncstate.eval.response.remotechanges": {
+        "message": "Przetwarzanie zdalnych zmian"
+    },
+    "syncstate.eval.response.revertlocalchanges": {
+        "message": "Wycofywanie zmian lokalnych"
+    },
+    "syncstate.eval.response.setdeviceinfo": {
+        "message": "Wysy?anie informacji o urz?dzeniu"
+    },
+    "syncstate.eval.response.synckey": {
+        "message": "Przetwarzanie SyncKey"
+    },
+    "syncstate.prepare.request.autodiscover": {
+        "message": "??danie zaktualizowanych ustawie? serwera"
+    },
+    "syncstate.prepare.request.deletefolder": {
+        "message": "Przygotowanie do usuni?cia folderu"
+    },
+    "syncstate.prepare.request.estimate": {
+        "message": "??danie oszacowanych zmian"
+    },
+    "syncstate.prepare.request.folders": {
+        "message": "Wysy?anie aktualizacji listy folder?w"
+    },
+    "syncstate.prepare.request.localchanges": {
+        "message": "Wysy?anie zmian lokalnych"
+    },
+    "syncstate.prepare.request.localdeletes": {
+        "message": "Wysy?anie usuni?tych lokalnie"
+    },
+    "syncstate.prepare.request.options": {
+        "message": "??danie opcji serwera"
+    },
+    "syncstate.prepare.request.provision": {
+        "message": "??danie provision"
+    },
+    "syncstate.prepare.request.remotechanges": {
+        "message": "??danie zdalnych zmian"
+    },
+    "syncstate.prepare.request.revertlocalchanges": {
+        "message": "Zbieranie zmian lokalnych"
+    },
+    "syncstate.prepare.request.setdeviceinfo": {
+        "message": "Wysy?anie informacji o urz?dzeniu"
+    },
+    "syncstate.prepare.request.synckey": {
+        "message": "??danie SyncKey"
+    },
+    "syncstate.preparing": {
+        "message": "Przygotowuj? nast?pny element do synchronizacji"
+    },
+    "syncstate.send.request.autodiscover": {
+        "message": "Oczekiwanie na zaktualizowane ustawienia serwera"
+    },
+    "syncstate.send.request.deletefolder": {
+        "message": "Oczekiwanie na usuni?cie folderu"
+    },
+    "syncstate.send.request.estimate": {
+        "message": "Oczekiwanie na oszacowanie zmian"
+    },
+    "syncstate.send.request.folders": {
+        "message": "Oczekiwanie na aktualizacj? listy folder?w"
+    },
+    "syncstate.send.request.localchanges": {
+        "message": "Oczekiwanie na potwierdzenie lokalnych zmian"
+    },
+    "syncstate.send.request.localdeletes": {
+        "message": "Oczekiwanie na potwierdzenie usuni?cia lokalnego"
+    },
+    "syncstate.send.request.options": {
+        "message": "Oczekiwanie na opcje serwera"
+    },
+    "syncstate.send.request.provision": {
+        "message": "Oczekiwanie na provision"
+    },
+    "syncstate.send.request.remotechanges": {
+        "message": "Oczekiwanie na zdalne zmiany"
+    },
+    "syncstate.send.request.revertlocalchanges": {
+        "message": "Oczekiwanie na najnowsze wersje"
+    },
+    "syncstate.send.request.setdeviceinfo": {
+        "message": "Wysy?anie informacji o urz?dzeniu"
+    },
+    "syncstate.send.request.synckey": {
+        "message": "Oczekiwanie na SyncKey"
+    },
+    "syncstate.syncing": {
+        "message": "Zainicjuj synchronizacj?"
+    }
+}
diff -Nru eas4tbsync-4.11/_locales/pt_BR/messages.json eas4tbsync-4.17/_locales/pt_BR/messages.json
--- eas4tbsync-4.11/_locales/pt_BR/messages.json	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/_locales/pt_BR/messages.json	2025-05-15 13:21:20.000000000 +0200
@@ -1,566 +1,566 @@
-{
-    "abCard.Anniversary": {
-        "message": "Anivers?rio:"
-    },
-    "abCard.AssistantName": {
-        "message": "Assistente:"
-    },
-    "abCard.AssistantPhoneNumber": {
-        "message": "Telefone Assistente:"
-    },
-    "abCard.Business2PhoneNumber": {
-        "message": "Telefone alternativo do trabalho:"
-    },
-    "abCard.BusinessFaxNumber": {
-        "message": "Fax de trabalho:"
-    },
-    "abCard.CarPhoneNumber": {
-        "message": "Telefone do carro:"
-    },
-    "abCard.CompanyMainPhone": {
-        "message": "Telefone principal do trabalho:"
-    },
-    "abCard.Email3Address": {
-        "message": "Email alternativo:"
-    },
-    "abCard.Home2PhoneNumber": {
-        "message": "Telefone alternativo residencial:"
-    },
-    "abCard.ManagerName": {
-        "message": "Gerenciar:"
-    },
-    "abCard.MiddleName": {
-        "message": "Nome do meio:"
-    },
-    "abCard.OtherAddress": {
-        "message": "Endere?o:"
-    },
-    "abCard.OtherCity": {
-        "message": "Cidade:"
-    },
-    "abCard.OtherCountry": {
-        "message": "Pa?s:"
-    },
-    "abCard.OtherState": {
-        "message": "Estado:"
-    },
-    "abCard.OtherZip": {
-        "message": "CEP:"
-    },
-    "abCard.RadioPhoneNumber": {
-        "message": "Telefone de r?dio:"
-    },
-    "abCard.Spouse": {
-        "message": "Esposa:"
-    },
-    "abCard.header.eas": {
-        "message": "Outros campos (EAS)"
-    },
-    "abCard.header.homenumbers": {
-        "message": "N?meros residenciais adicionais:"
-    },
-    "abCard.header.messaging": {
-        "message": "Mensagens:"
-    },
-    "abCard.header.otheraddress": {
-        "message": "Outro endere?o (EAS)"
-    },
-    "abCard.header.othernumbers": {
-        "message": "N?meros adicionais:"
-    },
-    "abCard.header.people": {
-        "message": "Pessoas:"
-    },
-    "abCard.header.worknumbers": {
-        "message": "N?meros de trabalho adicionais:"
-    },
-    "acl.readonly": {
-        "message": "Acesso ao servidor somente leitura (reverter altera??es locais)"
-    },
-    "acl.readwrite": {
-        "message": "Ler e escrever no servidor"
-    },
-    "add.description": {
-        "message": "Selecione uma das op??es de configura??o do servidor dispon?veis e insira os detalhes solicitados."
-    },
-    "add.name": {
-        "message": "Nome da conta:"
-    },
-    "add.ok": {
-        "message": "Adicionar conta"
-    },
-    "add.password": {
-        "message": "Senha:"
-    },
-    "add.server": {
-        "message": "Configura??o do servidor:"
-    },
-    "add.shortdescription": {
-        "message": "Informa??es de conta"
-    },
-    "add.title": {
-        "message": "Adicionando uma conta do Exchange ActiveSync ao TbSync"
-    },
-    "add.url": {
-        "message": "Endere?o do servidor:"
-    },
-    "add.urldescription": {
-        "message": "Deve ser suficiente fornecer apenas o endere?o b?sico do servidor (ex.: mail.yourserver.com). No entanto, tamb?m ? poss?vel fornecer a URL completa (ex.: https://mail.yourserver.com/Microsoft-Server-ActiveSync)."
-    },
-    "add.user": {
-        "message": "Usu?rio:"
-    },
-    "autocomplete.serverdirectory": {
-        "message": "servidor de diret?rio global"
-    },
-    "autodiscover.Failed": {
-        "message": "Descoberta autom?tica para usu?rio <##user##> falhou. As credenciais fornecidas estavam erradas ou seu provedor do ActiveSync tem um problema tempor?rio ou n?o oferece suporte ? descoberta autom?tica."
-    },
-    "autodiscover.NeedEmail": {
-        "message": "A descoberta autom?tica precisa de um endere?o de email v?lido"
-    },
-    "autodiscover.Ok": {
-        "message": "Descoberta autom?tica conclu?da com ?xito, agora voc? pode verificar as configura??es opcionais e estabelecer a conex?o de sincroniza??o."
-    },
-    "autodiscover.Querying": {
-        "message": "Procurando por configura??es..."
-    },
-    "config.auto": {
-        "message": "Configura??o do servidor ActiveSync (Descoberta Autom?tica)"
-    },
-    "config.custom": {
-        "message": "Configura??o do servidor ActiveSync"
-    },
-    "deletefolder.confirm": {
-        "message": "Voc? realmente deseja limpar permanentemente a pasta '##replace.1##' da lixeira?"
-    },
-    "deletefolder.menuentry": {
-        "message": "Remover permanentemente a pasta '##replace.1##' da lixeira"
-    },
-    "deletefolder.notallowed": {
-        "message": "Por favor, cancele a subscri??o da pasta '##replace.1##' antes de tentar limp?-lo do lixo."
-    },
-    "extensionDescription": {
-        "message": "Adiciona suporte para sincronizar contas do Exchange ActiveSync (contatos, tarefas e calend?rios) para o TbSync."
-    },
-    "extensionName": {
-        "message": "Provedor Exchange ActiveSync"
-    },
-    "helplink.BadItemSkipped": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
-    },
-    "helplink.global.clientdenied": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "manager.tabs.accountsettings": {
-        "message": "Configura??es da conta"
-    },
-    "manager.tabs.outOfOffice": {
-        "message": "Resposta autom?tica"
-    },
-    "manager.tabs.syncsettings": {
-        "message": "Op??es"
-    },
-    "newaccount.add_auto": {
-        "message": "Configura??es de descoberta autom?tica e adicionar conta"
-    },
-    "newaccount.add_custom": {
-        "message": "Adicionar conta"
-    },
-    "pref.AccountName": {
-        "message": "Nome da conta"
-    },
-    "pref.ActiveSyncVersion": {
-        "message": "Vers?o do ActiveSync"
-    },
-    "pref.DeviceId": {
-        "message": "ID Dispositivo ActiveSync"
-    },
-    "pref.ServerName": {
-        "message": "Endere?o do servidor"
-    },
-    "pref.ServerNameDescription": {
-        "message": "ex. mail.yourserver.com"
-    },
-    "pref.ShowTrashedFolders": {
-        "message": "Mostrar pastas encontradas na lixeira"
-    },
-    "pref.UserName": {
-        "message": "Usu?rio"
-    },
-    "pref.UserNameDescription": {
-        "message": "O nome do usu?rio geralmente ? o endere?o de e-mail da sua conta."
-    },
-    "pref.autodetect": {
-        "message": "melhor dispon?vel"
-    },
-    "pref.birthday": {
-        "message": "Enviar informa??es de anivers?rio"
-    },
-    "pref.calendaroptions": {
-        "message": "Op??es de calend?rio"
-    },
-    "pref.contactoptions": {
-        "message": "Op??es de contato"
-    },
-    "pref.displayoverride": {
-        "message": "Substituir nome de exibi??o com Nome + Segundo nome"
-    },
-    "pref.generaloptions": {
-        "message": "Op??es gerais"
-    },
-    "pref.provision": {
-        "message": "Refor?ar provisionamento (requiredo pelo Kerio)"
-    },
-    "pref.seperator.comma": {
-        "message": "V?rgula"
-    },
-    "pref.seperator.description": {
-        "message": "Separador para campo de endere?o de m?ltiplas linhas."
-    },
-    "pref.seperator.linebreak": {
-        "message": "Quebra de linha"
-    },
-    "pref.synclimit.1month": {
-        "message": "a partir de 4 semanas atr?s"
-    },
-    "pref.synclimit.2weeks": {
-        "message": "a partir de 2 semanas atr?s"
-    },
-    "pref.synclimit.3month": {
-        "message": "a partir de 3 meses atr?s"
-    },
-    "pref.synclimit.6month": {
-        "message": "a partir de 6 meses atr?s"
-    },
-    "pref.synclimit.all": {
-        "message": "tudo"
-    },
-    "pref.synclimit.description": {
-        "message": "Per?odo de sincroniza??o:"
-    },
-    "pref.usehttps": {
-        "message": "Utilizar conex?o segura (conectar via https)"
-    },
-    "recyclebin": {
-        "message": "Lixeira"
-    },
-    "servertype.auto": {
-        "message": "Configura??o autom?tica"
-    },
-    "servertype.custom": {
-        "message": "Configura??o personalizada"
-    },
-    "servertype.description.auto": {
-        "message": "A configura??o para muitos servidores do ActiveSync pode ser descoberta fornecendo apenas seu endere?o de e-mail."
-    },
-    "servertype.description.custom": {
-        "message": "Configure sua conta fornecendo manualmente o endere?o do servidor que voc? deseja conectar."
-    },
-    "servertype.description.office365": {
-        "message": "Contas conectadas ao Office 365 utilizam um processo de autentica??o moderno chamado OAuth 2.0 que tamb?m suporta autentica??o multi-Fator (MFA)."
-    },
-    "servertype.office365": {
-        "message": "Microsoft Office 365"
-    },
-    "servertype.unlock": {
-        "message": "Clique duas vezes para desbloquear todas as configura??es do servidor predefinidas."
-    },
-    "status.401": {
-        "message": "N?o foi poss?vel autenticar, verifique o nome de usu?rio e senha (HTTP Erro 401)."
-    },
-    "status.403": {
-        "message": "Conex?o rejeitada pelo servidor (proibido) (HTTP Erro 403)."
-    },
-    "status.404": {
-        "message": "Usu?rio n?o encontrado (HTTP Erro 404)."
-    },
-    "status.449": {
-        "message": "O servidor solicita o provisionamento (HTTP Erro 449)."
-    },
-    "status.500": {
-        "message": "Erro de servidor desconhecido (HTTP Erro 500)."
-    },
-    "status.503": {
-        "message": "Servi?o indispon?vel (HTTP Erro 503)."
-    },
-    "status.BadItemSkipped": {
-        "message": "Item inv?lido ignorado: ##replace.1##"
-    },
-    "status.FolderDelete.3": {
-        "message": "N?o ? poss?vel excluir uma pasta do sistema."
-    },
-    "status.FolderDelete.4": {
-        "message": "?? Folder does not exist (status 4), resyncing ??"
-    },
-    "status.FolderDelete.6": {
-        "message": "O comando n?o p?de ser conclu?do, ocorreu um erro no servidor."
-    },
-    "status.FolderDelete.9": {
-        "message": "?? Invalid synchronization key (status 9), resyncing ??"
-    },
-    "status.FolderSync.9": {
-        "message": "?? Invalid synchronization key (status 9), resyncing ??"
-    },
-    "status.InvalidServerOptions": {
-        "message": "O servidor n?o fornece informa??es sobre as vers?es do ActiveSync com suporte. O EAS est? bloqueado para este usu?rio ou esse cliente (TbSync)? Voc? pode tentar definir a vers?o do ActiveSync manualmente."
-    },
-    "status.OK": {
-        "message": "OK"
-    },
-    "status.ServerRejectedRequest": {
-        "message": "O servidor EAS rejeitou a ?ltima solicita??o."
-    },
-    "status.ServerRejectedSomeItems": {
-        "message": "O servidor EAS n?o aceitou ##replace.1## elementos."
-    },
-    "status.Sync.12": {
-        "message": "?? Folder hierarchy changed (status 12), resyncing ??"
-    },
-    "status.Sync.3": {
-        "message": "?? Invalid synchronization key (status 3), resyncing ??"
-    },
-    "status.Sync.4": {
-        "message": "?? Malformed request (status 4) ??"
-    },
-    "status.Sync.5": {
-        "message": "?? Temporary server issues or invalid item (status 5) ??"
-    },
-    "status.Sync.6": {
-        "message": "?? Invalid item (status 6) ??"
-    },
-    "status.Sync.8": {
-        "message": "?? Object not found (status 8) ??"
-    },
-    "status.aborted": {
-        "message": "N?o sincronizado"
-    },
-    "status.disabled": {
-        "message": "Desativado"
-    },
-    "status.empty-response": {
-        "message": "O servidor enviou uma resposta vazia inesperada."
-    },
-    "status.forbiddenCalendarItemInTasksFolder": {
-        "message": "?? Forbidden calendar item in a task folder (please resort) ??"
-    },
-    "status.forbiddenTasksItemInCalendarFolder": {
-        "message": "?? Forbidden task item in a calendar folder (please resort) ??"
-    },
-    "status.global.101": {
-        "message": "A solicita??o cont?m WBXML, mas n?o p?de ser decodificada em XML (Erro EAS 101)."
-    },
-    "status.global.102": {
-        "message": "A solicita??o cont?m WBXML, mas n?o p?de ser decodificada em XML (Erro EAS 102)."
-    },
-    "status.global.103": {
-        "message": "O XML fornecido na solicita??o n?o segue os requisitos do protocolo (Erro EAS 103)."
-    },
-    "status.global.110": {
-        "message": "O servidor relatou um erro interno e n?o devemos tentar novamente imediatamente. A sincroniza??o peri?dica autom?tica foi desativada por 30 minutos (Erro 110 do EAS)."
-    },
-    "status.global.clientdenied": {
-        "message": "O servidor EAS reporta <##replace.2##> (status ##replace.1##) e n?o permite que o TbSync acesse sua conta."
-    },
-    "status.httperror": {
-        "message": "Erro de comunica??o (HTTP status ##replace.1##)."
-    },
-    "status.invalid": {
-        "message": "Resposta inv?lida do servidor (lixo)."
-    },
-    "status.malformed-xml": {
-        "message": "N?o foi poss?vel analisar XML. Verifique o log de eventos para obter detalhes."
-    },
-    "status.modified": {
-        "message": "Modifica??es locais"
-    },
-    "status.network": {
-        "message": "N?o foi poss?vel conectar ao servidor (##replace.1##)."
-    },
-    "status.networkerror": {
-        "message": "N?o foi poss?vel conectar ao servidor."
-    },
-    "status.nosupportedeasversion": {
-        "message": "O servidor n?o suporta o ActiveSync v2.5 ou v14.0 (somente ##replace.1##). TbSync n?o funcionar? com este servidor ActiveSync."
-    },
-    "status.notargets": {
-        "message": "Anulando a sincroniza??o, porque os destinos de sincroniza??o n?o puderam ser criados."
-    },
-    "status.notsupportedeasversion": {
-        "message": "O servidor n?o suporta o ActiveSync selecionado v##replace.1## (somente ##replace.2##)."
-    },
-    "status.notsyncronized": {
-        "message": "A conta precisa ser sincronizada, pelo menos, um item est? fora de sincronia."
-    },
-    "status.nouserhost": {
-        "message": "Nome de usu?rio e/ou servidor ausente. Por favor, forne?a esses valores."
-    },
-    "status.pending": {
-        "message": "Esperando para ser sincronizado"
-    },
-    "status.policy.2": {
-        "message": "N?o h? pol?tica para este cliente. Entre em contato com o administrador do servidor ou desabilite o provisionamento para essa conta."
-    },
-    "status.policy.3": {
-        "message": "Valor de PolicyType desconhecido. Entre em contato com o administrador do servidor ou desabilite o provisionamento para essa conta."
-    },
-    "status.policy.4": {
-        "message": "Os dados da pol?tica no servidor est?o corrompidos (possivelmente adulterados). Entre em contato com o administrador do servidor ou desabilite o provisionamento para essa conta."
-    },
-    "status.policy.5": {
-        "message": "O cliente est? reconhecendo a chave de pol?tica incorreta. Entre em contato com o administrador do servidor ou desabilite o provisionamento para essa conta."
-    },
-    "status.provision": {
-        "message": "O provisionamento falhou com o status <##replace.1##>"
-    },
-    "status.response-contains-no-data": {
-        "message": "A resposta do servidor n?o cont?m dados."
-    },
-    "status.resync-loop": {
-        "message": "Ocorreu um erro do qual n?o conseguimos recuperar ao reativar a conta. Por favor, desative a conta e tente novamente. (Erro: loop de ressincroniza??o)"
-    },
-    "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.syncing": {
-        "message": "Sincronizando"
-    },
-    "status.timeout": {
-        "message": "Tempo limite de comunica??o."
-    },
-    "status.wbxml-parse-error": {
-        "message": "O servidor enviou uma resposta ileg?vel."
-    },
-    "status.wbxmlerror": {
-        "message": "A sincroniza??o falhou. O servidor respondeu com status <##replace.1##>."
-    },
-    "status.wbxmlmissingfield": {
-        "message": "Viola??o do protocolo ActiveSync: o campo obrigat?rio <##replace.1##> est? faltando na resposta do servidor."
-    },
-    "syncstate.accountdone": {
-        "message": "Sincroniza??o finalizada"
-    },
-    "syncstate.done": {
-        "message": "Preparando o pr?ximo item para sincroniza??o"
-    },
-    "syncstate.eval.response.autodiscover": {
-        "message": "Aguardando as configura??es do servidor atualizadas"
-    },
-    "syncstate.eval.response.deletefolder": {
-        "message": "Pasta exclu?da"
-    },
-    "syncstate.eval.response.estimate": {
-        "message": "Processando a estimativa de altera??es"
-    },
-    "syncstate.eval.response.folders": {
-        "message": "Processando a atualiza??o da lista de pastas"
-    },
-    "syncstate.eval.response.localchanges": {
-        "message": "Processando reconhecimento de altera??es locais"
-    },
-    "syncstate.eval.response.localdeletes": {
-        "message": "Processando reconhecimento de exclus?es locais"
-    },
-    "syncstate.eval.response.options": {
-        "message": "Processando op??es do servidor"
-    },
-    "syncstate.eval.response.provision": {
-        "message": "Processando provis?o"
-    },
-    "syncstate.eval.response.remotechanges": {
-        "message": "Processando altera??es remotas"
-    },
-    "syncstate.eval.response.revertlocalchanges": {
-        "message": "Revertendo altera??es locais"
-    },
-    "syncstate.eval.response.setdeviceinfo": {
-        "message": "Enviando informa??es do dispositivo"
-    },
-    "syncstate.eval.response.synckey": {
-        "message": "Processando SyncKey"
-    },
-    "syncstate.prepare.request.autodiscover": {
-        "message": "Solicitando configura??es do servidor atualizadas"
-    },
-    "syncstate.prepare.request.deletefolder": {
-        "message": "Preparando-se para excluir pasta"
-    },
-    "syncstate.prepare.request.estimate": {
-        "message": "Solicitando estimativa de altera??es"
-    },
-    "syncstate.prepare.request.folders": {
-        "message": "Enviando lista de pastas atualizadas"
-    },
-    "syncstate.prepare.request.localchanges": {
-        "message": "Enviando altera??es locais"
-    },
-    "syncstate.prepare.request.localdeletes": {
-        "message": "Enviando exclus?es locais"
-    },
-    "syncstate.prepare.request.options": {
-        "message": "Solicitando op??es do servidor"
-    },
-    "syncstate.prepare.request.provision": {
-        "message": "Solicitando provis?o"
-    },
-    "syncstate.prepare.request.remotechanges": {
-        "message": "Solicitando altera??es remotas"
-    },
-    "syncstate.prepare.request.revertlocalchanges": {
-        "message": "Coletando altera??es locais"
-    },
-    "syncstate.prepare.request.setdeviceinfo": {
-        "message": "Enviando informa??es do dispositivo"
-    },
-    "syncstate.prepare.request.synckey": {
-        "message": "Solicitando SyncKey"
-    },
-    "syncstate.preparing": {
-        "message": "Preparando o pr?ximo item para sincroniza??o"
-    },
-    "syncstate.send.request.autodiscover": {
-        "message": "Aguardando as configura??es do servidor atualizadas"
-    },
-    "syncstate.send.request.deletefolder": {
-        "message": "Aguardando a pasta ser exclu?da"
-    },
-    "syncstate.send.request.estimate": {
-        "message": "Aguardando a estimativa de altera??es"
-    },
-    "syncstate.send.request.folders": {
-        "message": "Aguardando a atualiza??o da lista de pastas"
-    },
-    "syncstate.send.request.localchanges": {
-        "message": "Aguardando confirma??o de altera??es locais"
-    },
-    "syncstate.send.request.localdeletes": {
-        "message": "Aguardando o reconhecimento de exclus?es locais"
-    },
-    "syncstate.send.request.options": {
-        "message": "Aguardando por op??es do servidor"
-    },
-    "syncstate.send.request.provision": {
-        "message": "Agurdandando provis?o"
-    },
-    "syncstate.send.request.remotechanges": {
-        "message": "Aguardando altera??es remotas"
-    },
-    "syncstate.send.request.revertlocalchanges": {
-        "message": "Aguardando as vers?es mais recentes"
-    },
-    "syncstate.send.request.setdeviceinfo": {
-        "message": "Enviando informa??es do dispositivo"
-    },
-    "syncstate.send.request.synckey": {
-        "message": "Esperando SyncKey"
-    },
-    "syncstate.syncing": {
-        "message": "Inicializar sincroniza??o"
-    }
-}
+{
+    "abCard.Anniversary": {
+        "message": "Anivers?rio:"
+    },
+    "abCard.AssistantName": {
+        "message": "Assistente:"
+    },
+    "abCard.AssistantPhoneNumber": {
+        "message": "Telefone Assistente:"
+    },
+    "abCard.Business2PhoneNumber": {
+        "message": "Telefone alternativo do trabalho:"
+    },
+    "abCard.BusinessFaxNumber": {
+        "message": "Fax de trabalho:"
+    },
+    "abCard.CarPhoneNumber": {
+        "message": "Telefone do carro:"
+    },
+    "abCard.CompanyMainPhone": {
+        "message": "Telefone principal do trabalho:"
+    },
+    "abCard.Email3Address": {
+        "message": "Email alternativo:"
+    },
+    "abCard.Home2PhoneNumber": {
+        "message": "Telefone alternativo residencial:"
+    },
+    "abCard.ManagerName": {
+        "message": "Gerenciar:"
+    },
+    "abCard.MiddleName": {
+        "message": "Nome do meio:"
+    },
+    "abCard.OtherAddress": {
+        "message": "Endere?o:"
+    },
+    "abCard.OtherCity": {
+        "message": "Cidade:"
+    },
+    "abCard.OtherCountry": {
+        "message": "Pa?s:"
+    },
+    "abCard.OtherState": {
+        "message": "Estado:"
+    },
+    "abCard.OtherZip": {
+        "message": "CEP:"
+    },
+    "abCard.RadioPhoneNumber": {
+        "message": "Telefone de r?dio:"
+    },
+    "abCard.Spouse": {
+        "message": "Esposa:"
+    },
+    "abCard.header.eas": {
+        "message": "Outros campos (EAS)"
+    },
+    "abCard.header.homenumbers": {
+        "message": "N?meros residenciais adicionais:"
+    },
+    "abCard.header.messaging": {
+        "message": "Mensagens:"
+    },
+    "abCard.header.otheraddress": {
+        "message": "Outro endere?o (EAS)"
+    },
+    "abCard.header.othernumbers": {
+        "message": "N?meros adicionais:"
+    },
+    "abCard.header.people": {
+        "message": "Pessoas:"
+    },
+    "abCard.header.worknumbers": {
+        "message": "N?meros de trabalho adicionais:"
+    },
+    "acl.readonly": {
+        "message": "Acesso ao servidor somente leitura (reverter altera??es locais)"
+    },
+    "acl.readwrite": {
+        "message": "Ler e escrever no servidor"
+    },
+    "add.description": {
+        "message": "Selecione uma das op??es de configura??o do servidor dispon?veis e insira os detalhes solicitados."
+    },
+    "add.name": {
+        "message": "Nome da conta:"
+    },
+    "add.ok": {
+        "message": "Adicionar conta"
+    },
+    "add.password": {
+        "message": "Senha:"
+    },
+    "add.server": {
+        "message": "Configura??o do servidor:"
+    },
+    "add.shortdescription": {
+        "message": "Informa??es de conta"
+    },
+    "add.title": {
+        "message": "Adicionando uma conta do Exchange ActiveSync ao TbSync"
+    },
+    "add.url": {
+        "message": "Endere?o do servidor:"
+    },
+    "add.urldescription": {
+        "message": "Deve ser suficiente fornecer apenas o endere?o b?sico do servidor (ex.: mail.yourserver.com). No entanto, tamb?m ? poss?vel fornecer a URL completa (ex.: https://mail.yourserver.com/Microsoft-Server-ActiveSync)."
+    },
+    "add.user": {
+        "message": "Usu?rio:"
+    },
+    "autocomplete.serverdirectory": {
+        "message": "servidor de diret?rio global"
+    },
+    "autodiscover.Failed": {
+        "message": "Descoberta autom?tica para usu?rio <##user##> falhou. As credenciais fornecidas estavam erradas ou seu provedor do ActiveSync tem um problema tempor?rio ou n?o oferece suporte ? descoberta autom?tica."
+    },
+    "autodiscover.NeedEmail": {
+        "message": "A descoberta autom?tica precisa de um endere?o de email v?lido"
+    },
+    "autodiscover.Ok": {
+        "message": "Descoberta autom?tica conclu?da com ?xito, agora voc? pode verificar as configura??es opcionais e estabelecer a conex?o de sincroniza??o."
+    },
+    "autodiscover.Querying": {
+        "message": "Procurando por configura??es..."
+    },
+    "config.auto": {
+        "message": "Configura??o do servidor ActiveSync (Descoberta Autom?tica)"
+    },
+    "config.custom": {
+        "message": "Configura??o do servidor ActiveSync"
+    },
+    "deletefolder.confirm": {
+        "message": "Voc? realmente deseja limpar permanentemente a pasta '##replace.1##' da lixeira?"
+    },
+    "deletefolder.menuentry": {
+        "message": "Remover permanentemente a pasta '##replace.1##' da lixeira"
+    },
+    "deletefolder.notallowed": {
+        "message": "Por favor, cancele a subscri??o da pasta '##replace.1##' antes de tentar limp?-lo do lixo."
+    },
+    "extensionDescription": {
+        "message": "Adiciona suporte para sincronizar contas do Exchange ActiveSync (contatos, tarefas e calend?rios) para o TbSync."
+    },
+    "extensionName": {
+        "message": "Provedor Exchange ActiveSync"
+    },
+    "helplink.BadItemSkipped": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
+    },
+    "helplink.global.clientdenied": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "manager.tabs.accountsettings": {
+        "message": "Configura??es da conta"
+    },
+    "manager.tabs.outOfOffice": {
+        "message": "Resposta autom?tica"
+    },
+    "manager.tabs.syncsettings": {
+        "message": "Op??es"
+    },
+    "newaccount.add_auto": {
+        "message": "Configura??es de descoberta autom?tica e adicionar conta"
+    },
+    "newaccount.add_custom": {
+        "message": "Adicionar conta"
+    },
+    "pref.AccountName": {
+        "message": "Nome da conta"
+    },
+    "pref.ActiveSyncVersion": {
+        "message": "Vers?o do ActiveSync"
+    },
+    "pref.DeviceId": {
+        "message": "ID Dispositivo ActiveSync"
+    },
+    "pref.ServerName": {
+        "message": "Endere?o do servidor"
+    },
+    "pref.ServerNameDescription": {
+        "message": "ex. mail.yourserver.com"
+    },
+    "pref.ShowTrashedFolders": {
+        "message": "Mostrar pastas encontradas na lixeira"
+    },
+    "pref.UserName": {
+        "message": "Usu?rio"
+    },
+    "pref.UserNameDescription": {
+        "message": "O nome do usu?rio geralmente ? o endere?o de e-mail da sua conta."
+    },
+    "pref.autodetect": {
+        "message": "melhor dispon?vel"
+    },
+    "pref.birthday": {
+        "message": "Enviar informa??es de anivers?rio"
+    },
+    "pref.calendaroptions": {
+        "message": "Op??es de calend?rio"
+    },
+    "pref.contactoptions": {
+        "message": "Op??es de contato"
+    },
+    "pref.displayoverride": {
+        "message": "Substituir nome de exibi??o com Nome + Segundo nome"
+    },
+    "pref.generaloptions": {
+        "message": "Op??es gerais"
+    },
+    "pref.provision": {
+        "message": "Refor?ar provisionamento (requiredo pelo Kerio)"
+    },
+    "pref.seperator.comma": {
+        "message": "V?rgula"
+    },
+    "pref.seperator.description": {
+        "message": "Separador para campo de endere?o de m?ltiplas linhas."
+    },
+    "pref.seperator.linebreak": {
+        "message": "Quebra de linha"
+    },
+    "pref.synclimit.1month": {
+        "message": "a partir de 4 semanas atr?s"
+    },
+    "pref.synclimit.2weeks": {
+        "message": "a partir de 2 semanas atr?s"
+    },
+    "pref.synclimit.3month": {
+        "message": "a partir de 3 meses atr?s"
+    },
+    "pref.synclimit.6month": {
+        "message": "a partir de 6 meses atr?s"
+    },
+    "pref.synclimit.all": {
+        "message": "tudo"
+    },
+    "pref.synclimit.description": {
+        "message": "Per?odo de sincroniza??o:"
+    },
+    "pref.usehttps": {
+        "message": "Utilizar conex?o segura (conectar via https)"
+    },
+    "recyclebin": {
+        "message": "Lixeira"
+    },
+    "servertype.auto": {
+        "message": "Configura??o autom?tica"
+    },
+    "servertype.custom": {
+        "message": "Configura??o personalizada"
+    },
+    "servertype.description.auto": {
+        "message": "A configura??o para muitos servidores do ActiveSync pode ser descoberta fornecendo apenas seu endere?o de e-mail."
+    },
+    "servertype.description.custom": {
+        "message": "Configure sua conta fornecendo manualmente o endere?o do servidor que voc? deseja conectar."
+    },
+    "servertype.description.office365": {
+        "message": "Contas conectadas ao Office 365 utilizam um processo de autentica??o moderno chamado OAuth 2.0 que tamb?m suporta autentica??o multi-Fator (MFA)."
+    },
+    "servertype.office365": {
+        "message": "Microsoft Office 365"
+    },
+    "servertype.unlock": {
+        "message": "Clique duas vezes para desbloquear todas as configura??es do servidor predefinidas."
+    },
+    "status.401": {
+        "message": "N?o foi poss?vel autenticar, verifique o nome de usu?rio e senha (HTTP Erro 401)."
+    },
+    "status.403": {
+        "message": "Conex?o rejeitada pelo servidor (proibido) (HTTP Erro 403)."
+    },
+    "status.404": {
+        "message": "Usu?rio n?o encontrado (HTTP Erro 404)."
+    },
+    "status.449": {
+        "message": "O servidor solicita o provisionamento (HTTP Erro 449)."
+    },
+    "status.500": {
+        "message": "Erro de servidor desconhecido (HTTP Erro 500)."
+    },
+    "status.503": {
+        "message": "Servi?o indispon?vel (HTTP Erro 503)."
+    },
+    "status.BadItemSkipped": {
+        "message": "Item inv?lido ignorado: ##replace.1##"
+    },
+    "status.FolderDelete.3": {
+        "message": "N?o ? poss?vel excluir uma pasta do sistema."
+    },
+    "status.FolderDelete.4": {
+        "message": "?? Folder does not exist (status 4), resyncing ??"
+    },
+    "status.FolderDelete.6": {
+        "message": "O comando n?o p?de ser conclu?do, ocorreu um erro no servidor."
+    },
+    "status.FolderDelete.9": {
+        "message": "?? Invalid synchronization key (status 9), resyncing ??"
+    },
+    "status.FolderSync.9": {
+        "message": "?? Invalid synchronization key (status 9), resyncing ??"
+    },
+    "status.InvalidServerOptions": {
+        "message": "O servidor n?o fornece informa??es sobre as vers?es do ActiveSync com suporte. O EAS est? bloqueado para este usu?rio ou esse cliente (TbSync)? Voc? pode tentar definir a vers?o do ActiveSync manualmente."
+    },
+    "status.OK": {
+        "message": "OK"
+    },
+    "status.ServerRejectedRequest": {
+        "message": "O servidor EAS rejeitou a ?ltima solicita??o."
+    },
+    "status.ServerRejectedSomeItems": {
+        "message": "O servidor EAS n?o aceitou ##replace.1## elementos."
+    },
+    "status.Sync.12": {
+        "message": "?? Folder hierarchy changed (status 12), resyncing ??"
+    },
+    "status.Sync.3": {
+        "message": "?? Invalid synchronization key (status 3), resyncing ??"
+    },
+    "status.Sync.4": {
+        "message": "?? Malformed request (status 4) ??"
+    },
+    "status.Sync.5": {
+        "message": "?? Temporary server issues or invalid item (status 5) ??"
+    },
+    "status.Sync.6": {
+        "message": "?? Invalid item (status 6) ??"
+    },
+    "status.Sync.8": {
+        "message": "?? Object not found (status 8) ??"
+    },
+    "status.aborted": {
+        "message": "N?o sincronizado"
+    },
+    "status.disabled": {
+        "message": "Desativado"
+    },
+    "status.empty-response": {
+        "message": "O servidor enviou uma resposta vazia inesperada."
+    },
+    "status.forbiddenCalendarItemInTasksFolder": {
+        "message": "?? Forbidden calendar item in a task folder (please resort) ??"
+    },
+    "status.forbiddenTasksItemInCalendarFolder": {
+        "message": "?? Forbidden task item in a calendar folder (please resort) ??"
+    },
+    "status.global.101": {
+        "message": "A solicita??o cont?m WBXML, mas n?o p?de ser decodificada em XML (Erro EAS 101)."
+    },
+    "status.global.102": {
+        "message": "A solicita??o cont?m WBXML, mas n?o p?de ser decodificada em XML (Erro EAS 102)."
+    },
+    "status.global.103": {
+        "message": "O XML fornecido na solicita??o n?o segue os requisitos do protocolo (Erro EAS 103)."
+    },
+    "status.global.110": {
+        "message": "O servidor relatou um erro interno e n?o devemos tentar novamente imediatamente. A sincroniza??o peri?dica autom?tica foi desativada por 30 minutos (Erro 110 do EAS)."
+    },
+    "status.global.clientdenied": {
+        "message": "O servidor EAS reporta <##replace.2##> (status ##replace.1##) e n?o permite que o TbSync acesse sua conta."
+    },
+    "status.httperror": {
+        "message": "Erro de comunica??o (HTTP status ##replace.1##)."
+    },
+    "status.invalid": {
+        "message": "Resposta inv?lida do servidor (lixo)."
+    },
+    "status.malformed-xml": {
+        "message": "N?o foi poss?vel analisar XML. Verifique o log de eventos para obter detalhes."
+    },
+    "status.modified": {
+        "message": "Modifica??es locais"
+    },
+    "status.network": {
+        "message": "N?o foi poss?vel conectar ao servidor (##replace.1##)."
+    },
+    "status.networkerror": {
+        "message": "N?o foi poss?vel conectar ao servidor."
+    },
+    "status.nosupportedeasversion": {
+        "message": "O servidor n?o suporta o ActiveSync v2.5 ou v14.0 (somente ##replace.1##). TbSync n?o funcionar? com este servidor ActiveSync."
+    },
+    "status.notargets": {
+        "message": "Anulando a sincroniza??o, porque os destinos de sincroniza??o n?o puderam ser criados."
+    },
+    "status.notsupportedeasversion": {
+        "message": "O servidor n?o suporta o ActiveSync selecionado v##replace.1## (somente ##replace.2##)."
+    },
+    "status.notsyncronized": {
+        "message": "A conta precisa ser sincronizada, pelo menos, um item est? fora de sincronia."
+    },
+    "status.nouserhost": {
+        "message": "Nome de usu?rio e/ou servidor ausente. Por favor, forne?a esses valores."
+    },
+    "status.pending": {
+        "message": "Esperando para ser sincronizado"
+    },
+    "status.policy.2": {
+        "message": "N?o h? pol?tica para este cliente. Entre em contato com o administrador do servidor ou desabilite o provisionamento para essa conta."
+    },
+    "status.policy.3": {
+        "message": "Valor de PolicyType desconhecido. Entre em contato com o administrador do servidor ou desabilite o provisionamento para essa conta."
+    },
+    "status.policy.4": {
+        "message": "Os dados da pol?tica no servidor est?o corrompidos (possivelmente adulterados). Entre em contato com o administrador do servidor ou desabilite o provisionamento para essa conta."
+    },
+    "status.policy.5": {
+        "message": "O cliente est? reconhecendo a chave de pol?tica incorreta. Entre em contato com o administrador do servidor ou desabilite o provisionamento para essa conta."
+    },
+    "status.provision": {
+        "message": "O provisionamento falhou com o status <##replace.1##>"
+    },
+    "status.response-contains-no-data": {
+        "message": "A resposta do servidor n?o cont?m dados."
+    },
+    "status.resync-loop": {
+        "message": "Ocorreu um erro do qual n?o conseguimos recuperar ao reativar a conta. Por favor, desative a conta e tente novamente. (Erro: loop de ressincroniza??o)"
+    },
+    "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.syncing": {
+        "message": "Sincronizando"
+    },
+    "status.timeout": {
+        "message": "Tempo limite de comunica??o."
+    },
+    "status.wbxml-parse-error": {
+        "message": "O servidor enviou uma resposta ileg?vel."
+    },
+    "status.wbxmlerror": {
+        "message": "A sincroniza??o falhou. O servidor respondeu com status <##replace.1##>."
+    },
+    "status.wbxmlmissingfield": {
+        "message": "Viola??o do protocolo ActiveSync: o campo obrigat?rio <##replace.1##> est? faltando na resposta do servidor."
+    },
+    "syncstate.accountdone": {
+        "message": "Sincroniza??o finalizada"
+    },
+    "syncstate.done": {
+        "message": "Preparando o pr?ximo item para sincroniza??o"
+    },
+    "syncstate.eval.response.autodiscover": {
+        "message": "Aguardando as configura??es do servidor atualizadas"
+    },
+    "syncstate.eval.response.deletefolder": {
+        "message": "Pasta exclu?da"
+    },
+    "syncstate.eval.response.estimate": {
+        "message": "Processando a estimativa de altera??es"
+    },
+    "syncstate.eval.response.folders": {
+        "message": "Processando a atualiza??o da lista de pastas"
+    },
+    "syncstate.eval.response.localchanges": {
+        "message": "Processando reconhecimento de altera??es locais"
+    },
+    "syncstate.eval.response.localdeletes": {
+        "message": "Processando reconhecimento de exclus?es locais"
+    },
+    "syncstate.eval.response.options": {
+        "message": "Processando op??es do servidor"
+    },
+    "syncstate.eval.response.provision": {
+        "message": "Processando provis?o"
+    },
+    "syncstate.eval.response.remotechanges": {
+        "message": "Processando altera??es remotas"
+    },
+    "syncstate.eval.response.revertlocalchanges": {
+        "message": "Revertendo altera??es locais"
+    },
+    "syncstate.eval.response.setdeviceinfo": {
+        "message": "Enviando informa??es do dispositivo"
+    },
+    "syncstate.eval.response.synckey": {
+        "message": "Processando SyncKey"
+    },
+    "syncstate.prepare.request.autodiscover": {
+        "message": "Solicitando configura??es do servidor atualizadas"
+    },
+    "syncstate.prepare.request.deletefolder": {
+        "message": "Preparando-se para excluir pasta"
+    },
+    "syncstate.prepare.request.estimate": {
+        "message": "Solicitando estimativa de altera??es"
+    },
+    "syncstate.prepare.request.folders": {
+        "message": "Enviando lista de pastas atualizadas"
+    },
+    "syncstate.prepare.request.localchanges": {
+        "message": "Enviando altera??es locais"
+    },
+    "syncstate.prepare.request.localdeletes": {
+        "message": "Enviando exclus?es locais"
+    },
+    "syncstate.prepare.request.options": {
+        "message": "Solicitando op??es do servidor"
+    },
+    "syncstate.prepare.request.provision": {
+        "message": "Solicitando provis?o"
+    },
+    "syncstate.prepare.request.remotechanges": {
+        "message": "Solicitando altera??es remotas"
+    },
+    "syncstate.prepare.request.revertlocalchanges": {
+        "message": "Coletando altera??es locais"
+    },
+    "syncstate.prepare.request.setdeviceinfo": {
+        "message": "Enviando informa??es do dispositivo"
+    },
+    "syncstate.prepare.request.synckey": {
+        "message": "Solicitando SyncKey"
+    },
+    "syncstate.preparing": {
+        "message": "Preparando o pr?ximo item para sincroniza??o"
+    },
+    "syncstate.send.request.autodiscover": {
+        "message": "Aguardando as configura??es do servidor atualizadas"
+    },
+    "syncstate.send.request.deletefolder": {
+        "message": "Aguardando a pasta ser exclu?da"
+    },
+    "syncstate.send.request.estimate": {
+        "message": "Aguardando a estimativa de altera??es"
+    },
+    "syncstate.send.request.folders": {
+        "message": "Aguardando a atualiza??o da lista de pastas"
+    },
+    "syncstate.send.request.localchanges": {
+        "message": "Aguardando confirma??o de altera??es locais"
+    },
+    "syncstate.send.request.localdeletes": {
+        "message": "Aguardando o reconhecimento de exclus?es locais"
+    },
+    "syncstate.send.request.options": {
+        "message": "Aguardando por op??es do servidor"
+    },
+    "syncstate.send.request.provision": {
+        "message": "Agurdandando provis?o"
+    },
+    "syncstate.send.request.remotechanges": {
+        "message": "Aguardando altera??es remotas"
+    },
+    "syncstate.send.request.revertlocalchanges": {
+        "message": "Aguardando as vers?es mais recentes"
+    },
+    "syncstate.send.request.setdeviceinfo": {
+        "message": "Enviando informa??es do dispositivo"
+    },
+    "syncstate.send.request.synckey": {
+        "message": "Esperando SyncKey"
+    },
+    "syncstate.syncing": {
+        "message": "Inicializar sincroniza??o"
+    }
+}
diff -Nru eas4tbsync-4.11/_locales/Readme.txt eas4tbsync-4.17/_locales/Readme.txt
--- eas4tbsync-4.11/_locales/Readme.txt	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/_locales/Readme.txt	2019-09-30 17:35:10.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 eas4tbsync-4.11/_locales/ro/messages.json eas4tbsync-4.17/_locales/ro/messages.json
--- eas4tbsync-4.11/_locales/ro/messages.json	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/_locales/ro/messages.json	2025-05-15 13:21:20.000000000 +0200
@@ -1,566 +1,566 @@
-{
-    "abCard.Anniversary": {
-        "message": "Anniversary:"
-    },
-    "abCard.AssistantName": {
-        "message": "Assistant:"
-    },
-    "abCard.AssistantPhoneNumber": {
-        "message": "Assistant Phone:"
-    },
-    "abCard.Business2PhoneNumber": {
-        "message": "Work Alternative Phone:"
-    },
-    "abCard.BusinessFaxNumber": {
-        "message": "Work Fax:"
-    },
-    "abCard.CarPhoneNumber": {
-        "message": "Car Phone:"
-    },
-    "abCard.CompanyMainPhone": {
-        "message": "Work Main Phone:"
-    },
-    "abCard.Email3Address": {
-        "message": "Alternative Email:"
-    },
-    "abCard.Home2PhoneNumber": {
-        "message": "Home Alternative Phone:"
-    },
-    "abCard.ManagerName": {
-        "message": "Manager:"
-    },
-    "abCard.MiddleName": {
-        "message": "Middle name:"
-    },
-    "abCard.OtherAddress": {
-        "message": "Address:"
-    },
-    "abCard.OtherCity": {
-        "message": "City:"
-    },
-    "abCard.OtherCountry": {
-        "message": "Country:"
-    },
-    "abCard.OtherState": {
-        "message": "State:"
-    },
-    "abCard.OtherZip": {
-        "message": "ZIP Code:"
-    },
-    "abCard.RadioPhoneNumber": {
-        "message": "Radio Phone:"
-    },
-    "abCard.Spouse": {
-        "message": "Spouse:"
-    },
-    "abCard.header.eas": {
-        "message": "Other Fields (EAS)"
-    },
-    "abCard.header.homenumbers": {
-        "message": "Additional home numbers:"
-    },
-    "abCard.header.messaging": {
-        "message": "Messaging:"
-    },
-    "abCard.header.otheraddress": {
-        "message": "Other Address (EAS)"
-    },
-    "abCard.header.othernumbers": {
-        "message": "Additional numbers:"
-    },
-    "abCard.header.people": {
-        "message": "People:"
-    },
-    "abCard.header.worknumbers": {
-        "message": "Additional work numbers:"
-    },
-    "acl.readonly": {
-        "message": "Read-only server access (revert local changes)"
-    },
-    "acl.readwrite": {
-        "message": "Read from and write to server"
-    },
-    "add.description": {
-        "message": "Please select one of the available server configuration options and enter the requested details. "
-    },
-    "add.name": {
-        "message": "Account name:"
-    },
-    "add.ok": {
-        "message": "Add account"
-    },
-    "add.password": {
-        "message": "Password:"
-    },
-    "add.server": {
-        "message": "Server configuration:"
-    },
-    "add.shortdescription": {
-        "message": "Account information"
-    },
-    "add.title": {
-        "message": "Adding an Exchange ActiveSync account to TbSync"
-    },
-    "add.url": {
-        "message": "Server address:"
-    },
-    "add.urldescription": {
-        "message": "It should be sufficient to provide just the basic server address (e.g.: mail.yourserver.com). However, it is also possible to provide the full URL (e.g.: https://mail.yourserver.com/Microsoft-Server-ActiveSync)."
-    },
-    "add.user": {
-        "message": "User name (email address):"
-    },
-    "autocomplete.serverdirectory": {
-        "message": "global server directory"
-    },
-    "autodiscover.Failed": {
-        "message": "Autodiscover for user <##user##> failed. Either the provided credentials were wrong or your ActiveSync provider has a temporary issue, or does not support Autodiscover."
-    },
-    "autodiscover.NeedEmail": {
-        "message": "Autodiscover needs a valid email address as user name."
-    },
-    "autodiscover.Ok": {
-        "message": "Autodiscover completed successfully, you can now check the optional settings and establish the synchronization connection."
-    },
-    "autodiscover.Querying": {
-        "message": "Searching for settings?"
-    },
-    "config.auto": {
-        "message": "ActiveSync server configuration (Autodiscover)"
-    },
-    "config.custom": {
-        "message": "ActiveSync server configuration"
-    },
-    "deletefolder.confirm": {
-        "message": "Do you really want to PERMANENTLY PURGE folder ?##replace.1##? from trash?"
-    },
-    "deletefolder.menuentry": {
-        "message": "Permanently purge folder ?##replace.1##? from trash"
-    },
-    "deletefolder.notallowed": {
-        "message": "Please unsubscribe folder ?##replace.1##? before trying to purge it from trash."
-    },
-    "extensionDescription": {
-        "message": "Add sync support for Exchange ActiveSync accounts to TbSync (contacts, tasks and calendars)."
-    },
-    "extensionName": {
-        "message": "Provider for Exchange ActiveSync"
-    },
-    "helplink.BadItemSkipped": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
-    },
-    "helplink.global.clientdenied": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "manager.tabs.accountsettings": {
-        "message": "Account settings"
-    },
-    "manager.tabs.outOfOffice": {
-        "message": "Auto responder"
-    },
-    "manager.tabs.syncsettings": {
-        "message": "Options"
-    },
-    "newaccount.add_auto": {
-        "message": "Autodiscover settings and add account"
-    },
-    "newaccount.add_custom": {
-        "message": "Add account"
-    },
-    "pref.AccountName": {
-        "message": "Description"
-    },
-    "pref.ActiveSyncVersion": {
-        "message": "ActiveSync version"
-    },
-    "pref.DeviceId": {
-        "message": "ActiveSync device ID"
-    },
-    "pref.ServerName": {
-        "message": "Server address"
-    },
-    "pref.ServerNameDescription": {
-        "message": "e.g. mail.yourserver.com"
-    },
-    "pref.ShowTrashedFolders": {
-        "message": "Show folders found in trash"
-    },
-    "pref.UserName": {
-        "message": "User name"
-    },
-    "pref.UserNameDescription": {
-        "message": "User name is usually the email address of your account."
-    },
-    "pref.autodetect": {
-        "message": "best available"
-    },
-    "pref.birthday": {
-        "message": "Send birthday information"
-    },
-    "pref.calendaroptions": {
-        "message": "Calendar options"
-    },
-    "pref.contactoptions": {
-        "message": "Contact options"
-    },
-    "pref.displayoverride": {
-        "message": "Override Display Name with ?First Name? + ?Second Name?"
-    },
-    "pref.generaloptions": {
-        "message": "General options"
-    },
-    "pref.provision": {
-        "message": "Enforce provisioning (required by Kerio)"
-    },
-    "pref.seperator.comma": {
-        "message": "Comma"
-    },
-    "pref.seperator.description": {
-        "message": "Separator for multiline address field."
-    },
-    "pref.seperator.linebreak": {
-        "message": "Line break"
-    },
-    "pref.synclimit.1month": {
-        "message": "from 4 weeks ago"
-    },
-    "pref.synclimit.2weeks": {
-        "message": "from 2 weeks ago"
-    },
-    "pref.synclimit.3month": {
-        "message": "from 3 months ago"
-    },
-    "pref.synclimit.6month": {
-        "message": "from 6 months ago"
-    },
-    "pref.synclimit.all": {
-        "message": "everything"
-    },
-    "pref.synclimit.description": {
-        "message": "Synchronization period: "
-    },
-    "pref.usehttps": {
-        "message": "Use secure connection (connect via https)"
-    },
-    "recyclebin": {
-        "message": "Trash"
-    },
-    "servertype.auto": {
-        "message": "Automatic configuration"
-    },
-    "servertype.custom": {
-        "message": "Custom configuration"
-    },
-    "servertype.description.auto": {
-        "message": "The configuration for many ActiveSync servers can be discovered by providing just your email address."
-    },
-    "servertype.description.custom": {
-        "message": "Setup your account by manually providing the address of the server you want to connect."
-    },
-    "servertype.description.office365": {
-        "message": "Accounts connected to Office 365 use a modern authentication process called OAuth 2.0 which also supports Multi-Factor-Authentication (MFA)."
-    },
-    "servertype.office365": {
-        "message": "Microsoft Office 365"
-    },
-    "servertype.unlock": {
-        "message": "Double click to unlock all predefined server settings."
-    },
-    "status.401": {
-        "message": "Could not authenticate, check username and password (HTTP Error 401)."
-    },
-    "status.403": {
-        "message": "Server rejected connection (forbidden) (HTTP Error 403)."
-    },
-    "status.404": {
-        "message": "User not found (HTTP Error 404)."
-    },
-    "status.449": {
-        "message": "Server requests provisioning (HTTP Error 449)."
-    },
-    "status.500": {
-        "message": "Unknown Server Error (HTTP Error 500)."
-    },
-    "status.503": {
-        "message": "Service unavailable (HTTP Error 503)."
-    },
-    "status.BadItemSkipped": {
-        "message": "Bad Item Skipped: ##replace.1##"
-    },
-    "status.FolderDelete.3": {
-        "message": "Cannot delete a system folder (status 3)"
-    },
-    "status.FolderDelete.4": {
-        "message": "Folder does not exist (status 4), resyncing"
-    },
-    "status.FolderDelete.6": {
-        "message": "Command could not be completed, an error occurred on the server (status 6)"
-    },
-    "status.FolderDelete.9": {
-        "message": "Invalid synchronization key (status 9), resyncing"
-    },
-    "status.FolderSync.9": {
-        "message": "Invalid synchronization key (status 9), resyncing"
-    },
-    "status.InvalidServerOptions": {
-        "message": "The server does not provide information about the supported ActiveSync versions. Is EAS blocked for this user or this client (TbSync)? You could try to set the ActiveSync version manually."
-    },
-    "status.OK": {
-        "message": "OK"
-    },
-    "status.ServerRejectedRequest": {
-        "message": "The EAS Server rejected the last request."
-    },
-    "status.ServerRejectedSomeItems": {
-        "message": "The EAS server did not accept ##replace.1## elements."
-    },
-    "status.Sync.12": {
-        "message": "Folder hierarchy changed (status 12), resyncing"
-    },
-    "status.Sync.3": {
-        "message": "Invalid synchronization key (status 3), resyncing"
-    },
-    "status.Sync.4": {
-        "message": "Malformed request (status 4)"
-    },
-    "status.Sync.5": {
-        "message": "Temporary server issues or invalid item (status 5)"
-    },
-    "status.Sync.6": {
-        "message": "Invalid item (status 6)"
-    },
-    "status.Sync.8": {
-        "message": "Object not found (status 8)"
-    },
-    "status.aborted": {
-        "message": "Not synchronized"
-    },
-    "status.disabled": {
-        "message": "Disabled"
-    },
-    "status.empty-response": {
-        "message": "Server sends unexpected empty response."
-    },
-    "status.forbiddenCalendarItemInTasksFolder": {
-        "message": "Forbidden calendar item in a task folder (please resort)"
-    },
-    "status.forbiddenTasksItemInCalendarFolder": {
-        "message": "Forbidden task item in a calendar folder (please resort)"
-    },
-    "status.global.101": {
-        "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 101)."
-    },
-    "status.global.102": {
-        "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 102)."
-    },
-    "status.global.103": {
-        "message": "The XML provided in the request does not follow the protocol requirements (EAS Error 103)."
-    },
-    "status.global.110": {
-        "message": "The server reported an internal error and we should not retry immediately. Automatic periodic sync has been disabled for 30 minutes (EAS Error 110)."
-    },
-    "status.global.clientdenied": {
-        "message": "The EAS server reports <##replace.2##> (status ##replace.1##) and does not allow TbSync to access your account."
-    },
-    "status.httperror": {
-        "message": "Communication error (HTTP status ##replace.1##)."
-    },
-    "status.invalid": {
-        "message": "Invalid server response (junk)."
-    },
-    "status.malformed-xml": {
-        "message": "Could not parse XML. Check event log for details."
-    },
-    "status.modified": {
-        "message": "Local modifications"
-    },
-    "status.network": {
-        "message": "Could not connect to server (##replace.1##)."
-    },
-    "status.networkerror": {
-        "message": "Could not connect to server."
-    },
-    "status.nosupportedeasversion": {
-        "message": "Server does not support ActiveSync v2.5 or v14.0 (only ##replace.1##). TbSync will not work with this ActiveSync server."
-    },
-    "status.notargets": {
-        "message": "Aborting Sync, because sync targets could not be created."
-    },
-    "status.notsupportedeasversion": {
-        "message": "Server does not support selected ActiveSync v##replace.1## (only ##replace.2##)."
-    },
-    "status.notsyncronized": {
-        "message": "Account needs to be synchronized, at least one item is out of sync."
-    },
-    "status.nouserhost": {
-        "message": "Missing username and/or server. Please provide those values."
-    },
-    "status.pending": {
-        "message": "Waiting to be synchronized"
-    },
-    "status.policy.2": {
-        "message": "There is no policy for this client. Contact your server administrator or disable provisioning for this account."
-    },
-    "status.policy.3": {
-        "message": "Unknown PolicyType value. Contact your server administrator or disable provisioning for this account."
-    },
-    "status.policy.4": {
-        "message": "The policy data on the server is corrupted (possibly tampered with). Contact your server administrator or disable provisioning for this account."
-    },
-    "status.policy.5": {
-        "message": "The client is acknowledging the wrong policy key. Contact your server administrator or disable provisioning for this account."
-    },
-    "status.provision": {
-        "message": "Provisioning failed with status <##replace.1##>"
-    },
-    "status.response-contains-no-data": {
-        "message": "Response from the server contains no data."
-    },
-    "status.resync-loop": {
-        "message": "There was an error from which we could not recover by resyncing the account. Please disable the account and try again. (Error: resync loop)"
-    },
-    "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.syncing": {
-        "message": "Synchronizing"
-    },
-    "status.timeout": {
-        "message": "Communication timeout."
-    },
-    "status.wbxml-parse-error": {
-        "message": "Server sends unreadable response."
-    },
-    "status.wbxmlerror": {
-        "message": "Sync failed. Server responded with status <##replace.1##>."
-    },
-    "status.wbxmlmissingfield": {
-        "message": "ActiveSync protocol violation: Mandatory field <##replace.1##> is missing from server response."
-    },
-    "syncstate.accountdone": {
-        "message": "Finished account"
-    },
-    "syncstate.done": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.eval.response.autodiscover": {
-        "message": "Processing updated server settings"
-    },
-    "syncstate.eval.response.deletefolder": {
-        "message": "Folder deleted"
-    },
-    "syncstate.eval.response.estimate": {
-        "message": "Processing change estimate"
-    },
-    "syncstate.eval.response.folders": {
-        "message": "Processing folder list update"
-    },
-    "syncstate.eval.response.localchanges": {
-        "message": "Processing acknowledgment of local changes"
-    },
-    "syncstate.eval.response.localdeletes": {
-        "message": "Processing acknowledgment of local deletes"
-    },
-    "syncstate.eval.response.options": {
-        "message": "Processing server options"
-    },
-    "syncstate.eval.response.provision": {
-        "message": "Processing provision"
-    },
-    "syncstate.eval.response.remotechanges": {
-        "message": "Processing remote changes"
-    },
-    "syncstate.eval.response.revertlocalchanges": {
-        "message": "Reverting local changes"
-    },
-    "syncstate.eval.response.setdeviceinfo": {
-        "message": "Sending device information"
-    },
-    "syncstate.eval.response.synckey": {
-        "message": "Processing SyncKey"
-    },
-    "syncstate.prepare.request.autodiscover": {
-        "message": "Requesting updated server settings"
-    },
-    "syncstate.prepare.request.deletefolder": {
-        "message": "Preparing to delete folder"
-    },
-    "syncstate.prepare.request.estimate": {
-        "message": "Requesting change estimate"
-    },
-    "syncstate.prepare.request.folders": {
-        "message": "Sending folder list update"
-    },
-    "syncstate.prepare.request.localchanges": {
-        "message": "Sending local changes"
-    },
-    "syncstate.prepare.request.localdeletes": {
-        "message": "Sending local deletes"
-    },
-    "syncstate.prepare.request.options": {
-        "message": "Requesting server options"
-    },
-    "syncstate.prepare.request.provision": {
-        "message": "Requesting provision"
-    },
-    "syncstate.prepare.request.remotechanges": {
-        "message": "Requesting remote changes"
-    },
-    "syncstate.prepare.request.revertlocalchanges": {
-        "message": "Collecting local changes"
-    },
-    "syncstate.prepare.request.setdeviceinfo": {
-        "message": "Sending device information"
-    },
-    "syncstate.prepare.request.synckey": {
-        "message": "Requesting SyncKey"
-    },
-    "syncstate.preparing": {
-        "message": "Preparing next item for synchronization"
-    },
-    "syncstate.send.request.autodiscover": {
-        "message": "Waiting for updated server settings"
-    },
-    "syncstate.send.request.deletefolder": {
-        "message": "Waiting for folder to be deleted"
-    },
-    "syncstate.send.request.estimate": {
-        "message": "Waiting for change estimate"
-    },
-    "syncstate.send.request.folders": {
-        "message": "Waiting for folder list update"
-    },
-    "syncstate.send.request.localchanges": {
-        "message": "Waiting for acknowledgment of local changes"
-    },
-    "syncstate.send.request.localdeletes": {
-        "message": "Waiting for acknowledgment of local deletes"
-    },
-    "syncstate.send.request.options": {
-        "message": "Waiting for server options"
-    },
-    "syncstate.send.request.provision": {
-        "message": "Waiting for provision"
-    },
-    "syncstate.send.request.remotechanges": {
-        "message": "Waiting for remote changes"
-    },
-    "syncstate.send.request.revertlocalchanges": {
-        "message": "Waiting for most recent versions"
-    },
-    "syncstate.send.request.setdeviceinfo": {
-        "message": "Sending device information"
-    },
-    "syncstate.send.request.synckey": {
-        "message": "Waiting for SyncKey"
-    },
-    "syncstate.syncing": {
-        "message": "Initialize synchronization"
-    }
-}
+{
+    "abCard.Anniversary": {
+        "message": "Anniversary:"
+    },
+    "abCard.AssistantName": {
+        "message": "Assistant:"
+    },
+    "abCard.AssistantPhoneNumber": {
+        "message": "Assistant Phone:"
+    },
+    "abCard.Business2PhoneNumber": {
+        "message": "Work Alternative Phone:"
+    },
+    "abCard.BusinessFaxNumber": {
+        "message": "Work Fax:"
+    },
+    "abCard.CarPhoneNumber": {
+        "message": "Car Phone:"
+    },
+    "abCard.CompanyMainPhone": {
+        "message": "Work Main Phone:"
+    },
+    "abCard.Email3Address": {
+        "message": "Alternative Email:"
+    },
+    "abCard.Home2PhoneNumber": {
+        "message": "Home Alternative Phone:"
+    },
+    "abCard.ManagerName": {
+        "message": "Manager:"
+    },
+    "abCard.MiddleName": {
+        "message": "Middle name:"
+    },
+    "abCard.OtherAddress": {
+        "message": "Address:"
+    },
+    "abCard.OtherCity": {
+        "message": "City:"
+    },
+    "abCard.OtherCountry": {
+        "message": "Country:"
+    },
+    "abCard.OtherState": {
+        "message": "State:"
+    },
+    "abCard.OtherZip": {
+        "message": "ZIP Code:"
+    },
+    "abCard.RadioPhoneNumber": {
+        "message": "Radio Phone:"
+    },
+    "abCard.Spouse": {
+        "message": "Spouse:"
+    },
+    "abCard.header.eas": {
+        "message": "Other Fields (EAS)"
+    },
+    "abCard.header.homenumbers": {
+        "message": "Additional home numbers:"
+    },
+    "abCard.header.messaging": {
+        "message": "Messaging:"
+    },
+    "abCard.header.otheraddress": {
+        "message": "Other Address (EAS)"
+    },
+    "abCard.header.othernumbers": {
+        "message": "Additional numbers:"
+    },
+    "abCard.header.people": {
+        "message": "People:"
+    },
+    "abCard.header.worknumbers": {
+        "message": "Additional work numbers:"
+    },
+    "acl.readonly": {
+        "message": "Read-only server access (revert local changes)"
+    },
+    "acl.readwrite": {
+        "message": "Read from and write to server"
+    },
+    "add.description": {
+        "message": "Please select one of the available server configuration options and enter the requested details. "
+    },
+    "add.name": {
+        "message": "Account name:"
+    },
+    "add.ok": {
+        "message": "Add account"
+    },
+    "add.password": {
+        "message": "Password:"
+    },
+    "add.server": {
+        "message": "Server configuration:"
+    },
+    "add.shortdescription": {
+        "message": "Account information"
+    },
+    "add.title": {
+        "message": "Adding an Exchange ActiveSync account to TbSync"
+    },
+    "add.url": {
+        "message": "Server address:"
+    },
+    "add.urldescription": {
+        "message": "It should be sufficient to provide just the basic server address (e.g.: mail.yourserver.com). However, it is also possible to provide the full URL (e.g.: https://mail.yourserver.com/Microsoft-Server-ActiveSync)."
+    },
+    "add.user": {
+        "message": "User name (email address):"
+    },
+    "autocomplete.serverdirectory": {
+        "message": "global server directory"
+    },
+    "autodiscover.Failed": {
+        "message": "Autodiscover for user <##user##> failed. Either the provided credentials were wrong or your ActiveSync provider has a temporary issue, or does not support Autodiscover."
+    },
+    "autodiscover.NeedEmail": {
+        "message": "Autodiscover needs a valid email address as user name."
+    },
+    "autodiscover.Ok": {
+        "message": "Autodiscover completed successfully, you can now check the optional settings and establish the synchronization connection."
+    },
+    "autodiscover.Querying": {
+        "message": "Searching for settings?"
+    },
+    "config.auto": {
+        "message": "ActiveSync server configuration (Autodiscover)"
+    },
+    "config.custom": {
+        "message": "ActiveSync server configuration"
+    },
+    "deletefolder.confirm": {
+        "message": "Do you really want to PERMANENTLY PURGE folder ?##replace.1##? from trash?"
+    },
+    "deletefolder.menuentry": {
+        "message": "Permanently purge folder ?##replace.1##? from trash"
+    },
+    "deletefolder.notallowed": {
+        "message": "Please unsubscribe folder ?##replace.1##? before trying to purge it from trash."
+    },
+    "extensionDescription": {
+        "message": "Add sync support for Exchange ActiveSync accounts to TbSync (contacts, tasks and calendars)."
+    },
+    "extensionName": {
+        "message": "Provider for Exchange ActiveSync"
+    },
+    "helplink.BadItemSkipped": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
+    },
+    "helplink.global.clientdenied": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "manager.tabs.accountsettings": {
+        "message": "Account settings"
+    },
+    "manager.tabs.outOfOffice": {
+        "message": "Auto responder"
+    },
+    "manager.tabs.syncsettings": {
+        "message": "Options"
+    },
+    "newaccount.add_auto": {
+        "message": "Autodiscover settings and add account"
+    },
+    "newaccount.add_custom": {
+        "message": "Add account"
+    },
+    "pref.AccountName": {
+        "message": "Description"
+    },
+    "pref.ActiveSyncVersion": {
+        "message": "ActiveSync version"
+    },
+    "pref.DeviceId": {
+        "message": "ActiveSync device ID"
+    },
+    "pref.ServerName": {
+        "message": "Server address"
+    },
+    "pref.ServerNameDescription": {
+        "message": "e.g. mail.yourserver.com"
+    },
+    "pref.ShowTrashedFolders": {
+        "message": "Show folders found in trash"
+    },
+    "pref.UserName": {
+        "message": "User name"
+    },
+    "pref.UserNameDescription": {
+        "message": "User name is usually the email address of your account."
+    },
+    "pref.autodetect": {
+        "message": "best available"
+    },
+    "pref.birthday": {
+        "message": "Send birthday information"
+    },
+    "pref.calendaroptions": {
+        "message": "Calendar options"
+    },
+    "pref.contactoptions": {
+        "message": "Contact options"
+    },
+    "pref.displayoverride": {
+        "message": "Override Display Name with ?First Name? + ?Second Name?"
+    },
+    "pref.generaloptions": {
+        "message": "General options"
+    },
+    "pref.provision": {
+        "message": "Enforce provisioning (required by Kerio)"
+    },
+    "pref.seperator.comma": {
+        "message": "Comma"
+    },
+    "pref.seperator.description": {
+        "message": "Separator for multiline address field."
+    },
+    "pref.seperator.linebreak": {
+        "message": "Line break"
+    },
+    "pref.synclimit.1month": {
+        "message": "from 4 weeks ago"
+    },
+    "pref.synclimit.2weeks": {
+        "message": "from 2 weeks ago"
+    },
+    "pref.synclimit.3month": {
+        "message": "from 3 months ago"
+    },
+    "pref.synclimit.6month": {
+        "message": "from 6 months ago"
+    },
+    "pref.synclimit.all": {
+        "message": "everything"
+    },
+    "pref.synclimit.description": {
+        "message": "Synchronization period: "
+    },
+    "pref.usehttps": {
+        "message": "Use secure connection (connect via https)"
+    },
+    "recyclebin": {
+        "message": "Trash"
+    },
+    "servertype.auto": {
+        "message": "Automatic configuration"
+    },
+    "servertype.custom": {
+        "message": "Custom configuration"
+    },
+    "servertype.description.auto": {
+        "message": "The configuration for many ActiveSync servers can be discovered by providing just your email address."
+    },
+    "servertype.description.custom": {
+        "message": "Setup your account by manually providing the address of the server you want to connect."
+    },
+    "servertype.description.office365": {
+        "message": "Accounts connected to Office 365 use a modern authentication process called OAuth 2.0 which also supports Multi-Factor-Authentication (MFA)."
+    },
+    "servertype.office365": {
+        "message": "Microsoft Office 365"
+    },
+    "servertype.unlock": {
+        "message": "Double click to unlock all predefined server settings."
+    },
+    "status.401": {
+        "message": "Could not authenticate, check username and password (HTTP Error 401)."
+    },
+    "status.403": {
+        "message": "Server rejected connection (forbidden) (HTTP Error 403)."
+    },
+    "status.404": {
+        "message": "User not found (HTTP Error 404)."
+    },
+    "status.449": {
+        "message": "Server requests provisioning (HTTP Error 449)."
+    },
+    "status.500": {
+        "message": "Unknown Server Error (HTTP Error 500)."
+    },
+    "status.503": {
+        "message": "Service unavailable (HTTP Error 503)."
+    },
+    "status.BadItemSkipped": {
+        "message": "Bad Item Skipped: ##replace.1##"
+    },
+    "status.FolderDelete.3": {
+        "message": "Cannot delete a system folder (status 3)"
+    },
+    "status.FolderDelete.4": {
+        "message": "Folder does not exist (status 4), resyncing"
+    },
+    "status.FolderDelete.6": {
+        "message": "Command could not be completed, an error occurred on the server (status 6)"
+    },
+    "status.FolderDelete.9": {
+        "message": "Invalid synchronization key (status 9), resyncing"
+    },
+    "status.FolderSync.9": {
+        "message": "Invalid synchronization key (status 9), resyncing"
+    },
+    "status.InvalidServerOptions": {
+        "message": "The server does not provide information about the supported ActiveSync versions. Is EAS blocked for this user or this client (TbSync)? You could try to set the ActiveSync version manually."
+    },
+    "status.OK": {
+        "message": "OK"
+    },
+    "status.ServerRejectedRequest": {
+        "message": "The EAS Server rejected the last request."
+    },
+    "status.ServerRejectedSomeItems": {
+        "message": "The EAS server did not accept ##replace.1## elements."
+    },
+    "status.Sync.12": {
+        "message": "Folder hierarchy changed (status 12), resyncing"
+    },
+    "status.Sync.3": {
+        "message": "Invalid synchronization key (status 3), resyncing"
+    },
+    "status.Sync.4": {
+        "message": "Malformed request (status 4)"
+    },
+    "status.Sync.5": {
+        "message": "Temporary server issues or invalid item (status 5)"
+    },
+    "status.Sync.6": {
+        "message": "Invalid item (status 6)"
+    },
+    "status.Sync.8": {
+        "message": "Object not found (status 8)"
+    },
+    "status.aborted": {
+        "message": "Not synchronized"
+    },
+    "status.disabled": {
+        "message": "Disabled"
+    },
+    "status.empty-response": {
+        "message": "Server sends unexpected empty response."
+    },
+    "status.forbiddenCalendarItemInTasksFolder": {
+        "message": "Forbidden calendar item in a task folder (please resort)"
+    },
+    "status.forbiddenTasksItemInCalendarFolder": {
+        "message": "Forbidden task item in a calendar folder (please resort)"
+    },
+    "status.global.101": {
+        "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 101)."
+    },
+    "status.global.102": {
+        "message": "The request contains WBXML but it could not be decoded into XML (EAS Error 102)."
+    },
+    "status.global.103": {
+        "message": "The XML provided in the request does not follow the protocol requirements (EAS Error 103)."
+    },
+    "status.global.110": {
+        "message": "The server reported an internal error and we should not retry immediately. Automatic periodic sync has been disabled for 30 minutes (EAS Error 110)."
+    },
+    "status.global.clientdenied": {
+        "message": "The EAS server reports <##replace.2##> (status ##replace.1##) and does not allow TbSync to access your account."
+    },
+    "status.httperror": {
+        "message": "Communication error (HTTP status ##replace.1##)."
+    },
+    "status.invalid": {
+        "message": "Invalid server response (junk)."
+    },
+    "status.malformed-xml": {
+        "message": "Could not parse XML. Check event log for details."
+    },
+    "status.modified": {
+        "message": "Local modifications"
+    },
+    "status.network": {
+        "message": "Could not connect to server (##replace.1##)."
+    },
+    "status.networkerror": {
+        "message": "Could not connect to server."
+    },
+    "status.nosupportedeasversion": {
+        "message": "Server does not support ActiveSync v2.5 or v14.0 (only ##replace.1##). TbSync will not work with this ActiveSync server."
+    },
+    "status.notargets": {
+        "message": "Aborting Sync, because sync targets could not be created."
+    },
+    "status.notsupportedeasversion": {
+        "message": "Server does not support selected ActiveSync v##replace.1## (only ##replace.2##)."
+    },
+    "status.notsyncronized": {
+        "message": "Account needs to be synchronized, at least one item is out of sync."
+    },
+    "status.nouserhost": {
+        "message": "Missing username and/or server. Please provide those values."
+    },
+    "status.pending": {
+        "message": "Waiting to be synchronized"
+    },
+    "status.policy.2": {
+        "message": "There is no policy for this client. Contact your server administrator or disable provisioning for this account."
+    },
+    "status.policy.3": {
+        "message": "Unknown PolicyType value. Contact your server administrator or disable provisioning for this account."
+    },
+    "status.policy.4": {
+        "message": "The policy data on the server is corrupted (possibly tampered with). Contact your server administrator or disable provisioning for this account."
+    },
+    "status.policy.5": {
+        "message": "The client is acknowledging the wrong policy key. Contact your server administrator or disable provisioning for this account."
+    },
+    "status.provision": {
+        "message": "Provisioning failed with status <##replace.1##>"
+    },
+    "status.response-contains-no-data": {
+        "message": "Response from the server contains no data."
+    },
+    "status.resync-loop": {
+        "message": "There was an error from which we could not recover by resyncing the account. Please disable the account and try again. (Error: resync loop)"
+    },
+    "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.syncing": {
+        "message": "Synchronizing"
+    },
+    "status.timeout": {
+        "message": "Communication timeout."
+    },
+    "status.wbxml-parse-error": {
+        "message": "Server sends unreadable response."
+    },
+    "status.wbxmlerror": {
+        "message": "Sync failed. Server responded with status <##replace.1##>."
+    },
+    "status.wbxmlmissingfield": {
+        "message": "ActiveSync protocol violation: Mandatory field <##replace.1##> is missing from server response."
+    },
+    "syncstate.accountdone": {
+        "message": "Finished account"
+    },
+    "syncstate.done": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.eval.response.autodiscover": {
+        "message": "Processing updated server settings"
+    },
+    "syncstate.eval.response.deletefolder": {
+        "message": "Folder deleted"
+    },
+    "syncstate.eval.response.estimate": {
+        "message": "Processing change estimate"
+    },
+    "syncstate.eval.response.folders": {
+        "message": "Processing folder list update"
+    },
+    "syncstate.eval.response.localchanges": {
+        "message": "Processing acknowledgment of local changes"
+    },
+    "syncstate.eval.response.localdeletes": {
+        "message": "Processing acknowledgment of local deletes"
+    },
+    "syncstate.eval.response.options": {
+        "message": "Processing server options"
+    },
+    "syncstate.eval.response.provision": {
+        "message": "Processing provision"
+    },
+    "syncstate.eval.response.remotechanges": {
+        "message": "Processing remote changes"
+    },
+    "syncstate.eval.response.revertlocalchanges": {
+        "message": "Reverting local changes"
+    },
+    "syncstate.eval.response.setdeviceinfo": {
+        "message": "Sending device information"
+    },
+    "syncstate.eval.response.synckey": {
+        "message": "Processing SyncKey"
+    },
+    "syncstate.prepare.request.autodiscover": {
+        "message": "Requesting updated server settings"
+    },
+    "syncstate.prepare.request.deletefolder": {
+        "message": "Preparing to delete folder"
+    },
+    "syncstate.prepare.request.estimate": {
+        "message": "Requesting change estimate"
+    },
+    "syncstate.prepare.request.folders": {
+        "message": "Sending folder list update"
+    },
+    "syncstate.prepare.request.localchanges": {
+        "message": "Sending local changes"
+    },
+    "syncstate.prepare.request.localdeletes": {
+        "message": "Sending local deletes"
+    },
+    "syncstate.prepare.request.options": {
+        "message": "Requesting server options"
+    },
+    "syncstate.prepare.request.provision": {
+        "message": "Requesting provision"
+    },
+    "syncstate.prepare.request.remotechanges": {
+        "message": "Requesting remote changes"
+    },
+    "syncstate.prepare.request.revertlocalchanges": {
+        "message": "Collecting local changes"
+    },
+    "syncstate.prepare.request.setdeviceinfo": {
+        "message": "Sending device information"
+    },
+    "syncstate.prepare.request.synckey": {
+        "message": "Requesting SyncKey"
+    },
+    "syncstate.preparing": {
+        "message": "Preparing next item for synchronization"
+    },
+    "syncstate.send.request.autodiscover": {
+        "message": "Waiting for updated server settings"
+    },
+    "syncstate.send.request.deletefolder": {
+        "message": "Waiting for folder to be deleted"
+    },
+    "syncstate.send.request.estimate": {
+        "message": "Waiting for change estimate"
+    },
+    "syncstate.send.request.folders": {
+        "message": "Waiting for folder list update"
+    },
+    "syncstate.send.request.localchanges": {
+        "message": "Waiting for acknowledgment of local changes"
+    },
+    "syncstate.send.request.localdeletes": {
+        "message": "Waiting for acknowledgment of local deletes"
+    },
+    "syncstate.send.request.options": {
+        "message": "Waiting for server options"
+    },
+    "syncstate.send.request.provision": {
+        "message": "Waiting for provision"
+    },
+    "syncstate.send.request.remotechanges": {
+        "message": "Waiting for remote changes"
+    },
+    "syncstate.send.request.revertlocalchanges": {
+        "message": "Waiting for most recent versions"
+    },
+    "syncstate.send.request.setdeviceinfo": {
+        "message": "Sending device information"
+    },
+    "syncstate.send.request.synckey": {
+        "message": "Waiting for SyncKey"
+    },
+    "syncstate.syncing": {
+        "message": "Initialize synchronization"
+    }
+}
diff -Nru eas4tbsync-4.11/_locales/ru/messages.json eas4tbsync-4.17/_locales/ru/messages.json
--- eas4tbsync-4.11/_locales/ru/messages.json	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/_locales/ru/messages.json	2025-05-15 13:21:20.000000000 +0200
@@ -1,566 +1,566 @@
-{
-    "abCard.Anniversary": {
-        "message": "???? ????????:"
-    },
-    "abCard.AssistantName": {
-        "message": "????????:"
-    },
-    "abCard.AssistantPhoneNumber": {
-        "message": "??????? ?????????:"
-    },
-    "abCard.Business2PhoneNumber": {
-        "message": "??????? ??????? 2:"
-    },
-    "abCard.BusinessFaxNumber": {
-        "message": "??????? ????:"
-    },
-    "abCard.CarPhoneNumber": {
-        "message": "????????????? ???????:"
-    },
-    "abCard.CompanyMainPhone": {
-        "message": "???????? ??????? ???????:"
-    },
-    "abCard.Email3Address": {
-        "message": "???????? Email:"
-    },
-    "abCard.Home2PhoneNumber": {
-        "message": "???????? ??????? 2:"
-    },
-    "abCard.ManagerName": {
-        "message": "????????????:"
-    },
-    "abCard.MiddleName": {
-        "message": "????????:"
-    },
-    "abCard.OtherAddress": {
-        "message": "?????:"
-    },
-    "abCard.OtherCity": {
-        "message": "?????:"
-    },
-    "abCard.OtherCountry": {
-        "message": "??????:"
-    },
-    "abCard.OtherState": {
-        "message": "???????:"
-    },
-    "abCard.OtherZip": {
-        "message": "???????? ??????:"
-    },
-    "abCard.RadioPhoneNumber": {
-        "message": "????????????:"
-    },
-    "abCard.Spouse": {
-        "message": "??????:"
-    },
-    "abCard.header.eas": {
-        "message": "?????? ???? (EAS)"
-    },
-    "abCard.header.homenumbers": {
-        "message": "?????????????? ???????? ??????:"
-    },
-    "abCard.header.messaging": {
-        "message": "??????????:"
-    },
-    "abCard.header.otheraddress": {
-        "message": "?????? ????? (EAS)"
-    },
-    "abCard.header.othernumbers": {
-        "message": "?????????????? ??????:"
-    },
-    "abCard.header.people": {
-        "message": "????:"
-    },
-    "abCard.header.worknumbers": {
-        "message": "?????????????? ??????? ??????:"
-    },
-    "acl.readonly": {
-        "message": "?????? ? ??????? ?????? ??? ?????? (???????? ????????? ?????????)"
-    },
-    "acl.readwrite": {
-        "message": "?????? ? ?????? ?? ??????"
-    },
-    "add.description": {
-        "message": "??????????, ???????? ???? ?? ????????? ?????????? ???????????? ??????? ? ??????? ????????? ??????????. "
-    },
-    "add.name": {
-        "message": "??? ????????:"
-    },
-    "add.ok": {
-        "message": "???????? ???????"
-    },
-    "add.password": {
-        "message": "??????:"
-    },
-    "add.server": {
-        "message": "???????????? ???????:"
-    },
-    "add.shortdescription": {
-        "message": "?????????? ?? ??????? ??????"
-    },
-    "add.title": {
-        "message": "???????? Exchange ActiveSync ??????? ??? TbSync"
-    },
-    "add.url": {
-        "message": "????? ???????:"
-    },
-    "add.urldescription": {
-        "message": "?????????? ??????? ?????? ??????? ????? ??????? (????????: mail.yourserver.com). ?????? ????? ????? ??????? ?????? URL-????? (????????: https://mail.yourserver.com/Microsoft-Server-ActiveSync)."
-    },
-    "add.user": {
-        "message": "??? ???????????? (email ?????):"
-    },
-    "autocomplete.serverdirectory": {
-        "message": "?????????? ??????? ???????"
-    },
-    "autodiscover.Failed": {
-        "message": "??????????????? ??? ???????????? <##user##> ?? ???????. ???? ??????????????? ??????? ?????? ???? ?????????????, ???? ? ?????? ?????????? ActiveSync ???? ????????? ????????, ??? ?? ?????????????? ???????????????."
-    },
-    "autodiscover.NeedEmail": {
-        "message": "??????????????? ????? ?????????????? ????? ??????????? ????? ? ???????? ????? ????????????."
-    },
-    "autodiscover.Ok": {
-        "message": "??????????????? ??????? ?????????, ?????? ?? ?????? ????????? ?????????????? ????????? ? ?????????? ?????????? ?????????????."
-    },
-    "autodiscover.Querying": {
-        "message": "????? ?????????"
-    },
-    "config.auto": {
-        "message": "ActiveSync ???????????? ??????? (???????????????)"
-    },
-    "config.custom": {
-        "message": "ActiveSync ???????????? ???????"
-    },
-    "deletefolder.confirm": {
-        "message": "?? ????????????? ?????? ??????????? ????????? ????? ?##replace.1##? ?? ????????"
-    },
-    "deletefolder.menuentry": {
-        "message": "??????????? ????????? ????? ?##replace.1##? ?? ???????"
-    },
-    "deletefolder.notallowed": {
-        "message": "?????????? ?? ???????? ????? ?##replace.1##? ?????? ??? ???????? ???????? ?? ?? ??????."
-    },
-    "extensionDescription": {
-        "message": "????????? ? TbSync ????????? ????????????? ??? ??????? ??????? Exchange ????? ???????????? ?? http/https ???????? ActiveSync (????????, ?????? ? ?????????)."
-    },
-    "extensionName": {
-        "message": "Provider for Exchange ActiveSync"
-    },
-    "helplink.BadItemSkipped": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
-    },
-    "helplink.global.clientdenied": {
-        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
-    },
-    "helplink.security": {
-        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
-    },
-    "manager.tabs.accountsettings": {
-        "message": "????????? ????????"
-    },
-    "manager.tabs.outOfOffice": {
-        "message": "????????????"
-    },
-    "manager.tabs.syncsettings": {
-        "message": "????????? ?????????????"
-    },
-    "newaccount.add_auto": {
-        "message": "????????? ??????????????? ? ?????????? ????????"
-    },
-    "newaccount.add_custom": {
-        "message": "???????? ???????"
-    },
-    "pref.AccountName": {
-        "message": "??? ????????"
-    },
-    "pref.ActiveSyncVersion": {
-        "message": "?????? ActiveSync"
-    },
-    "pref.DeviceId": {
-        "message": "????????????? ??????????"
-    },
-    "pref.ServerName": {
-        "message": "????? ???????"
-    },
-    "pref.ServerNameDescription": {
-        "message": "????????: mail.yourserver.com"
-    },
-    "pref.ShowTrashedFolders": {
-        "message": "?????????? ?????, ????????? ? ???????"
-    },
-    "pref.UserName": {
-        "message": "??? ????????????"
-    },
-    "pref.UserNameDescription": {
-        "message": "??? ???????????? ?????? ???????? ??????? ??????????? ????? ????? ??????? ??????."
-    },
-    "pref.autodetect": {
-        "message": "?????? ?? ?????????"
-    },
-    "pref.birthday": {
-        "message": "????????? ?????????? ? ???? ????????"
-    },
-    "pref.calendaroptions": {
-        "message": "????????? ?????????"
-    },
-    "pref.contactoptions": {
-        "message": "????????? ????????"
-    },
-    "pref.displayoverride": {
-        "message": "?????????????? ???????????? ??? ? ??????? ????? + ?????????"
-    },
-    "pref.generaloptions": {
-        "message": "????? ?????????"
-    },
-    "pref.provision": {
-        "message": "????????? ???????????? (????????? ??? Kerio)"
-    },
-    "pref.seperator.comma": {
-        "message": "???????"
-    },
-    "pref.seperator.description": {
-        "message": "????????? ??? ?????????????? ???? ??????."
-    },
-    "pref.seperator.linebreak": {
-        "message": "?????? ??????"
-    },
-    "pref.synclimit.1month": {
-        "message": "?? 4 ?????? ?????"
-    },
-    "pref.synclimit.2weeks": {
-        "message": "?? 2 ?????? ?????"
-    },
-    "pref.synclimit.3month": {
-        "message": "?? 3 ??????? ?????"
-    },
-    "pref.synclimit.6month": {
-        "message": "?? 6 ??????? ?????"
-    },
-    "pref.synclimit.all": {
-        "message": "???"
-    },
-    "pref.synclimit.description": {
-        "message": "?????? ?????????????:"
-    },
-    "pref.usehttps": {
-        "message": "???????????? ?????????? ?????????? (?????????? ????? https)"
-    },
-    "recyclebin": {
-        "message": "???????"
-    },
-    "servertype.auto": {
-        "message": "?????????????? ?????????"
-    },
-    "servertype.custom": {
-        "message": "?????? ?????????"
-    },
-    "servertype.description.auto": {
-        "message": "??? ??????????? ???????????? ????????? ???????? ActiveSync ?????????? ??????? ?????? ????? ????? ??????????? ?????."
-    },
-    "servertype.description.custom": {
-        "message": "????????? ???? ??????? ??????, ??????? ?????? ????? ???????, ? ???????? ?? ?????? ????????????."
-    },
-    "servertype.description.office365": {
-        "message": "??????? ??????, ???????????? ? Office 365, ?????????? ??????????? ??????? ?????????????? ??? ????????? OAuth 2.0, ??????? ????? ???????????? ?????????????? ?????????????? (MFA)."
-    },
-    "servertype.office365": {
-        "message": "Microsoft Office 365"
-    },
-    "servertype.unlock": {
-        "message": "?????? ????????, ????? ?????????????? ??? ???????????????? ????????? ???????."
-    },
-    "status.401": {
-        "message": "?? ??????? ?????????????????, ????????? ??? ???????????? ? ??????. (HTTP ?????? 401)."
-    },
-    "status.403": {
-        "message": "?????? ???????? ?????????? (?????????) (HTTP ?????? 403)."
-    },
-    "status.404": {
-        "message": "???????????? ?? ?????? (HTTP ?????? 404)."
-    },
-    "status.449": {
-        "message": "????????? ??????? ??????????? (HTTP ?????? 449)."
-    },
-    "status.500": {
-        "message": "??????????? ?????? ??????? (HTTP ?????? 500)."
-    },
-    "status.503": {
-        "message": "?????? ?????????? (HTTP ?????? 503)."
-    },
-    "status.BadItemSkipped": {
-        "message": "?????? ??????? ????????: ##replace.1##"
-    },
-    "status.FolderDelete.3": {
-        "message": "?? ??????? ??????? ????????? ?????."
-    },
-    "status.FolderDelete.4": {
-        "message": "????? ?? ?????????? (?????? 4), ????????? ?????????????"
-    },
-    "status.FolderDelete.6": {
-        "message": "??????? ?? ????? ???? ?????????, ?? ??????? ???????? ??????."
-    },
-    "status.FolderDelete.9": {
-        "message": "???????? ???? ????????????? (?????? 9), ????????? ?????????????"
-    },
-    "status.FolderSync.9": {
-        "message": "???????? ???? ????????????? (?????? 9), ????????? ?????????????"
-    },
-    "status.InvalidServerOptions": {
-        "message": "?????? ?? ????????????? ?????????? ? ?????????????? ??????? ActiveSync. EAS ?????????? ??? ????? ???????????? ??? ????? ??????? (TbSync)? ?? ?????? ??????????? ?????????? ?????? ActiveSync ???????."
-    },
-    "status.OK": {
-        "message": "??????"
-    },
-    "status.ServerRejectedRequest": {
-        "message": "?????? EAS ???????? ??? ????????? ??????."
-    },
-    "status.ServerRejectedSomeItems": {
-        "message": "?????? EAS ?? ?????? ???????? ##replace.1##."
-    },
-    "status.Sync.12": {
-        "message": "???????? ???????? ????? (?????? 12), ????????? ?????????????"
-    },
-    "status.Sync.3": {
-        "message": "???????? ???? ????????????? (?????? 3), ????????? ?????????????"
-    },
-    "status.Sync.4": {
-        "message": "???????? ?????? (?????? 4)"
-    },
-    "status.Sync.5": {
-        "message": "????????? ???????? ? ???????? ??? ???????????? ??????? (?????? 5)"
-    },
-    "status.Sync.6": {
-        "message": "???????????? ??????? (?????? 6)"
-    },
-    "status.Sync.8": {
-        "message": "?????? ?? ?????? (?????? 8)"
-    },
-    "status.aborted": {
-        "message": "?? ????????????????"
-    },
-    "status.disabled": {
-        "message": "??????? ?? ???????, ????????????? ?????????."
-    },
-    "status.empty-response": {
-        "message": "?????? ?????????? ??????????? ?????? ?????."
-    },
-    "status.forbiddenCalendarItemInTasksFolder": {
-        "message": "??????????? ??????? ????????? ? ????? ????? (??????????, ?????????)"
-    },
-    "status.forbiddenTasksItemInCalendarFolder": {
-        "message": "??????????? ??????? ?????? ? ????? ????????? (??????????, ?????????)"
-    },
-    "status.global.101": {
-        "message": "?????? ???????? WBXML ?? ?? ?? ????? ???? ??????????? ? XML (EAS ?????? 101)."
-    },
-    "status.global.102": {
-        "message": "?????? ???????? WBXML ?? ?? ?? ????? ???? ??????????? ? XML (EAS ?????? 102)."
-    },
-    "status.global.103": {
-        "message": "XML, ????????? ? ???????, ?? ????????????? ??????????? ????????? (EAS ?????? 103)."
-    },
-    "status.global.110": {
-        "message": "?????? ??????? ? ?????????? ??????, ? ?? ?? ?????? ?????????? ????????? ???????. ?????????????? ????????????? ????????????? ???? ????????? ?? 30 ????? (?????? EAS 110)."
-    },
-    "status.global.clientdenied": {
-        "message": "?????? ??????? EAS <##replace.2##> (?????? ##replace.1##) ? ?? ????????? TbSync ?????? ? ?????? ????????."
-    },
-    "status.httperror": {
-        "message": "?????? ????? (HTTP ?????? ##replace.1##)."
-    },
-    "status.invalid": {
-        "message": "???????????? ????? ??????? (????? ? ??????)."
-    },
-    "status.malformed-xml": {
-        "message": "?? ??????? ????????? XML. ????????? ?????? ??????? ??? ???????."
-    },
-    "status.modified": {
-        "message": "????????? ?????????"
-    },
-    "status.network": {
-        "message": "?? ??????? ???????????? ? ??????? (##replace.1##)."
-    },
-    "status.networkerror": {
-        "message": "?? ??????? ???????????? ? ???????."
-    },
-    "status.nosupportedeasversion": {
-        "message": "?????? ?? ???????????? ActiveSync v2.5 ??? v14.0 (?????? ##replace.1##). TbSync ?? ????? ???????? ? ???? ActiveSync ????????."
-    },
-    "status.notargets": {
-        "message": "?????? ?????????????, ????????? ???? ????????????? ?? ????? ???? ???????."
-    },
-    "status.notsupportedeasversion": {
-        "message": "?????? ?? ???????????? ????????? ActiveSync v##replace.1## (?????? ##replace.2##)."
-    },
-    "status.notsyncronized": {
-        "message": "??????? ?????? ???? ???????????????, ?? ??????? ???? ???? ??????? ?? ???????????????."
-    },
-    "status.nouserhost": {
-        "message": "??????????? ??? ???????????? ?/??? ???????. ??????? ??? ????????."
-    },
-    "status.pending": {
-        "message": "???????? ???? ????????????????"
-    },
-    "status.policy.2": {
-        "message": "??? ????? ??????? ??? ????????. ?????????? ? ?????????????? ?????? ??????? ??? ????????? ????????????? ????? ????????."
-    },
-    "status.policy.3": {
-        "message": "??????????? ???????? ???????? ??? ????? ???????. ?????????? ? ?????????????? ?????? ??????? ??? ????????? ????????????? ????? ????????."
-    },
-    "status.policy.4": {
-        "message": "?????? ???????? ?? ??????? ?????????? (????????, ?????????). ?????????? ? ?????????????? ?????? ??????? ??? ????????? ????????????? ????? ????????."
-    },
-    "status.policy.5": {
-        "message": "?????? ????????? ???????????? ???? ????????. ?????????? ? ?????????????? ?????? ??????? ??? ????????? ????????????? ????? ????????."
-    },
-    "status.provision": {
-        "message": "?????????????? ?? ??????? ?? ???????? <##replace.1##>"
-    },
-    "status.response-contains-no-data": {
-        "message": "????? ?? ??????? ?? ???????? ??????."
-    },
-    "status.resync-loop": {
-        "message": "????????? ??????, ??-?? ??????? ?? ??????? ???????????????????? ???????. ????????? ??????? ? ????????? ???????. (??????: ????????? ?????????????)"
-    },
-    "status.security": {
-        "message": "?? ??????? ?????????? ?????????? ??????????. ?? ??????????? ??????????????? ??? ?????????? ?????????? ??? ??????? ??? ? Thunderbird? (##replace.1##)"
-    },
-    "status.skipped": {
-        "message": "???? ?? ??????????????, ?????????"
-    },
-    "status.syncing": {
-        "message": "?????????????"
-    },
-    "status.timeout": {
-        "message": "????-??? ?????."
-    },
-    "status.wbxml-parse-error": {
-        "message": "?????? ?????????? ?????????? ?????."
-    },
-    "status.wbxmlerror": {
-        "message": "?????? ?????????????. ?????? ??????? ???????? <##replace.1##>."
-    },
-    "status.wbxmlmissingfield": {
-        "message": "ActiveSync ???????? ???????: ???????????? ???? <##replace.1##> ??????????? ? ?????? ???????."
-    },
-    "syncstate.accountdone": {
-        "message": "??????????? ???????"
-    },
-    "syncstate.done": {
-        "message": "?????????? ?????????? ???????? ??? ?????????????"
-    },
-    "syncstate.eval.response.autodiscover": {
-        "message": "????????? ??????????? ???????? ???????"
-    },
-    "syncstate.eval.response.deletefolder": {
-        "message": "????? ???????"
-    },
-    "syncstate.eval.response.estimate": {
-        "message": "????????? ?????? ?????????"
-    },
-    "syncstate.eval.response.folders": {
-        "message": "????????? ?????????? ????? ?????"
-    },
-    "syncstate.eval.response.localchanges": {
-        "message": "????????? ????????????? ????????? ?????????"
-    },
-    "syncstate.eval.response.localdeletes": {
-        "message": "????????? ????????????? ????????? ????????"
-    },
-    "syncstate.eval.response.options": {
-        "message": "????????? ???????? ???????"
-    },
-    "syncstate.eval.response.provision": {
-        "message": "????????? ??????????????"
-    },
-    "syncstate.eval.response.remotechanges": {
-        "message": "????????? ????????? ?????????"
-    },
-    "syncstate.eval.response.revertlocalchanges": {
-        "message": "????? ????????? ?????????"
-    },
-    "syncstate.eval.response.setdeviceinfo": {
-        "message": "????????? ?????????? ?? ??????????"
-    },
-    "syncstate.eval.response.synckey": {
-        "message": "????????? ????????? ?????????????"
-    },
-    "syncstate.prepare.request.autodiscover": {
-        "message": "?????? ??????????? ???????? ???????"
-    },
-    "syncstate.prepare.request.deletefolder": {
-        "message": "?????????? ? ???????? ?????"
-    },
-    "syncstate.prepare.request.estimate": {
-        "message": "?????? ?????? ?????????"
-    },
-    "syncstate.prepare.request.folders": {
-        "message": "???????? ?????????? ????? ?????"
-    },
-    "syncstate.prepare.request.localchanges": {
-        "message": "???????? ????????? ?????????"
-    },
-    "syncstate.prepare.request.localdeletes": {
-        "message": "???????? ????????? ????????"
-    },
-    "syncstate.prepare.request.options": {
-        "message": "?????? ???????? ???????"
-    },
-    "syncstate.prepare.request.provision": {
-        "message": "?????? ??? ??????????????"
-    },
-    "syncstate.prepare.request.remotechanges": {
-        "message": "?????? ????????? ?????????"
-    },
-    "syncstate.prepare.request.revertlocalchanges": {
-        "message": "???? ????????? ?????????"
-    },
-    "syncstate.prepare.request.setdeviceinfo": {
-        "message": "????????? ?????????? ?? ??????????"
-    },
-    "syncstate.prepare.request.synckey": {
-        "message": "?????? ????????? ?????????????"
-    },
-    "syncstate.preparing": {
-        "message": "?????????? ?????????? ???????? ??? ?????????????"
-    },
-    "syncstate.send.request.autodiscover": {
-        "message": "???????? ??????????? ???????? ???????"
-    },
-    "syncstate.send.request.deletefolder": {
-        "message": "???????? ???????? ?????"
-    },
-    "syncstate.send.request.estimate": {
-        "message": "???????? ?????? ?????????"
-    },
-    "syncstate.send.request.folders": {
-        "message": "???????? ?????????? ????? ?????"
-    },
-    "syncstate.send.request.localchanges": {
-        "message": "???????? ????????????? ????????? ?????????"
-    },
-    "syncstate.send.request.localdeletes": {
-        "message": "???????? ????????????? ????????? ????????"
-    },
-    "syncstate.send.request.options": {
-        "message": "???????? ???????? ???????"
-    },
-    "syncstate.send.request.provision": {
-        "message": "???????? ??????????????"
-    },
-    "syncstate.send.request.remotechanges": {
-        "message": "???????? ????????? ?????????"
-    },
-    "syncstate.send.request.revertlocalchanges": {
-        "message": "???????? ????? ????????? ??????"
-    },
-    "syncstate.send.request.setdeviceinfo": {
-        "message": "????????? ?????????? ?? ??????????"
-    },
-    "syncstate.send.request.synckey": {
-        "message": "???????? ????????? ?????????????"
-    },
-    "syncstate.syncing": {
-        "message": "????????????? ?????????????"
-    }
-}
+{
+    "abCard.Anniversary": {
+        "message": "???? ????????:"
+    },
+    "abCard.AssistantName": {
+        "message": "????????:"
+    },
+    "abCard.AssistantPhoneNumber": {
+        "message": "??????? ?????????:"
+    },
+    "abCard.Business2PhoneNumber": {
+        "message": "??????? ??????? 2:"
+    },
+    "abCard.BusinessFaxNumber": {
+        "message": "??????? ????:"
+    },
+    "abCard.CarPhoneNumber": {
+        "message": "????????????? ???????:"
+    },
+    "abCard.CompanyMainPhone": {
+        "message": "???????? ??????? ???????:"
+    },
+    "abCard.Email3Address": {
+        "message": "???????? Email:"
+    },
+    "abCard.Home2PhoneNumber": {
+        "message": "???????? ??????? 2:"
+    },
+    "abCard.ManagerName": {
+        "message": "????????????:"
+    },
+    "abCard.MiddleName": {
+        "message": "????????:"
+    },
+    "abCard.OtherAddress": {
+        "message": "?????:"
+    },
+    "abCard.OtherCity": {
+        "message": "?????:"
+    },
+    "abCard.OtherCountry": {
+        "message": "??????:"
+    },
+    "abCard.OtherState": {
+        "message": "???????:"
+    },
+    "abCard.OtherZip": {
+        "message": "???????? ??????:"
+    },
+    "abCard.RadioPhoneNumber": {
+        "message": "????????????:"
+    },
+    "abCard.Spouse": {
+        "message": "??????:"
+    },
+    "abCard.header.eas": {
+        "message": "?????? ???? (EAS)"
+    },
+    "abCard.header.homenumbers": {
+        "message": "?????????????? ???????? ??????:"
+    },
+    "abCard.header.messaging": {
+        "message": "??????????:"
+    },
+    "abCard.header.otheraddress": {
+        "message": "?????? ????? (EAS)"
+    },
+    "abCard.header.othernumbers": {
+        "message": "?????????????? ??????:"
+    },
+    "abCard.header.people": {
+        "message": "????:"
+    },
+    "abCard.header.worknumbers": {
+        "message": "?????????????? ??????? ??????:"
+    },
+    "acl.readonly": {
+        "message": "?????? ? ??????? ?????? ??? ?????? (???????? ????????? ?????????)"
+    },
+    "acl.readwrite": {
+        "message": "?????? ? ?????? ?? ??????"
+    },
+    "add.description": {
+        "message": "??????????, ???????? ???? ?? ????????? ?????????? ???????????? ??????? ? ??????? ????????? ??????????. "
+    },
+    "add.name": {
+        "message": "??? ????????:"
+    },
+    "add.ok": {
+        "message": "???????? ???????"
+    },
+    "add.password": {
+        "message": "??????:"
+    },
+    "add.server": {
+        "message": "???????????? ???????:"
+    },
+    "add.shortdescription": {
+        "message": "?????????? ?? ??????? ??????"
+    },
+    "add.title": {
+        "message": "???????? Exchange ActiveSync ??????? ??? TbSync"
+    },
+    "add.url": {
+        "message": "????? ???????:"
+    },
+    "add.urldescription": {
+        "message": "?????????? ??????? ?????? ??????? ????? ??????? (????????: mail.yourserver.com). ?????? ????? ????? ??????? ?????? URL-????? (????????: https://mail.yourserver.com/Microsoft-Server-ActiveSync)."
+    },
+    "add.user": {
+        "message": "??? ???????????? (email ?????):"
+    },
+    "autocomplete.serverdirectory": {
+        "message": "?????????? ??????? ???????"
+    },
+    "autodiscover.Failed": {
+        "message": "??????????????? ??? ???????????? <##user##> ?? ???????. ???? ??????????????? ??????? ?????? ???? ?????????????, ???? ? ?????? ?????????? ActiveSync ???? ????????? ????????, ??? ?? ?????????????? ???????????????."
+    },
+    "autodiscover.NeedEmail": {
+        "message": "??????????????? ????? ?????????????? ????? ??????????? ????? ? ???????? ????? ????????????."
+    },
+    "autodiscover.Ok": {
+        "message": "??????????????? ??????? ?????????, ?????? ?? ?????? ????????? ?????????????? ????????? ? ?????????? ?????????? ?????????????."
+    },
+    "autodiscover.Querying": {
+        "message": "????? ?????????"
+    },
+    "config.auto": {
+        "message": "ActiveSync ???????????? ??????? (???????????????)"
+    },
+    "config.custom": {
+        "message": "ActiveSync ???????????? ???????"
+    },
+    "deletefolder.confirm": {
+        "message": "?? ????????????? ?????? ??????????? ????????? ????? ?##replace.1##? ?? ????????"
+    },
+    "deletefolder.menuentry": {
+        "message": "??????????? ????????? ????? ?##replace.1##? ?? ???????"
+    },
+    "deletefolder.notallowed": {
+        "message": "?????????? ?? ???????? ????? ?##replace.1##? ?????? ??? ???????? ???????? ?? ?? ??????."
+    },
+    "extensionDescription": {
+        "message": "????????? ? TbSync ????????? ????????????? ??? ??????? ??????? Exchange ????? ???????????? ?? http/https ???????? ActiveSync (????????, ?????? ? ?????????)."
+    },
+    "extensionName": {
+        "message": "Provider for Exchange ActiveSync"
+    },
+    "helplink.BadItemSkipped": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/Error:-Bad-item-skipped"
+    },
+    "helplink.global.clientdenied": {
+        "message": "https://github.com/jobisoft/EAS-4-TbSync/wiki/What-if-TbSync-is-blocked-by-my-server%3F"
+    },
+    "helplink.security": {
+        "message": "https://github.com/jobisoft/TbSync/wiki/How-to-use-TbSync-with-self-signed-or-otherwise-untrusted-certificates%3F"
+    },
+    "manager.tabs.accountsettings": {
+        "message": "????????? ????????"
+    },
+    "manager.tabs.outOfOffice": {
+        "message": "????????????"
+    },
+    "manager.tabs.syncsettings": {
+        "message": "????????? ?????????????"
+    },
+    "newaccount.add_auto": {
+        "message": "????????? ??????????????? ? ?????????? ????????"
+    },
+    "newaccount.add_custom": {
+        "message": "???????? ???????"
+    },
+    "pref.AccountName": {
+        "message": "??? ????????"
+    },
+    "pref.ActiveSyncVersion": {
+        "message": "?????? ActiveSync"
+    },
+    "pref.DeviceId": {
+        "message": "????????????? ??????????"
+    },
+    "pref.ServerName": {
+        "message": "????? ???????"
+    },
+    "pref.ServerNameDescription": {
+        "message": "????????: mail.yourserver.com"
+    },
+    "pref.ShowTrashedFolders": {
+        "message": "?????????? ?????, ????????? ? ???????"
+    },
+    "pref.UserName": {
+        "message": "??? ????????????"
+    },
+    "pref.UserNameDescription": {
+        "message": "??? ???????????? ?????? ???????? ??????? ??????????? ????? ????? ??????? ??????."
+    },
+    "pref.autodetect": {
+        "message": "?????? ?? ?????????"
+    },
+    "pref.birthday": {
+        "message": "????????? ?????????? ? ???? ????????"
+    },
+    "pref.calendaroptions": {
+        "message": "????????? ?????????"
+    },
+    "pref.contactoptions": {
+        "message": "????????? ????????"
+    },
+    "pref.displayoverride": {
+        "message": "?????????????? ???????????? ??? ? ??????? ????? + ?????????"
+    },
+    "pref.generaloptions": {
+        "message": "????? ?????????"
+    },
+    "pref.provision": {
+        "message": "????????? ???????????? (????????? ??? Kerio)"
+    },
+    "pref.seperator.comma": {
+        "message": "???????"
+    },
+    "pref.seperator.description": {
+        "message": "????????? ??? ?????????????? ???? ??????."
+    },
+    "pref.seperator.linebreak": {
+        "message": "?????? ??????"
+    },
+    "pref.synclimit.1month": {
+        "message": "?? 4 ?????? ?????"
+    },
+    "pref.synclimit.2weeks": {
+        "message": "?? 2 ?????? ?????"
+    },
+    "pref.synclimit.3month": {
+        "message": "?? 3 ??????? ?????"
+    },
+    "pref.synclimit.6month": {
+        "message": "?? 6 ??????? ?????"
+    },
+    "pref.synclimit.all": {
+        "message": "???"
+    },
+    "pref.synclimit.description": {
+        "message": "?????? ?????????????:"
+    },
+    "pref.usehttps": {
+        "message": "???????????? ?????????? ?????????? (?????????? ????? https)"
+    },
+    "recyclebin": {
+        "message": "???????"
+    },
+    "servertype.auto": {
+        "message": "?????????????? ?????????"
+    },
+    "servertype.custom": {
+        "message": "?????? ?????????"
+    },
+    "servertype.description.auto": {
+        "message": "??? ??????????? ???????????? ????????? ???????? ActiveSync ?????????? ??????? ?????? ????? ????? ??????????? ?????."
+    },
+    "servertype.description.custom": {
+        "message": "????????? ???? ??????? ??????, ??????? ?????? ????? ???????, ? ???????? ?? ?????? ????????????."
+    },
+    "servertype.description.office365": {
+        "message": "??????? ??????, ???????????? ? Office 365, ?????????? ??????????? ??????? ?????????????? ??? ????????? OAuth 2.0, ??????? ????? ???????????? ?????????????? ?????????????? (MFA)."
+    },
+    "servertype.office365": {
+        "message": "Microsoft Office 365"
+    },
+    "servertype.unlock": {
+        "message": "?????? ????????, ????? ?????????????? ??? ???????????????? ????????? ???????."
+    },
+    "status.401": {
+        "message": "?? ??????? ?????????????????, ????????? ??? ???????????? ? ??????. (HTTP ?????? 401)."
+    },
+    "status.403": {
+        "message": "?????? ???????? ?????????? (?????????) (HTTP ?????? 403)."
+    },
+    "status.404": {
+        "message": "???????????? ?? ?????? (HTTP ?????? 404)."
+    },
+    "status.449": {
+        "message": "????????? ??????? ??????????? (HTTP ?????? 449)."
+    },
+    "status.500": {
+        "message": "??????????? ?????? ??????? (HTTP ?????? 500)."
+    },
+    "status.503": {
+        "message": "?????? ?????????? (HTTP ?????? 503)."
+    },
+    "status.BadItemSkipped": {
+        "message": "?????? ??????? ????????: ##replace.1##"
+    },
+    "status.FolderDelete.3": {
+        "message": "?? ??????? ??????? ????????? ?????."
+    },
+    "status.FolderDelete.4": {
+        "message": "????? ?? ?????????? (?????? 4), ????????? ?????????????"
+    },
+    "status.FolderDelete.6": {
+        "message": "??????? ?? ????? ???? ?????????, ?? ??????? ???????? ??????."
+    },
+    "status.FolderDelete.9": {
+        "message": "???????? ???? ????????????? (?????? 9), ????????? ?????????????"
+    },
+    "status.FolderSync.9": {
+        "message": "???????? ???? ????????????? (?????? 9), ????????? ?????????????"
+    },
+    "status.InvalidServerOptions": {
+        "message": "?????? ?? ????????????? ?????????? ? ?????????????? ??????? ActiveSync. EAS ?????????? ??? ????? ???????????? ??? ????? ??????? (TbSync)? ?? ?????? ??????????? ?????????? ?????? ActiveSync ???????."
+    },
+    "status.OK": {
+        "message": "??????"
+    },
+    "status.ServerRejectedRequest": {
+        "message": "?????? EAS ???????? ??? ????????? ??????."
+    },
+    "status.ServerRejectedSomeItems": {
+        "message": "?????? EAS ?? ?????? ???????? ##replace.1##."
+    },
+    "status.Sync.12": {
+        "message": "???????? ???????? ????? (?????? 12), ????????? ?????????????"
+    },
+    "status.Sync.3": {
+        "message": "???????? ???? ????????????? (?????? 3), ????????? ?????????????"
+    },
+    "status.Sync.4": {
+        "message": "???????? ?????? (?????? 4)"
+    },
+    "status.Sync.5": {
+        "message": "????????? ???????? ? ???????? ??? ???????????? ??????? (?????? 5)"
+    },
+    "status.Sync.6": {
+        "message": "???????????? ??????? (?????? 6)"
+    },
+    "status.Sync.8": {
+        "message": "?????? ?? ?????? (?????? 8)"
+    },
+    "status.aborted": {
+        "message": "?? ????????????????"
+    },
+    "status.disabled": {
+        "message": "??????? ?? ???????, ????????????? ?????????."
+    },
+    "status.empty-response": {
+        "message": "?????? ?????????? ??????????? ?????? ?????."
+    },
+    "status.forbiddenCalendarItemInTasksFolder": {
+        "message": "??????????? ??????? ????????? ? ????? ????? (??????????, ?????????)"
+    },
+    "status.forbiddenTasksItemInCalendarFolder": {
+        "message": "??????????? ??????? ?????? ? ????? ????????? (??????????, ?????????)"
+    },
+    "status.global.101": {
+        "message": "?????? ???????? WBXML ?? ?? ?? ????? ???? ??????????? ? XML (EAS ?????? 101)."
+    },
+    "status.global.102": {
+        "message": "?????? ???????? WBXML ?? ?? ?? ????? ???? ??????????? ? XML (EAS ?????? 102)."
+    },
+    "status.global.103": {
+        "message": "XML, ????????? ? ???????, ?? ????????????? ??????????? ????????? (EAS ?????? 103)."
+    },
+    "status.global.110": {
+        "message": "?????? ??????? ? ?????????? ??????, ? ?? ?? ?????? ?????????? ????????? ???????. ?????????????? ????????????? ????????????? ???? ????????? ?? 30 ????? (?????? EAS 110)."
+    },
+    "status.global.clientdenied": {
+        "message": "?????? ??????? EAS <##replace.2##> (?????? ##replace.1##) ? ?? ????????? TbSync ?????? ? ?????? ????????."
+    },
+    "status.httperror": {
+        "message": "?????? ????? (HTTP ?????? ##replace.1##)."
+    },
+    "status.invalid": {
+        "message": "???????????? ????? ??????? (????? ? ??????)."
+    },
+    "status.malformed-xml": {
+        "message": "?? ??????? ????????? XML. ????????? ?????? ??????? ??? ???????."
+    },
+    "status.modified": {
+        "message": "????????? ?????????"
+    },
+    "status.network": {
+        "message": "?? ??????? ???????????? ? ??????? (##replace.1##)."
+    },
+    "status.networkerror": {
+        "message": "?? ??????? ???????????? ? ???????."
+    },
+    "status.nosupportedeasversion": {
+        "message": "?????? ?? ???????????? ActiveSync v2.5 ??? v14.0 (?????? ##replace.1##). TbSync ?? ????? ???????? ? ???? ActiveSync ????????."
+    },
+    "status.notargets": {
+        "message": "?????? ?????????????, ????????? ???? ????????????? ?? ????? ???? ???????."
+    },
+    "status.notsupportedeasversion": {
+        "message": "?????? ?? ???????????? ????????? ActiveSync v##replace.1## (?????? ##replace.2##)."
+    },
+    "status.notsyncronized": {
+        "message": "??????? ?????? ???? ???????????????, ?? ??????? ???? ???? ??????? ?? ???????????????."
+    },
+    "status.nouserhost": {
+        "message": "??????????? ??? ???????????? ?/??? ???????. ??????? ??? ????????."
+    },
+    "status.pending": {
+        "message": "???????? ???? ????????????????"
+    },
+    "status.policy.2": {
+        "message": "??? ????? ??????? ??? ????????. ?????????? ? ?????????????? ?????? ??????? ??? ????????? ????????????? ????? ????????."
+    },
+    "status.policy.3": {
+        "message": "??????????? ???????? ???????? ??? ????? ???????. ?????????? ? ?????????????? ?????? ??????? ??? ????????? ????????????? ????? ????????."
+    },
+    "status.policy.4": {
+        "message": "?????? ???????? ?? ??????? ?????????? (????????, ?????????). ?????????? ? ?????????????? ?????? ??????? ??? ????????? ????????????? ????? ????????."
+    },
+    "status.policy.5": {
+        "message": "?????? ????????? ???????????? ???? ????????. ?????????? ? ?????????????? ?????? ??????? ??? ????????? ????????????? ????? ????????."
+    },
+    "status.provision": {
+        "message": "?????????????? ?? ??????? ?? ???????? <##replace.1##>"
+    },
+    "status.response-contains-no-data": {
+        "message": "????? ?? ??????? ?? ???????? ??????."
+    },
+    "status.resync-loop": {
+        "message": "????????? ??????, ??-?? ??????? ?? ??????? ???????????????????? ???????. ????????? ??????? ? ????????? ???????. (??????: ????????? ?????????????)"
+    },
+    "status.security": {
+        "message": "?? ??????? ?????????? ?????????? ??????????. ?? ??????????? ??????????????? ??? ?????????? ?????????? ??? ??????? ??? ? Thunderbird? (##replace.1##)"
+    },
+    "status.skipped": {
+        "message": "???? ?? ??????????????, ?????????"
+    },
+    "status.syncing": {
+        "message": "?????????????"
+    },
+    "status.timeout": {
+        "message": "????-??? ?????."
+    },
+    "status.wbxml-parse-error": {
+        "message": "?????? ?????????? ?????????? ?????."
+    },
+    "status.wbxmlerror": {
+        "message": "?????? ?????????????. ?????? ??????? ???????? <##replace.1##>."
+    },
+    "status.wbxmlmissingfield": {
+        "message": "ActiveSync ???????? ???????: ???????????? ???? <##replace.1##> ??????????? ? ?????? ???????."
+    },
+    "syncstate.accountdone": {
+        "message": "??????????? ???????"
+    },
+    "syncstate.done": {
+        "message": "?????????? ?????????? ???????? ??? ?????????????"
+    },
+    "syncstate.eval.response.autodiscover": {
+        "message": "????????? ??????????? ???????? ???????"
+    },
+    "syncstate.eval.response.deletefolder": {
+        "message": "????? ???????"
+    },
+    "syncstate.eval.response.estimate": {
+        "message": "????????? ?????? ?????????"
+    },
+    "syncstate.eval.response.folders": {
+        "message": "????????? ?????????? ????? ?????"
+    },
+    "syncstate.eval.response.localchanges": {
+        "message": "????????? ????????????? ????????? ?????????"
+    },
+    "syncstate.eval.response.localdeletes": {
+        "message": "????????? ????????????? ????????? ????????"
+    },
+    "syncstate.eval.response.options": {
+        "message": "????????? ???????? ???????"
+    },
+    "syncstate.eval.response.provision": {
+        "message": "????????? ??????????????"
+    },
+    "syncstate.eval.response.remotechanges": {
+        "message": "????????? ????????? ?????????"
+    },
+    "syncstate.eval.response.revertlocalchanges": {
+        "message": "????? ????????? ?????????"
+    },
+    "syncstate.eval.response.setdeviceinfo": {
+        "message": "????????? ?????????? ?? ??????????"
+    },
+    "syncstate.eval.response.synckey": {
+        "message": "????????? ????????? ?????????????"
+    },
+    "syncstate.prepare.request.autodiscover": {
+        "message": "?????? ??????????? ???????? ???????"
+    },
+    "syncstate.prepare.request.deletefolder": {
+        "message": "?????????? ? ???????? ?????"
+    },
+    "syncstate.prepare.request.estimate": {
+        "message": "?????? ?????? ?????????"
+    },
+    "syncstate.prepare.request.folders": {
+        "message": "???????? ?????????? ????? ?????"
+    },
+    "syncstate.prepare.request.localchanges": {
+        "message": "???????? ????????? ?????????"
+    },
+    "syncstate.prepare.request.localdeletes": {
+        "message": "???????? ????????? ????????"
+    },
+    "syncstate.prepare.request.options": {
+        "message": "?????? ???????? ???????"
+    },
+    "syncstate.prepare.request.provision": {
+        "message": "?????? ??? ??????????????"
+    },
+    "syncstate.prepare.request.remotechanges": {
+        "message": "?????? ????????? ?????????"
+    },
+    "syncstate.prepare.request.revertlocalchanges": {
+        "message": "???? ????????? ?????????"
+    },
+    "syncstate.prepare.request.setdeviceinfo": {
+        "message": "????????? ?????????? ?? ??????????"
+    },
+    "syncstate.prepare.request.synckey": {
+        "message": "?????? ????????? ?????????????"
+    },
+    "syncstate.preparing": {
+        "message": "?????????? ?????????? ???????? ??? ?????????????"
+    },
+    "syncstate.send.request.autodiscover": {
+        "message": "???????? ??????????? ???????? ???????"
+    },
+    "syncstate.send.request.deletefolder": {
+        "message": "???????? ???????? ?????"
+    },
+    "syncstate.send.request.estimate": {
+        "message": "???????? ?????? ?????????"
+    },
+    "syncstate.send.request.folders": {
+        "message": "???????? ?????????? ????? ?????"
+    },
+    "syncstate.send.request.localchanges": {
+        "message": "???????? ????????????? ????????? ?????????"
+    },
+    "syncstate.send.request.localdeletes": {
+        "message": "???????? ????????????? ????????? ????????"
+    },
+    "syncstate.send.request.options": {
+        "message": "???????? ???????? ???????"
+    },
+    "syncstate.send.request.provision": {
+        "message": "???????? ??????????????"
+    },
+    "syncstate.send.request.remotechanges": {
+        "message": "???????? ????????? ?????????"
+    },
+    "syncstate.send.request.revertlocalchanges": {
+        "message": "???????? ????? ????????? ??????"
+    },
+    "syncstate.send.request.setdeviceinfo": {
+        "message": "????????? ?????????? ?? ??????????"
+    },
+    "syncstate.send.request.synckey": {
+        "message": "???????? ????????? ?????????????"
+    },
+    "syncstate.syncing": {
+        "message": "????????????? ?????????????"
+    }
+}
diff -Nru eas4tbsync-4.11/Makebeta eas4tbsync-4.17/Makebeta
--- eas4tbsync-4.11/Makebeta	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/Makebeta	1970-01-01 01:00:00.000000000 +0100
@@ -1,34 +0,0 @@
-#!/bin/bash
-# This file is part of EAS-4-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                   : EAS-4-TbSync.xpi
-
-git clean -df
-git checkout -- .
-git pull
-
-version=$(cat manifest.json | jq -r .version)
-updatefile=update-eas.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/static getApiVersion() { return \"/static getApiVersion() { return \"Beta /g" "content/provider.js"
-
-echo "Releasing version $version via beta release channel (will include updateURL)"
-sed -i "s|\"name\": \"__MSG_extensionName__\",|\"name\": \"EAS for 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 eas4tbsync-4.11/Makefile eas4tbsync-4.17/Makefile
--- eas4tbsync-4.11/Makefile	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/Makefile	1970-01-01 01:00:00.000000000 +0100
@@ -1,25 +0,0 @@
-# This file is part of EAS-4-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/.
-
-PACKAGE_NAME=EAS-4-TbSync
-
-ARCHIVE_NAME=$(PACKAGE_NAME).xpi
-
-PACKAGE_FILES= \
-	content \
-	_locales \
-	manifest.json \
-	CONTRIBUTORS.md \
-	LICENSE README.md \
-	background.js
-
-all: clean $(PACKAGE_FILES)
-	zip -r $(ARCHIVE_NAME) $(PACKAGE_FILES)
-
-clean:
-	rm -f $(ARCHIVE_NAME)
-
-.PHONY: clean
diff -Nru eas4tbsync-4.11/Makefile.bat eas4tbsync-4.17/Makefile.bat
--- eas4tbsync-4.11/Makefile.bat	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/Makefile.bat	1970-01-01 01:00:00.000000000 +0100
@@ -1,9 +0,0 @@
- at echo off
-REM  This file is part of EAS-4-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 EAS-4-TbSync.xpi
-"C:\Program Files\7-Zip\7zG.exe" a -tzip EAS-4-TbSync.xpi content _locales manifest.json CONTRIBUTORS.md LICENSE README.md background.js
diff -Nru eas4tbsync-4.11/manifest.json eas4tbsync-4.17/manifest.json
--- eas4tbsync-4.11/manifest.json	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/manifest.json	2025-07-28 19:37:06.000000000 +0200
@@ -1,35 +1,44 @@
-{
-  "applications": {
-    "gecko": {
-      "id": "eas4tbsync at jobisoft.de",
-      "strict_min_version": "128.0",
-      "strict_max_version": "128.*"
-    }
-  },
-  "manifest_version": 2,
-  "name": "__MSG_extensionName__",
-  "version": "4.11",
-  "author": "John Bieling",
-  "homepage_url": "https://github.com/jobisoft/EAS-4-TbSync/",
-  "default_locale": "en-US",
-  "description": "__MSG_extensionDescription__",
-  "icons": {
-    "32": "content/skin/eas32.png"
-  },
-  "background": {
-    "scripts": ["background.js"]
-  },
-  "permissions": [
-    "notifications"
-  ],
-  "experiment_apis": {
-    "BootstrapLoader": {
-      "schema": "content/api/BootstrapLoader/schema.json",
-      "parent": {
-        "scopes": ["addon_parent"],
-        "paths": [["BootstrapLoader"]],
-        "script": "content/api/BootstrapLoader/implementation.js"
-      }
-    }
-  }
-}
+{
+  "applications": {
+    "gecko": {
+      "id": "eas4tbsync at jobisoft.de",
+      "strict_min_version": "136.0",
+      "strict_max_version": "140.*"
+    }
+  },
+  "manifest_version": 2,
+  "name": "__MSG_extensionName__",
+  "version": "4.17",
+  "author": "John Bieling",
+  "homepage_url": "https://github.com/jobisoft/EAS-4-TbSync/",
+  "default_locale": "en-US",
+  "description": "__MSG_extensionDescription__",
+  "icons": {
+    "32": "content/skin/eas32.png"
+  },
+  "background": {
+    "type": "module",
+    "scripts": ["background.js"]
+  },
+  "permissions": [
+    "notifications"
+  ],
+  "experiment_apis": {
+    "LegacyHelper": {
+      "schema": "api/LegacyHelper/schema.json",
+      "parent": {
+        "scopes": ["addon_parent"],
+        "paths": [["LegacyHelper"]],
+        "script": "api/LegacyHelper/implementation.js"
+      }
+    },
+    "EAS4TbSync": {
+      "schema": "api/EAS4TbSync/schema.json",
+      "parent": {
+        "scopes": ["addon_parent"],
+        "paths": [["EAS4TbSync"]],
+        "script": "api/EAS4TbSync/implementation.js"
+      }
+    }
+  }
+}
diff -Nru eas4tbsync-4.11/README.md eas4tbsync-4.17/README.md
--- eas4tbsync-4.11/README.md	2024-08-19 20:22:14.000000000 +0200
+++ eas4tbsync-4.17/README.md	2019-11-30 13:30:50.000000000 +0100
@@ -1,23 +1,23 @@
-# EAS-4-TbSync
-
-This provider add-on adds Exchange ActiveSync (EAS v2.5 & v14.0) synchronization capabilities to [TbSync](https://github.com/jobisoft/TbSync/).
-
-More information can be found in the [wiki](https://github.com/jobisoft/EAS-4-TbSync/wiki/About:-Provider-for-Exchange-ActiveSync) of this repository
-
-## Want to add or fix a localization?
-To help translating this project, please visit [crowdin.com](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.
-
-
-## External data sources
-
-* TbSync uses a [timezone mapping](https://github.com/mj1856/TimeZoneConverter/blob/master/src/TimeZoneConverter/Data/Mapping.csv.gz) provided by [Matt Johnson](https://github.com/mj1856)
-
-
-## Icon sources and attributions
-
-#### CC0 Public Domain
-* [365_*.png] by [Microsoft / Wikimedia](https://commons.wikimedia.org/w/index.php?curid=21546299), converted from [SVG to PNG](https://ezgif.com/svg-to-png)
-
-#### CC-BY 3.0
-* [eas*.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/64484/exchange_ms_icon)
-* [exchange_300.png] derived from [Microsoft Exchange Icon #270871](https://icon-library.net/icon/microsoft-exchange-icon-10.html), [resized](www.simpleimageresizer.com/)
+# EAS-4-TbSync
+
+This provider add-on adds Exchange ActiveSync (EAS v2.5 & v14.0) synchronization capabilities to [TbSync](https://github.com/jobisoft/TbSync/).
+
+More information can be found in the [wiki](https://github.com/jobisoft/EAS-4-TbSync/wiki/About:-Provider-for-Exchange-ActiveSync) of this repository
+
+## Want to add or fix a localization?
+To help translating this project, please visit [crowdin.com](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.
+
+
+## External data sources
+
+* TbSync uses a [timezone mapping](https://github.com/mj1856/TimeZoneConverter/blob/master/src/TimeZoneConverter/Data/Mapping.csv.gz) provided by [Matt Johnson](https://github.com/mj1856)
+
+
+## Icon sources and attributions
+
+#### CC0 Public Domain
+* [365_*.png] by [Microsoft / Wikimedia](https://commons.wikimedia.org/w/index.php?curid=21546299), converted from [SVG to PNG](https://ezgif.com/svg-to-png)
+
+#### CC-BY 3.0
+* [eas*.png] by [FatCow Web Hosting](https://www.iconfinder.com/icons/64484/exchange_ms_icon)
+* [exchange_300.png] derived from [Microsoft Exchange Icon #270871](https://icon-library.net/icon/microsoft-exchange-icon-10.html), [resized](www.simpleimageresizer.com/)
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/screenshots/AddEASAccount.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/screenshots/AddEASAccount.png sind verschieden.
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/screenshots/autodiscover.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/screenshots/autodiscover.png sind verschieden.
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/screenshots/install.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/screenshots/install.png sind verschieden.
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/screenshots/options.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/screenshots/options.png sind verschieden.
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/unused/icons/cape.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/unused/icons/cape.png sind verschieden.
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/unused/icons/catman.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/unused/icons/catman.png sind verschieden.
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/unused/icons/discon.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/unused/icons/discon.png sind verschieden.
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/unused/icons/help.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/unused/icons/help.png sind verschieden.
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/unused/icons/old2_sync16.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/unused/icons/old2_sync16.png sind verschieden.
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/unused/icons/old2_sync16_r.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/unused/icons/old2_sync16_r.png sind verschieden.
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/unused/icons/old_sync16.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/unused/icons/old_sync16.png sind verschieden.
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/unused/icons/settings.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/unused/icons/settings.png sind verschieden.
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/unused/icons/slider-off.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/unused/icons/slider-off.png sind verschieden.
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/unused/icons/slider-on.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/unused/icons/slider-on.png sind verschieden.
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/unused/icons/sync.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/unused/icons/sync.png sind verschieden.
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/unused/icons/syncsmall.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/unused/icons/syncsmall.png sind verschieden.
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/unused/icons/t3_sync16.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/unused/icons/t3_sync16.png sind verschieden.
Bin?rdateien /tmp/ElwDXJcQR9/eas4tbsync-4.11/unused/icons/t3_sync16_r.png und /tmp/A5GQ5YmoSG/eas4tbsync-4.17/unused/icons/t3_sync16_r.png sind verschieden.


More information about the Pkg-mozext-maintainers mailing list