[Pkg-mozext-maintainers] Bug#1082086: bookworm-pu: package eas4tbsync/4.11-1~deb12u1
Mechtilde Stehmann
mechtilde at debian.org
Wed Sep 18 09:23:47 BST 2024
Package: release.debian.org
Severity: normal
Tags: bookworm
X-Debbugs-Cc: eas4tbsync at packages.debian.org, mechtilde at debian.org
Control: affects -1 + src:eas4tbsync
User: release.debian.org at packages.debian.org
Usertags: pu
[ Reason ]
Thunderbird will come with a new version (>=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.
-------------- next part --------------
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 at 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 at 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 at 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 at 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 at 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",
More information about the Pkg-mozext-maintainers
mailing list