diff -Nru thunderbird-78.5.0+build3/browser/base/content/browser.js thunderbird-78.7.1+build1/browser/base/content/browser.js --- thunderbird-78.5.0+build3/browser/base/content/browser.js 2020-11-18 16:42:50.000000000 +0000 +++ thunderbird-78.7.1+build1/browser/base/content/browser.js 2021-02-05 18:21:07.000000000 +0000 @@ -89,6 +89,7 @@ WebNavigationFrames: "resource://gre/modules/WebNavigationFrames.jsm", fxAccounts: "resource://gre/modules/FxAccounts.jsm", webrtcUI: "resource:///modules/webrtcUI.jsm", + WebsiteFilter: "resource:///modules/policies/WebsiteFilter.jsm", ZoomUI: "resource:///modules/ZoomUI.jsm", }); diff -Nru thunderbird-78.5.0+build3/browser/base/content/nsContextMenu.js thunderbird-78.7.1+build1/browser/base/content/nsContextMenu.js --- thunderbird-78.5.0+build3/browser/base/content/nsContextMenu.js 2020-11-18 16:42:50.000000000 +0000 +++ thunderbird-78.7.1+build1/browser/base/content/nsContextMenu.js 2021-02-05 18:21:07.000000000 +0000 @@ -453,6 +453,16 @@ "context-savelink", this.onSaveableLink || this.onPlainTextLink ); + if ( + (this.onSaveableLink || this.onPlainTextLink) && + Services.policies.status === Services.policies.ACTIVE + ) { + this.setItemAttr( + "context-savelink", + "disabled", + !WebsiteFilter.isAllowed(this.linkURL) + ); + } // Save image depends on having loaded its content, video and audio don't. this.showItem("context-saveimage", this.onLoadedImage || this.onCanvas); diff -Nru thunderbird-78.5.0+build3/browser/components/enterprisepolicies/helpers/WebsiteFilter.jsm thunderbird-78.7.1+build1/browser/components/enterprisepolicies/helpers/WebsiteFilter.jsm --- thunderbird-78.5.0+build3/browser/components/enterprisepolicies/helpers/WebsiteFilter.jsm 2020-11-18 16:42:50.000000000 +0000 +++ thunderbird-78.7.1+build1/browser/components/enterprisepolicies/helpers/WebsiteFilter.jsm 2021-02-05 18:21:07.000000000 +0000 @@ -105,14 +105,18 @@ shouldLoad(contentLocation, loadInfo, mimeTypeGuess) { let contentType = loadInfo.externalContentPolicyType; + let url = contentLocation.spec; + if (contentLocation.scheme == "view-source") { + url = contentLocation.pathQueryRef; + } if ( contentType == Ci.nsIContentPolicy.TYPE_DOCUMENT || contentType == Ci.nsIContentPolicy.TYPE_SUBDOCUMENT ) { - if (this._blockPatterns.matches(contentLocation.spec.toLowerCase())) { + if (this._blockPatterns.matches(url.toLowerCase())) { if ( !this._exceptionsPatterns || - !this._exceptionsPatterns.matches(contentLocation.spec.toLowerCase()) + !this._exceptionsPatterns.matches(url.toLowerCase()) ) { return Ci.nsIContentPolicy.REJECT_POLICY; } @@ -130,4 +134,15 @@ createInstance(outer, iid) { return this.QueryInterface(iid); }, + isAllowed(url) { + if (this._blockPatterns?.matches(url.toLowerCase())) { + if ( + !this._exceptionsPatterns || + !this._exceptionsPatterns.matches(url.toLowerCase()) + ) { + return false; + } + } + return true; + }, }; diff -Nru thunderbird-78.5.0+build3/browser/components/enterprisepolicies/Policies.jsm thunderbird-78.7.1+build1/browser/components/enterprisepolicies/Policies.jsm --- thunderbird-78.5.0+build3/browser/components/enterprisepolicies/Policies.jsm 2020-11-18 16:42:50.000000000 +0000 +++ thunderbird-78.7.1+build1/browser/components/enterprisepolicies/Policies.jsm 2021-02-05 18:21:07.000000000 +0000 @@ -1455,9 +1455,11 @@ "layout.", "media.", "network.", + "pdfjs.", "places.", "print.", "signon.", + "spellchecker.", "ui.", "widget.", ]; @@ -2219,6 +2221,7 @@ function installAddonFromURL(url, extensionID, addon) { if ( addon && + addon.sourceURI && addon.sourceURI.spec == url && !addon.sourceURI.schemeIs("file") ) { @@ -2274,7 +2277,11 @@ )} - {url}` ); }, - onInstallEnded: () => { + /* eslint-disable-next-line no-shadow */ + onInstallEnded: (install, addon) => { + if (addon.type == "theme") { + addon.enable(); + } install.removeListener(listener); log.debug(`Installation succeeded - ${url}`); }, diff -Nru thunderbird-78.5.0+build3/browser/components/enterprisepolicies/tests/browser/browser.ini thunderbird-78.7.1+build1/browser/components/enterprisepolicies/tests/browser/browser.ini --- thunderbird-78.5.0+build3/browser/components/enterprisepolicies/tests/browser/browser.ini 2020-11-18 16:42:50.000000000 +0000 +++ thunderbird-78.7.1+build1/browser/components/enterprisepolicies/tests/browser/browser.ini 2021-02-05 18:21:07.000000000 +0000 @@ -7,6 +7,7 @@ policytest_v0.2.xpi policy_websitefilter_block.html policy_websitefilter_exception.html + policy_websitefilter_savelink.html ../../../../../toolkit/components/antitracking/test/browser/page.html ../../../../../toolkit/components/antitracking/test/browser/subResources.sjs extensionsettings.html diff -Nru thunderbird-78.5.0+build3/browser/components/enterprisepolicies/tests/browser/browser_policy_websitefilter.js thunderbird-78.7.1+build1/browser/components/enterprisepolicies/tests/browser/browser_policy_websitefilter.js --- thunderbird-78.5.0+build3/browser/components/enterprisepolicies/tests/browser/browser_policy_websitefilter.js 2020-11-18 16:42:50.000000000 +0000 +++ thunderbird-78.7.1+build1/browser/components/enterprisepolicies/tests/browser/browser_policy_websitefilter.js 2021-02-05 18:21:07.000000000 +0000 @@ -6,6 +6,7 @@ "http://mochi.test:8888/browser/browser/components/enterprisepolicies/tests/browser/"; const BLOCKED_PAGE = "policy_websitefilter_block.html"; const EXCEPTION_PAGE = "policy_websitefilter_exception.html"; +const SAVELINKAS_PAGE = "policy_websitefilter_savelink.html"; add_task(async function test_http() { await setupPolicyEngineWithJson({ @@ -18,6 +19,10 @@ }); await checkBlockedPage(SUPPORT_FILES_PATH + BLOCKED_PAGE, true); + await checkBlockedPage( + "view-source:" + SUPPORT_FILES_PATH + BLOCKED_PAGE, + true + ); await checkBlockedPage(SUPPORT_FILES_PATH + EXCEPTION_PAGE, false); }); @@ -49,3 +54,75 @@ await checkBlockedPage("file:///this_should_be_blocked", true); }); + +add_task(async function test_savelink() { + await setupPolicyEngineWithJson({ + policies: { + WebsiteFilter: { + Block: ["*://mochi.test/*policy_websitefilter_block*"], + }, + }, + }); + + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + SUPPORT_FILES_PATH + SAVELINKAS_PAGE + ); + + let contextMenu = document.getElementById("contentAreaContextMenu"); + let promiseContextMenuOpen = BrowserTestUtils.waitForEvent( + contextMenu, + "popupshown" + ); + await BrowserTestUtils.synthesizeMouse( + "#savelink_blocked", + 0, + 0, + { + type: "contextmenu", + button: 2, + centered: true, + }, + gBrowser.selectedBrowser + ); + await promiseContextMenuOpen; + + let saveLink = document.getElementById("context-savelink"); + is(saveLink.disabled, true, "Save Link As should be disabled"); + + let promiseContextMenuHidden = BrowserTestUtils.waitForEvent( + contextMenu, + "popuphidden" + ); + contextMenu.hidePopup(); + await promiseContextMenuHidden; + + promiseContextMenuOpen = BrowserTestUtils.waitForEvent( + contextMenu, + "popupshown" + ); + await BrowserTestUtils.synthesizeMouse( + "#savelink_notblocked", + 0, + 0, + { + type: "contextmenu", + button: 2, + centered: true, + }, + gBrowser.selectedBrowser + ); + await promiseContextMenuOpen; + + saveLink = document.getElementById("context-savelink"); + is(saveLink.disabled, false, "Save Link As should not be disabled"); + + promiseContextMenuHidden = BrowserTestUtils.waitForEvent( + contextMenu, + "popuphidden" + ); + contextMenu.hidePopup(); + await promiseContextMenuHidden; + + BrowserTestUtils.removeTab(tab); +}); diff -Nru thunderbird-78.5.0+build3/browser/components/enterprisepolicies/tests/browser/policy_websitefilter_savelink.html thunderbird-78.7.1+build1/browser/components/enterprisepolicies/tests/browser/policy_websitefilter_savelink.html --- thunderbird-78.5.0+build3/browser/components/enterprisepolicies/tests/browser/policy_websitefilter_savelink.html 1970-01-01 00:00:00.000000000 +0000 +++ thunderbird-78.7.1+build1/browser/components/enterprisepolicies/tests/browser/policy_websitefilter_savelink.html 2021-02-05 18:21:07.000000000 +0000 @@ -0,0 +1,11 @@ + + + + + Save Link As test + + + Should not be saveable
+ Should be saveable + + diff -Nru thunderbird-78.5.0+build3/browser/components/enterprisepolicies/tests/xpcshell/test_extensionsettings.js thunderbird-78.7.1+build1/browser/components/enterprisepolicies/tests/xpcshell/test_extensionsettings.js --- thunderbird-78.5.0+build3/browser/components/enterprisepolicies/tests/xpcshell/test_extensionsettings.js 2020-11-18 16:42:50.000000000 +0000 +++ thunderbird-78.7.1+build1/browser/components/enterprisepolicies/tests/xpcshell/test_extensionsettings.js 2021-02-05 18:21:07.000000000 +0000 @@ -17,6 +17,7 @@ const BASE_URL = `http://example.com/data`; let addonID = "policytest2@mozilla.com"; +let themeID = "policytheme@mozilla.com"; add_task(async function setup() { await AddonTestUtils.promiseStartupManager(); @@ -219,3 +220,36 @@ ); equal(newRestrictedDomains, restrictedDomains + ",example.com,example.org"); }); + +add_task(async function test_theme() { + let themeFile = AddonTestUtils.createTempWebExtensionFile({ + manifest: { + applications: { + gecko: { + id: themeID, + }, + }, + theme: {}, + }, + }); + + server.registerFile("/data/policy_theme.xpi", themeFile); + + await Promise.all([ + AddonTestUtils.promiseInstallEvent("onInstallEnded"), + setupPolicyEngineWithJson({ + policies: { + ExtensionSettings: { + "policytheme@mozilla.com": { + installation_mode: "normal_installed", + install_url: BASE_URL + "/policy_theme.xpi", + }, + }, + }, + }), + ]); + let currentTheme = Services.prefs.getCharPref("extensions.activeThemeID"); + equal(currentTheme, themeID, "Theme should be active"); + let addon = await AddonManager.getAddonByID(themeID); + await addon.uninstall(); +}); Binary files /tmp/tmpIoooFr/YUNwRo2tGy/thunderbird-78.5.0+build3/browser/components/newtab/data/content/tippytop/favicons/baidu-com.ico and /tmp/tmpIoooFr/K15BCor6vo/thunderbird-78.7.1+build1/browser/components/newtab/data/content/tippytop/favicons/baidu-com.ico differ Binary files /tmp/tmpIoooFr/YUNwRo2tGy/thunderbird-78.5.0+build3/browser/components/newtab/data/content/tippytop/favicons/baidu-com.png and /tmp/tmpIoooFr/K15BCor6vo/thunderbird-78.7.1+build1/browser/components/newtab/data/content/tippytop/favicons/baidu-com.png differ Binary files /tmp/tmpIoooFr/YUNwRo2tGy/thunderbird-78.5.0+build3/browser/components/newtab/data/content/tippytop/images/baidu-com@2x.png and /tmp/tmpIoooFr/K15BCor6vo/thunderbird-78.7.1+build1/browser/components/newtab/data/content/tippytop/images/baidu-com@2x.png differ diff -Nru thunderbird-78.5.0+build3/browser/components/newtab/data/content/tippytop/top_sites.json thunderbird-78.7.1+build1/browser/components/newtab/data/content/tippytop/top_sites.json --- thunderbird-78.5.0+build3/browser/components/newtab/data/content/tippytop/top_sites.json 2020-11-18 16:42:50.000000000 +0000 +++ thunderbird-78.7.1+build1/browser/components/newtab/data/content/tippytop/top_sites.json 2021-02-05 18:21:07.000000000 +0000 @@ -27,7 +27,7 @@ "title": "baidu", "url": "https://www.baidu.com/", "image_url": "images/baidu-com@2x.png", - "favicon_url": "favicons/baidu-com.ico" + "favicon_url": "favicons/baidu-com.png" }, { "title": "bbc", Binary files /tmp/tmpIoooFr/YUNwRo2tGy/thunderbird-78.5.0+build3/browser/components/search/extensions/baidu/favicon.ico and /tmp/tmpIoooFr/K15BCor6vo/thunderbird-78.7.1+build1/browser/components/search/extensions/baidu/favicon.ico differ Binary files /tmp/tmpIoooFr/YUNwRo2tGy/thunderbird-78.5.0+build3/browser/components/search/extensions/bing/favicon.ico and /tmp/tmpIoooFr/K15BCor6vo/thunderbird-78.7.1+build1/browser/components/search/extensions/bing/favicon.ico differ diff -Nru thunderbird-78.5.0+build3/browser/components/search/extensions/bing/manifest.json thunderbird-78.7.1+build1/browser/components/search/extensions/bing/manifest.json --- thunderbird-78.5.0+build3/browser/components/search/extensions/bing/manifest.json 2020-11-18 16:42:50.000000000 +0000 +++ thunderbird-78.7.1+build1/browser/components/search/extensions/bing/manifest.json 2021-02-05 18:21:07.000000000 +0000 @@ -1,8 +1,8 @@ { "name": "Bing", - "description": "Bing. Search by Microsoft.", + "description": "Microsoft Bing", "manifest_version": 2, - "version": "1.1", + "version": "1.1.1", "applications": { "gecko": { "id": "bing@search.mozilla.org" diff -Nru thunderbird-78.5.0+build3/browser/components/search/test/browser/browser_bing.js thunderbird-78.7.1+build1/browser/components/search/test/browser/browser_bing.js --- thunderbird-78.5.0+build3/browser/components/search/test/browser/browser_bing.js 2020-11-18 16:42:50.000000000 +0000 +++ thunderbird-78.7.1+build1/browser/components/search/test/browser/browser_bing.js 2021-02-05 18:21:08.000000000 +0000 @@ -47,7 +47,7 @@ const EXPECTED_ENGINE = { name: "Bing", alias: null, - description: "Bing. Search by Microsoft.", + description: "Microsoft Bing", searchForm: "https://www.bing.com/search?pc=MOZI&q=", hidden: false, wrappedJSObject: { diff -Nru thunderbird-78.5.0+build3/browser/config/version_display.txt thunderbird-78.7.1+build1/browser/config/version_display.txt --- thunderbird-78.5.0+build3/browser/config/version_display.txt 2020-11-18 16:43:12.000000000 +0000 +++ thunderbird-78.7.1+build1/browser/config/version_display.txt 2021-02-05 18:21:31.000000000 +0000 @@ -1 +1 @@ -78.5.0esr +78.7.0esr diff -Nru thunderbird-78.5.0+build3/browser/config/version.txt thunderbird-78.7.1+build1/browser/config/version.txt --- thunderbird-78.5.0+build3/browser/config/version.txt 2020-11-18 16:43:12.000000000 +0000 +++ thunderbird-78.7.1+build1/browser/config/version.txt 2021-02-05 18:21:31.000000000 +0000 @@ -1 +1 @@ -78.5.0 +78.7.0 diff -Nru thunderbird-78.5.0+build3/browser/extensions/pdfjs/content/PdfJsNetwork.jsm thunderbird-78.7.1+build1/browser/extensions/pdfjs/content/PdfJsNetwork.jsm --- thunderbird-78.5.0+build3/browser/extensions/pdfjs/content/PdfJsNetwork.jsm 2020-11-18 16:42:50.000000000 +0000 +++ thunderbird-78.7.1+build1/browser/extensions/pdfjs/content/PdfJsNetwork.jsm 2021-02-05 18:21:07.000000000 +0000 @@ -94,6 +94,7 @@ var rangeStr = args.begin + "-" + (args.end - 1); xhr.setRequestHeader("Range", "bytes=" + rangeStr); pendingRequest.expectedStatus = 206; + xhr.channel.QueryInterface(Ci.nsIHttpChannel).redirectionLimit = 0; } else { pendingRequest.expectedStatus = 200; } diff -Nru thunderbird-78.5.0+build3/browser/installer/allowed-dupes.mn thunderbird-78.7.1+build1/browser/installer/allowed-dupes.mn --- thunderbird-78.5.0+build3/browser/installer/allowed-dupes.mn 2020-11-18 16:42:50.000000000 +0000 +++ thunderbird-78.7.1+build1/browser/installer/allowed-dupes.mn 2021-02-05 18:21:07.000000000 +0000 @@ -63,6 +63,7 @@ browser/defaults/settings/pinning/pins.json browser/defaults/settings/main/example.json browser/defaults/settings/main/search-default-override-allowlist.json +browser/defaults/settings/main/url-classifier-skip-urls.json #ifdef MOZ_EME_WIN32_ARTIFACT gmp-clearkey/0.1/manifest.json diff -Nru thunderbird-78.5.0+build3/browser/installer/windows/nsis/shared.nsh thunderbird-78.7.1+build1/browser/installer/windows/nsis/shared.nsh --- thunderbird-78.5.0+build3/browser/installer/windows/nsis/shared.nsh 2020-11-18 16:42:50.000000000 +0000 +++ thunderbird-78.7.1+build1/browser/installer/windows/nsis/shared.nsh 2021-02-05 18:21:07.000000000 +0000 @@ -1609,7 +1609,22 @@ ${Unless} ${Errors} ; This is all protected by a user choice hash in Windows 8 so it won't ; help, but it also won't hurt. - AppAssocReg::SetAppAsDefaultAll "$R9" + AppAssocReg::SetAppAsDefault "$R9" ".htm" "file" + Pop $0 + AppAssocReg::SetAppAsDefault "$R9" ".html" "file" + Pop $0 + AppAssocReg::SetAppAsDefault "$R9" ".shtml" "file" + Pop $0 + AppAssocReg::SetAppAsDefault "$R9" ".webp" "file" + Pop $0 + AppAssocReg::SetAppAsDefault "$R9" ".xht" "file" + Pop $0 + AppAssocReg::SetAppAsDefault "$R9" ".xhtml" "file" + Pop $0 + AppAssocReg::SetAppAsDefault "$R9" "http" "protocol" + Pop $0 + AppAssocReg::SetAppAsDefault "$R9" "https" "protocol" + Pop $0 ${EndUnless} ${RemoveDeprecatedKeys} ${MigrateTaskBarShortcut} diff -Nru thunderbird-78.5.0+build3/browser/installer/windows/nsis/uninstaller.nsi thunderbird-78.7.1+build1/browser/installer/windows/nsis/uninstaller.nsi --- thunderbird-78.5.0+build3/browser/installer/windows/nsis/uninstaller.nsi 2020-11-18 16:42:50.000000000 +0000 +++ thunderbird-78.7.1+build1/browser/installer/windows/nsis/uninstaller.nsi 2021-02-05 18:21:08.000000000 +0000 @@ -241,7 +241,7 @@ ; Restore back the registry view ${If} ${RunningX64} ${OrIf} ${IsNativeARM64} - SetRegView lastUsed + SetRegView lastused ${EndIf} ${If} $0 == 0 diff -Nru thunderbird-78.5.0+build3/build/moz.configure/warnings.configure thunderbird-78.7.1+build1/build/moz.configure/warnings.configure --- thunderbird-78.5.0+build3/build/moz.configure/warnings.configure 2020-11-18 16:42:50.000000000 +0000 +++ thunderbird-78.7.1+build1/build/moz.configure/warnings.configure 2021-02-05 18:21:07.000000000 +0000 @@ -223,6 +223,11 @@ when=depends(build_project) (lambda build_project: build_project == 'js')) +# Disable broken missing-braces warning on old clang versions +check_and_add_gcc_warning( + '-Wno-missing-braces', + when=depends(c_compiler)(lambda c: c.type == 'clang' and c.version < '6.0')) + # Please keep these last in this file add_old_configure_assignment('_WARNINGS_CFLAGS', warnings_flags.cflags) diff -Nru thunderbird-78.5.0+build3/BUILDID thunderbird-78.7.1+build1/BUILDID --- thunderbird-78.5.0+build3/BUILDID 2020-11-18 17:06:30.000000000 +0000 +++ thunderbird-78.7.1+build1/BUILDID 2021-02-05 18:42:46.000000000 +0000 @@ -1 +1 @@ -20201116161136 \ No newline at end of file +20210203182138 \ No newline at end of file diff -Nru thunderbird-78.5.0+build3/Cargo.lock thunderbird-78.7.1+build1/Cargo.lock --- thunderbird-78.5.0+build3/Cargo.lock 2020-11-18 16:42:50.000000000 +0000 +++ thunderbird-78.7.1+build1/Cargo.lock 2021-02-05 18:21:07.000000000 +0000 @@ -898,9 +898,9 @@ [[package]] name = "cssparser" -version = "0.27.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" +checksum = "809d22aba9ffd53e9028f2d37261f1826ef613d0e96b1a5ddeefa97cde82bcca" dependencies = [ "cssparser-macros", "dtoa-short", diff -Nru thunderbird-78.5.0+build3/comm/calendar/base/backend/icaljs/calICSService.js thunderbird-78.7.1+build1/comm/calendar/base/backend/icaljs/calICSService.js --- thunderbird-78.5.0+build3/comm/calendar/base/backend/icaljs/calICSService.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/base/backend/icaljs/calICSService.js 2021-02-05 18:23:40.000000000 +0000 @@ -53,6 +53,16 @@ }, get valueAsIcalString() { + let propertyStr = this.innerObject.toICALString(); + if (propertyStr.match(/:/g).length == 1) { + // For property containing only one colon, e.g. `GEO:latitude;longitude`, + // the left hand side must be the property name, the right hand side must + // be property value. + return propertyStr.slice(propertyStr.indexOf(":") + 1); + } + // For property containing many or no colons, retrieve the property value + // according to its type. An example is + // `ATTENDEE;MEMBER="mailto:foo@example.com": mailto:bar@example.com` let type = this.innerObject.type; return this.innerObject .getValues() diff -Nru thunderbird-78.5.0+build3/comm/calendar/base/content/calendar-chrome-startup.js thunderbird-78.7.1+build1/comm/calendar/base/content/calendar-chrome-startup.js --- thunderbird-78.5.0+build3/comm/calendar/base/content/calendar-chrome-startup.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/base/content/calendar-chrome-startup.js 2021-02-05 18:23:40.000000000 +0000 @@ -33,6 +33,12 @@ * startup as the application window is loaded, before tabs are restored. */ async function loadCalendarComponent() { + if (loadCalendarComponent.hasBeenCalled) { + cal.ERROR("loadCalendarComponent was called more than once for a single window"); + return; + } + loadCalendarComponent.hasBeenCalled = true; + await uninstallLightningAddon(); document diff -Nru thunderbird-78.5.0+build3/comm/calendar/base/content/dialogs/calendar-event-dialog.xhtml thunderbird-78.7.1+build1/comm/calendar/base/content/dialogs/calendar-event-dialog.xhtml --- thunderbird-78.5.0+build3/comm/calendar/base/content/dialogs/calendar-event-dialog.xhtml 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/base/content/dialogs/calendar-event-dialog.xhtml 2021-02-05 18:23:40.000000000 +0000 @@ -211,10 +211,6 @@ modifiers="accel" key="&event.dialog.saveandclose.key;" command="cmd_accept"/> - .toolbarbutton-icon, diff -Nru thunderbird-78.5.0+build3/comm/calendar/base/themes/common/widgets/calendar-widgets.css thunderbird-78.7.1+build1/comm/calendar/base/themes/common/widgets/calendar-widgets.css --- thunderbird-78.5.0+build3/comm/calendar/base/themes/common/widgets/calendar-widgets.css 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/base/themes/common/widgets/calendar-widgets.css 2021-02-05 18:23:40.000000000 +0000 @@ -70,14 +70,16 @@ -moz-user-focus: normal; } -:root[lwt-tree] .view-navigation-button { +:root[lwt-tree] .view-navigation-button, +:root[lwt-tree-brighttext] .view-navigation-button { -moz-appearance: none; -moz-user-focus: normal; border: 1px solid transparent; border-radius: var(--toolbarbutton-border-radius); } -:root[lwt-tree] .view-navigation-button:not([disabled="true"]):hover { +:root[lwt-tree] .view-navigation-button:not([disabled="true"]):hover, +:root[lwt-tree-brighttext] .view-navigation-button:not([disabled="true"]):hover { background: var(--toolbarbutton-hover-background); border-color: var(--toolbarbutton-hover-bordercolor); box-shadow: var(--toolbarbutton-hover-boxshadow); diff -Nru thunderbird-78.5.0+build3/comm/calendar/base/themes/common/widgets/minimonth.css thunderbird-78.7.1+build1/comm/calendar/base/themes/common/widgets/minimonth.css --- thunderbird-78.5.0+build3/comm/calendar/base/themes/common/widgets/minimonth.css 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/base/themes/common/widgets/minimonth.css 2021-02-05 18:23:40.000000000 +0000 @@ -26,20 +26,21 @@ --mmDaySelectedTodayBorderColor: #67acd8; } -:root[lwt-tree] calendar-minimonth { - --mmMainColor: var(--sidebar-text-color); - --mmMainBackground: var(--sidebar-background-color); +:root[lwt-tree] calendar-minimonth, +:root[lwt-tree-brighttext] calendar-minimonth { + --mmMainColor: var(--sidebar-text-color, FieldText); + --mmMainBackground: var(--sidebar-background-color, Field); --mmHighlightColor: var(--sidebar-highlight-text-color, HighlightText); --mmHighlightBackground: var(--sidebar-highlight-background-color, Highlight); --mmHighlightBorderColor: var(--sidebar-highlight-background-color, Highlight); - --mmBoxBackground: var(--sidebar-background-color); - --mmBoxBorderColor: var(--sidebar-background-color); + --mmBoxBackground: var(--sidebar-background-color, Field); + --mmBoxBorderColor: var(--sidebar-background-color, Field); --mmDayTodayColor: var(--sidebar-highlight-text-color, HighlightText); --mmDayTodayBackground: var(--sidebar-highlight-background-color, Highlight); --mmDayTodayBorderColor: var(--sidebar-highlight-text-color, HighlightText); - --mmDayColor: var(--sidebar-text-color); - --mmDayBorderColor: var(--sidebar-background-color); - --mmDayOtherColor: var(--sidebar-text-color); + --mmDayColor: var(--sidebar-text-color, FieldText); + --mmDayBorderColor: var(--sidebar-background-color, Field); + --mmDayOtherColor: var(--sidebar-text-color, FieldText); --mmDayOtherBackground: rgba(0, 0, 0, 0.1); --mmDayOtherBorderColor: Transparent; } diff -Nru thunderbird-78.5.0+build3/comm/calendar/base/themes/linux/lightning.css thunderbird-78.7.1+build1/comm/calendar/base/themes/linux/lightning.css --- thunderbird-78.5.0+build3/comm/calendar/base/themes/linux/lightning.css 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/base/themes/linux/lightning.css 2021-02-05 18:23:40.000000000 +0000 @@ -43,7 +43,6 @@ /* Lightning sidebar in calendar and task mode */ #ltnSidebar { background-color: -moz-field; - border-bottom: 1px solid ThreeDShadow; } /* Today pane button in status bar */ diff -Nru thunderbird-78.5.0+build3/comm/calendar/base/themes/osx/calendar-task-view.css thunderbird-78.7.1+build1/comm/calendar/base/themes/osx/calendar-task-view.css --- thunderbird-78.5.0+build3/comm/calendar/base/themes/osx/calendar-task-view.css 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/base/themes/osx/calendar-task-view.css 2021-02-05 18:23:40.000000000 +0000 @@ -6,9 +6,7 @@ #calendar-task-details-container { background-color: ButtonFace; - border-bottom-width: 0; padding-top: 2px; - overflow: hidden; } #other-actions-box { diff -Nru thunderbird-78.5.0+build3/comm/calendar/base/themes/windows/calendar-task-view.css thunderbird-78.7.1+build1/comm/calendar/base/themes/windows/calendar-task-view.css --- thunderbird-78.5.0+build3/comm/calendar/base/themes/windows/calendar-task-view.css 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/base/themes/windows/calendar-task-view.css 2021-02-05 18:23:40.000000000 +0000 @@ -15,11 +15,7 @@ } #calendar-task-details-container { - border-top: 1px solid ThreeDShadow; - border-left: 1px solid ThreeDShadow; - border-right: 0; - border-bottom: 0; - overflow: hidden; + padding-top: 0; } #other-actions-box { @@ -61,11 +57,6 @@ border-top-width: 0; } -#calendar-task-details-container { - border-top-width: 0; - padding-top: 0; -} - @media (-moz-windows-default-theme) { #task-addition-box { background-color: #f8f8f8; diff -Nru thunderbird-78.5.0+build3/comm/calendar/lightning/content/imip-bar.js thunderbird-78.7.1+build1/comm/calendar/lightning/content/imip-bar.js --- thunderbird-78.5.0+build3/comm/calendar/lightning/content/imip-bar.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/lightning/content/imip-bar.js 2021-02-05 18:23:40.000000000 +0000 @@ -65,11 +65,13 @@ // We need to extend the HideMessageHeaderPane function to also hide the // message header pane. Otherwise, the imip bar will still be shown when // changing folders. - ltnImipBar.tbHideMessageHeaderPane = HideMessageHeaderPane; - HideMessageHeaderPane = function(...args) { - ltnImipBar.resetBar(); - ltnImipBar.tbHideMessageHeaderPane(...args); - }; + if (!ltnImipBar.tbHideMessageHeaderPane) { + ltnImipBar.tbHideMessageHeaderPane = HideMessageHeaderPane; + HideMessageHeaderPane = function(...args) { + ltnImipBar.resetBar(); + ltnImipBar.tbHideMessageHeaderPane(...args); + }; + } // Set up our observers Services.obs.addObserver(ltnImipBar, "onItipItemCreation"); diff -Nru thunderbird-78.5.0+build3/comm/calendar/providers/caldav/CalDavCalendar.jsm thunderbird-78.7.1+build1/comm/calendar/providers/caldav/CalDavCalendar.jsm --- thunderbird-78.5.0+build3/comm/calendar/providers/caldav/CalDavCalendar.jsm 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/providers/caldav/CalDavCalendar.jsm 2021-02-05 18:23:40.000000000 +0000 @@ -620,8 +620,7 @@ // for instance) so we'd best re-fetch in order to know // the current state of the item // Observers will be notified in getUpdatedItem() - this.getUpdatedItem(parentItem, aListener); - return; + this.safeRefresh(); } else if (response.serverError) { status = Cr.NS_ERROR_NOT_AVAILABLE; detail = "Server Replied with " + response.status; diff -Nru thunderbird-78.5.0+build3/comm/calendar/providers/caldav/modules/CalDavRequest.jsm thunderbird-78.7.1+build1/comm/calendar/providers/caldav/modules/CalDavRequest.jsm --- thunderbird-78.5.0+build3/comm/calendar/providers/caldav/modules/CalDavRequest.jsm 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/providers/caldav/modules/CalDavRequest.jsm 2021-02-05 18:23:40.000000000 +0000 @@ -253,7 +253,7 @@ }); this.completed = new Promise((resolve, reject) => { this._oncompleted = resolve; - this._oncompleteerror = reject; + this._oncompletederror = reject; }); } diff -Nru thunderbird-78.5.0+build3/comm/calendar/providers/storage/CalStorageCalendar.jsm thunderbird-78.7.1+build1/comm/calendar/providers/storage/CalStorageCalendar.jsm --- thunderbird-78.5.0+build3/comm/calendar/providers/storage/CalStorageCalendar.jsm 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/providers/storage/CalStorageCalendar.jsm 2021-02-05 18:23:40.000000000 +0000 @@ -1769,7 +1769,7 @@ } let rec = item.recurrenceInfo; - let exc = await this.getEventFromRow(row, false); + let exc = await this.getEventFromRow(row); rec.modifyException(exc, true); }); @@ -1781,7 +1781,7 @@ } let rec = item.recurrenceInfo; - let exc = await this.getTodoFromRow(row, false); + let exc = await this.getTodoFromRow(row); rec.modifyException(exc, true); }); diff -Nru thunderbird-78.5.0+build3/comm/calendar/test/browser/eventDialog/browser_eventDialog.js thunderbird-78.7.1+build1/comm/calendar/test/browser/eventDialog/browser_eventDialog.js --- thunderbird-78.5.0+build3/comm/calendar/test/browser/eventDialog/browser_eventDialog.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/test/browser/eventDialog/browser_eventDialog.js 2021-02-05 18:23:40.000000000 +0000 @@ -209,6 +209,41 @@ Assert.ok(true, "Test ran to completion"); }); +/** + * Test that using CTRL+Enter does not result in two events being created. + * This only happens in the dialog window. See bug 1668478. + */ +add_task(async function testCtrlEnterShortcut() { + createCalendar(controller, CALENDARNAME); + switchToView(controller, "day"); + goToDate(controller, 2020, 9, 1); + + let createBox = lookupEventBox("day", CANVAS_BOX, null, 1, 8); + await invokeEventDialog(controller, createBox, async (event, iframe) => { + await setData(event, iframe, { + title: EVENTTITLE, + location: EVENTLOCATION, + description: EVENTDESCRIPTION, + }); + EventUtils.synthesizeKey("VK_RETURN", { ctrlKey: true }, event.window); + }); + + switchToView(controller, "month"); + + // Give the event boxes enough time to appear before checking for duplicates. + controller.sleep(2000); + + let events = document.querySelectorAll("calendar-month-day-box-item"); + Assert.equal(events.length, 1, "event was created once"); + + if (Services.focus.activeWindow != controller.window) { + await BrowserTestUtils.waitForEvent(controller.window, "focus"); + } + + events[0].focus(); + EventUtils.synthesizeKey("VK_DELETE", {}, controller.window); +}); + function checkTooltip(row, col, startTime, endTime) { let item = lookupEventBox("month", CANVAS_BOX, row, col, null, EVENTPATH); diff -Nru thunderbird-78.5.0+build3/comm/calendar/test/unit/data/previous.json thunderbird-78.7.1+build1/comm/calendar/test/unit/data/previous.json --- thunderbird-78.5.0+build3/comm/calendar/test/unit/data/previous.json 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/test/unit/data/previous.json 2021-02-05 18:23:40.000000000 +0000 @@ -1,5 +1,5 @@ { - "version": "2.2019c", + "version": "2.2020a", "aliases": [ "AUS Central Standard Time", "AUS Eastern Standard Time", @@ -9,6 +9,7 @@ "Alaskan Standard Time", "America/Argentina/ComodRivadavia", "America/Buenos_Aires", + "America/Godthab", "America/Louisville", "America/Montreal", "America/Santa_Isabel", @@ -242,7 +243,6 @@ "America/Fort_Nelson", "America/Fortaleza", "America/Glace_Bay", - "America/Godthab", "America/Goose_Bay", "America/Grand_Turk", "America/Grenada", @@ -296,6 +296,7 @@ "America/North_Dakota/Beulah", "America/North_Dakota/Center", "America/North_Dakota/New_Salem", + "America/Nuuk", "America/Ojinaga", "America/Panama", "America/Pangnirtung", diff -Nru thunderbird-78.5.0+build3/comm/calendar/test/unit/test_ics_service.js thunderbird-78.7.1+build1/comm/calendar/test/unit/test_ics_service.js --- thunderbird-78.5.0+build3/comm/calendar/test/unit/test_ics_service.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/test/unit/test_ics_service.js 2021-02-05 18:23:40.000000000 +0000 @@ -174,6 +174,11 @@ equal(prop.value, "A\\nB"); equal(prop.valueAsIcalString, "A\\\\nB"); equal(prop.valueAsDatetime, null); + + prop = svc.createIcalProperty("GEO"); + prop.value = "43.4913662534171;12.085559129715"; + equal(prop.value, "43.4913662534171;12.085559129715"); + equal(prop.valueAsIcalString, "43.4913662534171;12.085559129715"); } function test_icalcomponent() { diff -Nru thunderbird-78.5.0+build3/comm/calendar/test/unit/test_storage_get_items.js thunderbird-78.7.1+build1/comm/calendar/test/unit/test_storage_get_items.js --- thunderbird-78.5.0+build3/comm/calendar/test/unit/test_storage_get_items.js 1970-01-01 00:00:00.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/test/unit/test_storage_get_items.js 2021-02-05 18:23:40.000000000 +0000 @@ -0,0 +1,215 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Tests for the CalStorageCalendar.getItems method. + */ + +do_get_profile(); + +/** + * The bug we are interested in testing requires the calendar to clear its + * caches in order to take effect. Since we can't directly access the internals + * of the calendar here, we instead provide a custom function that lets us + * create more than one calendar with the same id. + */ +function createStorageCalendar(id) { + let db = Services.dirsvc.get("TmpD", Ci.nsIFile); + db.append("test_storage.sqlite"); + let uri = Services.io.newFileURI(db); + + // Make sure timezone service is initialized + Cc["@mozilla.org/calendar/timezone-service;1"].getService(Ci.calIStartupService).startup(null); + + let calendar = Cc["@mozilla.org/calendar/calendar;1?type=storage"].createInstance( + Ci.calISyncWriteCalendar + ); + + calendar.uri = uri; + calendar.id = id; + return cal.async.promisifyCalendar(calendar); +} + +/** + * Tests that recurring event/todo exceptions have their properties properly + * loaded. See bug 1664731. + * + * @param {number} filterType - Number indicating the filter type. + * @param {calIITemBase} originalItem - The original item to add to the calendar. + * @param {object} originalProps - The initial properites of originalItem we + * change. + * @param {object} changedProps - The changed properties of originalItem.. + */ +async function doPropertiesTest(filterType, originalItem, originalProps, changedProps) { + for (let [key, value] of Object.entries(originalProps)) { + if (key == "CATEGORIES") { + originalItem.setCategories(value); + } else { + originalItem.setProperty(key, value); + } + } + + let calId = cal.getUUID(); + let calendar = createStorageCalendar(calId); + await calendar.addItem(originalItem); + + let filter = + filterType | + Ci.calICalendar.ITEM_FILTER_COMPLETED_ALL | + Ci.calICalendar.ITEM_FILTER_CLASS_OCCURRENCES; + + let savedItems = await calendar.getItems( + filter, + 0, + cal.createDateTime("20201201T000000Z"), + cal.createDateTime("20201231T000000Z") + ); + + Assert.equal(savedItems.length, 5, `saved ${savedItems.length} items successfully`); + + // Ensure all occurrences have the correct properties initially. + for (let item of savedItems) { + for (let [key, value] of Object.entries(originalProps)) { + if (key == "CATEGORIES") { + Assert.equal( + item.getCategories().join(), + value.join(), + `item categories are set to ${value}` + ); + } else { + Assert.equal(item.getProperty(key), value, `item property "${key}" is set to "${value}"`); + } + } + } + + // Grab the occurrence whose properties we want to modify. + let targetOccurrence = savedItems[2]; + let targetException = targetOccurrence.clone(); + + let targetDate = + filterType & Ci.calICalendar.ITEM_FILTER_TYPE_TODO + ? targetOccurrence.entryDate + : targetOccurrence.startDate; + + targetDate = targetDate.clone(); + + // Make the changes to the properties. + for (let [key, value] of Object.entries(changedProps)) { + if (key == "CATEGORIES") { + targetException.setCategories(value); + } else { + targetException.setProperty(key, value); + } + } + + await calendar.modifyItem( + cal.itip.prepareSequence(targetException, targetOccurrence), + targetOccurrence + ); + + // Get a fresh copy of the items by using a new calendar with the same id. + let itemsAfterUpdate = await createStorageCalendar(calId).getItems( + filter, + 0, + cal.createDateTime("20201201T000000Z"), + cal.createDateTime("20201231T000000Z") + ); + + Assert.equal(itemsAfterUpdate.length, 5, "expected occurrence count retrieved from query"); + + // Compare each property we changed to ensure the target occurrence has + // the properties we expect. + for (let item of itemsAfterUpdate) { + let isException = targetDate.compare(item.recurrenceId) == 0; + let label = isException ? "occurrence exception" : "unmodified occurrence"; + let checkedProps = isException ? changedProps : originalProps; + + for (let [key, value] of Object.entries(checkedProps)) { + if (key == "CATEGORIES") { + Assert.equal( + item.getCategories().join(), + value.join(), + `item categories are set to ${value}` + ); + } else { + Assert.equal( + item.getProperty(key), + value, + `property "${key}" is set to "${value}" for ${label}` + ); + } + } + } +} + +/** + * Test event exceptions load their properties. + */ +add_task(async function testEventPropertiesForRecurringExceptionsLoad() { + let event = cal.createEvent(dedent` + BEGIN:VEVENT + CREATED:20201211T000000Z + LAST-MODIFIED:20201211T000000Z + DTSTAMP:20201210T080410Z + UID:c1a6cfe7-7fbb-4bfb-a00d-861e07c649a5 + SUMMARY:Original Test Event + DTSTART:20201211T000000Z + DTEND:20201211T110000Z + RRULE:FREQ=DAILY;UNTIL=20201215T140000Z + END:VEVENT + `); + + let originalProps = { + DESCRIPTION: "This is a test event.", + CATEGORIES: ["Birthday"], + LOCATION: "Castara", + }; + + let changedProps = { + DESCRIPTION: "This is an edited occurrence.", + CATEGORIES: ["Holiday"], + LOCATION: "Georgetown", + }; + + return doPropertiesTest( + Ci.calICalendar.ITEM_FILTER_TYPE_EVENT, + event, + originalProps, + changedProps + ); +}); + +/** + * Test todo exceptions load their properties. + */ +add_task(async function testTodoPropertiesForRecurringExceptionsLoad() { + let todo = cal.createTodo(dedent` + BEGIN:VTODO + CREATED:20201211T000000Z + LAST-MODIFIED:20201211T000000Z + DTSTAMP:20201210T080410Z + UID:c1a6cfe7-7fbb-4bfb-a00d-861e07c649a5 + SUMMARY:Original Test Event + DTSTART:20201211T000000Z + DTEND:20201211T110000Z + RRULE:FREQ=DAILY;UNTIL=20201215T140000Z + END:VTODO + `); + + let originalProps = { + DESCRIPTION: "This is a test todo.", + CATEGORIES: ["Birthday"], + LOCATION: "Castara", + STATUS: "NEEDS-ACTION", + }; + + let changedProps = { + DESCRIPTION: "This is an edited occurrence.", + CATEGORIES: ["Holiday"], + LOCATION: "Georgetown", + STATUS: "COMPLETE", + }; + + return doPropertiesTest(Ci.calICalendar.ITEM_FILTER_TYPE_TODO, todo, originalProps, changedProps); +}); diff -Nru thunderbird-78.5.0+build3/comm/calendar/test/unit/xpcshell-shared.ini thunderbird-78.7.1+build1/comm/calendar/test/unit/xpcshell-shared.ini --- thunderbird-78.5.0+build3/comm/calendar/test/unit/xpcshell-shared.ini 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/test/unit/xpcshell-shared.ini 2021-02-05 18:23:40.000000000 +0000 @@ -47,6 +47,7 @@ [test_search_service.js] [test_startup_service.js] [test_storage.js] +[test_storage_get_items.js] [test_timezone.js] [test_timezone_changes.js] [test_timezone_definition.js] diff -Nru thunderbird-78.5.0+build3/comm/calendar/timezones/zones.json thunderbird-78.7.1+build1/comm/calendar/timezones/zones.json --- thunderbird-78.5.0+build3/comm/calendar/timezones/zones.json 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/calendar/timezones/zones.json 2021-02-05 18:23:40.000000000 +0000 @@ -1,5 +1,5 @@ { - "version": "2.2020a", + "version": "2.2020d", "aliases": { "AUS Central Standard Time": { "aliasTo": "Australia/Darwin" @@ -504,7 +504,7 @@ "BEGIN:STANDARD\r\nTZOFFSETFROM:+0000\r\nTZOFFSETTO:+0000\r\nTZNAME:+00\r\nDTSTART:19700101T000000\r\nEND:STANDARD", "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0000\r\nTZOFFSETTO:+0100\r\nTZNAME:+01\r\nDTSTART:20180325T020000\r\nRDATE:20180325T020000\r\nRDATE:20180617T020000\r\nEND:DAYLIGHT", "BEGIN:STANDARD\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0000\r\nTZNAME:+00\r\nDTSTART:20180513T030000\r\nRDATE:20180513T030000\r\nEND:STANDARD", - "BEGIN:STANDARD\r\nTZOFFSETFROM:+0000\r\nTZOFFSETTO:+0100\r\nTZNAME:+01\r\nDTSTART:20190609T020000\r\nRDATE:20190609T020000\r\nRDATE:20200531T020000\r\nRDATE:20210516T020000\r\nRDATE:20220508T020000\r\nRDATE:20230423T020000\r\nRDATE:20240414T020000\r\nEND:STANDARD", + "BEGIN:STANDARD\r\nTZOFFSETFROM:+0000\r\nTZOFFSETTO:+0100\r\nTZNAME:+01\r\nDTSTART:20190609T020000\r\nRDATE:20190609T020000\r\nRDATE:20200531T020000\r\nRDATE:20210516T020000\r\nRDATE:20220508T020000\r\nRDATE:20230430T020000\r\nRDATE:20240414T020000\r\nEND:STANDARD", "BEGIN:STANDARD\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0100\r\nTZNAME:+01\r\nDTSTART:20181028T030000\r\nRDATE:20181028T030000\r\nEND:STANDARD", "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0000\r\nTZNAME:+00\r\nDTSTART:20190505T030000\r\nRDATE:20190505T030000\r\nRDATE:20200419T030000\r\nRDATE:20210411T030000\r\nRDATE:20220327T030000\r\nRDATE:20230319T030000\r\nRDATE:20240310T030000\r\nEND:DAYLIGHT" ], @@ -561,7 +561,7 @@ "BEGIN:STANDARD\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0000\r\nTZNAME:+00\r\nDTSTART:20180513T030000\r\nRDATE:20180513T030000\r\nEND:STANDARD", "BEGIN:STANDARD\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0100\r\nTZNAME:+01\r\nDTSTART:20181028T030000\r\nRDATE:20181028T030000\r\nEND:STANDARD", "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0000\r\nTZNAME:+00\r\nDTSTART:20190505T030000\r\nRDATE:20190505T030000\r\nRDATE:20200419T030000\r\nRDATE:20210411T030000\r\nRDATE:20220327T030000\r\nRDATE:20230319T030000\r\nRDATE:20240310T030000\r\nEND:DAYLIGHT", - "BEGIN:STANDARD\r\nTZOFFSETFROM:+0000\r\nTZOFFSETTO:+0100\r\nTZNAME:+01\r\nDTSTART:20190609T020000\r\nRDATE:20190609T020000\r\nRDATE:20200531T020000\r\nRDATE:20210516T020000\r\nRDATE:20220508T020000\r\nRDATE:20230423T020000\r\nRDATE:20240414T020000\r\nEND:STANDARD" + "BEGIN:STANDARD\r\nTZOFFSETFROM:+0000\r\nTZOFFSETTO:+0100\r\nTZNAME:+01\r\nDTSTART:20190609T020000\r\nRDATE:20190609T020000\r\nRDATE:20200531T020000\r\nRDATE:20210516T020000\r\nRDATE:20220508T020000\r\nRDATE:20230430T020000\r\nRDATE:20240414T020000\r\nEND:STANDARD" ], "latitude": "+0270900", "longitude": "-0131200" @@ -1093,9 +1093,9 @@ "America/Dawson": { "ics": [ "BEGIN:STANDARD\r\nTZOFFSETFROM:-0800\r\nTZOFFSETTO:-0800\r\nTZNAME:PST\r\nDTSTART:19700101T000000\r\nEND:STANDARD", - "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:-0800\r\nTZOFFSETTO:-0700\r\nTZNAME:PDT\r\nDTSTART:20180311T020000\r\nRDATE:20180311T020000\r\nRDATE:20190310T020000\r\nEND:DAYLIGHT", + "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:-0800\r\nTZOFFSETTO:-0700\r\nTZNAME:PDT\r\nDTSTART:20180311T020000\r\nRDATE:20180311T020000\r\nRDATE:20190310T020000\r\nRDATE:20200308T020000\r\nEND:DAYLIGHT", "BEGIN:STANDARD\r\nTZOFFSETFROM:-0700\r\nTZOFFSETTO:-0800\r\nTZNAME:PST\r\nDTSTART:20181104T020000\r\nRDATE:20181104T020000\r\nRDATE:20191103T020000\r\nEND:STANDARD", - "BEGIN:STANDARD\r\nTZOFFSETFROM:-0800\r\nTZOFFSETTO:-0700\r\nTZNAME:MST\r\nDTSTART:20200308T020000\r\nRDATE:20200308T020000\r\nEND:STANDARD" + "BEGIN:STANDARD\r\nTZOFFSETFROM:-0700\r\nTZOFFSETTO:-0700\r\nTZNAME:MST\r\nDTSTART:20201101T000000\r\nRDATE:20201101T000000\r\nEND:STANDARD" ], "latitude": "+0640400", "longitude": "-1392500" @@ -1866,9 +1866,9 @@ "America/Whitehorse": { "ics": [ "BEGIN:STANDARD\r\nTZOFFSETFROM:-0800\r\nTZOFFSETTO:-0800\r\nTZNAME:PST\r\nDTSTART:19700101T000000\r\nEND:STANDARD", - "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:-0800\r\nTZOFFSETTO:-0700\r\nTZNAME:PDT\r\nDTSTART:20180311T020000\r\nRDATE:20180311T020000\r\nRDATE:20190310T020000\r\nEND:DAYLIGHT", + "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:-0800\r\nTZOFFSETTO:-0700\r\nTZNAME:PDT\r\nDTSTART:20180311T020000\r\nRDATE:20180311T020000\r\nRDATE:20190310T020000\r\nRDATE:20200308T020000\r\nEND:DAYLIGHT", "BEGIN:STANDARD\r\nTZOFFSETFROM:-0700\r\nTZOFFSETTO:-0800\r\nTZNAME:PST\r\nDTSTART:20181104T020000\r\nRDATE:20181104T020000\r\nRDATE:20191103T020000\r\nEND:STANDARD", - "BEGIN:STANDARD\r\nTZOFFSETFROM:-0800\r\nTZOFFSETTO:-0700\r\nTZNAME:MST\r\nDTSTART:20200308T020000\r\nRDATE:20200308T020000\r\nEND:STANDARD" + "BEGIN:STANDARD\r\nTZOFFSETFROM:-0700\r\nTZOFFSETTO:-0700\r\nTZNAME:MST\r\nDTSTART:20201101T000000\r\nRDATE:20201101T000000\r\nEND:STANDARD" ], "latitude": "+0604300", "longitude": "-1350300" @@ -1899,8 +1899,9 @@ }, "Antarctica/Casey": { "ics": [ - "BEGIN:STANDARD\r\nTZOFFSETFROM:+0800\r\nTZOFFSETTO:+1100\r\nTZNAME:+11\r\nDTSTART:19700101T000000\r\nEND:STANDARD", - "BEGIN:STANDARD\r\nTZOFFSETFROM:+1100\r\nTZOFFSETTO:+0800\r\nTZNAME:+08\r\nDTSTART:20180311T040000\r\nRDATE:20180311T040000\r\nEND:STANDARD" + "BEGIN:STANDARD\r\nTZOFFSETFROM:+0000\r\nTZOFFSETTO:+0800\r\nTZNAME:+08\r\nDTSTART:19700101T000000\r\nEND:STANDARD", + "BEGIN:STANDARD\r\nTZOFFSETFROM:+0800\r\nTZOFFSETTO:+1100\r\nTZNAME:+11\r\nDTSTART:20181007T040000\r\nRDATE:20181007T040000\r\nRDATE:20191004T030000\r\nRDATE:20201004T000100\r\nEND:STANDARD", + "BEGIN:STANDARD\r\nTZOFFSETFROM:+1100\r\nTZOFFSETTO:+0800\r\nTZNAME:+08\r\nDTSTART:20180311T040000\r\nRDATE:20180311T040000\r\nRDATE:20190317T030000\r\nRDATE:20200308T030000\r\nEND:STANDARD" ], "latitude": "-0661700", "longitude": "+1103100" @@ -1921,7 +1922,8 @@ }, "Antarctica/Macquarie": { "ics": [ - "BEGIN:STANDARD\r\nTZOFFSETFROM:+1100\r\nTZOFFSETTO:+1100\r\nTZNAME:+11\r\nDTSTART:19700101T000000\r\nEND:STANDARD" + "BEGIN:STANDARD\r\nTZOFFSETFROM:+1100\r\nTZOFFSETTO:+1000\r\nTZNAME:AEST\r\nDTSTART:19700405T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU\r\nEND:STANDARD", + "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:+1000\r\nTZOFFSETTO:+1100\r\nTZNAME:AEDT\r\nDTSTART:19701004T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU\r\nEND:DAYLIGHT" ], "latitude": "-0543000", "longitude": "+1585700" @@ -2166,18 +2168,22 @@ }, "Asia/Gaza": { "ics": [ - "BEGIN:STANDARD\r\nTZOFFSETFROM:+0300\r\nTZOFFSETTO:+0200\r\nTZNAME:EET\r\nDTSTART:19701031T010000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SA\r\nEND:STANDARD", - "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0300\r\nTZNAME:EEST\r\nDTSTART:20190329T000000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1FR\r\nEND:DAYLIGHT", - "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0300\r\nTZNAME:EEST\r\nDTSTART:20180324T010000\r\nRDATE:20180324T010000\r\nEND:DAYLIGHT" + "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0300\r\nTZNAME:EEST\r\nDTSTART:20200328T000000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYMONTHDAY=24,25,26,27,28,29,30;BYDAY=SA\r\nEND:DAYLIGHT", + "BEGIN:STANDARD\r\nTZOFFSETFROM:+0300\r\nTZOFFSETTO:+0200\r\nTZNAME:EET\r\nDTSTART:20201024T010000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYMONTHDAY=24,25,26,27,28,29,30;BYDAY=SA\r\nEND:STANDARD", + "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0300\r\nTZNAME:EEST\r\nDTSTART:20180324T010000\r\nRDATE:20180324T010000\r\nRDATE:20190329T000000\r\nEND:DAYLIGHT", + "BEGIN:STANDARD\r\nTZOFFSETFROM:+0300\r\nTZOFFSETTO:+0200\r\nTZNAME:EET\r\nDTSTART:20181027T010000\r\nRDATE:20181027T010000\r\nRDATE:20191026T000000\r\nEND:STANDARD", + "BEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0200\r\nTZNAME:EET\r\nDTSTART:19700101T000000\r\nEND:STANDARD" ], "latitude": "+0313000", "longitude": "+0342800" }, "Asia/Hebron": { "ics": [ - "BEGIN:STANDARD\r\nTZOFFSETFROM:+0300\r\nTZOFFSETTO:+0200\r\nTZNAME:EET\r\nDTSTART:19701031T010000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SA\r\nEND:STANDARD", - "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0300\r\nTZNAME:EEST\r\nDTSTART:20190329T000000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1FR\r\nEND:DAYLIGHT", - "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0300\r\nTZNAME:EEST\r\nDTSTART:20180324T010000\r\nRDATE:20180324T010000\r\nEND:DAYLIGHT" + "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0300\r\nTZNAME:EEST\r\nDTSTART:20200328T000000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYMONTHDAY=24,25,26,27,28,29,30;BYDAY=SA\r\nEND:DAYLIGHT", + "BEGIN:STANDARD\r\nTZOFFSETFROM:+0300\r\nTZOFFSETTO:+0200\r\nTZNAME:EET\r\nDTSTART:20201024T010000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYMONTHDAY=24,25,26,27,28,29,30;BYDAY=SA\r\nEND:STANDARD", + "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0300\r\nTZNAME:EEST\r\nDTSTART:20180324T010000\r\nRDATE:20180324T010000\r\nRDATE:20190329T000000\r\nEND:DAYLIGHT", + "BEGIN:STANDARD\r\nTZOFFSETFROM:+0300\r\nTZOFFSETTO:+0200\r\nTZNAME:EET\r\nDTSTART:20181027T010000\r\nRDATE:20181027T010000\r\nRDATE:20191026T000000\r\nEND:STANDARD", + "BEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0200\r\nTZNAME:EET\r\nDTSTART:19700101T000000\r\nEND:STANDARD" ], "latitude": "+0313200", "longitude": "+0350542" @@ -3381,8 +3387,8 @@ "Pacific/Fiji": { "ics": [ "BEGIN:STANDARD\r\nTZOFFSETFROM:+1300\r\nTZOFFSETTO:+1200\r\nTZNAME:+12\r\nDTSTART:19700118T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=1;BYMONTHDAY=12,13,14,15,16,17,18;BYDAY=SU\r\nEND:STANDARD", - "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:+1200\r\nTZOFFSETTO:+1300\r\nTZNAME:+13\r\nDTSTART:20191110T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=2SU\r\nEND:DAYLIGHT", - "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:+1200\r\nTZOFFSETTO:+1300\r\nTZNAME:+13\r\nDTSTART:20181104T020000\r\nRDATE:20181104T020000\r\nEND:DAYLIGHT" + "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:+1200\r\nTZOFFSETTO:+1300\r\nTZNAME:+13\r\nDTSTART:20211114T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=2SU\r\nEND:DAYLIGHT", + "BEGIN:DAYLIGHT\r\nTZOFFSETFROM:+1200\r\nTZOFFSETTO:+1300\r\nTZNAME:+13\r\nDTSTART:20181104T020000\r\nRDATE:20181104T020000\r\nRDATE:20191110T020000\r\nRDATE:20201220T020000\r\nEND:DAYLIGHT" ], "latitude": "-0180800", "longitude": "+1782500" diff -Nru thunderbird-78.5.0+build3/comm/chat/components/public/imIAccount.idl thunderbird-78.7.1+build1/comm/chat/components/public/imIAccount.idl --- thunderbird-78.5.0+build3/comm/chat/components/public/imIAccount.idl 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/chat/components/public/imIAccount.idl 2021-02-05 18:23:40.000000000 +0000 @@ -144,13 +144,17 @@ /* When a connection error occurred, this value indicates the type of error */ readonly attribute short connectionErrorReason; - /* When a certificate error occurs, the host/port that caused a + /** + * When a certificate error occurs, the host/port that caused a * SSL/certificate error when connecting to it. This is only valid when - * connectionErrorReason is one of ERROR_CERT_*. */ + * connectionErrorReason is one of ERROR_CERT_* + */ readonly attribute AUTF8String connectionTarget; - /* When a certificate error occurs, the nsITransportSecurityInfo error of - * the socket. This should only be set when connectionTarget is set. */ - readonly attribute nsITransportSecurityInfo secInfo; + /** + * When a certificate error occurs, the nsITransportSecurityInfo error of + * the socket. This should only be set when connectionTarget is set. + */ + readonly attribute nsITransportSecurityInfo securityInfo; /* Possible connection error reasons: ERROR_NETWORK_ERROR and ERROR_ENCRYPTION_ERROR are not fatal and diff -Nru thunderbird-78.5.0+build3/comm/chat/content/accounts.css thunderbird-78.7.1+build1/comm/chat/content/accounts.css --- thunderbird-78.5.0+build3/comm/chat/content/accounts.css 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/chat/content/accounts.css 2021-02-05 18:23:40.000000000 +0000 @@ -17,7 +17,6 @@ richlistitem[selected="true"]:not([state="disconnected"]) .connectButton, richlistitem[selected="true"][state="disconnected"] .disconnectButton, richlistitem[selected="true"][state="disconnecting"] .disconnectButton, -richlistitem[selected="true"]:not([certError="true"]) .addException, richlistitem:not([selected="true"]) .addException, richlistitem:not([selected="true"]) .autoSignOn, richlistitem:not([reconnectPending="true"]) description[anonid="reconnect"] diff -Nru thunderbird-78.5.0+build3/comm/chat/content/chat-account-richlistitem.js thunderbird-78.7.1+build1/comm/chat/content/chat-account-richlistitem.js --- thunderbird-78.5.0+build3/comm/chat/content/chat-account-richlistitem.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/chat/content/chat-account-richlistitem.js 2021-02-05 18:23:40.000000000 +0000 @@ -72,8 +72,6 @@ - ) * = onBinaryDataReceived(ArrayBuffer ) @@ -116,6 +116,12 @@ "nsIScriptableUnicodeConverter" ); +/** + * @implements {nsIStreamListener} + * @implements {nsIRequestObserver} + * @implements {nsITransportEventSink} + * @implements {nsIProtocolProxyCallback} + */ var Socket = { // Use this to use binary mode for the binaryMode: false, @@ -136,7 +142,7 @@ readWriteTimeout: 0, // A nsITransportSecurityInfo instance giving details about the certificate error. - secInfo: null, + securityInfo: null, /* ***************************************************************************** @@ -156,7 +162,7 @@ aPort = aOriginPort ) { if (Services.io.offline) { - throw Components.Exception("", Cr.NS_ERROR_FAILURE); + throw Components.Exception("Offline, can't connect", Cr.NS_ERROR_FAILURE); } // This won't work for Linux due to bug 758848. @@ -519,31 +525,13 @@ let nssErrorsService = Cc["@mozilla.org/nss_errors_service;1"].getService( Ci.nsINSSErrorsService ); - if ( - (aStatus <= - nssErrorsService.getXPCOMFromNSSError( - nssErrorsService.NSS_SEC_ERROR_BASE - ) && - aStatus >= - nssErrorsService.getXPCOMFromNSSError( - nssErrorsService.NSS_SEC_ERROR_LIMIT - 1 - )) || - (aStatus <= - nssErrorsService.getXPCOMFromNSSError( - nssErrorsService.NSS_SSL_ERROR_BASE - ) && - aStatus >= - nssErrorsService.getXPCOMFromNSSError( - nssErrorsService.NSS_SSL_ERROR_LIMIT - 1 - )) - ) { - this.onBadCertificate( - nssErrorsService.getErrorClass(aStatus) == - nssErrorsService.ERROR_CLASS_SSL_PROTOCOL, - nssErrorsService.getErrorMessage(aStatus) - ); - return; - } + this.securityInfo = this.transport.securityInfo.QueryInterface( + Ci.nsITransportSecurityInfo + ); + this.onConnectionSecurityError( + aStatus, + nssErrorsService.getErrorMessage(aStatus) + ); } this.onConnectionClosed(); }, @@ -701,7 +689,7 @@ // Called when a socket request's network is reset. onConnectionReset() {}, // Called when the certificate provided by the server didn't satisfy NSS. - onBadCertificate(aNSSErrorMessage) {}, + onConnectionSecurityError(aTLSError, aNSSErrorMessage) {}, // Called when the other end has closed the connection. onConnectionClosed() {}, diff -Nru thunderbird-78.5.0+build3/comm/chat/protocols/irc/irc.jsm thunderbird-78.7.1+build1/comm/chat/protocols/irc/irc.jsm --- thunderbird-78.5.0+build3/comm/chat/protocols/irc/irc.jsm 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/chat/protocols/irc/irc.jsm 2021-02-05 18:23:40.000000000 +0000 @@ -917,14 +917,14 @@ _("connection.error.timeOut") ); }, - onBadCertificate(aIsSslError, aNSSErrorMessage) { + onConnectionSecurityError(aTLSError, aNSSErrorMessage) { this.WARN( "Bad certificate or SSL connection for " + this._account.name + ":\n" + aNSSErrorMessage ); - let error = this._account.handleBadCertificate(this, aIsSslError); + let error = this._account.handleConnectionSecurityError(this); this._account.gotDisconnected(error, aNSSErrorMessage); }, diff -Nru thunderbird-78.5.0+build3/comm/chat/protocols/xmpp/xmpp-base.jsm thunderbird-78.7.1+build1/comm/chat/protocols/xmpp/xmpp-base.jsm --- thunderbird-78.5.0+build3/comm/chat/protocols/xmpp/xmpp-base.jsm 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/chat/protocols/xmpp/xmpp-base.jsm 2021-02-05 18:23:40.000000000 +0000 @@ -2680,7 +2680,7 @@ conv.supportChatStateNotifications = !!state; }, - /* Called when there is an error in the xmpp session */ + /** Called when there is an error in the XMPP session */ onError(aError, aException) { if (aError === null || aError === undefined) { aError = Ci.prplIAccount.ERROR_OTHER_ERROR; diff -Nru thunderbird-78.5.0+build3/comm/chat/protocols/xmpp/xmpp-session.jsm thunderbird-78.7.1+build1/comm/chat/protocols/xmpp/xmpp-session.jsm --- thunderbird-78.5.0+build3/comm/chat/protocols/xmpp/xmpp-session.jsm 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/chat/protocols/xmpp/xmpp-session.jsm 2021-02-05 18:23:40.000000000 +0000 @@ -369,8 +369,8 @@ onConnectionClosed() { this._networkError(_("connection.error.serverClosedConnection")); }, - onBadCertificate(aIsSslError, aNSSErrorMessage) { - let error = this._account.handleBadCertificate(this, aIsSslError); + onConnectionSecurityError(aTLSError, aNSSErrorMessage) { + let error = this._account.handleConnectionSecurityError(this); this.onError(error, aNSSErrorMessage); }, onConnectionReset() { diff -Nru thunderbird-78.5.0+build3/comm/.gecko_rev.yml thunderbird-78.7.1+build1/comm/.gecko_rev.yml --- thunderbird-78.5.0+build3/comm/.gecko_rev.yml 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/.gecko_rev.yml 2021-02-05 18:23:40.000000000 +0000 @@ -1,8 +1,8 @@ --- GECKO_BASE_REPOSITORY: https://hg.mozilla.org/mozilla-unified GECKO_HEAD_REPOSITORY: https://hg.mozilla.org/releases/mozilla-esr78 -GECKO_HEAD_REF: FIREFOX_78_5_0esr_BUILD1 -GECKO_HEAD_REV: d482421dc3fe22020f2c57f573ed902f6d302ffa +GECKO_HEAD_REF: FIREFOX_78_7_0esr_BUILD1 +GECKO_HEAD_REV: 0b2a3be4915be03d5434bd445234b7145f4d7dab ### For comm-central # GECKO_BASE_REPOSITORY: https://hg.mozilla.org/mozilla-unified diff -Nru thunderbird-78.5.0+build3/comm/ldap/c-sdk/libraries/libprldap/ldappr-io.c thunderbird-78.7.1+build1/comm/ldap/c-sdk/libraries/libprldap/ldappr-io.c --- thunderbird-78.5.0+build3/comm/ldap/c-sdk/libraries/libprldap/ldappr-io.c 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/ldap/c-sdk/libraries/libprldap/ldappr-io.c 2021-02-05 18:23:40.000000000 +0000 @@ -271,6 +271,9 @@ pds[i].in_flags |= prldap_eventmap[j].evm_nspr; } } + // We want to hear about out-of-band/high priority packets. + // We need this to hear about security layer errors (e.g. bad certs). + pds[i].in_flags |= PR_POLL_EXCEPT; } fds[i].lpoll_revents = 0; /* clear revents */ } diff -Nru thunderbird-78.5.0+build3/comm/ldap/xpcom/public/nsILDAPMessageListener.idl thunderbird-78.7.1+build1/comm/ldap/xpcom/public/nsILDAPMessageListener.idl --- thunderbird-78.5.0+build3/comm/ldap/xpcom/public/nsILDAPMessageListener.idl 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/ldap/xpcom/public/nsILDAPMessageListener.idl 2021-02-05 18:23:40.000000000 +0000 @@ -7,8 +7,8 @@ #include "nsISupports.idl" interface nsILDAPMessage; - interface nsILDAPConnection; +interface nsITransportSecurityInfo; /** * A callback interface to be implemented by any objects that want to @@ -19,22 +19,31 @@ interface nsILDAPMessageListener : nsISupports { /** - * Messages received are passed back via this function. + * Invoked when Init has completed successfully LDAP operations can + * proceed. + */ + void onLDAPInit(); + + /** + * Messages from LDAP operations are passed back via this function. * - * @arg aMessage The message that was returned, NULL if none was. + * @param aMessage The message that was returned, NULL if none was. * * XXX semantics of NULL? */ void onLDAPMessage(in nsILDAPMessage aMessage); + /** - * Notify the listener that the Init has completed, passing - * in the results from the connection initialization. The - * Reason for this is to allow us to do asynchronous DNS - * lookups, preresolving hostnames. + * Indicates that an error has occured - either during init, or due to + * an LDAP operation. * - * @arg aConn The LDAP connection in question - * @arg aStatus The result from the LDAP connection init + * @param status The error code. + * @param secInfo The securityInfo object for the connection, if status + * is a security (NSS) error. Null otherwise. + * @param location If status is an NSS error code, this holds the location + * of the failed operation (":"). */ - void onLDAPInit(in nsILDAPConnection aConn, in nsresult aStatus); + void onLDAPError(in nsresult status, in nsITransportSecurityInfo secInfo, in ACString location); }; + diff -Nru thunderbird-78.5.0+build3/comm/ldap/xpcom/src/nsLDAPConnection.cpp thunderbird-78.7.1+build1/comm/ldap/xpcom/src/nsLDAPConnection.cpp --- thunderbird-78.5.0+build3/comm/ldap/xpcom/src/nsLDAPConnection.cpp 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/ldap/xpcom/src/nsLDAPConnection.cpp 2021-02-05 18:23:40.000000000 +0000 @@ -11,6 +11,8 @@ #include "nsIDNSRecord.h" #include "nsLDAPConnection.h" #include "nsLDAPMessage.h" +#include "nsLDAPSecurityGlue.h" +#include "nsITransportSecurityInfo.h" #include "nsThreadUtils.h" #include "nsIConsoleService.h" #include "nsIDNSService.h" @@ -23,6 +25,7 @@ #include "nsILDAPURL.h" #include "nsIObserverService.h" #include "mozilla/Services.h" +#include "NSSErrorsService.h" #include "nsMemory.h" #include "nsLDAPUtils.h" #include "nsProxyRelease.h" @@ -109,15 +112,18 @@ // Get the port number, SSL flag for use later, once the DNS server(s) // has resolved the host part. - rv = aUrl->GetPort(&mPort); - NS_ENSURE_SUCCESS(rv, rv); uint32_t options; rv = aUrl->GetOptions(&options); NS_ENSURE_SUCCESS(rv, rv); - mSSL = options & nsILDAPURL::OPT_SECURE; + rv = aUrl->GetPort(&mPort); + NS_ENSURE_SUCCESS(rv, rv); + if (mPort == -1) { + mPort = mSSL ? LDAPS_PORT : LDAP_PORT; + } + nsCOMPtr curThread = do_GetCurrentThread(); if (!curThread) { NS_ERROR("nsLDAPConnection::Init(): couldn't get current thread"); @@ -214,17 +220,24 @@ * and this leads to starvation. * We have to do a copy of pending operations. */ - nsTArray pending_operations; + nsTArray pending_operations; { MutexAutoLock lock(mPendingOperationsMutex); for (auto iter = mPendingOperations.Iter(); !iter.Done(); iter.Next()) { - pending_operations.AppendElement(iter.UserData()); + nsLDAPOperation* op = static_cast(iter.UserData()); + pending_operations.AppendElement(op); } } - for (uint32_t i = 0; i < pending_operations.Length(); i++) { - pending_operations[i]->AbandonExt(); + for (auto op : pending_operations) { + // Tell the operation to free any refcounts it can. + op->Clear(); + // Would be nice to tell the server that it can abort any operations + // it's currently processing, but we'd have to send the ABANDON from + // the thread, and we're shutting down our LDAP handle right now! + // SO. Future/aspirational: + // op->AbandonExt(); } - Close(); + Close(); // Byebye LDAP handle. } else { MOZ_ASSERT_UNREACHABLE("unexpected topic"); return NS_ERROR_UNEXPECTED; @@ -364,6 +377,7 @@ return NS_OK; } +// Helper to invoke the OnLDAPMessage() callback on the main thread. class nsOnLDAPMessageRunnable : public Runnable { public: nsOnLDAPMessageRunnable(nsLDAPMessage* aMsg, bool aClear) @@ -396,6 +410,8 @@ return listener->OnLDAPMessage(m_msg); } +// This is called from the STS thread, to invoke the listeners +// OnLDAPMessage() callback out on the main thread. nsresult nsLDAPConnection::InvokeMessageCallback(LDAPMessage* aMsgHandle, nsILDAPMessage* aMsg, int32_t aOperation, @@ -439,6 +455,30 @@ return NS_OK; } +// Called on the STS thread, to signal errors to the listener on the main +// thread. +void nsLDAPConnection::InvokeErrorCallback(int32_t opID, nsresult status, + nsISupports* secInfo) { + nsCOMPtr listener; + { + nsCOMPtr operation; + MutexAutoLock lock(mPendingOperationsMutex); + mPendingOperations.Get((uint32_t)opID, getter_AddRefs(operation)); + if (!operation) { + return; + } + operation->GetMessageListener(getter_AddRefs(listener)); + } + if (!listener) { + return; + } + nsPrintfCString location("%s:%d", mDNSHost.get(), mPort); + nsCOMPtr tsi = do_QueryInterface(secInfo); + NS_DispatchToMainThread(NS_NewRunnableFunction("InvokeErrorCallback", [=]() { + listener->OnLDAPError(status, tsi, location); + })); +} + NS_IMETHODIMP nsLDAPConnection::OnLookupComplete(nsICancelable* aRequest, nsIDNSRecord* aRecord, nsresult aStatus) { @@ -512,9 +552,7 @@ // new, synchronous DNS lookup, which might hang (but hopefully // if we've come this far, DNS is working properly). // - mConnectionHandle = - ldap_init(mResolvedIP.get(), - mPort == -1 ? (mSSL ? LDAPS_PORT : LDAP_PORT) : mPort); + mConnectionHandle = ldap_init(mResolvedIP.get(), mPort); // Check that we got a proper connection, and if so, setup the // threading functions for this connection. // @@ -548,9 +586,6 @@ // This code sets up the current connection to use PSM for SSL // functionality. Making this use libssldap instead for // non-browser user shouldn't be hard. - - extern nsresult nsLDAPInstallSSL(LDAP * ld, const char* aHostName); - if (mSSL) { if (ldap_set_option(mConnectionHandle, LDAP_OPT_SSL, LDAP_OPT_ON) != LDAP_SUCCESS) { @@ -571,15 +606,15 @@ } } - // Drop the DNS request object, we no longer need it, and set the flag - // indicating that DNS has finished. - // + // Finished with the DNS request object. mDNSRequest = nullptr; - mDNSHost.Truncate(); // Call the listener, and then we can release our reference to it. - // - mInitListener->OnLDAPInit(this, rv); + if (NS_SUCCEEDED(rv)) { + mInitListener->OnLDAPInit(); + } else { + mInitListener->OnLDAPError(rv, nullptr, ""_ns); + } mInitListener = nullptr; return rv; @@ -620,12 +655,33 @@ // XXX do we need a timer? return thread->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL); case -1: { - int errCode; + // An error occurred. + int errLDAP; ldap_get_option(mConnection->mConnectionHandle, LDAP_OPT_ERROR_NUMBER, - &errCode); + &errLDAP); MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Error, ("ldap_result() failed (on id=%d): %s", mOperationID, - ldap_err2string(errCode))); + ldap_err2string(errLDAP))); + + // All the LDAP codes can be mapped to nsresult. + // But we also want to know specifically about recoverable security + // errors (self-signed cert etc...). LDAP has no concept of these, so + // we have to break the abstraction and delve into some lower layers + // to get what we want. + nsresult status = + NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, errLDAP); + nsCOMPtr secInfo; + // We know we're using libprldap, so there'll be an NSPR error code. + PRErrorCode errPR = PR_GetError(); + if (mozilla::psm::IsNSSErrorCode(errPR)) { + // It's a security error. So we also want the associated security + // info (which is in the nsLDAPSecurityGlue layer). + status = mozilla::psm::GetXPCOMFromNSSError(errPR); + nsLDAPGetSecInfo(mConnection->mConnectionHandle, + getter_AddRefs(secInfo)); + } + mConnection->InvokeErrorCallback(mOperationID, status, secInfo); + // Remove operation from the Pending table. mConnection->RemovePendingOperation((uint32_t)mOperationID); return NS_ERROR_FAILURE; diff -Nru thunderbird-78.5.0+build3/comm/ldap/xpcom/src/nsLDAPConnection.h thunderbird-78.7.1+build1/comm/ldap/xpcom/src/nsLDAPConnection.h --- thunderbird-78.5.0+build3/comm/ldap/xpcom/src/nsLDAPConnection.h 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/ldap/xpcom/src/nsLDAPConnection.h 2021-02-05 18:23:40.000000000 +0000 @@ -96,6 +96,7 @@ */ nsresult InvokeMessageCallback(LDAPMessage* aMsgHandle, nsILDAPMessage* aMsg, int32_t aOperation, bool aRemoveOpFromConnQ); + void InvokeErrorCallback(int32_t opID, nsresult status, nsISupports* secInfo); /** * Dispatch an operation to the socket thread. This is intended for use by diff -Nru thunderbird-78.5.0+build3/comm/ldap/xpcom/src/nsLDAPOperation.cpp thunderbird-78.7.1+build1/comm/ldap/xpcom/src/nsLDAPOperation.cpp --- thunderbird-78.5.0+build3/comm/ldap/xpcom/src/nsLDAPOperation.cpp 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/ldap/xpcom/src/nsLDAPOperation.cpp 2021-02-05 18:23:40.000000000 +0000 @@ -653,6 +653,9 @@ return NS_ERROR_NOT_INITIALIZED; } + MOZ_LOG(gLDAPLogModule, mozilla::LogLevel::Debug, + ("nsLDAPOperation::AbandonExt() called (msgid=%d)", mMsgID)); + // XXX handle controls here if (mServerControls || mClientControls) { return NS_ERROR_NOT_IMPLEMENTED; diff -Nru thunderbird-78.5.0+build3/comm/ldap/xpcom/src/nsLDAPSecurityGlue.cpp thunderbird-78.7.1+build1/comm/ldap/xpcom/src/nsLDAPSecurityGlue.cpp --- thunderbird-78.5.0+build3/comm/ldap/xpcom/src/nsLDAPSecurityGlue.cpp 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/ldap/xpcom/src/nsLDAPSecurityGlue.cpp 2021-02-05 18:23:40.000000000 +0000 @@ -31,18 +31,11 @@ // LDAP per-socket data structure. // -typedef struct { +struct nsLDAPSSLSocketClosure { + nsLDAPSSLSocketClosure() : sessionClosure(nullptr), securityInfo(nullptr) {} nsLDAPSSLSessionClosure* sessionClosure; /* session info */ -} nsLDAPSSLSocketClosure; - -// free the per-socket data structure as necessary -// -static void nsLDAPSSLFreeSocketClosure(nsLDAPSSLSocketClosure** aClosure) { - if (aClosure && *aClosure) { - free(*aClosure); - *aClosure = nullptr; - } -} + nsCOMPtr securityInfo; +}; // Replacement close() function, which cleans up local stuff associated // with this socket, and then calls the real close function. @@ -50,8 +43,6 @@ extern "C" int LDAP_CALLBACK nsLDAPSSLClose(int s, struct lextiof_socket_private* socketarg) { PRLDAPSocketInfo socketInfo; - nsLDAPSSLSocketClosure* socketClosure; - nsLDAPSSLSessionClosure* sessionClosure; // get the socketInfo associated with this socket // @@ -65,22 +56,19 @@ // save off the session closure data in an automatic, since we're going to // need to call through it // - socketClosure = + nsLDAPSSLSocketClosure* socketClosure = reinterpret_cast(socketInfo.soinfo_appdata); if (!socketClosure) { NS_ERROR("nsLDAPSSLClose(): no socketClosure to be had"); return -1; } - sessionClosure = socketClosure->sessionClosure; - - // free the socket closure data - // - nsLDAPSSLFreeSocketClosure( - reinterpret_cast(&socketInfo.soinfo_appdata)); // call the real close function - // - return (*(sessionClosure->realClose))(s, socketarg); + nsLDAPSSLSessionClosure* sessionClosure = socketClosure->sessionClosure; + int ret = (*(sessionClosure->realClose))(s, socketarg); + + delete socketClosure; + return ret; } // Replacement connection function. Calls the real connect function, @@ -146,15 +134,9 @@ } // Allocate a structure to hold our socket-specific data. - // - socketClosure = static_cast( - moz_xmalloc(sizeof(nsLDAPSSLSocketClosure))); - if (!socketClosure) { - NS_WARNING("nsLDAPSSLConnect(): unable to allocate socket closure"); - goto close_socket_and_exit_with_error; - } - memset(socketClosure, 0, sizeof(nsLDAPSSLSocketClosure)); + socketClosure = new nsLDAPSSLSocketClosure; socketClosure->sessionClosure = sessionClosure; + socketClosure->securityInfo = nullptr; // Add the NSPR layer for SSL provided by PSM to this socket. sps = nsSocketProviderService::GetOrCreate(); @@ -200,8 +182,9 @@ } } - // Attach our closure to the socketInfo. - // + // Attach our closure to the socketInfo, making sure to stash the + // securityInfo so we can get at it later during error handling. + socketClosure->securityInfo = securityInfo; socketInfo.soinfo_appdata = reinterpret_cast(socketClosure); if (prldap_set_socket_info(intfd, *socketargp, &socketInfo) != LDAP_SUCCESS) { @@ -214,7 +197,7 @@ PR_Close(socketInfo.soinfo_prfd); } if (socketClosure) { - nsLDAPSSLFreeSocketClosure(&socketClosure); + delete socketClosure; } if (intfd >= 0 && *socketargp) { (*(sessionClosure->realClose))(intfd, *socketargp); @@ -331,3 +314,24 @@ return NS_OK; } + +// Fetch the securityInfo associated with a secure ldap connection. +// Fails if no securityInfo is found (e.g. if called on an ldap connection +// which wasn't augmented with nsLDAPInstallSSL()). +nsresult nsLDAPGetSecInfo(LDAP* ld, nsISupports** secInfo) { + NS_ENSURE_ARG_POINTER(secInfo); + + PRLDAPSocketInfo soinfo; + soinfo.soinfo_size = PRLDAP_SOCKETINFO_SIZE; + int code = prldap_get_default_socket_info(ld, &soinfo); + if (code != LDAP_SUCCESS) { + return NS_ERROR_FAILURE; + } + nsLDAPSSLSocketClosure* socketClosure = + reinterpret_cast(soinfo.soinfo_appdata); + if (!socketClosure) { + return NS_ERROR_FAILURE; + } + NS_IF_ADDREF(*secInfo = socketClosure->securityInfo); + return NS_OK; +} diff -Nru thunderbird-78.5.0+build3/comm/ldap/xpcom/src/nsLDAPSecurityGlue.h thunderbird-78.7.1+build1/comm/ldap/xpcom/src/nsLDAPSecurityGlue.h --- thunderbird-78.5.0+build3/comm/ldap/xpcom/src/nsLDAPSecurityGlue.h 1970-01-01 00:00:00.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/ldap/xpcom/src/nsLDAPSecurityGlue.h 2021-02-05 18:23:40.000000000 +0000 @@ -0,0 +1,15 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _nsLDAPSecurityGlue_h_ +#define _nsLDAPSecurityGlue_h_ + +typedef struct ldap LDAP; +class nsISupports; + +nsresult nsLDAPInstallSSL(LDAP* ld, const char* aHostName); +nsresult nsLDAPGetSecInfo(LDAP* ld, nsISupports** secInfo); + +#endif // _nsLDAPSecurityGlue_h_ diff -Nru thunderbird-78.5.0+build3/comm/ldap/xpcom/src/nsLDAPService.cpp thunderbird-78.7.1+build1/comm/ldap/xpcom/src/nsLDAPService.cpp --- thunderbird-78.5.0+build3/comm/ldap/xpcom/src/nsLDAPService.cpp 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/ldap/xpcom/src/nsLDAPService.cpp 2021-02-05 18:23:40.000000000 +0000 @@ -527,10 +527,11 @@ return NS_OK; } -// void onLDAPInit (in nsILDAPConnection aConn, in nsresult aStatus); */ -// +NS_IMETHODIMP nsLDAPService::OnLDAPInit() { return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHODIMP -nsLDAPService::OnLDAPInit(nsILDAPConnection* aConn, nsresult aStatus) { +nsLDAPService::OnLDAPError(nsresult status, nsITransportSecurityInfo* secInfo, + nsACString const& location) { return NS_ERROR_NOT_IMPLEMENTED; } diff -Nru thunderbird-78.5.0+build3/comm/ldap/xpcom/src/nsLDAPSyncQuery.cpp thunderbird-78.7.1+build1/comm/ldap/xpcom/src/nsLDAPSyncQuery.cpp --- thunderbird-78.5.0+build3/comm/ldap/xpcom/src/nsLDAPSyncQuery.cpp 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/ldap/xpcom/src/nsLDAPSyncQuery.cpp 2021-02-05 18:23:40.000000000 +0000 @@ -20,6 +20,7 @@ // nsLDAPSyncQuery::nsLDAPSyncQuery() : mFinished(false), // This is a control variable for event loop + mFinishedStatus(NS_OK), mProtocolVersion(nsILDAPConnection::VERSION3) {} // Destructor @@ -46,7 +47,7 @@ NS_ERROR( "nsLDAPSyncQuery::OnLDAPMessage(): unexpected " "error in aMessage->GetType()"); - FinishLDAPQuery(); + FinishLDAPQuery(rv); return NS_ERROR_UNEXPECTED; } @@ -67,7 +68,8 @@ // the search is finished; we're all done // - return OnLDAPSearchResult(aMessage); + FinishLDAPQuery(NS_OK); + return NS_OK; default: @@ -84,16 +86,14 @@ } } -// void onLDAPInit (in nsresult aStatus); -// NS_IMETHODIMP -nsLDAPSyncQuery::OnLDAPInit(nsILDAPConnection* aConn, nsresult aStatus) { +nsLDAPSyncQuery::OnLDAPInit() { nsresult rv; // temp for xpcom return values // create and initialize an LDAP operation (to be used for the bind) // mOperation = do_CreateInstance("@mozilla.org/network/ldap-operation;1", &rv); if (NS_FAILED(rv)) { - FinishLDAPQuery(); + FinishLDAPQuery(rv); return NS_ERROR_FAILURE; } @@ -101,7 +101,7 @@ // rv = mOperation->Init(mConnection, this, nullptr); if (NS_FAILED(rv)) { - FinishLDAPQuery(); + FinishLDAPQuery(rv); return NS_ERROR_UNEXPECTED; // this should never happen } @@ -109,13 +109,20 @@ // rv = mOperation->SimpleBind(EmptyCString()); if (NS_FAILED(rv)) { - FinishLDAPQuery(); + FinishLDAPQuery(rv); return NS_ERROR_FAILURE; } return NS_OK; } +NS_IMETHODIMP +nsLDAPSyncQuery::OnLDAPError(nsresult status, nsITransportSecurityInfo* secInfo, + nsACString const& location) { + FinishLDAPQuery(status); + return NS_OK; +} + nsresult nsLDAPSyncQuery::OnLDAPBind(nsILDAPMessage* aMessage) { int32_t errCode; @@ -128,14 +135,16 @@ NS_ERROR( "nsLDAPSyncQuery::OnLDAPBind(): couldn't get " "error code from aMessage"); - FinishLDAPQuery(); + FinishLDAPQuery(rv); return NS_ERROR_FAILURE; } // check to be sure the bind succeeded // if (errCode != nsILDAPErrors::SUCCESS) { - FinishLDAPQuery(); + // All the LDAP codes can be mapped into nsresult + nsresult status = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, errCode); + FinishLDAPQuery(status); return NS_ERROR_FAILURE; } @@ -151,7 +160,7 @@ NS_WARNING( "nsLDAPSyncQuery:OnLDAPSearchEntry(): " "aMessage->GetAttributes() failed"); - FinishLDAPQuery(); + FinishLDAPQuery(rv); return rv; } @@ -160,12 +169,12 @@ // Get the values of this attribute. // XXX better failure handling nsTArray vals; - rv = aMessage->GetValues("objectClass", vals); + rv = aMessage->GetValues(attributes[i].get(), vals); if (NS_FAILED(rv)) { NS_WARNING( "nsLDAPSyncQuery:OnLDAPSearchEntry(): " "aMessage->GetValues() failed"); - FinishLDAPQuery(); + FinishLDAPQuery(rv); break; } @@ -178,14 +187,6 @@ } } - return rv; -} - -nsresult nsLDAPSyncQuery::OnLDAPSearchResult(nsILDAPMessage* aMessage) { - // We are done with the LDAP search. - // Release the control variable for the eventloop and other members - // - FinishLDAPQuery(); return NS_OK; } @@ -199,7 +200,7 @@ NS_ERROR( "nsLDAPSyncQuery::StartLDAPSearch(): couldn't " "create @mozilla.org/network/ldap-operation;1"); - FinishLDAPQuery(); + FinishLDAPQuery(rv); return NS_ERROR_FAILURE; } @@ -210,7 +211,7 @@ NS_ERROR( "nsLDAPSyncQuery::StartLDAPSearch(): couldn't " "initialize LDAP operation"); - FinishLDAPQuery(); + FinishLDAPQuery(rv); return NS_ERROR_UNEXPECTED; } @@ -219,7 +220,7 @@ nsAutoCString urlFilter; rv = mServerURL->GetFilter(urlFilter); if (NS_FAILED(rv)) { - FinishLDAPQuery(); + FinishLDAPQuery(rv); return NS_ERROR_UNEXPECTED; } @@ -228,7 +229,7 @@ nsAutoCString dn; rv = mServerURL->GetDn(dn); if (NS_FAILED(rv)) { - FinishLDAPQuery(); + FinishLDAPQuery(rv); return NS_ERROR_UNEXPECTED; } @@ -237,14 +238,14 @@ int32_t scope; rv = mServerURL->GetScope(&scope); if (NS_FAILED(rv)) { - FinishLDAPQuery(); + FinishLDAPQuery(rv); return NS_ERROR_UNEXPECTED; } nsAutoCString attributes; rv = mServerURL->GetAttributes(attributes); if (NS_FAILED(rv)) { - FinishLDAPQuery(); + FinishLDAPQuery(rv); return NS_ERROR_UNEXPECTED; } @@ -252,7 +253,7 @@ rv = mOperation->SearchExt(dn, scope, urlFilter, attributes, 0, 0); if (NS_FAILED(rv)) { - FinishLDAPQuery(); + FinishLDAPQuery(rv); return NS_ERROR_FAILURE; } @@ -274,7 +275,7 @@ NS_ERROR( "nsLDAPSyncQuery::InitConnection(): could " "not create @mozilla.org/network/ldap-connection;1"); - FinishLDAPQuery(); + FinishLDAPQuery(rv); return NS_ERROR_FAILURE; } @@ -284,24 +285,25 @@ NS_ERROR( "nsLDAPSyncQuery::InitConnection(): mServerURL " "is NULL"); - FinishLDAPQuery(); + FinishLDAPQuery(NS_ERROR_NOT_INITIALIZED); return NS_ERROR_NOT_INITIALIZED; } rv = mConnection->Init(mServerURL, EmptyCString(), this, nullptr, mProtocolVersion); if (NS_FAILED(rv)) { - FinishLDAPQuery(); + FinishLDAPQuery(rv); return NS_ERROR_UNEXPECTED; // this should never happen } return NS_OK; } -void nsLDAPSyncQuery::FinishLDAPQuery() { +void nsLDAPSyncQuery::FinishLDAPQuery(nsresult status) { // We are done with the LDAP operation. // Release the Control variable for the eventloop // mFinished = true; + mFinishedStatus = status; // Release member variables // @@ -345,11 +347,10 @@ // while (!mFinished) NS_ENSURE_STATE(NS_ProcessNextEvent(currentThread)); - // Return results - // - if (!mResults.IsEmpty()) { + if (NS_SUCCEEDED(mFinishedStatus)) { *_retval = ToNewUnicode(mResults); - if (!_retval) rv = NS_ERROR_OUT_OF_MEMORY; + } else { + *_retval = nullptr; } - return rv; + return mFinishedStatus; } diff -Nru thunderbird-78.5.0+build3/comm/ldap/xpcom/src/nsLDAPSyncQuery.h thunderbird-78.7.1+build1/comm/ldap/xpcom/src/nsLDAPSyncQuery.h --- thunderbird-78.5.0+build3/comm/ldap/xpcom/src/nsLDAPSyncQuery.h 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/ldap/xpcom/src/nsLDAPSyncQuery.h 2021-02-05 18:23:40.000000000 +0000 @@ -37,7 +37,8 @@ nsCOMPtr mOperation; // current ldap op nsCOMPtr mServerURL; // LDAP URL bool mFinished; // control variable for eventQ - nsString mResults; // values to return + nsresult mFinishedStatus; // final result of async operation. + nsString mResults; // data returned by async operation. uint32_t mProtocolVersion; // LDAP version to use nsresult InitConnection(); @@ -47,11 +48,9 @@ // add to the results set nsresult OnLDAPSearchEntry(nsILDAPMessage* aMessage); - nsresult OnLDAPSearchResult(nsILDAPMessage* aMessage); - // kick off a search nsresult StartLDAPSearch(); // Clean up after the LDAP Query is done. - void FinishLDAPQuery(); + void FinishLDAPQuery(nsresult status); }; diff -Nru thunderbird-78.5.0+build3/comm/mail/app/profile/all-thunderbird.js thunderbird-78.7.1+build1/comm/mail/app/profile/all-thunderbird.js --- thunderbird-78.5.0+build3/comm/mail/app/profile/all-thunderbird.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/app/profile/all-thunderbird.js 2021-02-05 18:23:40.000000000 +0000 @@ -104,7 +104,7 @@ #endif // Base URL for web-based support pages. -pref("app.support.baseURL", "https://support.thunderbird.net/%LOCALE%/%APP%/%APPBUILDID%/"); +pref("app.support.baseURL", "https://support.thunderbird.net/%APP%/%VERSION%/%OS%/%LOCALE%/"); // Base url for web-based feedback pages. pref("app.feedback.baseURL", "https://input.mozilla.org/%LOCALE%/feedback/%APP%/%VERSION%/"); @@ -112,6 +112,12 @@ // Show error messages in error console. pref("javascript.options.showInConsole", true); +#ifdef NIGHTLY_BUILD +pref("signon.management.page.os-auth.enabled", true); +#else +pref("signon.management.page.os-auth.enabled", false); +#endif + // Controls enabling of the extension system logging (can reduce performance) pref("extensions.logging.enabled", false); pref("extensions.overlayloader.loglevel", "warn"); diff -Nru thunderbird-78.5.0+build3/comm/mail/base/content/commandglue.js thunderbird-78.7.1+build1/comm/mail/base/content/commandglue.js --- thunderbird-78.5.0+build3/comm/mail/base/content/commandglue.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/base/content/commandglue.js 2021-02-05 18:23:40.000000000 +0000 @@ -144,7 +144,18 @@ let quotaUsagePercentage = q => Number((100n * BigInt(q.usage)) / BigInt(q.limit)); - let folderQuota = folder.getQuota(); + // For display on main window panel only include quota names containing + // "STORAGE" or "MESSAGE". This will exclude unusual quota names containing + // items like "MAILBOX" and "LEVEL" from the panel bargraph. All quota names + // will still appear on the folder properties quota window. + // Note: Quota name is typically something like "User Quota / STORAGE". + let folderQuota = folder + .getQuota() + .filter( + quota => + quota.name.toUpperCase().includes("STORAGE") || + quota.name.toUpperCase().includes("MESSAGE") + ); // If folderQuota not empty, find the index of the element with highest // percent usage and determine if it is above the panel display threshold. if (folderQuota.length > 0) { diff -Nru thunderbird-78.5.0+build3/comm/mail/base/content/folderDisplay.js thunderbird-78.7.1+build1/comm/mail/base/content/folderDisplay.js --- thunderbird-78.5.0+build3/comm/mail/base/content/folderDisplay.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/base/content/folderDisplay.js 2021-02-05 18:23:40.000000000 +0000 @@ -18,6 +18,9 @@ var gFolderDisplay = null; var gMessageDisplay = null; +// An object to help collecting reading statistics of secure emails. +var gSecureMsgProbe = {}; + /** * Maintains a list of listeners for all FolderDisplayWidget instances in this * window. The assumption is that because of our multiplexed tab @@ -83,6 +86,29 @@ }; /** + * Update gSecureMsgProbe and report to telemetry if necessary. + */ +function reportMsgRead({ isNewRead = false, key = null }) { + if (isNewRead) { + gSecureMsgProbe.isNewRead = true; + } + if (key) { + gSecureMsgProbe.key = key; + } + if (gSecureMsgProbe.key && gSecureMsgProbe.isNewRead) { + Services.telemetry.keyedScalarAdd( + "tb.mails.read_secure", + gSecureMsgProbe.key, + 1 + ); + } +} + +window.addEventListener("secureMsgLoaded", event => { + reportMsgRead({ key: event.detail.key }); +}); + +/** * Abstraction for a widget that (roughly speaking) displays the contents of * folders. The widget belongs to a tab and has a lifetime as long as the tab * that contains it. This class is strictly concerned with the UI aspects of @@ -1424,6 +1450,12 @@ let msgHdr = selected.length ? selected[0] : null; this.messageDisplay.onDisplayingMessage(msgHdr); + // Reset gSecureMsgProbe. + gSecureMsgProbe = { + key: null, + isNewRead: false, + }; + // Although deletes should now be so fast that the user has no time to do // anything, treat the user explicitly choosing to display a different // message as invalidating the choice we automatically made for them when diff -Nru thunderbird-78.5.0+build3/comm/mail/base/content/gloda-autocomplete-input.js thunderbird-78.7.1+build1/comm/mail/base/content/gloda-autocomplete-input.js --- thunderbird-78.5.0+build3/comm/mail/base/content/gloda-autocomplete-input.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/base/content/gloda-autocomplete-input.js 2021-02-05 18:23:40.000000000 +0000 @@ -28,9 +28,6 @@ const { GlodaIMSearcher } = ChromeUtils.import( "resource:///modules/search_im.jsm" ); - const { XPCOMUtils } = ChromeUtils.import( - "resource://gre/modules/XPCOMUtils.jsm" - ); /** * The MozGlodaAutocompleteInput widget is used to display the autocomplete search bar. @@ -80,17 +77,6 @@ super.connectedCallback(); this.setAttribute("is", "gloda-autocomplete-input"); - - XPCOMUtils.defineLazyPreferenceGetter( - this, - "glodaEnabled", - "mailnews.database.global.indexer.enabled", - true, - (pref, oldVal, newVal) => { - this.toggleAttribute("hidden", !newVal); - } - ); - this.glodaCompleter = null; // @implements {nsIObserver} @@ -175,8 +161,6 @@ "autocomplete-did-enter-text" ); - this.toggleAttribute("hidden", !this.glodaEnabled); - // make sure we set our emptytext here from the get-go if (this.hasAttribute("placeholder")) { this.placeholder = this.getAttribute("placeholder"); diff -Nru thunderbird-78.5.0+build3/comm/mail/base/content/mailCommands.js thunderbird-78.7.1+build1/comm/mail/base/content/mailCommands.js --- thunderbird-78.5.0+build3/comm/mail/base/content/mailCommands.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/base/content/mailCommands.js 2021-02-05 18:23:40.000000000 +0000 @@ -514,6 +514,9 @@ ? Ci.nsMsgViewCommandType.markMessagesRead : Ci.nsMsgViewCommandType.markMessagesUnread ); + if (markRead) { + reportMsgRead({ isNewRead: true }); + } } function MarkSelectedMessagesFlagged(markFlagged) { diff -Nru thunderbird-78.5.0+build3/comm/mail/base/content/mailWidgets.js thunderbird-78.7.1+build1/comm/mail/base/content/mailWidgets.js --- thunderbird-78.5.0+build3/comm/mail/base/content/mailWidgets.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/base/content/mailWidgets.js 2021-02-05 18:23:40.000000000 +0000 @@ -2137,6 +2137,17 @@ }); input.addEventListener("keyup", event => { + // Trigger the onRecipientsChanged method for every letter typed or + // deleted in order to properly update the "Send" button and trigger + // the save as draft prompt even before the creation of any pill. + if ( + event.key.length == 1 || + (event.key.length > 1 && /[^a-zA-Z0-9]/.test(event.key)) || + ["Backspace", "Delete"].includes(event.key) + ) { + onRecipientsChanged(false); + } + // Change the min size of the input field on typing only if the // current width is smaller than 80% of its container's width or none // arrow keys were pressed to prevent overflow. diff -Nru thunderbird-78.5.0+build3/comm/mail/base/content/mailWindowOverlay.js thunderbird-78.7.1+build1/comm/mail/base/content/mailWindowOverlay.js --- thunderbird-78.5.0+build3/comm/mail/base/content/mailWindowOverlay.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/base/content/mailWindowOverlay.js 2021-02-05 18:23:40.000000000 +0000 @@ -2926,6 +2926,8 @@ function TransportErrorUrlListener() {} TransportErrorUrlListener.prototype = { + OnStartRunningUrl(url) {}, + OnStopRunningUrl(url, exitCode) { let nssErrorsService = Cc["@mozilla.org/nss_errors_service;1"].getService( Ci.nsINSSErrorsService @@ -3581,6 +3583,7 @@ var headers = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); headers.appendElement(msgHdr); msgHdr.folder.markMessagesRead(headers, true); + reportMsgRead({ isNewRead: true }); } function ClearPendingReadTimer() { diff -Nru thunderbird-78.5.0+build3/comm/mail/base/content/mainMailToolbox.inc.xhtml thunderbird-78.7.1+build1/comm/mail/base/content/mainMailToolbox.inc.xhtml --- thunderbird-78.5.0+build3/comm/mail/base/content/mainMailToolbox.inc.xhtml 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/base/content/mainMailToolbox.inc.xhtml 2021-02-05 18:23:40.000000000 +0000 @@ -233,11 +233,13 @@ + key="key_toggleRead" + command="cmd_markAsRead"/> + key="key_toggleRead" + command="cmd_markAsUnread"/> + class="gloda-search-widget chromeclass-toolbar-additional"> + + 0) { - let message = gFolderDisplay.selectedMessage; - let isMessageIndexed = Gloda.isMessageIndexed(message); - openConversation.disabled = !isMessageIndexed; + // Check because this menuitem element is not present in messageWindow.xhtml. + if (openConversation) { + openConversation.disabled = !glodaEnabled; + if (glodaEnabled && gFolderDisplay.selectedCount > 0) { + let message = gFolderDisplay.selectedMessage; + let isMessageIndexed = Gloda.isMessageIndexed(message); + openConversation.disabled = !isMessageIndexed; + } } if (SelectedMessagesAreRead()) { diff -Nru thunderbird-78.5.0+build3/comm/mail/base/content/msgMail3PaneWindow.js thunderbird-78.7.1+build1/comm/mail/base/content/msgMail3PaneWindow.js --- thunderbird-78.5.0+build3/comm/mail/base/content/msgMail3PaneWindow.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/base/content/msgMail3PaneWindow.js 2021-02-05 18:23:40.000000000 +0000 @@ -363,8 +363,10 @@ // re-insert the messagePaneBoxWrapper back into the document. But the dtor // doesn't fire when the element is removed from the document. Manually // call destroy here to avoid a nasty leak. - document.getElementById("messagepane").destroy(); + let messagePane = document.getElementById("messagepane"); + messagePane.destroy(); document.getElementById("FindToolbar").destroy(); + let footerBox = desiredParent.lastElementChild; if (footerBox && footerBox.id == "messenger-notification-footer") { desiredParent.insertBefore(messagePaneSplitter, footerBox); @@ -374,10 +376,12 @@ desiredParent.appendChild(messagePaneBoxWrapper); } - ExtensionParent.apiManager.emit( - "extension-browser-inserted", - document.getElementById("messagepane") - ); + if (messagePane._progressListenerAdded) { + ExtensionParent.apiManager.emit( + "extension-browser-inserted", + messagePane + ); + } if (msgWindow) { // Reassigning statusFeedback adds a progress listener to the new docShell. @@ -491,7 +495,7 @@ // the default, to allow the OS theme to properly handle the color scheme. if ( AppConstants.platform != "linux" && - Services.prefs.getCharPref("extensions.activeThemeID") == + Services.prefs.getCharPref("extensions.activeThemeID", "") == "default-theme@mozilla.org" ) { return; @@ -678,6 +682,22 @@ document.getElementById("multimessage") ); + // Depending on the pref, hide/show the gloda toolbar search widgets. + XPCOMUtils.defineLazyPreferenceGetter( + this, + "gGlodaEnabled", + "mailnews.database.global.indexer.enabled", + true, + (pref, oldVal, newVal) => { + for (let widget of document.querySelectorAll(".gloda-search-widget")) { + widget.hidden = !newVal; + } + } + ); + for (let widget of document.querySelectorAll(".gloda-search-widget")) { + widget.hidden = !this.gGlodaEnabled; + } + window.addEventListener("AppCommand", HandleAppCommandEvent, true); // Set up the appmenus. (This has to happen after the DOM has loaded.) diff -Nru thunderbird-78.5.0+build3/comm/mail/base/content/nsContextMenu.js thunderbird-78.7.1+build1/comm/mail/base/content/nsContextMenu.js --- thunderbird-78.5.0+build3/comm/mail/base/content/nsContextMenu.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/base/content/nsContextMenu.js 2021-02-05 18:23:40.000000000 +0000 @@ -118,7 +118,7 @@ onAudio: this.onAudio, onCanvas: this.onCanvas, onEditable: this.onEditable, - srcUrl: this.mediaURL, + srcUrl: this.mediaURL || this.imageURL, linkText: this.onLink ? this.linkText() : undefined, linkUrl: this.linkURL, selectionText: this.isTextSelected diff -Nru thunderbird-78.5.0+build3/comm/mail/base/content/specialTabs.js thunderbird-78.7.1+build1/comm/mail/base/content/specialTabs.js --- thunderbird-78.5.0+build3/comm/mail/base/content/specialTabs.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/base/content/specialTabs.js 2021-02-05 18:23:40.000000000 +0000 @@ -257,13 +257,14 @@ }, onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI) { if (this.mProgressListener) { - this.mProgressListener.onRefreshAttempted( + return this.mProgressListener.onRefreshAttempted( aWebProgress, aURI, aDelay, aSameURI ); } + return true; }, QueryInterface: ChromeUtils.generateQI([ Ci.nsIWebProgressListener, diff -Nru thunderbird-78.5.0+build3/comm/mail/base/content/tabmail.js thunderbird-78.7.1+build1/comm/mail/base/content/tabmail.js --- thunderbird-78.5.0+build3/comm/mail/base/content/tabmail.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/base/content/tabmail.js 2021-02-05 18:23:40.000000000 +0000 @@ -675,7 +675,7 @@ onRefreshAttempted: (aWebProgress, ...args) => { let browser = aWebProgress.QueryInterface(Ci.nsIDocShellTreeItem) .sameTypeRootTreeItem.chromeEventHandler; - this._callTabListeners("onRefreshAttempted", [ + return this._callTabListeners("onRefreshAttempted", [ browser, aWebProgress, ...args, @@ -2033,15 +2033,19 @@ } _callTabListeners(aMethod, aArgs) { + let rv = true; for (let listener of this.mTabsProgressListeners.values()) { if (aMethod in listener) { try { - listener[aMethod](...aArgs); + if (!listener[aMethod](...aArgs)) { + rv = false; + } } catch (e) { Cu.reportError(e); } } } + return rv; } disconnectedCallback() { diff -Nru thunderbird-78.5.0+build3/comm/mail/base/content/toolbarIconColor.js thunderbird-78.7.1+build1/comm/mail/base/content/toolbarIconColor.js --- thunderbird-78.5.0+build3/comm/mail/base/content/toolbarIconColor.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/base/content/toolbarIconColor.js 2021-02-05 18:23:40.000000000 +0000 @@ -58,6 +58,10 @@ // getComputedStyle(). _toolbarLuminanceCache: new Map(), + // A cache of the current sidebar color to avoid unnecessary conditions and + // luminance calculations. + _sidebarColorCache: null, + inferFromText(reason, reasonValue) { if (!this._initialized) { return; @@ -80,6 +84,7 @@ case "windowlwthemeupdate": // Theme change, we'll need to recalculate all color values. this._toolbarLuminanceCache.clear(); + this._sidebarColorCache = null; break; case "toolbarvisibilitychange": // Toolbar changes dont require reset of the cached color values. @@ -122,5 +127,41 @@ toolbar.setAttribute("brighttext", "true"); } } + + // On Linux, we need to detect if the OS theme caused a text color change in + // the sidebar icons and properly update the brighttext attribute. + if ( + reason == "activate" && + AppConstants.platform == "linux" && + Services.prefs.getCharPref("extensions.activeThemeID", "") == + "default-theme@mozilla.org" + ) { + let folderTree = document.getElementById("folderTree"); + if (!folderTree) { + return; + } + + let sidebarColor = getComputedStyle(folderTree).color; + // Interrupt if the sidebar color didn't change. + if (sidebarColor == this._sidebarColorCache) { + return; + } + + this._sidebarColorCache = sidebarColor; + + let mainWindow = document.getElementById("messengerWindow"); + if (!mainWindow) { + return; + } + + let [r, g, b] = parseRGB(sidebarColor); + let luminance = 0.2125 * r + 0.7154 * g + 0.0721 * b; + + if (luminance <= 110) { + mainWindow.removeAttribute("lwt-tree-brighttext"); + } else { + mainWindow.setAttribute("lwt-tree-brighttext", "true"); + } + } }, }; diff -Nru thunderbird-78.5.0+build3/comm/mail/base/modules/DNS.jsm thunderbird-78.7.1+build1/comm/mail/base/modules/DNS.jsm --- thunderbird-78.5.0+build3/comm/mail/base/modules/DNS.jsm 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/base/modules/DNS.jsm 2021-02-05 18:23:40.000000000 +0000 @@ -38,20 +38,24 @@ _open() { function findLibrary() { let lastException = null; - let libnames = [ - ctypes.libraryName("resolv.9"), - ctypes.libraryName("resolv"), + let candidates = [ + { name: "resolv.9", suffix: "" }, + { name: "resolv", suffix: ".2" }, + { name: "resolv", suffix: "" }, ]; - for (let libname of libnames) { + let tried = []; + for (let candidate of candidates) { try { - return ctypes.open(libname); + let name = ctypes.libraryName(candidate.name) + candidate.suffix; + tried.push(name); + return ctypes.open(name); } catch (ex) { lastException = ex; } } throw new Error( "Could not find libresolv in any of " + - libnames + + tried + " Exception: " + lastException + "\n" diff -Nru thunderbird-78.5.0+build3/comm/mail/base/modules/ExtensionsUI.jsm thunderbird-78.7.1+build1/comm/mail/base/modules/ExtensionsUI.jsm --- thunderbird-78.5.0+build3/comm/mail/base/modules/ExtensionsUI.jsm 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/base/modules/ExtensionsUI.jsm 2021-02-05 18:23:40.000000000 +0000 @@ -886,6 +886,30 @@ }); } + // Reject add-ons using the legacy API. We cannot use the general "ignore + // unknown APIs" policy, as add-ons using the Legacy API from TB68 will + // not do anything, confusing the user. + if (data.manifest.legacy) { + let subject = { + wrappedJSObject: { + browser, + originatingURI: null, + installs: [ + { + addon: info.addon, + name: info.addon.name, + error: 0, + }, + ], + install: null, + cancel: null, + }, + }; + Services.obs.notifyObservers(subject, "addon-install-failed"); + info.reject(); + return; + } + this.showPermissionsPrompt(browser, strings, info.icon, histkey).then( answer => { if (answer) { diff -Nru thunderbird-78.5.0+build3/comm/mail/base/modules/QuickFilterManager.jsm thunderbird-78.7.1+build1/comm/mail/base/modules/QuickFilterManager.jsm --- thunderbird-78.5.0+build3/comm/mail/base/modules/QuickFilterManager.jsm 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/base/modules/QuickFilterManager.jsm 2021-02-05 18:23:40.000000000 +0000 @@ -1152,7 +1152,7 @@ let panel = aDocument.getElementById("qfb-text-search-upsell"); if ( (Services.focus.activeWindow != aDocument.defaultView || - aDocument.commandDispatcher.focusedElement != aNode) && + aDocument.commandDispatcher.focusedElement != aNode.inputField) && panel.state == "open" ) { panel.hidePopup(); @@ -1198,15 +1198,16 @@ }, reflectInDOM(aNode, aFilterValue, aDocument, aMuxer, aFromPFP) { + let panel = aDocument.getElementById("qfb-text-search-upsell"); + if (aFromPFP == "nosale") { - let panel = aDocument.getElementById("qfb-text-search-upsell"); if (panel.state != "closed") { panel.hidePopup(); } return; } + if (aFromPFP == "upsell") { - let panel = aDocument.getElementById("qfb-text-search-upsell"); let line1 = aDocument.getElementById("qfb-upsell-line-one"); let line2 = aDocument.getElementById("qfb-upsell-line-two"); line1.value = line1.getAttribute("fmt").replace("#1", aFilterValue.text); @@ -1214,30 +1215,34 @@ if ( panel.state == "closed" && - aDocument.commandDispatcher.focusedElement == aNode + aDocument.commandDispatcher.focusedElement == aNode.inputField ) { - let filterBar = aDocument.getElementById("quick-filter-bar"); - // panel.sizeTo(filterBar.clientWidth - 20, filterBar.clientHeight - 20); - panel.openPopup(filterBar, "after_end", -7, 7, false, true); + panel.openPopup( + aDocument.getElementById("quick-filter-bar"), + "after_end", + -7, + 7, + false, + true + ); } return; } // Make sure we have no visible upsell on state change while our textbox - // retains focus. - let panel = aDocument.getElementById("qfb-text-search-upsell"); + // retains focus. if (panel.state != "closed") { panel.hidePopup(); } // Update the text if it has changed (linux does weird things with empty - // text if we're transitioning emptytext to emptytext) + // text if we're transitioning emptytext to emptytext). let desiredValue = aFilterValue.text || ""; if (aNode.value != desiredValue) { aNode.value = desiredValue; } - // Update our expando buttons + // Update our expanded filters buttons. let states = aFilterValue.states; for (let name in this.textFilterDefs) { let textFilter = this.textFilterDefs[name]; @@ -1245,7 +1250,7 @@ states[textFilter.name]; } - // Show the expando? + // Toggle the expanded filters visibility. aDocument.getElementById("quick-filter-bar-filter-text-bar").collapsed = aFilterValue.text == null; }, diff -Nru thunderbird-78.5.0+build3/comm/mail/base/modules/SearchSpec.jsm thunderbird-78.7.1+build1/comm/mail/base/modules/SearchSpec.jsm --- thunderbird-78.5.0+build3/comm/mail/base/modules/SearchSpec.jsm 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/base/modules/SearchSpec.jsm 2021-02-05 18:23:40.000000000 +0000 @@ -464,11 +464,14 @@ } } } - // If both scopes work, honor the onlineSearch request, unless we're - // filtering (quick search and/or a view selected). + // If both scopes work, honor the onlineSearch request, for saved search folders (!filtering) + // and the search dialog (!displayedFolder). // If only one works, use it. Otherwise, default to offline if (onlineAvailable && offlineAvailable) { - scope = !filtering && this.onlineSearch ? serverScope : offlineScope; + scope = + (!filtering || !this.owner.displayedFolder) && this.onlineSearch + ? serverScope + : offlineScope; } else if (onlineAvailable) { scope = serverScope; } else { diff -Nru thunderbird-78.5.0+build3/comm/mail/base/modules/ThemeVariableMap.jsm thunderbird-78.7.1+build1/comm/mail/base/modules/ThemeVariableMap.jsm --- thunderbird-78.5.0+build3/comm/mail/base/modules/ThemeVariableMap.jsm 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/base/modules/ThemeVariableMap.jsm 2021-02-05 18:23:40.000000000 +0000 @@ -4,6 +4,22 @@ var EXPORTED_SYMBOLS = ["ThemeVariableMap", "ThemeContentPropertyList"]; +var { AppConstants } = ChromeUtils.import( + "resource://gre/modules/AppConstants.jsm" +); + +var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); + +// A cache of the current sidebar color to avoid unnecessary conditions and +// luminance calculations. +var kSidebarColorCache = null; + +function parseRGB(aColorString) { + let rgb = aColorString.match(/^rgba?\((\d+), (\d+), (\d+)/); + rgb.shift(); + return rgb.map(x => parseInt(x)); +} + const ThemeVariableMap = [ [ "--lwt-accent-color-inactive", @@ -159,6 +175,42 @@ if (!rgbaChannels) { element.removeAttribute("lwt-tree"); element.removeAttribute("lwt-tree-brighttext"); + + // On Linux, the default theme picks up the right colors from GTK + // themes, but in the case of a dark GTK theme, we need to detect the + // text luminance to properly update the attributes. + if ( + AppConstants.platform == "linux" && + Services.prefs.getCharPref("extensions.activeThemeID", "") == + "default-theme@mozilla.org" + ) { + let sidebarColor = element.ownerGlobal.getComputedStyle(element) + .color; + + // Interrupt if the sidebar color didn't change. + if (sidebarColor == kSidebarColorCache) { + return null; + } + + kSidebarColorCache = sidebarColor; + + // We need to force a light theme before removing the pref in order + // to deal with the issue of the Default Theme not triggering any + // color update. We remove the pref to run our conditions on a + // clean state. + Services.prefs.setIntPref("ui.systemUsesDarkTheme", 0); + Services.prefs.clearUserPref("ui.systemUsesDarkTheme"); + + let [r, g, b] = parseRGB(sidebarColor); + let luminance = 0.2125 * r + 0.7154 * g + 0.0721 * b; + + // If the sidebar text color is light, we need to force a dark UI. + if (luminance > 110) { + element.setAttribute("lwt-tree-brighttext", "true"); + Services.prefs.setIntPref("ui.systemUsesDarkTheme", 1); + } + } + return null; } @@ -196,6 +248,12 @@ lwtProperty: "sidebar_border", }, ], + [ + "--sidebar-highlight-border-color", + { + lwtProperty: "sidebar_highlight_border", + }, + ], ]; const ThemeContentPropertyList = [ diff -Nru thunderbird-78.5.0+build3/comm/mail/components/accountcreation/content/createInBackend.js thunderbird-78.7.1+build1/comm/mail/components/accountcreation/content/createInBackend.js --- thunderbird-78.5.0+build3/comm/mail/components/accountcreation/content/createInBackend.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/components/accountcreation/content/createInBackend.js 2021-02-05 18:23:40.000000000 +0000 @@ -94,8 +94,14 @@ // STARTTLS inServer.socketType = Ci.nsMsgSocketType.alwaysSTARTTLS; } - // inServer.prettyName = config.displayName; - inServer.prettyName = config.identity.emailAddress; + + // If we already have an account with an identical name, generate a unique + // name for the new account to avoid duplicates. + inServer.prettyName = checkAccountNameAlreadyExists( + config.identity.emailAddress + ) + ? generateUniqueAccountName(config) + : config.identity.emailAddress; inServer.doBiff = true; inServer.biffMinutes = config.incoming.checkInterval; @@ -386,6 +392,46 @@ } /** + * Check whether the user's setup already has an account with the same email + * address. This might happen if the user uses the same email for different + * protocols (eg. IMAP and POP3). + * + * @param {string} name - The name or email address of the new account. + * @returns {boolean} True if an account with the same name is found. + */ +function checkAccountNameAlreadyExists(name) { + return MailServices.accounts.accounts.some( + a => a.incomingServer.prettyName == name + ); +} + +/** + * Generate a unique account name by appending the incoming protocol type, and + * a counter if necessary. + * + * @param {AccountConfig} config - The config data of the account being created. + * @returns {string} - The unique account name. + */ +function generateUniqueAccountName(config) { + // Generate a potential unique name. e.g. "foo@bar.com (POP3)". + let name = `${ + config.identity.emailAddress + } (${config.incoming.type.toUpperCase()})`; + + // If this name already exists, append a counter until we find a unique name. + if (checkAccountNameAlreadyExists(name)) { + let counter = 2; + while (checkAccountNameAlreadyExists(`${name}_${counter}`)) { + counter++; + } + // e.g. "foo@bar.com (POP3)_1". + name = `${name}_${counter}`; + } + + return name; +} + +/** * Check if there already is a "Local Folders". If not, create it. * Copied from AccountWizard.js with minor updates. */ diff -Nru thunderbird-78.5.0+build3/comm/mail/components/accountcreation/content/emailWizard.xhtml thunderbird-78.7.1+build1/comm/mail/components/accountcreation/content/emailWizard.xhtml --- thunderbird-78.5.0+build3/comm/mail/components/accountcreation/content/emailWizard.xhtml 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/components/accountcreation/content/emailWizard.xhtml 2021-02-05 18:23:40.000000000 +0000 @@ -24,7 +24,6 @@ title="&emailWizard.title;" onload="gEmailConfigWizard.onLoad();" onkeypress="gEmailConfigWizard.onKeyDown(event);" - onclose="gEmailConfigWizard.onWizardShutdown();" onunload="gEmailConfigWizard.onWizardShutdown();" lightweightthemes="true"> diff -Nru thunderbird-78.5.0+build3/comm/mail/components/accountcreation/content/exchangeAutoDiscover.js thunderbird-78.7.1+build1/comm/mail/components/accountcreation/content/exchangeAutoDiscover.js --- thunderbird-78.5.0+build3/comm/mail/components/accountcreation/content/exchangeAutoDiscover.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/components/accountcreation/content/exchangeAutoDiscover.js 2021-02-05 18:23:40.000000000 +0000 @@ -99,6 +99,7 @@ readAutoDiscoverResponse( xml, successive, + emailAddress, username, password, config => { @@ -235,6 +236,7 @@ function readAutoDiscoverResponse( autoDiscoverXML, successive, + emailAddress, username, password, successCallback, @@ -246,12 +248,12 @@ // redirect to other email address if ( - "Action" in autoDiscoverXML.Autodiscover.Response && - "Redirect" in autoDiscoverXML.Autodiscover.Response.Action + "Account" in autoDiscoverXML.Autodiscover.Response && + "RedirectAddr" in autoDiscoverXML.Autodiscover.Response.Account ) { - // + // let redirectEmailAddress = sanitize.emailAddress( - autoDiscoverXML.Autodiscover.Response.Action.Redirect + autoDiscoverXML.Autodiscover.Response.Account.RedirectAddr ); let domain = redirectEmailAddress.split("@").pop(); if (++gLoopCounter > 2) { @@ -260,11 +262,14 @@ successive.current = fetchConfigFromExchange( domain, redirectEmailAddress, - username, + // Per spec, need to authenticate with the original email address, + // not the redirected address (if not already overridden). + username || emailAddress, password, successCallback, errorCallback ); + return; } let config = readAutoDiscoverXML(autoDiscoverXML, username); diff -Nru thunderbird-78.5.0+build3/comm/mail/components/accountcreation/content/sanitizeDatatypes.js thunderbird-78.7.1+build1/comm/mail/components/accountcreation/content/sanitizeDatatypes.js --- thunderbird-78.5.0+build3/comm/mail/components/accountcreation/content/sanitizeDatatypes.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/components/accountcreation/content/sanitizeDatatypes.js 2021-02-05 18:23:40.000000000 +0000 @@ -113,6 +113,19 @@ return str.toLowerCase(); }, + + /** + * A value which resembles an email address. + */ + emailAddress(unchecked) { + let str = this.nonemptystring(unchecked); + if (!/^[a-z0-9\-%+_\.\*]+@[a-z0-9\-\.]+\.[a-z]+$/i.test(str)) { + throw new MalformedException("emailaddress_syntax.error", unchecked); + } + + return str.toLowerCase(); + }, + /** * A non-chrome URL that's safe to request. */ diff -Nru thunderbird-78.5.0+build3/comm/mail/components/activity/content/activity-widgets.js thunderbird-78.7.1+build1/comm/mail/components/activity/content/activity-widgets.js --- thunderbird-78.5.0+build3/comm/mail/components/activity/content/activity-widgets.js 2020-11-18 16:45:13.000000000 +0000 +++ thunderbird-78.7.1+build1/comm/mail/components/activity/content/activity-widgets.js 2021-02-05 18:23:40.000000000 +0000 @@ -611,7 +611,7 @@