[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1082086: marked as done (bookworm-pu: package eas4tbsync/4.11-1~deb12u1)



Your message dated Sat, 11 Jan 2025 11:03:08 +0000
with message-id <E1tWZGm-009jY0-S2@coccia.debian.org>
and subject line Close 1082086
has caused the Debian Bug report #1082086,
regarding bookworm-pu: package eas4tbsync/4.11-1~deb12u1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
1082086: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1082086
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: bookworm
X-Debbugs-Cc: eas4tbsync@packages.debian.org, mechtilde@debian.org
Control: affects -1 + src:eas4tbsync
User: release.debian.org@packages.debian.org
Usertags: pu

[ Reason ]
Thunderbird will come with a new version (>=128.2.x) 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 an
exchange server.

[ Tests ]
The same upstream code works with thunderbird >= 128.2 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
dependencies

[ Other info ]
The only reason is the new upcomming version of the thunderbird.
diffstat for eas4tbsync-4.8 eas4tbsync-4.11

 _locales/ja/messages.json                     |   22 
 background.js                                 |   24 
 content/api/BootstrapLoader/implementation.js |  742 ---------------
 content/bootstrap.js                          |    2 
 content/includes/calendarsync.js              |    1 
 content/includes/contactsync.js               |    3 
 content/includes/network.js                   | 1271 +++++++++++++-------------
 content/includes/sync.js                      |    1 
 content/includes/tasksync.js                  |    1 
 content/includes/tools.js                     |   10 
 content/includes/wbxmltools.js                |    3 
 content/includes/xmltools.js                  |    3 
 content/manager/createAccount.js              |   20 
 content/manager/createAccount.xhtml           |    2 
 content/provider.js                           |    3 
 debian/changelog                              |   21 
 debian/control                                |    5 
 manifest.json                                 |    6 
 18 files changed, 761 insertions(+), 1379 deletions(-)

diff -Nru eas4tbsync-4.8/background.js eas4tbsync-4.11/background.js
--- eas4tbsync-4.8/background.js	2023-12-03 00:43:29.000000000 +0100
+++ eas4tbsync-4.11/background.js	2024-08-19 20:22:14.000000000 +0200
@@ -1,26 +1,6 @@
-function isCompatible(version) {
-  let [ major, minor , patch ] = version.split(".").map(e => parseInt(e,10));
-  return (
-    major > 102 || 
-    (major == 102 && minor > 3) ||
-    (major == 102 && minor == 3 && patch > 2)
-  );
-}
-
 async function main() {
-  let { version } = await browser.runtime.getBrowserInfo();
-  if (isCompatible(version)) {
-    await messenger.BootstrapLoader.registerChromeUrl([ ["content", "eas4tbsync", "content/"] ]);
-    await messenger.BootstrapLoader.registerBootstrapScript("chrome://eas4tbsync/content/bootstrap.js");  
-  } else {
-    let manifest = browser.runtime.getManifest();
-    browser.notifications.create({
-      type: "basic",
-      iconUrl: browser.runtime.getURL("content/skin/eas32.png"),
-      title: `${manifest.name}`,
-      message: "Please update Thunderbird to at least 102.3.3 to be able to use this provider.",
-    });
-  }
+  await messenger.BootstrapLoader.registerChromeUrl([ ["content", "eas4tbsync", "content/"] ]);
+  await messenger.BootstrapLoader.registerBootstrapScript("chrome://eas4tbsync/content/bootstrap.js");  
 }
 
 main();
diff -Nru eas4tbsync-4.8/content/api/BootstrapLoader/implementation.js eas4tbsync-4.11/content/api/BootstrapLoader/implementation.js
--- eas4tbsync-4.8/content/api/BootstrapLoader/implementation.js	2023-12-03 00:43:29.000000000 +0100
+++ eas4tbsync-4.11/content/api/BootstrapLoader/implementation.js	2024-08-19 20:22:14.000000000 +0200
@@ -15,16 +15,6 @@
 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");
-var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-
-function getThunderbirdVersion() {
-  let parts = Services.appinfo.version.split(".");
-  return {
-    major: parseInt(parts[0]),
-    minor: parseInt(parts[1]),
-    revision: parts.length > 2 ? parseInt(parts[2]) : 0,
-  }
-}
 
 function getMessenger(context) {
   let apis = ["storage", "runtime", "extension", "i18n"];
@@ -51,13 +41,13 @@
   for (let api of apis) {
     switch (api) {
       case "storage":
-        XPCOMUtils.defineLazyGetter(messenger, "storage", () =>
+        ChromeUtils.defineLazyGetter(messenger, "storage", () =>
           getStorage()
         );
         break;
 
       default:
-        XPCOMUtils.defineLazyGetter(messenger, api, () =>
+        ChromeUtils.defineLazyGetter(messenger, api, () =>
           context.apiCan.findAPIPath(api)
         );
     }
@@ -65,607 +55,16 @@
   return messenger;
 }
 
-var BootstrapLoader_102 = class extends ExtensionCommon.ExtensionAPI {
-  getCards(e) {
-    // This gets triggered by real events but also manually by providing the outer window.
-    // The event is attached to the outer browser, get the inner one.
-    let doc;
-
-    // 78,86, and 87+ need special handholding. *Yeah*.
-    if (getThunderbirdVersion().major < 86) {
-      let ownerDoc = e.document || e.target.ownerDocument;
-      doc = ownerDoc.getElementById("html-view-browser").contentDocument;
-    } else if (getThunderbirdVersion().major < 87) {
-      let ownerDoc = e.document || e.target;
-      doc = ownerDoc.getElementById("html-view-browser").contentDocument;
-    } else {
-      doc = e.document || e.target;
-    }
-    return doc.querySelectorAll("addon-card");
-  }
-
-  // Add pref entry to 68
-  add68PrefsEntry(event) {
-    let id = this.menu_addonPrefs_id + "_" + this.uniqueRandomID;
-
-    // Get the best size of the icon (16px or bigger)
-    let iconSizes = this.extension.manifest.icons
-      ? Object.keys(this.extension.manifest.icons)
-      : [];
-    iconSizes.sort((a, b) => a - b);
-    let bestSize = iconSizes.filter(e => parseInt(e) >= 16).shift();
-    let icon = bestSize ? this.extension.manifest.icons[bestSize] : "";
-
-    let name = this.extension.manifest.name;
-    let entry = icon
-      ? event.target.ownerGlobal.MozXULElement.parseXULToFragment(
-        `<menuitem class="menuitem-iconic" id="${id}" image="${icon}" label="${name}" />`)
-      : event.target.ownerGlobal.MozXULElement.parseXULToFragment(
-        `<menuitem id="${id}" label="${name}" />`);
-
-    event.target.appendChild(entry);
-    let noPrefsElem = event.target.querySelector('[disabled="true"]');
-    // using collapse could be undone by core, so we use display none
-    // noPrefsElem.setAttribute("collapsed", "true");
-    noPrefsElem.style.display = "none";
-    event.target.ownerGlobal.document.getElementById(id).addEventListener("command", this);
-  }
-
-  // Event handler for the addon manager, to update the state of the options button.
-  handleEvent(e) {
-    switch (e.type) {
-      // 68 add-on options menu showing
-      case "popupshowing": {
-        this.add68PrefsEntry(e);
-      }
-        break;
-
-      // 78/88 add-on options menu/button click
-      case "click": {
-        e.preventDefault();
-        e.stopPropagation();
-        let BL = {}
-        BL.extension = this.extension;
-        BL.messenger = getMessenger(this.context);
-        let w = Services.wm.getMostRecentWindow("mail:3pane");
-        w.openDialog(this.pathToOptionsPage, "AddonOptions", "chrome,resizable,centerscreen", BL);
-      }
-        break;
-
-      // 68 add-on options menu command
-      case "command": {
-        let BL = {}
-        BL.extension = this.extension;
-        BL.messenger = getMessenger(this.context);
-        e.target.ownerGlobal.openDialog(this.pathToOptionsPage, "AddonOptions", "chrome,resizable,centerscreen", BL);
-      }
-        break;
-
-      // update, ViewChanged and manual call for add-on manager options overlay
-      default: {
-        let cards = this.getCards(e);
-        for (let card of cards) {
-          // Setup either the options entry in the menu or the button
-          if (card.addon.id == this.extension.id) {
-            let optionsMenu =
-              (getThunderbirdVersion().major > 78 && getThunderbirdVersion().major < 88) ||
-              (getThunderbirdVersion().major == 78 && getThunderbirdVersion().minor < 10) ||
-              (getThunderbirdVersion().major == 78 && getThunderbirdVersion().minor == 10 && getThunderbirdVersion().revision < 2);
-            if (optionsMenu) {
-              // Options menu in 78.0-78.10 and 79-87
-              let addonOptionsLegacyEntry = card.querySelector(".extension-options-legacy");
-              if (card.addon.isActive && !addonOptionsLegacyEntry) {
-                let addonOptionsEntry = card.querySelector("addon-options panel-list panel-item[action='preferences']");
-                addonOptionsLegacyEntry = card.ownerDocument.createElement("panel-item");
-                addonOptionsLegacyEntry.setAttribute("data-l10n-id", "preferences-addon-button");
-                addonOptionsLegacyEntry.classList.add("extension-options-legacy");
-                addonOptionsEntry.parentNode.insertBefore(
-                  addonOptionsLegacyEntry,
-                  addonOptionsEntry
-                );
-                card.querySelector(".extension-options-legacy").addEventListener("click", this);
-              } else if (!card.addon.isActive && addonOptionsLegacyEntry) {
-                addonOptionsLegacyEntry.remove();
-              }
-            } else {
-              // Add-on button in 88
-              let addonOptionsButton = card.querySelector(".extension-options-button2");
-              if (card.addon.isActive && !addonOptionsButton) {
-                addonOptionsButton = card.ownerDocument.createElement("button");
-                addonOptionsButton.classList.add("extension-options-button2");
-                addonOptionsButton.style["min-width"] = "auto";
-                addonOptionsButton.style["min-height"] = "auto";
-                addonOptionsButton.style["width"] = "24px";
-                addonOptionsButton.style["height"] = "24px";
-                addonOptionsButton.style["margin"] = "0";
-                addonOptionsButton.style["margin-inline-start"] = "8px";
-                addonOptionsButton.style["-moz-context-properties"] = "fill";
-                addonOptionsButton.style["fill"] = "currentColor";
-                addonOptionsButton.style["background-image"] = "url('chrome://messenger/skin/icons/developer.svg')";
-                addonOptionsButton.style["background-repeat"] = "no-repeat";
-                addonOptionsButton.style["background-position"] = "center center";
-                addonOptionsButton.style["padding"] = "1px";
-                addonOptionsButton.style["display"] = "flex";
-                addonOptionsButton.style["justify-content"] = "flex-end";
-                card.optionsButton.parentNode.insertBefore(
-                  addonOptionsButton,
-                  card.optionsButton
-                );
-                card.querySelector(".extension-options-button2").addEventListener("click", this);
-              } else if (!card.addon.isActive && addonOptionsButton) {
-                addonOptionsButton.remove();
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  // Some tab/add-on-manager related functions
-  getTabMail(window) {
-    return window.document.getElementById("tabmail");
-  }
-
-  // returns the outer browser, not the nested browser of the add-on manager
-  // events must be attached to the outer browser
-  getAddonManagerFromTab(tab) {
-    if (tab.browser && tab.mode.name == "contentTab") {
-      let win = tab.browser.contentWindow;
-      if (win && win.location.href == "about:addons") {
-        return win;
-      }
-    }
-  }
-
-  getAddonManagerFromWindow(window) {
-    let tabMail = this.getTabMail(window);
-    for (let tab of tabMail.tabInfo) {
-      let managerWindow = this.getAddonManagerFromTab(tab);
-      if (managerWindow) {
-        return managerWindow;
-      }
-    }
-  }
-
-  async getAddonManagerFromWindowWaitForLoad(window) {
-    let { setTimeout } = Services.wm.getMostRecentWindow("mail:3pane");
-
-    let tabMail = this.getTabMail(window);
-    for (let tab of tabMail.tabInfo) {
-      if (tab.browser && tab.mode.name == "contentTab") {
-        // Instead of registering a load observer, wait until its loaded. Not nice,
-        // but gets aroud a lot of edge cases.
-        while (!tab.pageLoaded) {
-          await new Promise(r => setTimeout(r, 150));
-        }
-        let managerWindow = this.getAddonManagerFromTab(tab);
-        if (managerWindow) {
-          return managerWindow;
-        }
-      }
-    }
-  }
-
-  setupAddonManager(managerWindow, forceLoad = false) {
-    if (!managerWindow) {
-      return;
-    }
-    if (
-      managerWindow &&
-      managerWindow[this.uniqueRandomID] &&
-      managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners
-    ) {
-      return;
-    }
-    managerWindow.document.addEventListener("ViewChanged", this);
-    managerWindow.document.addEventListener("update", this);
-    managerWindow.document.addEventListener("view-loaded", this);
-    managerWindow[this.uniqueRandomID] = {};
-    managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners = true;
-    if (forceLoad) {
-      this.handleEvent(managerWindow);
-    }
-  }
-
-  getAPI(context) {
-    this.uniqueRandomID = "AddOnNS" + context.extension.instanceId;
-    this.menu_addonPrefs_id = "addonPrefs";
-
-
-    this.pathToBootstrapScript = null;
-    this.pathToOptionsPage = null;
-    this.chromeHandle = null;
-    this.chromeData = null;
-    this.resourceData = null;
-    this.bootstrappedObj = {};
-
-    // make the extension object and the messenger object available inside
-    // the bootstrapped scope
-    this.bootstrappedObj.extension = context.extension;
-    this.bootstrappedObj.messenger = getMessenger(this.context);
-
-    this.BOOTSTRAP_REASONS = {
-      APP_STARTUP: 1,
-      APP_SHUTDOWN: 2,
-      ADDON_ENABLE: 3,
-      ADDON_DISABLE: 4,
-      ADDON_INSTALL: 5,
-      ADDON_UNINSTALL: 6, // not supported
-      ADDON_UPGRADE: 7,
-      ADDON_DOWNGRADE: 8,
-    };
-
-    const aomStartup = Cc["@mozilla.org/addons/addon-manager-startup;1"].getService(Ci.amIAddonManagerStartup);
-    const resProto = Cc["@mozilla.org/network/protocol;1?name=resource"].getService(Ci.nsISubstitutingProtocolHandler);
-
-    let self = this;
-
-    // TabMonitor to detect opening of tabs, to setup the options button in the add-on manager.
-    this.tabMonitor = {
-      onTabTitleChanged(tab) { },
-      onTabClosing(tab) { },
-      onTabPersist(tab) { },
-      onTabRestored(tab) { },
-      onTabSwitched(aNewTab, aOldTab) { },
-      async onTabOpened(tab) {
-        if (tab.browser && tab.mode.name == "contentTab") {
-          let { setTimeout } = Services.wm.getMostRecentWindow("mail:3pane");
-          // Instead of registering a load observer, wait until its loaded. Not nice,
-          // but gets aroud a lot of edge cases.
-          while (!tab.pageLoaded) {
-            await new Promise(r => setTimeout(r, 150));
-          }
-          self.setupAddonManager(self.getAddonManagerFromTab(tab));
-        }
-      },
-    };
-
-    return {
-      BootstrapLoader: {
-
-        registerOptionsPage(optionsUrl) {
-          self.pathToOptionsPage = optionsUrl.startsWith("chrome://")
-            ? optionsUrl
-            : context.extension.rootURI.resolve(optionsUrl);
-        },
-
-        openOptionsDialog(windowId) {
-          let window = context.extension.windowManager.get(windowId, context).window
-          let BL = {}
-          BL.extension = self.extension;
-          BL.messenger = getMessenger(self.context);
-          window.openDialog(self.pathToOptionsPage, "AddonOptions", "chrome,resizable,centerscreen", BL);
-        },
-
-        registerChromeUrl(data) {
-          let chromeData = [];
-          let resourceData = [];
-          for (let entry of data) {
-            if (entry[0] == "resource") resourceData.push(entry);
-            else chromeData.push(entry)
-          }
-
-          if (chromeData.length > 0) {
-            const manifestURI = Services.io.newURI(
-              "manifest.json",
-              null,
-              context.extension.rootURI
-            );
-            self.chromeHandle = aomStartup.registerChrome(manifestURI, chromeData);
-          }
-
-          for (let res of resourceData) {
-            // [ "resource", "shortname" , "path" ]
-            let uri = Services.io.newURI(
-              res[2],
-              null,
-              context.extension.rootURI
-            );
-            resProto.setSubstitutionWithFlags(
-              res[1],
-              uri,
-              resProto.ALLOW_CONTENT_ACCESS
-            );
-          }
-
-          self.chromeData = chromeData;
-          self.resourceData = resourceData;
-        },
-
-        registerBootstrapScript: async function (aPath) {
-          self.pathToBootstrapScript = aPath.startsWith("chrome://")
-            ? aPath
-            : context.extension.rootURI.resolve(aPath);
-
-          // Get the addon object belonging to this extension.
-          let addon = await AddonManager.getAddonByID(context.extension.id);
-          //make the addon globally available in the bootstrapped scope
-          self.bootstrappedObj.addon = addon;
-
-          // add BOOTSTRAP_REASONS to scope
-          for (let reason of Object.keys(self.BOOTSTRAP_REASONS)) {
-            self.bootstrappedObj[reason] = self.BOOTSTRAP_REASONS[reason];
-          }
-
-          // Load registered bootstrap scripts and execute its startup() function.
-          try {
-            if (self.pathToBootstrapScript) Services.scriptloader.loadSubScript(self.pathToBootstrapScript, self.bootstrappedObj, "UTF-8");
-            if (self.bootstrappedObj.startup) self.bootstrappedObj.startup.call(self.bootstrappedObj, self.extension.addonData, self.BOOTSTRAP_REASONS[self.extension.startupReason]);
-          } catch (e) {
-            Components.utils.reportError(e)
-          }
-
-          // Register window listener for main TB window
-          if (self.pathToOptionsPage) {
-            ExtensionSupport.registerWindowListener("injectListener_" + self.uniqueRandomID, {
-              chromeURLs: [
-                "chrome://messenger/content/messenger.xul",
-                "chrome://messenger/content/messenger.xhtml",
-              ],
-              async onLoadWindow(window) {
-                if (getThunderbirdVersion().major < 78) {
-                  let element_addonPrefs = window.document.getElementById(self.menu_addonPrefs_id);
-                  element_addonPrefs.addEventListener("popupshowing", self);
-                } else {
-                  // Add a tabmonitor, to be able to setup the options button/menu in the add-on manager.
-                  self.getTabMail(window).registerTabMonitor(self.tabMonitor);
-                  window[self.uniqueRandomID] = {};
-                  window[self.uniqueRandomID].hasTabMonitor = true;
-                  // Setup the options button/menu in the add-on manager, if it is already open.
-                  let managerWindow = await self.getAddonManagerFromWindowWaitForLoad(window);
-                  self.setupAddonManager(managerWindow, true);
-                }
-              },
-
-              onUnloadWindow(window) {
-              }
-            });
-          }
-        }
-      }
-    };
-  }
-
-  onShutdown(isAppShutdown) {
-    if (isAppShutdown) {
-      return; // the application gets unloaded anyway
-    }
-
-    //remove our entry in the add-on options menu
-    if (this.pathToOptionsPage) {
-      for (let window of Services.wm.getEnumerator("mail:3pane")) {
-        if (getThunderbirdVersion().major < 78) {
-          let element_addonPrefs = window.document.getElementById(this.menu_addonPrefs_id);
-          element_addonPrefs.removeEventListener("popupshowing", this);
-          // Remove our entry.
-          let entry = window.document.getElementById(this.menu_addonPrefs_id + "_" + this.uniqueRandomID);
-          if (entry) entry.remove();
-          // Do we have to unhide the noPrefsElement?
-          if (element_addonPrefs.children.length == 1) {
-            let noPrefsElem = element_addonPrefs.querySelector('[disabled="true"]');
-            noPrefsElem.style.display = "inline";
-          }
-        } else {
-          // Remove event listener for addon manager view changes
-          let managerWindow = this.getAddonManagerFromWindow(window);
-          if (
-            managerWindow && 
-            managerWindow[this.uniqueRandomID] && 
-            managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners
-          ) {
-            managerWindow.document.removeEventListener("ViewChanged", this);
-            managerWindow.document.removeEventListener("update", this);
-            managerWindow.document.removeEventListener("view-loaded", this);
-            managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners = false;
-
-            let cards = this.getCards(managerWindow);
-            if (getThunderbirdVersion().major < 88) {
-              // Remove options menu in 78-87
-              for (let card of cards) {
-                let addonOptionsLegacyEntry = card.querySelector(".extension-options-legacy");
-                if (addonOptionsLegacyEntry) addonOptionsLegacyEntry.remove();
-              }
-            } else {
-              // Remove options button in 88
-              for (let card of cards) {
-                if (card.addon.id == this.extension.id) {
-                  let addonOptionsButton = card.querySelector(".extension-options-button2");
-                  if (addonOptionsButton) addonOptionsButton.remove();
-                  break;
-                }
-              }
-            }
-          }
-
-          // Remove tabmonitor
-          if (window[this.uniqueRandomID].hasTabMonitor) {
-            this.getTabMail(window).unregisterTabMonitor(this.tabMonitor);
-            window[this.uniqueRandomID].hasTabMonitor = false;
-          }
-
-        }
-      }
-      // Stop listening for new windows.
-      ExtensionSupport.unregisterWindowListener("injectListener_" + this.uniqueRandomID);
-    }
-
-    // Execute registered shutdown()
-    try {
-      if (this.bootstrappedObj.shutdown) {
-        this.bootstrappedObj.shutdown(
-          this.extension.addonData,
-          isAppShutdown
-            ? this.BOOTSTRAP_REASONS.APP_SHUTDOWN
-            : this.BOOTSTRAP_REASONS.ADDON_DISABLE);
-      }
-    } catch (e) {
-      Components.utils.reportError(e)
-    }
-
-    if (this.resourceData) {
-      const resProto = Cc["@mozilla.org/network/protocol;1?name=resource"].getService(Ci.nsISubstitutingProtocolHandler);
-      for (let res of this.resourceData) {
-        // [ "resource", "shortname" , "path" ]
-        resProto.setSubstitution(
-          res[1],
-          null,
-        );
-      }
-    }
-
-    if (this.chromeHandle) {
-      this.chromeHandle.destruct();
-      this.chromeHandle = null;
-    }
-    // Flush all caches
-    Services.obs.notifyObservers(null, "startupcache-invalidate");
-    console.log("BootstrapLoader for " + this.extension.id + " unloaded!");
-  }
-};
-
 // Removed all extra code for backward compatibility for better maintainability.
-var BootstrapLoader_115 = class extends ExtensionCommon.ExtensionAPI {
-  getCards(e) {
-    // This gets triggered by real events but also manually by providing the outer window.
-    // The event is attached to the outer browser, get the inner one.
-    let doc = e.document || e.target;
-    return doc.querySelectorAll("addon-card");
-  }
-
-  // Event handler for the addon manager, to update the state of the options button.
-  handleEvent(e) {
-    switch (e.type) {
-      case "click": {
-        e.preventDefault();
-        e.stopPropagation();
-        let BL = {}
-        BL.extension = this.extension;
-        BL.messenger = getMessenger(this.context);
-        let w = Services.wm.getMostRecentWindow("mail:3pane");
-        w.openDialog(
-          this.pathToOptionsPage,
-          "AddonOptions",
-          "chrome,resizable,centerscreen",
-          BL
-        );
-      }
-        break;
-
-
-      // update, ViewChanged and manual call for add-on manager options overlay
-      default: {
-        let cards = this.getCards(e);
-        for (let card of cards) {
-          // Setup either the options entry in the menu or the button
-          if (card.addon.id == this.extension.id) {
-            // Add-on button
-            let addonOptionsButton = card.querySelector(
-              ".windowlistener-options-button"
-            );
-            if (card.addon.isActive && !addonOptionsButton) {
-              let origAddonOptionsButton = card.querySelector(".extension-options-button")
-              origAddonOptionsButton.setAttribute("hidden", "true");
-
-              addonOptionsButton = card.ownerDocument.createElement("button");
-              addonOptionsButton.classList.add("windowlistener-options-button");
-              addonOptionsButton.classList.add("extension-options-button");
-              card.optionsButton.parentNode.insertBefore(
-                addonOptionsButton,
-                card.optionsButton
-              );
-              card
-                .querySelector(".windowlistener-options-button")
-                .addEventListener("click", this);
-            } else if (!card.addon.isActive && addonOptionsButton) {
-              addonOptionsButton.remove();
-            }
-          }
-        }
-      }
-    }
-  }
-
-  // Some tab/add-on-manager related functions
-  getTabMail(window) {
-    return window.document.getElementById("tabmail");
-  }
-
-  // returns the outer browser, not the nested browser of the add-on manager
-  // events must be attached to the outer browser
-  getAddonManagerFromTab(tab) {
-    if (tab.browser && tab.mode.name == "contentTab") {
-      let win = tab.browser.contentWindow;
-      if (win && win.location.href == "about:addons") {
-        return win;
-      }
-    }
-  }
-
-  getAddonManagerFromWindow(window) {
-    let tabMail = this.getTabMail(window);
-    for (let tab of tabMail.tabInfo) {
-      let managerWindow = this.getAddonManagerFromTab(tab);
-      if (managerWindow) {
-        return managerWindow;
-      }
-    }
-  }
-
-  async getAddonManagerFromWindowWaitForLoad(window) {
-    let { setTimeout } = Services.wm.getMostRecentWindow("mail:3pane");
-
-    let tabMail = this.getTabMail(window);
-    for (let tab of tabMail.tabInfo) {
-      if (tab.browser && tab.mode.name == "contentTab") {
-        // Instead of registering a load observer, wait until its loaded. Not nice,
-        // but gets aroud a lot of edge cases.
-        while (!tab.pageLoaded) {
-          await new Promise(r => setTimeout(r, 150));
-        }
-        let managerWindow = this.getAddonManagerFromTab(tab);
-        if (managerWindow) {
-          return managerWindow;
-        }
-      }
-    }
-  }
-
-  setupAddonManager(managerWindow, forceLoad = false) {
-    if (!managerWindow) {
-      return;
-    }
-    if (!this.pathToOptionsPage) {
-      return;
-    }
-    if (
-      managerWindow &&
-      managerWindow[this.uniqueRandomID] &&
-      managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners
-    ) {
-      return;
-    }
-    
-    managerWindow.document.addEventListener("ViewChanged", this);
-    managerWindow.document.addEventListener("update", this);
-    managerWindow.document.addEventListener("view-loaded", this);
-    managerWindow[this.uniqueRandomID] = {};
-    managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners = true;
-    if (forceLoad) {
-      this.handleEvent(managerWindow);
-    }
-  }
-
+var BootstrapLoader = class extends ExtensionCommon.ExtensionAPI {
   getAPI(context) {
     this.uniqueRandomID = "AddOnNS" + context.extension.instanceId;
     this.menu_addonPrefs_id = "addonPrefs";
 
 
     this.pathToBootstrapScript = null;
-    this.pathToOptionsPage = null;
     this.chromeHandle = null;
     this.chromeData = null;
-    this.resourceData = null;
     this.bootstrappedObj = {};
 
     // make the extension object and the messenger object available inside
@@ -711,27 +110,10 @@
 
     return {
       BootstrapLoader: {
-
-        registerOptionsPage(optionsUrl) {
-          self.pathToOptionsPage = optionsUrl.startsWith("chrome://")
-            ? optionsUrl
-            : context.extension.rootURI.resolve(optionsUrl);
-        },
-
-        openOptionsDialog(windowId) {
-          let window = context.extension.windowManager.get(windowId, context).window
-          let BL = {}
-          BL.extension = self.extension;
-          BL.messenger = getMessenger(self.context);
-          window.openDialog(self.pathToOptionsPage, "AddonOptions", "chrome,resizable,centerscreen", BL);
-        },
-
         registerChromeUrl(data) {
           let chromeData = [];
-          let resourceData = [];
           for (let entry of data) {
-            if (entry[0] == "resource") resourceData.push(entry);
-            else chromeData.push(entry)
+            chromeData.push(entry)
           }
 
           if (chromeData.length > 0) {
@@ -743,22 +125,7 @@
             self.chromeHandle = aomStartup.registerChrome(manifestURI, chromeData);
           }
 
-          for (let res of resourceData) {
-            // [ "resource", "shortname" , "path" ]
-            let uri = Services.io.newURI(
-              res[2],
-              null,
-              context.extension.rootURI
-            );
-            resProto.setSubstitutionWithFlags(
-              res[1],
-              uri,
-              resProto.ALLOW_CONTENT_ACCESS
-            );
-          }
-
           self.chromeData = chromeData;
-          self.resourceData = resourceData;
         },
 
         registerBootstrapScript: async function (aPath) {
@@ -768,6 +135,7 @@
 
           // 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;
 
@@ -784,32 +152,6 @@
             Components.utils.reportError(e)
           }
 
-          // Register window listener for main TB window
-          if (self.pathToOptionsPage) {
-            ExtensionSupport.registerWindowListener("injectListener_" + self.uniqueRandomID, {
-              chromeURLs: [
-                "chrome://messenger/content/messenger.xul",
-                "chrome://messenger/content/messenger.xhtml",
-              ],
-              async onLoadWindow(window) {
-                if (getThunderbirdVersion().major < 78) {
-                  let element_addonPrefs = window.document.getElementById(self.menu_addonPrefs_id);
-                  element_addonPrefs.addEventListener("popupshowing", self);
-                } else {
-                  // Add a tabmonitor, to be able to setup the options button/menu in the add-on manager.
-                  self.getTabMail(window).registerTabMonitor(self.tabMonitor);
-                  window[self.uniqueRandomID] = {};
-                  window[self.uniqueRandomID].hasTabMonitor = true;
-                  // Setup the options button/menu in the add-on manager, if it is already open.
-                  let managerWindow = await self.getAddonManagerFromWindowWaitForLoad(window);
-                  self.setupAddonManager(managerWindow, true);
-                }
-              },
-
-              onUnloadWindow(window) {
-              }
-            });
-          }
         }
       }
     };
@@ -820,63 +162,6 @@
       return; // the application gets unloaded anyway
     }
 
-    //remove our entry in the add-on options menu
-    if (this.pathToOptionsPage) {
-      for (let window of Services.wm.getEnumerator("mail:3pane")) {
-        if (getThunderbirdVersion().major < 78) {
-          let element_addonPrefs = window.document.getElementById(this.menu_addonPrefs_id);
-          element_addonPrefs.removeEventListener("popupshowing", this);
-          // Remove our entry.
-          let entry = window.document.getElementById(this.menu_addonPrefs_id + "_" + this.uniqueRandomID);
-          if (entry) entry.remove();
-          // Do we have to unhide the noPrefsElement?
-          if (element_addonPrefs.children.length == 1) {
-            let noPrefsElem = element_addonPrefs.querySelector('[disabled="true"]');
-            noPrefsElem.style.display = "inline";
-          }
-        } else {
-          // Remove event listener for addon manager view changes
-          let managerWindow = this.getAddonManagerFromWindow(window);
-          if (
-            managerWindow && 
-            managerWindow[this.uniqueRandomID] && 
-            managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners
-          ) {
-            managerWindow.document.removeEventListener("ViewChanged", this);
-            managerWindow.document.removeEventListener("update", this);
-            managerWindow.document.removeEventListener("view-loaded", this);
-            managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners = false;
-
-            let cards = this.getCards(managerWindow);
-            if (getThunderbirdVersion().major < 88) {
-              // Remove options menu in 78-87
-              for (let card of cards) {
-                let addonOptionsLegacyEntry = card.querySelector(".extension-options-legacy");
-                if (addonOptionsLegacyEntry) addonOptionsLegacyEntry.remove();
-              }
-            } else {
-              // Remove options button in 88
-              for (let card of cards) {
-                if (card.addon.id == this.extension.id) {
-                  let addonOptionsButton = card.querySelector(".extension-options-button2");
-                  if (addonOptionsButton) addonOptionsButton.remove();
-                  break;
-                }
-              }
-            }
-          }
-
-          // Remove tabmonitor
-          if (window[this.uniqueRandomID].hasTabMonitor) {
-            this.getTabMail(window).unregisterTabMonitor(this.tabMonitor);
-            window[this.uniqueRandomID].hasTabMonitor = false;
-          }
-
-        }
-      }
-      // Stop listening for new windows.
-      ExtensionSupport.unregisterWindowListener("injectListener_" + this.uniqueRandomID);
-    }
 
     // Execute registered shutdown()
     try {
@@ -891,17 +176,6 @@
       Components.utils.reportError(e)
     }
 
-    if (this.resourceData) {
-      const resProto = Cc["@mozilla.org/network/protocol;1?name=resource"].getService(Ci.nsISubstitutingProtocolHandler);
-      for (let res of this.resourceData) {
-        // [ "resource", "shortname" , "path" ]
-        resProto.setSubstitution(
-          res[1],
-          null,
-        );
-      }
-    }
-
     if (this.chromeHandle) {
       this.chromeHandle.destruct();
       this.chromeHandle = null;
@@ -910,8 +184,4 @@
     Services.obs.notifyObservers(null, "startupcache-invalidate");
     console.log("BootstrapLoader for " + this.extension.id + " unloaded!");
   }
-};
-
-var BootstrapLoader = getThunderbirdVersion().major < 111
-  ? BootstrapLoader_102
-  : BootstrapLoader_115;
+};
\ Kein Zeilenumbruch am Dateiende.
diff -Nru eas4tbsync-4.8/content/bootstrap.js eas4tbsync-4.11/content/bootstrap.js
--- eas4tbsync-4.8/content/bootstrap.js	2023-12-03 00:43:29.000000000 +0100
+++ eas4tbsync-4.11/content/bootstrap.js	2024-08-19 20:22:14.000000000 +0200
@@ -8,8 +8,6 @@
 
 // no need to create namespace, we are in a sandbox
 
-var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-
 let onInitDoneObserver = {
     observe: async function (aSubject, aTopic, aData) {        
         let valid = false;
diff -Nru eas4tbsync-4.8/content/includes/calendarsync.js eas4tbsync-4.11/content/includes/calendarsync.js
--- eas4tbsync-4.8/content/includes/calendarsync.js	2023-12-03 00:43:29.000000000 +0100
+++ eas4tbsync-4.11/content/includes/calendarsync.js	2024-08-19 20:22:14.000000000 +0200
@@ -18,6 +18,7 @@
  CalTodo: "resource:///modules/CalTodo.jsm",
 }); 
 
+var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
 const cal = TbSync.lightning.cal;
 const ICAL = TbSync.lightning.ICAL;
 
diff -Nru eas4tbsync-4.8/content/includes/contactsync.js eas4tbsync-4.11/content/includes/contactsync.js
--- eas4tbsync-4.8/content/includes/contactsync.js	2023-12-03 00:43:29.000000000 +0100
+++ eas4tbsync-4.11/content/includes/contactsync.js	2024-08-19 20:22:14.000000000 +0200
@@ -21,6 +21,9 @@
     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 = {
diff -Nru eas4tbsync-4.8/content/includes/network.js eas4tbsync-4.11/content/includes/network.js
--- eas4tbsync-4.8/content/includes/network.js	2023-12-03 00:43:29.000000000 +0100
+++ eas4tbsync-4.11/content/includes/network.js	2024-08-19 20:22:14.000000000 +0200
@@ -5,29 +5,81 @@
  * 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";
+
+"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 = {
 
-var network = {  
-    
-    getEasURL: function(accountData) {
+    getEasURL: function (accountData) {
         let protocol = (accountData.getAccountProperty("https")) ? "https://"; : "http://";;
-        let h = protocol + accountData.getAccountProperty("host"); 
-        while (h.endsWith("/")) { h = h.slice(0,-1); }
+        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"; 
+        return h + "/Microsoft-Server-ActiveSync";
     },
-    
-    getAuthData: function(accountData) {
+
+    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() { 
+            get host() {
                 return "TbSync#" + accountData.accountID;
             },
 
@@ -39,213 +91,244 @@
                 return TbSync.passwordManager.getLoginInfo(this.host, "TbSync/EAS", this.user);
             },
 
-            updateLoginData: function(newUsername, newPassword) {
+            get accountname() {
+                return accountData.getAccountProperty("accountname");
+            },
+
+            updateLoginData: async function (newUsername, newPassword) {
                 let oldUsername = this.user;
-                TbSync.passwordManager.updateLoginInfo(this.host, "TbSync/EAS", oldUsername, newUsername, newPassword);
+                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");
+            removeLoginData: function () {
+                TbSync.passwordManager.removeLoginInfos(this.host, "TbSync/EAS");
             }
         };
         return authData;
-    },  
-    
-  // prepare and patch OAuth2 object
-  getOAuthObj: function(configObject = null) {
-    let accountname, user, host, accountID, servertype;
-      
-    let accountData = (configObject && configObject.hasOwnProperty("accountData")) ? configObject.accountData : null;
-    if (accountData) {
-      accountname = accountData.getAccountProperty("accountname");
-      user = accountData.getAccountProperty("user");
-      host = accountData.getAccountProperty("host");
-      servertype = accountData.getAccountProperty("servertype");
-      accountID = accountData.accountID;
-    } else {
-      accountname = (configObject && configObject.hasOwnProperty("accountname")) ? configObject.accountname : "";
-      user = (configObject && configObject.hasOwnProperty("user")) ? configObject.user : "";
-      host = (configObject && configObject.hasOwnProperty("host")) ? configObject.host : "";
-      servertype = (configObject && configObject.hasOwnProperty("servertype")) ? configObject.servertype : "";
-      accountID = "";
-    }
+    },
+
+    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 = "";
+        }
 
-    if (!["office365"].includes(servertype))
-      return null;
+        return contextData;
+    },
 
-    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;
-    }
+    // 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;
 
-    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;
-    }
+            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) {
-      let self = this;
-      rv.error = "";
-      rv.tokens = "";
-
-      // 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 (self.accessToken) self.accessToken = "";
-      
-      try {
-        await new Promise(function(resolve, reject) {
-          // 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.
-          self.connect(resolve, reject, /* with UI */ true, /* refresh */ false);
+        let oauth = new OAuth2(config.scope, {
+            authorizationEndpoint: config.auth_uri,
+            tokenEndpoint: config.token_uri,
+            clientId: config.client_id,
+            clientSecret: config.client_secret
         });
-        rv.tokens = self.tokens;
-        return true;
-      } catch (e) {
-        rv.error = eas.tools.isString(e) ? e : JSON.stringify(e);
-      }
-      
-      try {
-        switch (JSON.parse(rv.error).error) {
-          case "invalid_grant":
-            self.accessToken = "";
-            self.refreshToken = "";
-            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);
-      }
-      return false;
-    };
-
-    oauth.isExpired = function() {
-      const OAUTH_GRACE_TIME = 30 * 1000;
-      return (this.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.requestWindowFeatures = "chrome,private,centerscreen,width=500,height=750";
 
-      oauth.parseAndSanitizeTokenString = function(tokenString) {
-        let _tokensObj = {};
-        try {
-          _tokensObj = JSON.parse(tokenString);
-        } catch (e) {}
+        // 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 */
 
-        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;
-      };
-      
-      // Define getter/setter to act on the password manager password value belonging to this account/calendar
-      for (let oauthValue of OAUTHVALUES) {
-        Object.defineProperty(oauth, oauthValue[2], {
-          get: function() {
-            return this.parseAndSanitizeTokenString(this.authData.password)[oauthValue[0]];
-          },
-          set: function(val) {
-            let tokens = this.parseAndSanitizeTokenString(this.authData.password);
-            let valueChanged = (val != tokens[oauthValue[0]])
-            if (valueChanged) {
-              tokens[oauthValue[0]] = val;
-              this.authData.updateLoginData(this.authData.user, JSON.stringify(tokens));
+        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);
             }
-          },
-          enumerable: true,
+            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,
         });
-      }
-    }
-    
-    return oauth;
-  },    
 
-    getOAuthValue: function(currentTokenString, type = "access") {
+        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))
@@ -258,91 +341,91 @@
 
     sendRequest: async function (wbxml, command, syncData, allowSoftFail = false) {
         let ALLOWED_RETRIES = {
-            PasswordPrompt : 3,
-            NetworkError : 1,
+            PasswordPrompt: 3,
+            NetworkError: 1,
         }
-        
+
         let rv = {};
         let oauthData = eas.network.getOAuthObj({ accountData: syncData.accountData });
-        let syncState = syncData.getSyncState().state; 
-        
-        for (;;) {
+        let syncState = syncData.getSyncState().state;
+
+        for (; ;) {
 
-            if (rv.errorType) {                
+            if (rv.errorType) {
                 let retry = false;
-                
+
                 if (ALLOWED_RETRIES[rv.errorType] > 0) {
                     ALLOWED_RETRIES[rv.errorType]--;
-                    
+
 
                     switch (rv.errorType) {
-                        
-                        case "PasswordPrompt": 
-                        {
-                            
-                            if (oauthData) {
-                                oauthData.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;
-                                  authData.updateLoginData(credentials.username, credentials.password);
+
+                        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;
-                        
+                            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
+                            {
+                                // 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;
-                        
+                            break;
+
                     }
-                } 
-                
+                }
+
                 if (!retry) throw rv.errorObj;
             }
-            
+
             // check OAuth situation before connecting
-            if (oauthData && (!oauthData.accessToken || oauthData.isExpired())) {
-                syncData.setSyncState("oauthprompt");                                
+            if (oauthData && (!oauthData.getToken("accessToken") || oauthData.isExpired())) {
+                syncData.setSyncState("oauthprompt");
                 let _rv = {}
                 if (!(await oauthData.asyncConnect(_rv))) {
-                    throw eas.sync.finish("error", _rv.error); 
+                    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)) {
@@ -351,7 +434,7 @@
             } else {
                 return rv;
             }
-        }        
+        }
     },
 
     sendRequestPromise: function (wbxml, command, syncData, allowSoftFail = false) {
@@ -365,19 +448,20 @@
         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);
+        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);            
+        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);
-        
-        return new Promise(function(resolve,reject) {
-            // Create request handler - API changed with TB60 to new XMKHttpRequest()
-            syncData.req = new XMLHttpRequest();
+
+        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", eas.network.getEasURL(syncData.accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(connection.user) + '&DeviceType=' +encodeURIComponent(deviceType) + '&DeviceId=' + deviceId, 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");
@@ -388,7 +472,7 @@
                     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 {
@@ -422,9 +506,9 @@
                 }
             };
 
-            syncData.req.onload = function() {
+            syncData.req.onload = function () {
                 let response = syncData.req.responseText;
-                switch(syncData.req.status) {
+                switch (syncData.req.status) {
 
                     case 200: //OK
                         let msg = "Receiving data <" + syncData.getSyncState().state + "> for " + syncData.accountData.getAccountProperty("accountname");
@@ -459,12 +543,12 @@
                         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);
+                        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("");
@@ -475,7 +559,7 @@
             };
 
             syncData.req.send(encoded);
-            
+
         });
     },
 
@@ -489,21 +573,21 @@
 
 
     // RESPONSE EVALUATION
-    
-    logXML : function (wbxml, what) {
+
+    logXML: function (wbxml, what) {
         let rawxml = eas.wbxmltools.convert2xml(wbxml);
         let xml = null;
-        if (rawxml)  {
+        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));
+                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);
             }
@@ -516,12 +600,12 @@
                 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) {        
+    getDataFromResponse: function (wbxml, allowEmptyResponse = !eas.flags.allowEmptyResponse) {
         //check for empty wbxml
         if (wbxml.length === 0) {
             if (allowEmptyResponse) return null;
@@ -533,21 +617,21 @@
         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");
+        let synckey = eas.xmltools.getWbxmlDataField(wbxmlData, "Sync.Collections.Collection.SyncKey");
 
         if (synckey) {
             // This COULD be a cause of problems... 
@@ -558,24 +642,24 @@
         }
     },
 
-    checkStatus : function (syncData, wbxmlData, path, rootpath="", allowSoftFail = false) {
+    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 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]);
+            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];
+                fullpath = type + "." + elements[elements.length - 1];
             }
         }
 
@@ -587,7 +671,7 @@
         TbSync.dump("wbxml status check", type + ": " + fullpath + " = " + status);
 
         //handle errrors based on type
-        let statusType = type+"."+status;
+        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 
@@ -596,7 +680,7 @@
                 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
@@ -620,49 +704,49 @@
                     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) {
+        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 "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);
- */
-            }
-                
+                {
+                    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
@@ -671,14 +755,14 @@
                 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);
 
-        }		
+        }
     },
-    
+
 
 
 
@@ -689,25 +773,25 @@
 
 
     // WBXML COMM STUFF
-    
-    setDeviceInformation: async function (syncData)  {
+
+    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.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");
@@ -716,24 +800,24 @@
         syncData.setSyncState("eval.response.setdeviceinfo");
         let wbxmlData = eas.network.getDataFromResponse(response);
 
-        eas.network.checkStatus(syncData, wbxmlData,"Settings.Status");
+        eas.network.checkStatus(syncData, wbxmlData, "Settings.Status");
     },
 
-    getPolicykey: async function (syncData)  {
+    getPolicykey: async function (syncData) {
         //build WBXML to request provision
-       syncData.setSyncState("prepare.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.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");
+        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");
@@ -744,12 +828,12 @@
                 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);
+                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");
+            let policykey = eas.xmltools.getWbxmlDataField(wbxmlData, "Provision.Policies.Policy.PolicyKey");
             switch (policyStatus) {
                 case false:
                     throw eas.sync.finish("error", "wbxmlmissingfield::Provision.Policies.Policy.Status");
@@ -763,8 +847,8 @@
                 case "1":
                     if (policykey === false) {
                         throw eas.sync.finish("error", "wbxmlmissingfield::Provision.Policies.Policy.PolicyKey");
-                    } 
-                    TbSync.dump("PolicyKey","Received policykey (" + loop + "): " + policykey);
+                    }
+                    TbSync.dump("PolicyKey", "Received policykey (" + loop + "): " + policykey);
                     syncData.accountData.setAccountProperty("policykey", policykey);
                     break;
 
@@ -773,19 +857,19 @@
             }
 
             //build WBXML to acknowledge provision
-           syncData.setSyncState("prepare.request.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.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
         }
     },
@@ -795,15 +879,15 @@
         //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.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);
 
@@ -811,52 +895,52 @@
         // get data from wbxml response
         let wbxmlData = eas.network.getDataFromResponse(response);
         //check status
-        eas.network.checkStatus(syncData, wbxmlData,"Sync.Collections.Collection.Status");
+        eas.network.checkStatus(syncData, wbxmlData, "Sync.Collections.Collection.Status");
         //update synckey
         eas.network.updateSynckey(syncData, wbxmlData);
     },
 
-    getItemEstimate: async function (syncData)  {
+    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.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
@@ -878,7 +962,7 @@
         }
     },
 
-    getUserInfo: async function (syncData)  {
+    getUserInfo: async function (syncData) {
         if (!syncData.accountData.getAccountProperty("allowedEasCommands").split(",").includes("Settings")) {
             return;
         }
@@ -888,9 +972,9 @@
         let wbxml = eas.wbxmltools.createWBXML();
         wbxml.switchpage("Settings");
         wbxml.otag("Settings");
-            wbxml.otag("UserInformation");
-                wbxml.atag("Get");
-            wbxml.ctag();
+        wbxml.otag("UserInformation");
+        wbxml.atag("Get");
+        wbxml.ctag();
         wbxml.ctag();
 
         syncData.setSyncState("send.request.getuserinfo");
@@ -900,12 +984,12 @@
         syncData.setSyncState("eval.response.getuserinfo");
         let wbxmlData = eas.network.getDataFromResponse(response);
 
-        eas.network.checkStatus(syncData, wbxmlData,"Settings.Status");
+        eas.network.checkStatus(syncData, wbxmlData, "Settings.Status");
     },
 
 
 
-    
+
 
 
 
@@ -919,50 +1003,51 @@
         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.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++) {
+        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.accessToken || oauthData.isExpired())) {
+            if (oauthData && (!oauthData.getToken("accessToken") || oauthData.isExpired())) {
                 let _rv = {}
                 if (!(await oauthData.asyncConnect(_rv))) {
-                    throw eas.sync.finish("error", _rv.error); 
+                    throw eas.sync.finish("error", _rv.error);
                 }
-            } 
-            
+            }
+
             try {
-                let response = await new Promise(function(resolve, reject) {
-                    // Create request handler - API changed with TB60 to new XMKHttpRequest()
-                    let req = new XMLHttpRequest();
+                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", eas.network.getEasURL(accountData) + '?Cmd=' + command + '&User=' + encodeURIComponent(authData.user) + '&DeviceType=' +encodeURIComponent(deviceType) + '&DeviceId=' + deviceId, 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"));
@@ -970,7 +1055,7 @@
                             req.setRequestHeader("Authorization", 'Basic ' + TbSync.tools.b64encode(authData.user + ':' + authData.password));
                         }
                     }
-                    
+
                     if (accountData.getAccountProperty("asversion") == "2.5") {
                         req.setRequestHeader("MS-ASProtocolVersion", "2.5");
                     } else {
@@ -992,10 +1077,10 @@
                         reject("GAL Search Error");
                     };
 
-                    req.onload = function() {
+                    req.onload = function () {
                         let response = req.responseText;
-                        
-                        switch(req.status) {
+
+                        switch (req.status) {
 
                             case 200: //OK
                                 eas.network.logXML(response, "Received (GAL Search");
@@ -1008,27 +1093,27 @@
                                     resolve(response);
                                 }
                                 break;
-                              
+
                             case 401: // bad auth
-                                    resolve("401");
+                                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) {
-                        oauthData.accessToken = "";
+                        await oauthData.setToken("accessToken", "");
                         continue;
                     }
-                }                    
+                }
 
                 return response;
             } catch (e) {
@@ -1047,37 +1132,39 @@
 
 
 
-       // OPTIONS
+    // OPTIONS
 
-    getServerOptions: async function (syncData) {        
+    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.accessToken || oauthData.isExpired())) {
+            if (oauthData && (!oauthData.getToken("accessToken") || oauthData.isExpired())) {
                 let _rv = {};
-                syncData.setSyncState("oauthprompt");                                
+                syncData.setSyncState("oauthprompt");
                 if (!(await oauthData.asyncConnect(_rv))) {
                     throw eas.sync.finish("error", _rv.error);
                 }
             }
-            
-            let result = await new Promise(function(resolve,reject) {
-                syncData.req = new XMLHttpRequest();
+
+            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", eas.network.getEasURL(syncData.accountData), true);
+                syncData.req.open("OPTIONS", uri.spec, true);
                 syncData.req.overrideMimeType("text/plain");
-                syncData.req.setRequestHeader("User-Agent", userAgent);            
+                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"));
@@ -1093,21 +1180,21 @@
 
                 syncData.req.onerror = function () {
                     let responseData = {};
-                    responseData["MS-ASProtocolVersions"] =  syncData.req.getResponseHeader("MS-ASProtocolVersions");
-                    responseData["MS-ASProtocolCommands"] =  syncData.req.getResponseHeader("MS-ASProtocolCommands");                        
+                    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"]);
+                    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.req.onload = function () {
                     syncData.setSyncState("eval.request.options");
                     let responseData = {};
 
-                    switch(syncData.req.status) {
+                    switch (syncData.req.status) {
                         case 401: // AuthError
                             let rv = {};
                             rv.errorObj = eas.sync.finish("error", "401");
@@ -1116,39 +1203,39 @@
                             break;
 
                         case 200:
-                                responseData["MS-ASProtocolVersions"] =  syncData.req.getResponseHeader("MS-ASProtocolVersions");
-                                responseData["MS-ASProtocolCommands"] =  syncData.req.getResponseHeader("MS-ASProtocolCommands");                        
+                            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" +
+                            TbSync.dump("EAS OPTIONS with response (status: 200)", "\n" +
                                 "responseText: " + syncData.req.responseText + "\n" +
-                                "responseHeader(MS-ASProtocolVersions): " + responseData["MS-ASProtocolVersions"]+"\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();
+                            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();
+                            resolve();
                             break;
 
                     }
                 };
-                
+
                 syncData.setSyncState("send.request.options");
                 syncData.req.send();
-                
+
             });
-            
+
             if (result && result.hasOwnProperty("errorType") && result.errorType == "PasswordPrompt") {
                 if (allowedRetries > 0) {
                     if (oauthData) {
-                        oauthData.accessToken = "";
-                        retry = true;                            
+                        await oauthData.setToken("accessToken", "");
+                        retry = true;
                     } else {
                         syncData.setSyncState("passwordprompt");
                         let authData = eas.network.getAuthData(syncData.accountData);
@@ -1160,8 +1247,8 @@
                         }
                         let credentials = await TbSync.passwordManager.asyncPasswordPrompt(promptData, eas.openWindows);
                         if (credentials) {
-                          authData.updateLoginData(credentials.username, credentials.password);
-                          retry = true;
+                            await authData.updateLoginData(credentials.username, credentials.password);
+                            retry = true;
                         }
                     }
                 }
@@ -1170,7 +1257,7 @@
                     throw result.errorObj;
                 }
             }
-            
+
             allowedRetries--;
         } while (retry);
     },
@@ -1185,111 +1272,112 @@
 
 
     // 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.user, authData.password, 30*1000);
+        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("host", eas.network.stripAutodiscoverUrl(result.server));
             syncData.accountData.setAccountProperty("user", result.user);
-            syncData.accountData.setAccountProperty("https", (result.server.substring(0,5) == "https"));
+            syncData.accountData.setAccountProperty("https", (result.server.substring(0, 5) == "https"));
         }
 
         return result.errorcode;
     },
-    
-    stripAutodiscoverUrl: function(url) {
+
+    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);
+        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 (user, password, maxtimeout) {
+    getServerConnectionViaAutodiscover: async function (accountname, user, password, maxtimeout) {
         let urls = [];
         let parts = user.split("@");
-        
-        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});
-
-        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": "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++) {
+
+        for (let i = 0; i < urls.length; i++) {
             await TbSync.tools.sleep(200);
-            requests.push( eas.network.getServerConnectionViaAutodiscoverRedirectWrapper(urls[i].url, urls[i].user, password, maxtimeout) );
+            requests.push(eas.network.getServerConnectionViaAutodiscoverRedirectWrapper(
+                accountname,
+                urls[i].url,
+                urls[i].user,
+                password,
+                maxtimeout
+            ));
         }
 
         try {
-            responses = await Promise.all(requests); 
+            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));
+        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};
+                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")};
+                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};
+        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;        
+        return result;
     },
-       
-    getServerConnectionViaAutodiscoverRedirectWrapper : async function (url, user, password, maxtimeout) {        
-        //using HEAD to find URL redirects until response URL no longer changes 
-        // * XHR should follow redirects transparently, but that does not always work, POST data could get lost, so we
-        // * need to find the actual POST candidates (example: outlook.de accounts)
+
+    getServerConnectionViaAutodiscoverRedirectWrapper: async function (accountname, url, user, password, maxtimeout) {
         let result = {};
-        let method = "HEAD";
-        let connection = { url, user };
-        
-        do {            
+        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);
+                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 = "HEAD";
-            } else if (result.error == "POST candidate found") {
                 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)");
@@ -1298,13 +1386,13 @@
         } 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) {
-            
+
+        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';
@@ -1312,18 +1400,17 @@
             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
 
-            // Create request handler - API changed with TB60 to new XMKHttpRequest()
-            let req = new XMLHttpRequest();
+            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, connection.url, true);
+            req.open(method, uri.spec, true);
             req.timeout = maxtimeout;
             req.setRequestHeader("User-Agent", userAgent);
-            
-            let secure = (connection.url.substring(0,8).toLowerCase() == "https://";);
-            
+
+            let secure = (connection.url.substring(0, 8).toLowerCase() == "https://";);
+
             if (method == "POST") {
                 req.setRequestHeader("Content-Length", xml.length);
                 req.setRequestHeader("Content-Type", "text/xml");
@@ -1331,43 +1418,44 @@
                     // 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});
+                resolve({ "url": req.responseURL, "error": "timeout", "server": "", "user": connection.user });
             };
-           
+
             req.onerror = function () {
                 let error = TbSync.network.createTCPErrorFromFailedXHR(req);
                 if (!error) error = req.responseText;
-                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});
+                // 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;
                 }
 
-                //initiate rerun on HEAD request without redirect (rerun and do a POST on this)
-                if (method == "HEAD") {
-                    resolve({"url":req.responseURL, "error":"POST candidate found", "server":"", "user":connection.user});
+                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});
+                    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 + "]");
-                
+                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,
@@ -1376,16 +1464,16 @@
                     try {
                         data = eas.xmltools.getDataFromXMLString(req.responseText);
                     } catch (e) {
-                        resolve({"url":req.responseURL, "error":"bad response", "server":"", "user":connection.user});
+                        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});
+                            resolve({ "url": req.responseURL, "error": "redirect found", "server": "", "user": newuser });
 
                         } else if (data.Autodiscover.Response.Action.Settings) {
                             // get server settings
@@ -1393,67 +1481,64 @@
 
                             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});
+                                    resolve({ "url": req.responseURL, "error": "", "server": server[count].Url, "user": connection.user });
                                     return;
                                 }
                             }
                         }
                     } else {
-                        resolve({"url":req.responseURL, "error":"invalid", "server":"", "user":connection.user});
+                        resolve({ "url": req.responseURL, "error": "invalid", "server": "", "user": connection.user });
                     }
                 } else {
-                    resolve({"url":req.responseURL, "error":req.status, "server":"", "user":connection.user});                     
+                    resolve({ "url": req.responseURL, "error": req.status, "server": "", "user": connection.user });
                 }
             };
-            
-            if (method == "HEAD") req.send();
-            else  req.send(xml);
-            
+
+            req.send(xml);
         });
     },
-    
-    getServerConnectionViaAutodiscoverV2JsonRequest: function (url, maxtimeout) {
+
+    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
 
-            // Create request handler - API changed with TB60 to new XMKHttpRequest()
-            let req = new XMLHttpRequest();
+        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", url, 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":""});
+                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":""});
+                TbSync.dump("EAS autodiscover V2 with error (" + error + ")", "\n" + url + " => \n" + req.responseURL);
+                resolve({ "url": req.responseURL, "error": error, "server": "" });
             };
 
-            req.onload = function() { 
+            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)});
+                        resolve({ "url": req.responseURL, "error": "", "server": eas.network.stripAutodiscoverUrl(data.Url) });
                     } else {
-                        resolve({"url":req.responseURL, "error":"invalid", "server":""});
+                        resolve({ "url": req.responseURL, "error": "invalid", "server": "" });
                     }
                     return;
                 }
-                
-                resolve({"url":req.responseURL, "error":req.status, "server":""});                     
+
+                resolve({ "url": req.responseURL, "error": req.status, "server": "" });
             };
-            
-            req.send();            
+
+            req.send();
         });
-    }    
+    }
 }
diff -Nru eas4tbsync-4.8/content/includes/sync.js eas4tbsync-4.11/content/includes/sync.js
--- eas4tbsync-4.8/content/includes/sync.js	2023-12-03 00:43:29.000000000 +0100
+++ eas4tbsync-4.11/content/includes/sync.js	2024-08-19 20:22:14.000000000 +0200
@@ -9,6 +9,7 @@
 "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",
diff -Nru eas4tbsync-4.8/content/includes/tasksync.js eas4tbsync-4.11/content/includes/tasksync.js
--- eas4tbsync-4.8/content/includes/tasksync.js	2023-12-03 00:43:29.000000000 +0100
+++ eas4tbsync-4.11/content/includes/tasksync.js	2024-08-19 20:22:14.000000000 +0200
@@ -9,6 +9,7 @@
 "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",
diff -Nru eas4tbsync-4.8/content/includes/tools.js eas4tbsync-4.11/content/includes/tools.js
--- eas4tbsync-4.8/content/includes/tools.js	2023-12-03 00:43:29.000000000 +0100
+++ eas4tbsync-4.11/content/includes/tools.js	2024-08-19 20:22:14.000000000 +0200
@@ -6,7 +6,13 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
  */
  
- "use strict";
+"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 = {
 
@@ -435,7 +441,7 @@
             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);
diff -Nru eas4tbsync-4.8/content/includes/wbxmltools.js eas4tbsync-4.11/content/includes/wbxmltools.js
--- eas4tbsync-4.8/content/includes/wbxmltools.js	2023-12-03 00:43:29.000000000 +0100
+++ eas4tbsync-4.11/content/includes/wbxmltools.js	2024-08-19 20:22:14.000000000 +0200
@@ -6,8 +6,9 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
  */
  
- "use strict";
+"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
diff -Nru eas4tbsync-4.8/content/includes/xmltools.js eas4tbsync-4.11/content/includes/xmltools.js
--- eas4tbsync-4.8/content/includes/xmltools.js	2023-12-03 00:43:29.000000000 +0100
+++ eas4tbsync-4.11/content/includes/xmltools.js	2024-08-19 20:22:14.000000000 +0200
@@ -6,8 +6,9 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
  */
  
- "use strict";
+"use strict";
 
+var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
 var xmltools = {
 
     isString : function (obj) {
diff -Nru eas4tbsync-4.8/content/manager/createAccount.js eas4tbsync-4.11/content/manager/createAccount.js
--- eas4tbsync-4.8/content/manager/createAccount.js	2023-12-03 00:43:29.000000000 +0100
+++ eas4tbsync-4.11/content/manager/createAccount.js	2024-08-19 20:22:14.000000000 +0200
@@ -156,7 +156,11 @@
             updateTimer.initWithCallback({notify : function () {tbSyncEasNewAccount.updateAutodiscoverStatus()}}, 1000, 3);
 
             if (servertype == "office365") {
-                let v2 = await eas.network.getServerConnectionViaAutodiscoverV2JsonRequest("https://autodiscover-s.outlook.com/autodiscover/autodiscover.json?Email="+encodeURIComponent(user)+"&Protocol=ActiveSync");
+                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
@@ -173,7 +177,12 @@
                     error = TbSync.getString("status.404", "eas");
                 }
             } else {
-                let result = await eas.network.getServerConnectionViaAutodiscover(user, password, tbSyncEasNewAccount.maxTimeout*1000);
+                let result = await eas.network.getServerConnectionViaAutodiscover(
+                    accountname,
+                    user,
+                    password,
+                    tbSyncEasNewAccount.maxTimeout*1000
+                );
                 if (result.server) {
                     user = result.user;
                     url = result.server;
@@ -192,7 +201,7 @@
 
         //add if valid
         if (!error) {
-            tbSyncEasNewAccount.addAccount(user, password, servertype, accountname, url);
+            await tbSyncEasNewAccount.addAccount(user, password, servertype, accountname, url);
         }
         
         //end validation
@@ -214,6 +223,7 @@
             document.getElementById("tbsync.error.message").textContent = error;
             document.getElementById("tbsync.error").hidden = false;
         }            
+        window.sizeToContent();
     },
 
     updateAutodiscoverStatus: function () {
@@ -223,7 +233,7 @@
         document.getElementById('tbsync.newaccount.autodiscoverstatus').value  = TbSync.getString("autodiscover.Querying","eas") + timeout;
     },
 
-    addAccount (user, password, servertype, accountname, url) {
+    async addAccount (user, password, servertype, accountname, url) {
         let newAccountEntry = this.providerData.getDefaultAccountEntries();
         newAccountEntry.user = user;
         newAccountEntry.servertype = servertype;
@@ -237,7 +247,7 @@
 
         // Add the new account.
         let newAccountData = this.providerData.addAccount(accountname, newAccountEntry);
-        eas.network.getAuthData(newAccountData).updateLoginData(user, password);
+        await eas.network.getAuthData(newAccountData).updateLoginData(user, password);
 
         window.close();
     }
diff -Nru eas4tbsync-4.8/content/manager/createAccount.xhtml eas4tbsync-4.11/content/manager/createAccount.xhtml
--- eas4tbsync-4.8/content/manager/createAccount.xhtml	2023-12-03 00:43:29.000000000 +0100
+++ eas4tbsync-4.11/content/manager/createAccount.xhtml	2024-08-19 20:22:14.000000000 +0200
@@ -79,7 +79,7 @@
                 <label id='tbsync.newaccount.autodiscoverstatus' value="" />
             </hbox>
            
-            <vbox id="tbsync.error" style="width: 450px;">
+            <vbox id="tbsync.error">
                 <description id="tbsync.error.message" flex="1" style="font-weight: bold;"></description>
                 <vbox>
                   <button 
diff -Nru eas4tbsync-4.8/content/provider.js eas4tbsync-4.11/content/provider.js
--- eas4tbsync-4.8/content/provider.js	2023-12-03 00:43:29.000000000 +0100
+++ eas4tbsync-4.11/content/provider.js	2024-08-19 20:22:14.000000000 +0200
@@ -8,6 +8,9 @@
 
 "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;
 
diff -Nru eas4tbsync-4.8/debian/changelog eas4tbsync-4.11/debian/changelog
--- eas4tbsync-4.8/debian/changelog	2024-05-15 12:46:39.000000000 +0200
+++ eas4tbsync-4.11/debian/changelog	2024-09-18 09:43:23.000000000 +0200
@@ -1,3 +1,17 @@
+eas4tbsync (4.11-1~deb12u1) bookworm; urgency=medium
+
+  * [6c3dc26] Merge branch 'debian/sid' into debian/bookworm
+  * Prepared for release in bookworm (proposed-updates)
+
+ -- Mechtilde Stehmann <mechtilde@debian.org>  Wed, 18 Sep 2024 09:43:23 +0200
+
+eas4tbsync (4.11-1) unstable; urgency=medium
+
+  * [6db438f] New upstream version 4.11
+  * [d895bd7] Bumped version of dependencies in d/control
+
+ -- Mechtilde Stehmann <mechtilde@debian.org>  Sun, 01 Sep 2024 12:49:21 +0200
+
 eas4tbsync (4.8-1) unstable; urgency=medium
 
   * [cf34002] New upstream version 4.8
@@ -7,6 +21,13 @@
 
  -- Mechtilde Stehmann <mechtilde@debian.org>  Wed, 15 May 2024 12:46:39 +0200
 
+eas4tbsync (4.7-1~deb12u1) bookworm; urgency=medium
+
+  * [4af7393] Adjust version of dependencies
+  *     Prepared for release in bookworm (proposed-updates)
+
+ -- Mechtilde Stehmann <mechtilde@debian.org>  Sun, 22 Oct 2023 12:57:50 +0200
+
 eas4tbsync (4.7-1) unstable; urgency=medium
 
   * [a18dc06] Changed compression for tar.gz
diff -Nru eas4tbsync-4.8/debian/control eas4tbsync-4.11/debian/control
--- eas4tbsync-4.8/debian/control	2024-05-15 12:41:12.000000000 +0200
+++ eas4tbsync-4.11/debian/control	2024-09-14 19:13:29.000000000 +0200
@@ -15,8 +15,9 @@
 Package: webext-eas4tbsync
 Architecture: all
 Depends: ${misc:Depends}
- , thunderbird (>= 1:115.10)
- , webext-tbsync (>= 4.8)
+ , thunderbird (>= 1:128.0)
+ , thunderbird (<= 1:128.x)
+ , webext-tbsync (>= 4.12)
 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.8/_locales/ja/messages.json eas4tbsync-4.11/_locales/ja/messages.json
--- eas4tbsync-4.8/_locales/ja/messages.json	2023-12-03 00:43:29.000000000 +0100
+++ eas4tbsync-4.11/_locales/ja/messages.json	2024-08-19 20:22:14.000000000 +0200
@@ -60,13 +60,13 @@
         "message": "自宅電話番号 3:"
     },
     "abCard.header.messaging": {
-        "message": "Messaging:"
+        "message": "メッセージング:"
     },
     "abCard.header.otheraddress": {
         "message": "その他のアドレス (EAS)"
     },
     "abCard.header.othernumbers": {
-        "message": "Additional numbers:"
+        "message": "追加の電話番号:"
     },
     "abCard.header.people": {
         "message": "People:"
@@ -279,7 +279,7 @@
         "message": "ユーザーが見つかりません (HTTP エラー 404)。"
     },
     "status.449": {
-        "message": "Server requests provisioning (HTTP Error 449)."
+        "message": "サーバーがプロビジョニングを要求しています (HTTP エラー 449)。"
     },
     "status.500": {
         "message": "不明なサーバー エラー (HTTP エラー 500)。"
@@ -441,7 +441,7 @@
         "message": "Sync failed. Server responded with status <##replace.1##>."
     },
     "status.wbxmlmissingfield": {
-        "message": "ActiveSync protocol violation: Mandatory field <##replace.1##> is missing from server response."
+        "message": "ActiveSync プロトコル違反: 必須フィールド <##replace.1##> がサーバー応答から見つかりません。"
     },
     "syncstate.accountdone": {
         "message": "Finished account"
@@ -513,7 +513,7 @@
         "message": "Requesting remote changes"
     },
     "syncstate.prepare.request.revertlocalchanges": {
-        "message": "Collecting local changes"
+        "message": "ローカルの変更を収集中"
     },
     "syncstate.prepare.request.setdeviceinfo": {
         "message": "デバイス情報を送信中"
@@ -534,13 +534,13 @@
         "message": "Waiting for change estimate"
     },
     "syncstate.send.request.folders": {
-        "message": "Waiting for folder list update"
+        "message": "フォルダリストの更新を待機中"
     },
     "syncstate.send.request.localchanges": {
-        "message": "Waiting for acknowledgment of local changes"
+        "message": "ローカルの変更の承認を待機中"
     },
     "syncstate.send.request.localdeletes": {
-        "message": "Waiting for acknowledgment of local deletes"
+        "message": "ローカルの削除の承認を待機中"
     },
     "syncstate.send.request.options": {
         "message": "Waiting for server options"
@@ -549,7 +549,7 @@
         "message": "Waiting for provision"
     },
     "syncstate.send.request.remotechanges": {
-        "message": "Waiting for remote changes"
+        "message": "リモートの変更を待機中"
     },
     "syncstate.send.request.revertlocalchanges": {
         "message": "Waiting for most recent versions"
@@ -558,9 +558,9 @@
         "message": "デバイス情報を送信中"
     },
     "syncstate.send.request.synckey": {
-        "message": "Waiting for SyncKey"
+        "message": "同期キーを待機中"
     },
     "syncstate.syncing": {
-        "message": "Initialize synchronization"
+        "message": "同期を初期化中"
     }
 }
diff -Nru eas4tbsync-4.8/manifest.json eas4tbsync-4.11/manifest.json
--- eas4tbsync-4.8/manifest.json	2023-12-03 00:43:29.000000000 +0100
+++ eas4tbsync-4.11/manifest.json	2024-08-19 20:22:14.000000000 +0200
@@ -2,13 +2,13 @@
   "applications": {
     "gecko": {
       "id": "eas4tbsync@jobisoft.de",
-      "strict_min_version": "102.7.0",
-      "strict_max_version": "115.*"
+      "strict_min_version": "128.0",
+      "strict_max_version": "128.*"
     }
   },
   "manifest_version": 2,
   "name": "__MSG_extensionName__",
-  "version": "4.8",
+  "version": "4.11",
   "author": "John Bieling",
   "homepage_url": "https://github.com/jobisoft/EAS-4-TbSync/";,
   "default_locale": "en-US",

--- End Message ---
--- Begin Message ---
Version: 12.9
This update has been released as part of 12.9. Thank you for your contribution.

--- End Message ---

Reply to: