Package: release.debian.org
Severity: normal
Tags: bookworm
User: release.debian....@packages.debian.org
Usertags: pu
X-Debbugs-Cc: eas4tbs...@packages.debian.org, mechti...@debian.org
Control: affects -1 + src:eas4tbsync

[ Reason ]

This package is a dependency of the extension tbsync to thunderbird. After thunderbird is updated to version 115.* in bookwork it is necessary to update this extension too.

[ Impact ]

Otherwise this extension doesn't work anymore

[ Risks ]

Only tbsync, dav4tbsync and eas4tbsync are affected and will be updated too

[ 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 ]

There is a new version of dav4tbsync to work with thunderbird 115.x

[ Other info ]

The output of debdiff (stable vs stable-pu is attached)

Tbsync and dav4tbsync are already updated

Kind regards to the release team

Mechtilde

--
Mechtilde Stehmann
## Debian Developer
## PGP encryption welcome
## F0E3 7F3D C87A 4998 2899  39E7 F287 7BBA 141A AD7F
diffstat for eas4tbsync-4.1.5 eas4tbsync-4.7

 Makefile                                      |   25 
 background.js                                 |    2 
 content/api/BootstrapLoader/CHANGELOG.md      |   15 
 content/api/BootstrapLoader/implementation.js |  676 ++++++++++++++++++++------
 content/api/BootstrapLoader/schema.json       |    4 
 content/bootstrap.js                          |   10 
 content/includes/calendarsync.js              |   13 
 content/includes/network.js                   |   25 
 content/includes/tasksync.js                  |   32 +
 content/includes/tools.js                     |   16 
 content/manager/createAccount.xhtml           |    2 
 content/provider.js                           |   21 
 debian/changelog                              |   22 
 debian/control                                |    4 
 debian/gbp.conf                               |    2 
 manifest.json                                 |    6 
 16 files changed, 677 insertions(+), 198 deletions(-)

diff -Nru eas4tbsync-4.1.5/background.js eas4tbsync-4.7/background.js
--- eas4tbsync-4.1.5/background.js	2022-10-13 11:05:56.000000000 +0200
+++ eas4tbsync-4.7/background.js	2023-08-18 16:51:43.000000000 +0200
@@ -16,7 +16,7 @@
     let manifest = browser.runtime.getManifest();
     browser.notifications.create({
       type: "basic",
-      iconUrl: browser.runtime.getURL("content/skin/sabredav32.png"),
+      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.",
     });
diff -Nru eas4tbsync-4.1.5/content/api/BootstrapLoader/CHANGELOG.md eas4tbsync-4.7/content/api/BootstrapLoader/CHANGELOG.md
--- eas4tbsync-4.1.5/content/api/BootstrapLoader/CHANGELOG.md	2022-10-13 11:05:56.000000000 +0200
+++ eas4tbsync-4.7/content/api/BootstrapLoader/CHANGELOG.md	2023-08-18 16:51:43.000000000 +0200
@@ -1,3 +1,18 @@
+Version: 1.21
+-------------
+- Explicitly set hasAddonManagerEventListeners flag to false on uninstall
+
+Version: 1.20
+-------------
+- hard fork BootstrapLoader v1.19 implementation and continue to serve it for
+  Thunderbird 111 and older
+- BootstrapLoader v1.20 has removed a lot of unnecessary code used for backward
+  compatibility
+
+Version: 1.19
+-------------
+- fix race condition which could prevent the AOM tab to be monkey patched correctly
+
 Version: 1.18
 -------------
 - be precise on which revision the wrench symbol should be displayed, instead of
diff -Nru eas4tbsync-4.1.5/content/api/BootstrapLoader/implementation.js eas4tbsync-4.7/content/api/BootstrapLoader/implementation.js
--- eas4tbsync-4.1.5/content/api/BootstrapLoader/implementation.js	2022-10-13 11:05:56.000000000 +0200
+++ eas4tbsync-4.7/content/api/BootstrapLoader/implementation.js	2023-08-18 16:51:43.000000000 +0200
@@ -2,7 +2,7 @@
  * This file is provided by the addon-developer-support repository at
  * https://github.com/thundernest/addon-developer-support
  *
- * Version: 1.18
+ * Version: 1.21
  *
  * Author: John Bieling (j...@thunderbird.net)
  *
@@ -17,70 +17,65 @@
 var { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
 var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
-var BootstrapLoader = class extends ExtensionCommon.ExtensionAPI {
-  getMessenger(context) {   
-    let apis = [
-      "storage",
-      "runtime",
-      "extension",
-      "i18n",
-    ];
-
-    function getStorage() {
-      let localstorage = null;
-      try {
-        localstorage = context.apiCan.findAPIPath("storage");
-        localstorage.local.get = (...args) =>
-          localstorage.local.callMethodInParentProcess("get", args);
-        localstorage.local.set = (...args) =>
-          localstorage.local.callMethodInParentProcess("set", args);
-        localstorage.local.remove = (...args) =>
-          localstorage.local.callMethodInParentProcess("remove", args);
-        localstorage.local.clear = (...args) =>
-          localstorage.local.callMethodInParentProcess("clear", args);
-      } catch (e) {
-        console.info("Storage permission is missing");
-      }
-      return localstorage;
-    }
-    
-    let messenger = {};    
-    for (let api of apis) {
-      switch (api) {
-        case "storage":
-          XPCOMUtils.defineLazyGetter(messenger, "storage", () =>
-            getStorage()
-          );
-        break;
+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,
+  }
+}
 
-        default:
-          XPCOMUtils.defineLazyGetter(messenger, api, () =>
-            context.apiCan.findAPIPath(api)
-          );
-      }
+function getMessenger(context) {
+  let apis = ["storage", "runtime", "extension", "i18n"];
+
+  function getStorage() {
+    let localstorage = null;
+    try {
+      localstorage = context.apiCan.findAPIPath("storage");
+      localstorage.local.get = (...args) =>
+        localstorage.local.callMethodInParentProcess("get", args);
+      localstorage.local.set = (...args) =>
+        localstorage.local.callMethodInParentProcess("set", args);
+      localstorage.local.remove = (...args) =>
+        localstorage.local.callMethodInParentProcess("remove", args);
+      localstorage.local.clear = (...args) =>
+        localstorage.local.callMethodInParentProcess("clear", args);
+    } catch (e) {
+      console.info("Storage permission is missing");
     }
-    return messenger;
+    return localstorage;
   }
 
-  getThunderbirdVersion() {
-    let parts = Services.appinfo.version.split(".");
-    return {
-      major: parseInt(parts[0]),
-      minor: parseInt(parts[1]),
-      revision: parts.length > 2 ? parseInt(parts[2]) : 0,
+  let messenger = {};
+  for (let api of apis) {
+    switch (api) {
+      case "storage":
+        XPCOMUtils.defineLazyGetter(messenger, "storage", () =>
+          getStorage()
+        );
+        break;
+
+      default:
+        XPCOMUtils.defineLazyGetter(messenger, api, () =>
+          context.apiCan.findAPIPath(api)
+        );
     }
   }
-  
+  return messenger;
+}
+
+var BootstrapLoader_102 = class extends ExtensionCommon.ExtensionAPI {
   getCards(e) {
     // This gets triggered by real events but also manually by providing the outer window.
     // The event is attached to the outer browser, get the inner one.
     let doc;
-    
+
     // 78,86, and 87+ need special handholding. *Yeah*.
-    if (this.getThunderbirdVersion().major < 86) {
+    if (getThunderbirdVersion().major < 86) {
       let ownerDoc = e.document || e.target.ownerDocument;
       doc = ownerDoc.getElementById("html-view-browser").contentDocument;
-    } else if (this.getThunderbirdVersion().major < 87) {
+    } else if (getThunderbirdVersion().major < 87) {
       let ownerDoc = e.document || e.target;
       doc = ownerDoc.getElementById("html-view-browser").contentDocument;
     } else {
@@ -88,42 +83,42 @@
     }
     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 
+    let iconSizes = this.extension.manifest.icons
       ? Object.keys(this.extension.manifest.icons)
       : [];
-    iconSizes.sort((a,b)=>a-b);
+    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}" />`);
-    
+        `<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) {   
+  handleEvent(e) {
     switch (e.type) {
       // 68 add-on options menu showing
       case "popupshowing": {
         this.add68PrefsEntry(e);
       }
-      break;
+        break;
 
       // 78/88 add-on options menu/button click
       case "click": {
@@ -131,31 +126,31 @@
         e.stopPropagation();
         let BL = {}
         BL.extension = this.extension;
-        BL.messenger = this.getMessenger(this.context);
+        BL.messenger = getMessenger(this.context);
         let w = Services.wm.getMostRecentWindow("mail:3pane");
-        w.openDialog(this.pathToOptionsPage, "AddonOptions", "chrome,resizable,centerscreen", BL);        
+        w.openDialog(this.pathToOptionsPage, "AddonOptions", "chrome,resizable,centerscreen", BL);
       }
-      break;
-      
+        break;
+
       // 68 add-on options menu command
       case "command": {
         let BL = {}
         BL.extension = this.extension;
-        BL.messenger = this.getMessenger(this.context);
+        BL.messenger = getMessenger(this.context);
         e.target.ownerGlobal.openDialog(this.pathToOptionsPage, "AddonOptions", "chrome,resizable,centerscreen", BL);
       }
-      break;
-      
+        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 = 
-              (this.getThunderbirdVersion().major > 78 && this.getThunderbirdVersion().major < 88) ||
-              (this.getThunderbirdVersion().major == 78 && this.getThunderbirdVersion().minor < 10) ||
-              (this.getThunderbirdVersion().major == 78 && this.getThunderbirdVersion().minor == 10 && this.getThunderbirdVersion().revision < 2);
+            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");
@@ -204,10 +199,10 @@
           }
         }
       }
-    }      
-  }  
-  
-// Some tab/add-on-manager related functions
+    }
+  }
+
+  // Some tab/add-on-manager related functions
   getTabMail(window) {
     return window.document.getElementById("tabmail");
   }
@@ -215,7 +210,7 @@
   // 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) {
+    if (tab.browser && tab.mode.name == "contentTab") {
       let win = tab.browser.contentWindow;
       if (win && win.location.href == "about:addons") {
         return win;
@@ -226,9 +221,28 @@
   getAddonManagerFromWindow(window) {
     let tabMail = this.getTabMail(window);
     for (let tab of tabMail.tabInfo) {
-      let win = this.getAddonManagerFromTab(tab)
-      if (win) {
-        return win;
+      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;
+        }
       }
     }
   }
@@ -237,15 +251,16 @@
     if (!managerWindow) {
       return;
     }
-    if (managerWindow 
-          && managerWindow[this.uniqueRandomID]
-          && managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners
+    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.document.addEventListener("view-loaded", this);
     managerWindow[this.uniqueRandomID] = {};
     managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners = true;
     if (forceLoad) {
@@ -262,13 +277,13 @@
     this.pathToOptionsPage = null;
     this.chromeHandle = null;
     this.chromeData = null;
-    this.resourceData = 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 = this.getMessenger(this.context);
+    this.bootstrappedObj.messenger = getMessenger(this.context);
 
     this.BOOTSTRAP_REASONS = {
       APP_STARTUP: 1,
@@ -283,49 +298,413 @@
 
     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(aTab) {},
-      onTabClosing(aTab) {},
-      onTabPersist(aTab) {},
-      onTabRestored(aTab) {},
-      onTabSwitched(aNewTab, aOldTab) {
-        //self.setupAddonManager(self.getAddonManagerFromTab(aNewTab));
+      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));
+        }
       },
-      async onTabOpened(aTab) {
-        if (aTab.browser) {
-          if (!aTab.pageLoaded) {
-            // await a location change if browser is not loaded yet
-            await new Promise(resolve => {
-              let reporterListener = {
-                QueryInterface: ChromeUtils.generateQI([
-                  "nsIWebProgressListener",
-                  "nsISupportsWeakReference",
-                ]),
-                onStateChange() {},
-                onProgressChange() {},
-                onLocationChange(
-                    /* in nsIWebProgress*/ aWebProgress,
-                    /* in nsIRequest*/ aRequest,
-                    /* in nsIURI*/ aLocation
-                ) {
-                  aTab.browser.removeProgressListener(reporterListener);  
-                  resolve();
-                },
-                onStatusChange() {},
-                onSecurityChange() {},
-                onContentBlockingEvent() {}
-              }          
-              aTab.browser.addProgressListener(reporterListener);  
+    };
+
+    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) {
+              }
             });
           }
-          // Setup the ViewChange event listener in the outer browser of the add-on,
-          // but do not actually add the button/menu, as the inner browser is not yet ready,
-          // let the ViewChange event do it
-          self.setupAddonManager(self.getAddonManagerFromTab(aTab));
+        }
+      }
+    };
+  }
+
+  onShutdown(isAppShutdown) {
+    if (isAppShutdown) {
+      return; // the application gets unloaded anyway
+    }
+
+    //remove our entry in the add-on options menu
+    if (this.pathToOptionsPage) {
+      for (let window of Services.wm.getEnumerator("mail:3pane")) {
+        if (getThunderbirdVersion().major < 78) {
+          let element_addonPrefs = window.document.getElementById(this.menu_addonPrefs_id);
+          element_addonPrefs.removeEventListener("popupshowing", this);
+          // Remove our entry.
+          let entry = window.document.getElementById(this.menu_addonPrefs_id + "_" + this.uniqueRandomID);
+          if (entry) entry.remove();
+          // Do we have to unhide the noPrefsElement?
+          if (element_addonPrefs.children.length == 1) {
+            let noPrefsElem = element_addonPrefs.querySelector('[disabled="true"]');
+            noPrefsElem.style.display = "inline";
+          }
+        } else {
+          // Remove event listener for addon manager view changes
+          let managerWindow = this.getAddonManagerFromWindow(window);
+          if (
+            managerWindow && 
+            managerWindow[this.uniqueRandomID] && 
+            managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners
+          ) {
+            managerWindow.document.removeEventListener("ViewChanged", this);
+            managerWindow.document.removeEventListener("update", this);
+            managerWindow.document.removeEventListener("view-loaded", this);
+            managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners = false;
+
+            let cards = this.getCards(managerWindow);
+            if (getThunderbirdVersion().major < 88) {
+              // Remove options menu in 78-87
+              for (let card of cards) {
+                let addonOptionsLegacyEntry = card.querySelector(".extension-options-legacy");
+                if (addonOptionsLegacyEntry) addonOptionsLegacyEntry.remove();
+              }
+            } else {
+              // Remove options button in 88
+              for (let card of cards) {
+                if (card.addon.id == this.extension.id) {
+                  let addonOptionsButton = card.querySelector(".extension-options-button2");
+                  if (addonOptionsButton) addonOptionsButton.remove();
+                  break;
+                }
+              }
+            }
+          }
+
+          // Remove tabmonitor
+          if (window[this.uniqueRandomID].hasTabMonitor) {
+            this.getTabMail(window).unregisterTabMonitor(this.tabMonitor);
+            window[this.uniqueRandomID].hasTabMonitor = false;
+          }
+
+        }
+      }
+      // Stop listening for new windows.
+      ExtensionSupport.unregisterWindowListener("injectListener_" + this.uniqueRandomID);
+    }
+
+    // Execute registered shutdown()
+    try {
+      if (this.bootstrappedObj.shutdown) {
+        this.bootstrappedObj.shutdown(
+          this.extension.addonData,
+          isAppShutdown
+            ? this.BOOTSTRAP_REASONS.APP_SHUTDOWN
+            : this.BOOTSTRAP_REASONS.ADDON_DISABLE);
+      }
+    } catch (e) {
+      Components.utils.reportError(e)
+    }
+
+    if (this.resourceData) {
+      const resProto = Cc["@mozilla.org/network/protocol;1?name=resource"].getService(Ci.nsISubstitutingProtocolHandler);
+      for (let res of this.resourceData) {
+        // [ "resource", "shortname" , "path" ]
+        resProto.setSubstitution(
+          res[1],
+          null,
+        );
+      }
+    }
+
+    if (this.chromeHandle) {
+      this.chromeHandle.destruct();
+      this.chromeHandle = null;
+    }
+    // Flush all caches
+    Services.obs.notifyObservers(null, "startupcache-invalidate");
+    console.log("BootstrapLoader for " + this.extension.id + " unloaded!");
+  }
+};
+
+// Removed all extra code for backward compatibility for better maintainability.
+var BootstrapLoader_115 = class extends ExtensionCommon.ExtensionAPI {
+  getCards(e) {
+    // This gets triggered by real events but also manually by providing the outer window.
+    // The event is attached to the outer browser, get the inner one.
+    let doc = e.document || e.target;
+    return doc.querySelectorAll("addon-card");
+  }
+
+  // Event handler for the addon manager, to update the state of the options button.
+  handleEvent(e) {
+    switch (e.type) {
+      case "click": {
+        e.preventDefault();
+        e.stopPropagation();
+        let BL = {}
+        BL.extension = this.extension;
+        BL.messenger = getMessenger(this.context);
+        let w = Services.wm.getMostRecentWindow("mail:3pane");
+        w.openDialog(
+          this.pathToOptionsPage,
+          "AddonOptions",
+          "chrome,resizable,centerscreen",
+          BL
+        );
+      }
+        break;
+
+
+      // update, ViewChanged and manual call for add-on manager options overlay
+      default: {
+        let cards = this.getCards(e);
+        for (let card of cards) {
+          // Setup either the options entry in the menu or the button
+          if (card.addon.id == this.extension.id) {
+            // Add-on button
+            let addonOptionsButton = card.querySelector(
+              ".windowlistener-options-button"
+            );
+            if (card.addon.isActive && !addonOptionsButton) {
+              let origAddonOptionsButton = card.querySelector(".extension-options-button")
+              origAddonOptionsButton.setAttribute("hidden", "true");
+
+              addonOptionsButton = card.ownerDocument.createElement("button");
+              addonOptionsButton.classList.add("windowlistener-options-button");
+              addonOptionsButton.classList.add("extension-options-button");
+              card.optionsButton.parentNode.insertBefore(
+                addonOptionsButton,
+                card.optionsButton
+              );
+              card
+                .querySelector(".windowlistener-options-button")
+                .addEventListener("click", this);
+            } else if (!card.addon.isActive && addonOptionsButton) {
+              addonOptionsButton.remove();
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // Some tab/add-on-manager related functions
+  getTabMail(window) {
+    return window.document.getElementById("tabmail");
+  }
+
+  // returns the outer browser, not the nested browser of the add-on manager
+  // events must be attached to the outer browser
+  getAddonManagerFromTab(tab) {
+    if (tab.browser && tab.mode.name == "contentTab") {
+      let win = tab.browser.contentWindow;
+      if (win && win.location.href == "about:addons") {
+        return win;
+      }
+    }
+  }
+
+  getAddonManagerFromWindow(window) {
+    let tabMail = this.getTabMail(window);
+    for (let tab of tabMail.tabInfo) {
+      let managerWindow = this.getAddonManagerFromTab(tab);
+      if (managerWindow) {
+        return managerWindow;
+      }
+    }
+  }
+
+  async getAddonManagerFromWindowWaitForLoad(window) {
+    let { setTimeout } = Services.wm.getMostRecentWindow("mail:3pane");
+
+    let tabMail = this.getTabMail(window);
+    for (let tab of tabMail.tabInfo) {
+      if (tab.browser && tab.mode.name == "contentTab") {
+        // Instead of registering a load observer, wait until its loaded. Not nice,
+        // but gets aroud a lot of edge cases.
+        while (!tab.pageLoaded) {
+          await new Promise(r => setTimeout(r, 150));
+        }
+        let managerWindow = this.getAddonManagerFromTab(tab);
+        if (managerWindow) {
+          return managerWindow;
+        }
+      }
+    }
+  }
+
+  setupAddonManager(managerWindow, forceLoad = false) {
+    if (!managerWindow) {
+      return;
+    }
+    if (!this.pathToOptionsPage) {
+      return;
+    }
+    if (
+      managerWindow &&
+      managerWindow[this.uniqueRandomID] &&
+      managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners
+    ) {
+      return;
+    }
+    
+    managerWindow.document.addEventListener("ViewChanged", this);
+    managerWindow.document.addEventListener("update", this);
+    managerWindow.document.addEventListener("view-loaded", this);
+    managerWindow[this.uniqueRandomID] = {};
+    managerWindow[this.uniqueRandomID].hasAddonManagerEventListeners = true;
+    if (forceLoad) {
+      this.handleEvent(managerWindow);
+    }
+  }
+
+  getAPI(context) {
+    this.uniqueRandomID = "AddOnNS" + context.extension.instanceId;
+    this.menu_addonPrefs_id = "addonPrefs";
+
+
+    this.pathToBootstrapScript = null;
+    this.pathToOptionsPage = null;
+    this.chromeHandle = null;
+    this.chromeData = null;
+    this.resourceData = null;
+    this.bootstrappedObj = {};
+
+    // make the extension object and the messenger object available inside
+    // the bootstrapped scope
+    this.bootstrappedObj.extension = context.extension;
+    this.bootstrappedObj.messenger = getMessenger(this.context);
+
+    this.BOOTSTRAP_REASONS = {
+      APP_STARTUP: 1,
+      APP_SHUTDOWN: 2,
+      ADDON_ENABLE: 3,
+      ADDON_DISABLE: 4,
+      ADDON_INSTALL: 5,
+      ADDON_UNINSTALL: 6, // not supported
+      ADDON_UPGRADE: 7,
+      ADDON_DOWNGRADE: 8,
+    };
+
+    const aomStartup = Cc["@mozilla.org/addons/addon-manager-startup;1"].getService(Ci.amIAddonManagerStartup);
+    const resProto = Cc["@mozilla.org/network/protocol;1?name=resource"].getService(Ci.nsISubstitutingProtocolHandler);
+
+    let self = this;
+
+    // TabMonitor to detect opening of tabs, to setup the options button in the add-on manager.
+    this.tabMonitor = {
+      onTabTitleChanged(tab) { },
+      onTabClosing(tab) { },
+      onTabPersist(tab) { },
+      onTabRestored(tab) { },
+      onTabSwitched(aNewTab, aOldTab) { },
+      async onTabOpened(tab) {
+        if (tab.browser && tab.mode.name == "contentTab") {
+          let { setTimeout } = Services.wm.getMostRecentWindow("mail:3pane");
+          // Instead of registering a load observer, wait until its loaded. Not nice,
+          // but gets aroud a lot of edge cases.
+          while (!tab.pageLoaded) {
+            await new Promise(r => setTimeout(r, 150));
+          }
+          self.setupAddonManager(self.getAddonManagerFromTab(tab));
         }
       },
     };
@@ -343,8 +722,8 @@
           let window = context.extension.windowManager.get(windowId, context).window
           let BL = {}
           BL.extension = self.extension;
-          BL.messenger = self.getMessenger(self.context);
-          window.openDialog(self.pathToOptionsPage, "AddonOptions", "chrome,resizable,centerscreen", BL);        
+          BL.messenger = getMessenger(self.context);
+          window.openDialog(self.pathToOptionsPage, "AddonOptions", "chrome,resizable,centerscreen", BL);
         },
 
         registerChromeUrl(data) {
@@ -382,7 +761,7 @@
           self.resourceData = resourceData;
         },
 
-        registerBootstrapScript: async function(aPath) {
+        registerBootstrapScript: async function (aPath) {
           self.pathToBootstrapScript = aPath.startsWith("chrome://")
             ? aPath
             : context.extension.rootURI.resolve(aPath);
@@ -404,32 +783,30 @@
           } 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",              
+                "chrome://messenger/content/messenger.xhtml",
               ],
               async onLoadWindow(window) {
-                if (self.getThunderbirdVersion().major < 78) {
+                if (getThunderbirdVersion().major < 78) {
                   let element_addonPrefs = window.document.getElementById(self.menu_addonPrefs_id);
                   element_addonPrefs.addEventListener("popupshowing", self);
                 } else {
-                  // Setup the options button/menu in the add-on manager, if it is already open.
-                  self.setupAddonManager(
-                    self.getAddonManagerFromWindow(window),
-                    true
-                  );
                   // 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) {          
+              onUnloadWindow(window) {
               }
             });
           }
@@ -442,11 +819,11 @@
     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 (this.getThunderbirdVersion().major < 78) {
+        if (getThunderbirdVersion().major < 78) {
           let element_addonPrefs = window.document.getElementById(this.menu_addonPrefs_id);
           element_addonPrefs.removeEventListener("popupshowing", this);
           // Remove our entry.
@@ -454,19 +831,24 @@
           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";
-          }              
+            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) {
+          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 (this.getThunderbirdVersion().major < 88) {
+            if (getThunderbirdVersion().major < 88) {
               // Remove options menu in 78-87
               for (let card of cards) {
                 let addonOptionsLegacyEntry = card.querySelector(".extension-options-legacy");
@@ -483,13 +865,13 @@
               }
             }
           }
-          
+
           // Remove tabmonitor
           if (window[this.uniqueRandomID].hasTabMonitor) {
             this.getTabMail(window).unregisterTabMonitor(this.tabMonitor);
             window[this.uniqueRandomID].hasTabMonitor = false;
           }
-                    
+
         }
       }
       // Stop listening for new windows.
@@ -529,3 +911,7 @@
     console.log("BootstrapLoader for " + this.extension.id + " unloaded!");
   }
 };
+
+var BootstrapLoader = getThunderbirdVersion().major < 111
+  ? BootstrapLoader_102
+  : BootstrapLoader_115;
diff -Nru eas4tbsync-4.1.5/content/api/BootstrapLoader/schema.json eas4tbsync-4.7/content/api/BootstrapLoader/schema.json
--- eas4tbsync-4.1.5/content/api/BootstrapLoader/schema.json	2022-10-13 11:05:56.000000000 +0200
+++ eas4tbsync-4.7/content/api/BootstrapLoader/schema.json	2023-08-18 16:51:43.000000000 +0200
@@ -35,7 +35,7 @@
             "type": "array",
             "items": {
               "type": "array",
-              "items" : {
+              "items": {
                 "type": "string"
               }
             },
@@ -58,4 +58,4 @@
       }
     ]
   }
-]
+]
\ Kein Zeilenumbruch am Dateiende.
diff -Nru eas4tbsync-4.1.5/content/bootstrap.js eas4tbsync-4.7/content/bootstrap.js
--- eas4tbsync-4.1.5/content/bootstrap.js	2022-10-13 11:05:56.000000000 +0200
+++ eas4tbsync-4.7/content/bootstrap.js	2023-08-18 16:51:43.000000000 +0200
@@ -32,14 +32,8 @@
 
     Services.obs.addObserver(onInitDoneObserver, "tbsync.observer.initialized", false);
 
-    // The startup of TbSync is delayed until all add-ons have called their startup(),
-    // so all providers have registered the "tbsync.observer.initialized" observer.
-    // Once TbSync has finished its startup, all providers will be notified (also if
-    // TbSync itself is restarted) to load themself.
-    // If this is not startup, we need load manually.
-    if (reason != APP_STARTUP) {
-        onInitDoneObserver.observe();
-    }
+    // Did we miss the observer?
+    onInitDoneObserver.observe();
 }
 
 function shutdown(data, reason) {
diff -Nru eas4tbsync-4.1.5/content/includes/calendarsync.js eas4tbsync-4.7/content/includes/calendarsync.js
--- eas4tbsync-4.1.5/content/includes/calendarsync.js	2022-10-13 11:05:56.000000000 +0200
+++ eas4tbsync-4.7/content/includes/calendarsync.js	2023-08-18 16:51:43.000000000 +0200
@@ -348,11 +348,10 @@
         //C can be reconstucted from TB STATUS
         //O can be reconstructed by looking at the original value, or (if not present) by comparing EAS ownerID with TB ownerID
 
-        let countAttendees = {};
-        let attendees = item.getAttendees(countAttendees);
-        //if (!(isException && asversion == "2.5")) { //MeetingStatus is not supported in exceptions in EAS 2.5        
+        let attendees = item.getAttendees();
+        //if (!(isException && asversion == "2.5")) { //MeetingStatus is not supported in exceptions in EAS 2.5
         if (!isException) { //Exchange 2010 does not seem to support MeetingStatus at all in exceptions
-            if (countAttendees == 0) wbxml.atag("MeetingStatus", "0");
+            if (attendees.length == 0) wbxml.atag("MeetingStatus", "0");
             else {
                 //get owner information
                 let isReceived = false;
@@ -369,11 +368,11 @@
                 }
             }
         }
-        
+
         //Attendees
-        let TB_responseType = null;        
+        let TB_responseType = null;
         if (!(isException && asversion == "2.5")) { //attendees are not supported in exceptions in EAS 2.5
-            if (countAttendees.value > 0) {
+            if (attendees.length > 0) { //We should use it instead of countAttendees.value
                 wbxml.otag("Attendees");
                     for (let attendee of attendees) {
                         wbxml.otag("Attendee");
diff -Nru eas4tbsync-4.1.5/content/includes/network.js eas4tbsync-4.7/content/includes/network.js
--- eas4tbsync-4.1.5/content/includes/network.js	2022-10-13 11:05:56.000000000 +0200
+++ eas4tbsync-4.7/content/includes/network.js	2023-08-18 16:51:43.000000000 +0200
@@ -76,16 +76,15 @@
       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";,
-          // changed in beta 1.14.1, according to
-          // https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#default-and-consent
-          scope : "offline_access https://outlook.office.com/.default";, //"offline_access https://outlook.office.com/EAS.AccessAsUser.All";,
-          client_id : "2980deeb-7460-4723-864a-f9b0f10cd992",
+          client_id : customID != "" ? customID : "2980deeb-7460-4723-864a-f9b0f10cd992",
         }
         break;
       
@@ -93,7 +92,21 @@
         return null;
     }
 
-    let oauth = new OAuth2(config.auth_uri, config.token_uri, config.scope, config.client_id, config.client_secret);
+    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
@@ -691,7 +704,7 @@
                 wbxml.otag("Set");
                     wbxml.atag("Model", "Computer");
                     wbxml.atag("FriendlyName", "TbSync on Device " + syncData.accountData.getAccountProperty("deviceId").substring(4));
-                    wbxml.atag("OS", OS.Constants.Sys.Name);
+                    wbxml.atag("OS", Services.appinfo.OS);
                     wbxml.atag("UserAgent", syncData.accountData.getAccountProperty("useragent"));
                 wbxml.ctag();
             wbxml.ctag();
diff -Nru eas4tbsync-4.1.5/content/includes/tasksync.js eas4tbsync-4.7/content/includes/tasksync.js
--- eas4tbsync-4.1.5/content/includes/tasksync.js	2022-10-13 11:05:56.000000000 +0200
+++ eas4tbsync-4.7/content/includes/tasksync.js	2023-08-18 16:51:43.000000000 +0200
@@ -73,14 +73,38 @@
         eas.sync.mapEasPropertyToThunderbird ("Sensitivity", "CLASS", data, item);
         eas.sync.mapEasPropertyToThunderbird ("Importance", "PRIORITY", data, item);
 
+        let msTodoCompat = eas.prefs.getBoolPref("msTodoCompat");
+        
         item.clearAlarms();
-        if (data.ReminderSet && data.ReminderTime && data.UtcStartDate) {        
-            let UtcDate = eas.tools.createDateTime(data.UtcStartDate);
+        if (data.ReminderSet && data.ReminderTime) {
             let UtcAlarmDate = eas.tools.createDateTime(data.ReminderTime);
             let alarm = new CalAlarm();
-            alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_START; //TB saves new alarms as offsets, so we add them as such as well
-            alarm.offset = UtcAlarmDate.subtractDate(UtcDate);
             alarm.action = "DISPLAY";
+            
+            if (msTodoCompat)
+            {
+                // Microsoft To-Do only uses due dates (no start dates) an doesn't have a time part in the due date
+                // dirty hack: Use the reminder date as due date and set a reminder exactly to the due date
+                // drawback: only works if due date and reminder is set to the same day - this could maybe checked here but I don't know how
+                item.entryDate = UtcAlarmDate;
+                item.dueDate = UtcAlarmDate;
+                alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_START;
+                alarm.offset = TbSync.lightning.cal.createDuration();
+                alarm.offset.inSeconds = 0;
+            }
+            else if (data.UtcStartDate)
+            {
+                let UtcDate = eas.tools.createDateTime(data.UtcStartDate);
+                alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_START;
+                alarm.offset = UtcAlarmDate.subtractDate(UtcDate);
+            }
+            else
+            {
+                // Alternative solution for Microsoft To-Do:
+                // alarm correctly set but because time part of due date is always "0:00", all tasks for today are shown as overdue
+                alarm.related = Components.interfaces.calIAlarm.ALARM_RELATED_ABSOLUTE;
+                alarm.alarmDate = UtcAlarmDate;
+            }
             item.addAlarm(alarm);
         }
         
diff -Nru eas4tbsync-4.1.5/content/includes/tools.js eas4tbsync-4.7/content/includes/tools.js
--- eas4tbsync-4.1.5/content/includes/tools.js	2022-10-13 11:05:56.000000000 +0200
+++ eas4tbsync-4.7/content/includes/tools.js	2023-08-18 16:51:43.000000000 +0200
@@ -303,10 +303,8 @@
         if (test.timezoneOffset/-60 == curOffset) return test.timezone;
         
         //third try all others
-        let enumerator = tzService.timezoneIds;
-        while (enumerator.hasMore()) {
-            let id = enumerator.getNext();
-            let test = utcDateTime.getInTimezone(tzService.getTimezone(id));
+        for (let timezoneId of tzService.timezoneIds) {
+            let test = utcDateTime.getInTimezone(tzService.getTimezone(timezoneId));
             TbSync.dump("Matching TZ via current offset: " + test.timezone.tzid + " @ " + curOffset, test.timezoneOffset/-60);
             if (test.timezoneOffset/-60 == curOffset) return test.timezone;
         }
@@ -334,17 +332,15 @@
                 let tzService = TbSync.lightning.cal.timezoneService;
 
                 //cache timezones data from internal IANA data
-                let enumerator = tzService.timezoneIds;
-                while (enumerator.hasMore()) {
-                    let id = enumerator.getNext();
-                    let timezone = tzService.getTimezone(id);
+                for (let timezoneId of tzService.timezoneIds) {
+                    let timezone = tzService.getTimezone(timezoneId);
                     let tzInfo = eas.tools.getTimezoneInfo(timezone);
 
                     eas.cachedTimezoneData.bothOffsets[tzInfo.std.offset+":"+tzInfo.dst.offset] = timezone;
                     eas.cachedTimezoneData.stdOffset[tzInfo.std.offset] = timezone;
 
-                    eas.cachedTimezoneData.abbreviations[tzInfo.std.abbreviation] = id;
-                    eas.cachedTimezoneData.iana[id] = tzInfo;
+                    eas.cachedTimezoneData.abbreviations[tzInfo.std.abbreviation] = timezoneId;
+                    eas.cachedTimezoneData.iana[timezoneId] = tzInfo;
                     
                     //TbSync.dump("TZ ("+ tzInfo.std.id + " :: " + tzInfo.dst.id +  " :: " + tzInfo.std.displayname + " :: " + tzInfo.dst.displayname + " :: " + tzInfo.std.offset + " :: " + tzInfo.dst.offset + ")", tzService.getTimezone(id));
                 }
diff -Nru eas4tbsync-4.1.5/content/manager/createAccount.xhtml eas4tbsync-4.7/content/manager/createAccount.xhtml
--- eas4tbsync-4.1.5/content/manager/createAccount.xhtml	2022-10-13 11:05:56.000000000 +0200
+++ eas4tbsync-4.7/content/manager/createAccount.xhtml	2023-08-18 16:51:43.000000000 +0200
@@ -2,8 +2,6 @@
 <?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
 
 <window
-    width="500"
-    height="600"
     xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
     xmlns:html="http://www.w3.org/1999/xhtml";
     onload="tbSyncEasNewAccount.onLoad();"
diff -Nru eas4tbsync-4.1.5/content/provider.js eas4tbsync-4.7/content/provider.js
--- eas4tbsync-4.1.5/content/provider.js	2022-10-13 11:05:56.000000000 +0200
+++ eas4tbsync-4.7/content/provider.js	2023-08-18 16:51:43.000000000 +0200
@@ -38,8 +38,10 @@
         let branch = Services.prefs.getDefaultBranch("extensions.eas4tbsync.");
         branch.setIntPref("timeout", 90000);
         branch.setIntPref("maxitems", 50);
+        branch.setBoolPref("msTodoCompat", false);
         branch.setCharPref("clientID.type", "TbSync");
         branch.setCharPref("clientID.useragent", "Thunderbird ActiveSync");    
+        branch.setCharPref("oauth.clientID", "");
 
         eas.defaultTimezone = null;
         eas.utcTimezone = null;
@@ -102,18 +104,15 @@
             }
 
             let tzService = TbSync.lightning.cal.timezoneService;
-            let enumerator = tzService.timezoneIds;
-            while (enumerator.hasMore()) {
-                let id = enumerator.getNext();
-                if (!eas.ianaToWindowsTimezoneMap[id]) {
-                    TbSync.eventlog.add("info", eventLogInfo, "The IANA timezone <"+id+"> cannot be mapped to any Exchange timezone.");
+            for (let timezoneId of tzService.timezoneIds) {
+                if (!eas.ianaToWindowsTimezoneMap[timezoneId]) {
+                    TbSync.eventlog.add("info", eventLogInfo, "The IANA timezone <"+timezoneId+"> cannot be mapped to any Exchange timezone.");
                 }
             }
-
             
             //If an EAS calendar is currently NOT associated with an email identity, try to associate, 
             //but do not change any explicitly set association
-            // - A) find email identity and accociate (which sets organizer to that user identity)
+            // - A) find email identity and associate (which sets organizer to that user identity)
             // - B) overwrite default organizer with current best guess
             //TODO: Do this after email accounts changed, not only on restart? 
             let providerData = new TbSync.ProviderData("eas");
@@ -440,6 +439,14 @@
         // Fall through, if there was no error.
         return new TbSync.StatusData();   
     }
+
+
+    /**
+     * Return the custom OAuth2 ClientID.
+     */
+    static getCustomeOauthClientID() {
+        return eas.prefs.getCharPref("oauth.clientID");
+    }
 }
 
 
diff -Nru eas4tbsync-4.1.5/debian/changelog eas4tbsync-4.7/debian/changelog
--- eas4tbsync-4.1.5/debian/changelog	2022-10-14 13:46:15.000000000 +0200
+++ eas4tbsync-4.7/debian/changelog	2023-10-22 12:57:50.000000000 +0200
@@ -1,3 +1,25 @@
+eas4tbsync (4.7-1~deb12u1) bookworm; urgency=medium
+
+  * [4af7393] Adjust version of dependencies
+  *     Prepared for release in bookworm (proposed-updates)
+
+ -- Mechtilde Stehmann <mechti...@debian.org>  Sun, 22 Oct 2023 12:57:50 +0200
+
+eas4tbsync (4.7-1) unstable; urgency=medium
+
+  * [a18dc06] Changed compression for tar.gz
+  * [4286976] New upstream version 4.7
+  *     Removed double entries in the version before
+
+ -- Mechtilde Stehmann <mechti...@debian.org>  Tue, 12 Sep 2023 20:12:53 +0200
+
+eas4tbsync (4.1.5+git20230524+c788967-1) experimental; urgency=medium
+
+  * [976c125] Changed compression for using zip file
+  * [b9b95cd] New upstream version 4.1.5+git20230524+c788967
+
+ -- Mechtilde Stehmann <mechti...@debian.org>  Sat, 29 Jul 2023 20:48:42 +0200
+
 eas4tbsync (4.1.5-1) unstable; urgency=medium
 
   * [dc50cf2] New upstream version 4.1.5
diff -Nru eas4tbsync-4.1.5/debian/control eas4tbsync-4.7/debian/control
--- eas4tbsync-4.1.5/debian/control	2022-09-24 13:33:37.000000000 +0200
+++ eas4tbsync-4.7/debian/control	2023-10-22 12:47:25.000000000 +0200
@@ -15,8 +15,8 @@
 Package: webext-eas4tbsync
 Architecture: all
 Depends: ${misc:Depends}
- , thunderbird (>= 1:102.2)
- , webext-tbsync (>= 4.0)
+ , thunderbird (>= 1:115.3)
+ , webext-tbsync (>= 4.7)
 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.1.5/debian/gbp.conf eas4tbsync-4.7/debian/gbp.conf
--- eas4tbsync-4.1.5/debian/gbp.conf	2022-09-24 10:34:50.000000000 +0200
+++ eas4tbsync-4.7/debian/gbp.conf	2023-09-12 20:07:05.000000000 +0200
@@ -4,7 +4,7 @@
 # use pristine-tar:
 pristine-tar = True
 # generate gz compressed orig file
-compression = gz
+# compression = xz
 debian-branch = debian/sid
 upstream-branch = upstream
 
diff -Nru eas4tbsync-4.1.5/Makefile eas4tbsync-4.7/Makefile
--- eas4tbsync-4.1.5/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ eas4tbsync-4.7/Makefile	2023-08-18 16:51:43.000000000 +0200
@@ -0,0 +1,25 @@
+# This file is part of EAS-4-TbSync.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+PACKAGE_NAME=EAS-4-TbSync
+
+ARCHIVE_NAME=$(PACKAGE_NAME).xpi
+
+PACKAGE_FILES= \
+	content \
+	_locales \
+	manifest.json \
+	CONTRIBUTORS.md \
+	LICENSE README.md \
+	background.js
+
+all: clean $(PACKAGE_FILES)
+	zip -r $(ARCHIVE_NAME) $(PACKAGE_FILES)
+
+clean:
+	rm -f $(ARCHIVE_NAME)
+
+.PHONY: clean
diff -Nru eas4tbsync-4.1.5/manifest.json eas4tbsync-4.7/manifest.json
--- eas4tbsync-4.1.5/manifest.json	2022-10-13 11:05:56.000000000 +0200
+++ eas4tbsync-4.7/manifest.json	2023-08-18 16:51:43.000000000 +0200
@@ -2,13 +2,13 @@
   "applications": {
     "gecko": {
       "id": "eas4tbs...@jobisoft.de",
-      "strict_min_version": "102.3.0",
-      "strict_max_version": "102.*"
+      "strict_min_version": "102.7.0",
+      "strict_max_version": "115.*"
     }
   },
   "manifest_version": 2,
   "name": "__MSG_extensionName__",
-  "version": "4.1.5",
+  "version": "4.7",
   "author": "John Bieling",
   "homepage_url": "https://github.com/jobisoft/EAS-4-TbSync/";,
   "default_locale": "en-US",

Attachment: OpenPGP_signature.asc
Description: OpenPGP digital signature

Reply via email to