--HG--
rename : mail/base/content/mainPopupSet.inc.xhtml => mail/base/content/widgets/browserPopups.inc.xhtml
This commit is contained in:
Geoff Lankow 2022-11-30 11:46:28 +13:00
Родитель a0314f254f dc6adef1ae
Коммит a5e68baacf
48 изменённых файлов: 595 добавлений и 771 удалений

Просмотреть файл

@ -79,7 +79,6 @@ module.exports = {
"import/named": "error",
"import/namespace": "error",
"import/newline-after-import": "error",
"import/no-anonymous-default-export": "error",
"import/no-duplicates": "error",
"import/no-absolute-path": "error",
"import/no-named-default": "error",
@ -96,6 +95,12 @@ module.exports = {
"import/no-useless-path-segments": "error",
},
},
{
files: ["mail/components/storybook/**"],
rules: {
"import/no-unresolved": "off",
},
},
{
...removeOverrides(xpcshellTestConfig),
files: xpcshellTestPaths.map(path => `${path}**`),

Просмотреть файл

@ -2,4 +2,5 @@ pth:comm/testing/marionette
pth:comm/python/l10n
pth:comm/python/mach
pth:comm/taskcluster
pth:comm/python/rocbuild
pth:comm/python/thirdroc

Просмотреть файл

@ -6,7 +6,9 @@
pref("mailnews.start_page.url", "https://live.thunderbird.net/%APP%/start?locale=%LOCALE%&version=%VERSION%&channel=%CHANNEL%&os=%OS%&buildid=%APPBUILDID%");
// start page override to load after an update
pref("mailnews.start_page.override_url", "https://live.thunderbird.net/%APP%/whatsnew?locale=%LOCALE%&version=%VERSION%&channel=%CHANNEL%&os=%OS%&buildid=%APPBUILDID%&oldversion=%OLD_VERSION%");
// pref("mailnews.start_page.override_url", "https://live.thunderbird.net/%APP%/whatsnew?locale=%LOCALE%&version=%VERSION%&channel=%CHANNEL%&os=%OS%&buildid=%APPBUILDID%&oldversion=%OLD_VERSION%");
// Leave blank per bug 1695529 until the website has a proper "Thunderbird Daily" landing page
pref("mailnews.start_page.override_url", "");
// There's no Thunderbird Daily specific page or release notes
// URL user can browse to manually if for some reason all update installation

Просмотреть файл

@ -176,10 +176,10 @@
<vbox id="contextPaneFlexibleBox" flex="1">
<vbox flex="1" class="conv-chat" width="150">
<hbox align="baseline" class="conv-nicklist-header input-container">
<label id="participantLabel"
class="conv-nicklist-header-label"
<label class="conv-nicklist-header-label conv-header-label"
control="participantCount"
value="&chat.participants;"/>
value="&chat.participants;"
crop="end"/>
<html:input id="participantCount" readonly="readonly" class="plain"/>
</hbox>
<richlistbox id="nicklist" class="conv-nicklist"
@ -191,8 +191,8 @@
</vbox>
<splitter id="logsSplitter" class="conv-chat" collapse="after" orient="vertical"/>
<vbox flex="1" id="previousConversations" style="min-height: 200px;">
<label class="conv-logs-header-label"
id="participantLabel"
<label class="conv-logs-header-label conv-header-label"
crop="end"
value="&chat.previousConversations;"/>
<tree id="logTree" flex="1" hidecolumnpicker="true" seltype="single"
context="logTreeContext" onselect="chatHandler.onLogSelect();">

Просмотреть файл

@ -1,8 +0,0 @@
/* 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/. */
module.exports = {
parserOptions: {
sourceType: "module",
},
};

Просмотреть файл

@ -11,7 +11,7 @@ const path = require("path");
module.exports = {
stories: [
"../stories/**/*.stories.mdx",
"../stories/**/*.stories.@(js|jsx|ts|tsx)",
"../stories/**/*.stories.@(mjs|jsx|ts|tsx)",
],
addons: ["@storybook/addon-links", "@storybook/addon-essentials"],
framework: "@storybook/web-components",

Просмотреть файл

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { html } from "lit";
import "mail/themes/shared/mail/colors.css";
import "mail/themes/shared/mail/colors.css"; //eslint-disable-line import/no-unassigned-import
const FORMATTER = new Intl.NumberFormat("en", {
numberingSystem: "latn",

Просмотреть файл

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { html } from "lit";
import "mail/base/content/widgets/pane-splitter.js";
import "mail/base/content/widgets/pane-splitter.js"; //eslint-disable-line import/no-unassigned-import
export default {
title: "Widgets/Pane Splitter",

Просмотреть файл

@ -106,11 +106,9 @@ pref("temp.openpgp.inlineSigAttachExt", ".sig");
// debug log directory (if set, also enabled debugging)
pref("temp.openpgp.logDirectory", "");
// list of key servers to use (comma separated list)
pref("temp.openpgp.keyserver", "vks://keys.openpgp.org");
// auto select the first keyserver in the key server list
pref("temp.openpgp.autoKeyServerSelection", true);
// List of key servers to use (comma separated list), ordered by priority.
// Only the first supported keyserver will be used for uploading keys.
pref("mail.openpgp.keyserver_list", "vks://keys.openpgp.org, hkps://keys.mailvelope.com");
// keep passphrase for ... minutes
pref("temp.openpgp.maxIdleMinutes", 5);
@ -194,9 +192,6 @@ pref("temp.openpgp.warnDeprecatedGnuPG", true);
// warn if gpg-agent is found and "remember passphrase for X minutes is active"
pref("temp.openpgp.warnGpgAgentAndIdleTime", true);
// display a warning when all keys are to be refreshed
pref("temp.openpgp.warnRefreshAll", true);
// display a warning when the keys for all contacts are downloaded
pref("temp.openpgp.warnDownloadContactKeys", true);
@ -218,21 +213,6 @@ pref("temp.openpgp.searchKeyWithTor", false);
pref("temp.openpgp.searchKeyRequireTor", false);
pref("temp.openpgp.uploadKeyWithTor", false);
pref("temp.openpgp.uploadKeyRequireTor", false);
pref("temp.openpgp.refreshAllKeysWithTor", false);
pref("temp.openpgp.refreshAllKeysRequireTor", false);
// Hours per week that Enigmail is available for refreshing keys
// The smaller the hours available, the more often the refresh
// will happen to accommodate.
pref("temp.openpgp.hoursPerWeekEnigmailIsOn", 40);
// The minimum number of seconds to wait between refreshing keys.
// Applied if the refresh frequence from hoursPerWeekEnigmailIsOn
// goes too low
pref("temp.openpgp.refreshMinDelaySeconds", 300);
// Toggle to have user keys continuously refreshed
pref("temp.openpgp.keyRefreshOn", false);
// enable experimental features.
// WARNING: such features may unfinished functions or tests that can break

Просмотреть файл

@ -129,8 +129,6 @@ Enigmail.prototype = {
return;
}
//getEnigmailKeyRefreshService().start(getEnigmailKeyServer());
this.initialized = true;
lazy.EnigmailLog.DEBUG("core.jsm: Enigmail.initialize: END\n");

Просмотреть файл

@ -241,12 +241,13 @@ var EnigmailEncryption = {
},
/**
* Determine if the sender key ID or user ID can be used for signing and/or encryption
* Determine if the sender key ID or user ID can be used for signing and/or
* encryption
*
* @param sendFlags: Number - the send Flags; need to contain SEND_SIGNED and/or SEND_ENCRYPTED
* @param fromKeyId: String - the sender key ID
* @param {integer} sendFlags - The send Flags; need to contain SEND_SIGNED and/or SEND_ENCRYPTED
* @param {string} fromKeyId - The sender key ID
*
* @returns Object:
* @returns {object} object
* - keyId: String - the found key ID, or null if fromMailAddr is not valid
* - errorMsg: String - the error message if key not valid, or null if key is valid
*/

Просмотреть файл

@ -48,92 +48,119 @@ var KeyLookupHelper = {
* @returns {boolean} flags.foundUnchanged - All found keys are identical to already existing local keys.
* @returns {boolean} flags.collectedForLater - At least one key was added to CollectedKeysDB.
*/
isExpiredOrRevoked(keyTrust) {
return keyTrust.match(/e/i) || keyTrust.match(/r/i);
},
async _lookupAndImportOnKeyserver(mode, window, identifier) {
let keyImported = false;
let foundUpdated = false;
let foundUnchanged = false;
let collectedForLater = false;
let defKs = lazy.EnigmailKeyserverURIs.getDefaultKeyServer();
if (!defKs) {
let ksArray = lazy.EnigmailKeyserverURIs.getKeyServers();
if (!ksArray.length) {
return false;
}
let vks = await lazy.EnigmailKeyServer.downloadNoImport(identifier, defKs);
if (vks && "keyData" in vks) {
let errorInfo = {};
let keyList = await lazy.EnigmailKey.getKeyListFromKeyBlock(
vks.keyData,
errorInfo,
false,
true,
false
);
// We might get a zero length keyList, if we refuse to use the key
// that we received because of its properties.
if (keyList && keyList.length == 1) {
let oldKey = lazy.EnigmailKeyRing.getKeyById(keyList[0].fpr);
if (oldKey) {
await lazy.EnigmailKeyRing.importKeyDataSilent(
window,
vks.keyData,
true,
"0x" + keyList[0].fpr
);
let updatedKey = lazy.EnigmailKeyRing.getKeyById(keyList[0].fpr);
// If new imported/merged key is equal to old key,
// don't notify about new keys details.
if (JSON.stringify(oldKey) !== JSON.stringify(updatedKey)) {
foundUpdated = true;
keyImported = true;
if (mode == "interactive-import") {
lazy.EnigmailDialog.keyImportDlg(
window,
keyList.map(a => a.id)
);
}
} else {
foundUnchanged = true;
}
} else {
keyList = keyList.filter(k => k.userIds.length);
if (keyList.length && mode == "interactive-import") {
keyImported = await lazy.EnigmailKeyRing.importKeyDataWithConfirmation(
window,
keyList,
vks.keyData,
true
);
}
if (!keyImported) {
collectedForLater = true;
let db = await lazy.CollectedKeysDB.getInstance();
for (let newKey of keyList) {
// If key is known in the db: merge + update.
let key = await db.mergeExisting(newKey, vks.keyData, {
uri: lazy.EnigmailKeyServer.serverReqURL(
`0x${newKey.fpr}`,
defKs
),
type: "keyserver",
});
await db.storeKey(key);
}
}
}
} else {
if (keyList.length > 1) {
throw new Error(
"Unexpected multiple results from verifying keyserver."
);
}
console.debug(
"failed to process data retrieved from keyserver: " + errorInfo.value
let continueSearching = true;
for (let ks of ksArray) {
let foundKey;
if (ks.startsWith("vks://")) {
foundKey = await lazy.EnigmailKeyServer.downloadNoImport(
identifier,
ks
);
} else if (ks.startsWith("hkp://") || ks.startsWith("hkps://")) {
foundKey = await lazy.EnigmailKeyServer.searchAndDownloadSingleResultNoImport(
identifier,
ks
);
}
} else {
console.debug("searchKeysOnInternet no data found on keyserver");
if (foundKey && "keyData" in foundKey) {
let errorInfo = {};
let keyList = await lazy.EnigmailKey.getKeyListFromKeyBlock(
foundKey.keyData,
errorInfo,
false,
true,
false
);
// We might get a zero length keyList, if we refuse to use the key
// that we received because of its properties.
if (keyList && keyList.length == 1) {
let oldKey = lazy.EnigmailKeyRing.getKeyById(keyList[0].fpr);
if (oldKey) {
await lazy.EnigmailKeyRing.importKeyDataSilent(
window,
foundKey.keyData,
true,
"0x" + keyList[0].fpr
);
let updatedKey = lazy.EnigmailKeyRing.getKeyById(keyList[0].fpr);
// If new imported/merged key is equal to old key,
// don't notify about new keys details.
if (JSON.stringify(oldKey) !== JSON.stringify(updatedKey)) {
foundUpdated = true;
keyImported = true;
if (mode == "interactive-import") {
lazy.EnigmailDialog.keyImportDlg(
window,
keyList.map(a => a.id)
);
}
} else {
foundUnchanged = true;
}
} else {
keyList = keyList.filter(k => k.userIds.length);
keyList = keyList.filter(k => !this.isExpiredOrRevoked(k.keyTrust));
if (keyList.length && mode == "interactive-import") {
keyImported = await lazy.EnigmailKeyRing.importKeyDataWithConfirmation(
window,
keyList,
foundKey.keyData,
true
);
if (keyImported) {
// In interactive mode, don't offer the user to import keys multiple times.
// When silently collecting keys, it's fine to discover everything we can.
continueSearching = false;
}
}
if (!keyImported) {
collectedForLater = true;
let db = await lazy.CollectedKeysDB.getInstance();
for (let newKey of keyList) {
// If key is known in the db: merge + update.
let key = await db.mergeExisting(newKey, foundKey.keyData, {
uri: lazy.EnigmailKeyServer.serverReqURL(
`0x${newKey.fpr}`,
ks
),
type: "keyserver",
});
await db.storeKey(key);
}
}
}
} else {
if (keyList && keyList.length > 1) {
throw new Error("Unexpected multiple results from keyserver " + ks);
}
console.log(
"failed to process data retrieved from keyserver " +
ks +
": " +
errorInfo.value
);
}
}
if (!continueSearching) {
break;
}
}
return { keyImported, foundUpdated, foundUnchanged, collectedForLater };
@ -269,6 +296,7 @@ var KeyLookupHelper = {
wkdKeyImported = true;
}
newKeys = newKeys.filter(k => !this.isExpiredOrRevoked(k.keyTrust));
if (newKeys.length && mode == "interactive-import") {
wkdKeyImported =
wkdKeyImported ||

Просмотреть файл

@ -1,176 +0,0 @@
/*
* 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 https://mozilla.org/MPL/2.0/.
*/
"use strict";
const EXPORTED_SYMBOLS = ["EnigmailKeyRefreshService"];
const { XPCOMUtils } = ChromeUtils.importESModule(
"resource://gre/modules/XPCOMUtils.sys.mjs"
);
const lazy = {};
XPCOMUtils.defineLazyModuleGetters(lazy, {
EnigmailKeyRing: "chrome://openpgp/content/modules/keyRing.jsm",
EnigmailKeyServer: "chrome://openpgp/content/modules/keyserver.jsm",
EnigmailKeyserverURIs: "chrome://openpgp/content/modules/keyserverUris.jsm",
EnigmailLog: "chrome://openpgp/content/modules/log.jsm",
});
const ONE_HOUR_IN_MILLISEC = 60 * 60 * 1000;
let gTimer = null;
function getTimer() {
if (gTimer === null) {
gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
}
return gTimer;
}
function calculateMaxTimeForRefreshInMilliseconds(totalPublicKeys) {
const millisecondsAvailableForRefresh =
Services.prefs.getIntPref("temp.openpgp.hoursPerWeekEnigmailIsOn") *
ONE_HOUR_IN_MILLISEC;
return Math.floor(millisecondsAvailableForRefresh / totalPublicKeys);
}
function calculateWaitTimeInMilliseconds(totalPublicKeys) {
const randomNumber = crypto.getRandomValues(new Uint32Array(1));
const maxTimeForRefresh = calculateMaxTimeForRefreshInMilliseconds(
totalPublicKeys
);
const minDelay =
Services.prefs.getIntPref("temp.openpgp.refreshMinDelaySeconds") * 1000;
lazy.EnigmailLog.DEBUG(
"keyRefreshService.jsm: Wait time = random number: " +
randomNumber +
" % max time for refresh: " +
maxTimeForRefresh +
"\n"
);
let millisec = randomNumber % maxTimeForRefresh;
if (millisec < minDelay) {
millisec += minDelay;
}
lazy.EnigmailLog.DEBUG(
"keyRefreshService.jsm: Time until next refresh in milliseconds: " +
millisec +
"\n"
);
return millisec;
}
function refreshKey() {
const timer = getTimer();
refreshWith(lazy.EnigmailKeyServer, timer, true);
}
function restartTimerInOneHour(timer) {
timer.initWithCallback(
refreshKey,
ONE_HOUR_IN_MILLISEC,
Ci.nsITimer.TYPE_ONE_SHOT
);
}
function setupNextRefresh(timer, waitTime) {
timer.initWithCallback(refreshKey, waitTime, Ci.nsITimer.TYPE_ONE_SHOT);
}
function logMissingInformation(keyIdsExist, validKeyserversExist) {
if (!keyIdsExist) {
lazy.EnigmailLog.DEBUG(
"keyRefreshService.jsm: No keys available to refresh yet. Will recheck in an hour.\n"
);
}
if (!validKeyserversExist) {
lazy.EnigmailLog.DEBUG(
"keyRefreshService.jsm: Either no keyservers exist or the protocols specified are invalid. Will recheck in an hour.\n"
);
}
}
function getRandomKeyId(randomNumber) {
const keyRingLength = lazy.EnigmailKeyRing.getAllKeys().keyList.length;
if (keyRingLength === 0) {
return null;
}
return lazy.EnigmailKeyRing.getAllKeys().keyList[randomNumber % keyRingLength]
.keyId;
}
function refreshKeyIfReady(keyserver, readyToRefresh, keyId) {
if (readyToRefresh) {
lazy.EnigmailLog.DEBUG(
"keyRefreshService.jsm: refreshing key ID " + keyId + "\n"
);
return keyserver.download(keyId);
}
return Promise.resolve(0);
}
async function refreshWith(keyserver, timer, readyToRefresh) {
const keyId = getRandomKeyId(crypto.getRandomValues(new Uint32Array(1)));
const keyIdsExist = keyId !== null;
const validKeyserversExist = lazy.EnigmailKeyserverURIs.validKeyserversExist();
const ioService = Services.io;
if (keyIdsExist && validKeyserversExist) {
if (ioService && !ioService.offline) {
// don't try to refresh if we are offline
await refreshKeyIfReady(keyserver, readyToRefresh, keyId);
} else {
lazy.EnigmailLog.DEBUG(
"keyRefreshService.jsm: offline - not refreshing any key\n"
);
}
const waitTime = calculateWaitTimeInMilliseconds(
lazy.EnigmailKeyRing.getAllKeys().keyList.length
);
setupNextRefresh(timer, waitTime);
} else {
logMissingInformation(keyIdsExist, validKeyserversExist);
restartTimerInOneHour(timer);
}
}
/**
* Starts a process to continuously refresh keys on a random time interval and in random order.
*
* The default time period for all keys to be refreshed is one week, although the user can specifically set this in their preferences
* The wait time to refresh the next key is selected at random, from a range of zero milliseconds to the maximum time to refresh a key
*
* The maximum time to refresh a single key is calculated by averaging the total refresh time by the total number of public keys to refresh
* For example, if a user has 12 public keys to refresh, the maximum time to refresh a single key (by default) will be: milliseconds per week divided by 12
*
* This service does not keep state, it will restart each time Enigmail is initialized.
*
* @param keyserver | dependency injected for testability
*/
function start(keyserver) {
if (Services.prefs.getBoolPref("temp.openpgp.keyRefreshOn")) {
lazy.EnigmailLog.DEBUG("keyRefreshService.jsm: Started\n");
const timer = getTimer();
refreshWith(keyserver, timer, false);
}
}
/*
This module initializes the continuous key refresh functionality. This includes randomly selecting th key to refresh and the timing to wait between each refresh
*/
var EnigmailKeyRefreshService = {
start,
};

Просмотреть файл

@ -141,22 +141,20 @@ const accessHkpInternal = {
*/
async buildHkpPayload(actionFlag, searchTerms) {
switch (actionFlag) {
/*
case EnigmailConstants.UPLOAD_KEY:
let keyData = await EnigmailKeyRing.extractPublicKeys(
searchTerms, // TODO: confirm input is ID or fingerprint
case lazy.EnigmailConstants.UPLOAD_KEY:
let exitCodeObj = {};
let keyData = await lazy.EnigmailKeyRing.extractPublicKeys(
["0x" + searchTerms], // TODO: confirm input is ID or fingerprint
null,
null,
{},
null,
exitCodeObj,
{}
);
if (keyData.length === 0) {
if (exitCodeObj.value !== 0 || keyData.length === 0) {
return null;
}
let payLoad = "keytext=" + encodeURIComponent(keyData);
return payLoad;
*/
return 'keytext="' + encodeURIComponent(keyData) + '"';
case lazy.EnigmailConstants.DOWNLOAD_KEY:
case lazy.EnigmailConstants.DOWNLOAD_KEY_NO_IMPORT:
@ -205,7 +203,7 @@ const accessHkpInternal = {
url +=
"/pks/lookup?search=" +
escape(searchTerm) +
"&fingerprint=on&op=index&options=mr";
"&fingerprint=on&op=index&options=mr&exact=on";
}
return {
@ -312,23 +310,31 @@ const accessHkpInternal = {
} else {
let errorMsgObj = {},
importedKeysObj = {};
let importMinimal = false;
let r = lazy.EnigmailKeyRing.importKey(
null,
false,
xmlReq.responseText,
false,
"",
errorMsgObj,
importedKeysObj,
importMinimal
);
if (r === 0) {
resolve(importedKeysObj.value);
} else {
reject(
createError(lazy.EnigmailConstants.KEYSERVER_ERR_IMPORT_ERROR)
if (actionFlag === lazy.EnigmailConstants.DOWNLOAD_KEY) {
let importMinimal = false;
let r = lazy.EnigmailKeyRing.importKey(
null,
false,
xmlReq.responseText,
false,
"",
errorMsgObj,
importedKeysObj,
importMinimal
);
if (r === 0) {
resolve(importedKeysObj.value);
} else {
reject(
createError(
lazy.EnigmailConstants.KEYSERVER_ERR_IMPORT_ERROR
)
);
}
} else {
// DOWNLOAD_KEY_NO_IMPORT
resolve(xmlReq.responseText);
}
}
return;
@ -415,8 +421,14 @@ const accessHkpInternal = {
keyIdArr[i],
listener
);
if (Array.isArray(r)) {
retObj.keyList = retObj.keyList.concat(r);
if (autoImport) {
if (Array.isArray(r)) {
retObj.keyList = retObj.keyList.concat(r);
}
} else if (typeof r == "string") {
retObj.keyData = r;
} else {
retObj.result = r;
}
} catch (ex) {
retObj.result = ex.result;
@ -449,18 +461,14 @@ const accessHkpInternal = {
* @param keyserver: String - keyserver URL (optionally incl. protocol)
* @param listener: optional Object implementing the KeySrvListener API (above)
*
* @return: Promise<...>
* @return {boolean} - Returns true if the key was sent successfully
*/
async upload(keyIDs, keyserver, listener = null) {
lazy.EnigmailLog.DEBUG(
`keyserver.jsm: accessHkpInternal.upload(${keyIDs})\n`
);
let keyIdArr = keyIDs.split(/ +/);
let retObj = {
result: 0,
errorDetails: "",
keyList: [],
};
let rv = false;
for (let i = 0; i < keyIdArr.length; i++) {
try {
@ -471,14 +479,15 @@ const accessHkpInternal = {
listener
);
if (r === 0) {
retObj.keyList.push(keyIdArr[i]);
rv = true;
} else {
retObj.result = r;
rv = false;
break;
}
} catch (ex) {
retObj.result = ex.result;
retObj.errorDetails = ex.errorDetails;
throw retObj;
console.log(ex.errorDetails);
rv = false;
break;
}
if (listener && "onProgress" in listener) {
@ -486,7 +495,7 @@ const accessHkpInternal = {
}
}
return retObj;
return rv;
},
/**
@ -626,7 +635,7 @@ const accessKeyBase = {
*
* @return: Promise<Number (Status-ID)>
*/
accessKeyServer(actionFlag, keyId, listener) {
async accessKeyServer(actionFlag, keyId, listener) {
lazy.EnigmailLog.DEBUG(`keyserver.jsm: accessKeyBase: accessKeyServer()\n`);
return new Promise((resolve, reject) => {
@ -668,7 +677,7 @@ const accessKeyBase = {
case lazy.EnigmailConstants.DOWNLOAD_KEY_NO_IMPORT:
if (xmlReq.status >= 400 && xmlReq.status < 500) {
// key not found
resolve([]);
resolve(1);
} else if (xmlReq.status >= 500) {
lazy.EnigmailLog.DEBUG(
"keyserver.jsm: onload: " + xmlReq.responseText + "\n"
@ -679,8 +688,6 @@ const accessKeyBase = {
} else {
try {
let resp = JSON.parse(xmlReq.responseText);
let imported = [];
if (resp.status.code === 0) {
for (let hit in resp.them) {
lazy.EnigmailLog.DEBUG(
@ -690,22 +697,33 @@ const accessKeyBase = {
if (resp.them[hit] !== null) {
let errorMsgObj = {},
importedKeysObj = {};
let r = lazy.EnigmailKeyRing.importKey(
null,
false,
resp.them[hit].public_keys.primary.bundle,
false,
"",
errorMsgObj,
importedKeysObj
);
if (r === 0) {
imported.push(importedKeysObj.value);
if (actionFlag === lazy.EnigmailConstants.DOWNLOAD_KEY) {
let r = lazy.EnigmailKeyRing.importKey(
null,
false,
resp.them[hit].public_keys.primary.bundle,
false,
"",
errorMsgObj,
importedKeysObj
);
if (r === 0) {
resolve(importedKeysObj.value);
} else {
reject(
createError(
lazy.EnigmailConstants.KEYSERVER_ERR_IMPORT_ERROR
)
);
}
} else {
// DOWNLOAD_KEY_NO_IMPORT
resolve(resp.them[hit].public_keys.primary.bundle);
}
}
}
}
resolve(imported);
} catch (ex) {
reject(
createError(lazy.EnigmailConstants.KEYSERVER_ERR_UNKNOWN)
@ -924,32 +942,30 @@ const accessVksServer = {
*/
async buildJsonPayload(actionFlag, searchTerms, locale) {
switch (actionFlag) {
/*
case EnigmailConstants.UPLOAD_KEY:
let keyData = await EnigmailKeyRing.extractPublicKeys(
searchTerms, // must be id or fingerprint
case lazy.EnigmailConstants.UPLOAD_KEY:
let exitCodeObj = {};
let keyData = await lazy.EnigmailKeyRing.extractPublicKeys(
["0x" + searchTerms], // must be id or fingerprint
null,
null,
{},
null,
exitCodeObj,
{}
);
if (keyData.length === 0) {
if (exitCodeObj.value !== 0 || keyData.length === 0) {
return null;
}
let payLoad = JSON.stringify({
return JSON.stringify({
keytext: keyData,
});
return payLoad;
*/
case lazy.EnigmailConstants.GET_CONFIRMATION_LINK:
let payLoad = JSON.stringify({
return JSON.stringify({
token: searchTerms.token,
addresses: searchTerms.addresses,
locale: [locale],
});
return payLoad;
case lazy.EnigmailConstants.DOWNLOAD_KEY:
case lazy.EnigmailConstants.DOWNLOAD_KEY_NO_IMPORT:
@ -1301,27 +1317,22 @@ const accessVksServer = {
* @param keyserver: String - keyserver URL (optionally incl. protocol)
* @param listener: optional Object implementing the KeySrvListener API (above)
*
* @return: Promise<...>
* @return {boolean} - Returns true if the key was sent successfully
*/
async upload(keyIDs, keyserver, listener = null) {
lazy.EnigmailLog.DEBUG(
`keyserver.jsm: accessVksServer.upload(${keyIDs})\n`
);
let keyIdArr = keyIDs.split(/ +/);
let retObj = {
result: 0,
errorDetails: "",
keyList: [],
};
let rv = false;
for (let i = 0; i < keyIdArr.length; i++) {
let keyObj = lazy.EnigmailKeyRing.getKeyById(keyIdArr[i]);
if (!keyObj.secretAvailable) {
// VKS keyservers only accept uploading own keys
retObj.result = 1;
retObj.errorDetails = "NO_SECRET_KEY_AVAILABLE";
throw retObj;
throw new Error(
"public keyserver uploading supported only for user's own keys"
);
}
try {
@ -1332,20 +1343,18 @@ const accessVksServer = {
listener
);
if (typeof r === "string") {
retObj.keyList.push(keyIdArr[i]);
let req = await this.requestConfirmationLink(keyserver, r);
if (req >= 0) {
retObj.result = 0;
retObj.numEmails = req;
rv = true;
}
} else {
retObj.result = r;
rv = false;
break;
}
} catch (ex) {
retObj.result = ex.result;
retObj.errorDetails = ex.errorDetails;
throw retObj;
console.log(ex.errorDetails);
rv = false;
break;
}
if (listener && "onProgress" in listener) {
@ -1353,7 +1362,7 @@ const accessVksServer = {
}
}
return retObj;
return rv;
},
/**
@ -1449,12 +1458,12 @@ var EnigmailKeyServer = {
* Object: - result: Number - result Code (0 = OK),
* - keyList: Array of String - imported key FPR
*/
download(keyIDs, keyserver = null, listener) {
async download(keyIDs, keyserver = null, listener) {
let acc = getAccessType(keyserver);
return acc.download(true, keyIDs, keyserver, listener);
},
downloadNoImport(keyIDs, keyserver = null, listener) {
async downloadNoImport(keyIDs, keyserver = null, listener) {
let acc = getAccessType(keyserver);
return acc.download(false, keyIDs, keyserver, listener);
},
@ -1476,12 +1485,10 @@ var EnigmailKeyServer = {
* @param keyserver: String - keyserver URL (optionally incl. protocol)
* @param listener: optional Object implementing the KeySrvListener API (above)
*
* @return: Promise<Object>
* Object: - result: Number - result Code (0 = OK),
* - keyList: Array of String - imported key FPR
* @return {boolean} - Returns true if the key was sent successfully
*/
upload(keyIDs, keyserver = null, listener) {
async upload(keyIDs, keyserver = null, listener) {
let acc = getAccessType(keyserver);
return acc.upload(keyIDs, keyserver, listener);
},
@ -1504,11 +1511,32 @@ var EnigmailKeyServer = {
* - status: String: one of ''=valid, r=revoked, e=expired
* - uid: Array of Strings with UIDs
*/
searchKeyserver(searchString, keyserver = null, listener) {
async searchKeyserver(searchString, keyserver = null, listener) {
let acc = getAccessType(keyserver);
return acc.search(searchString, keyserver, listener);
},
async searchAndDownloadSingleResultNoImport(
searchString,
keyserver = null,
listener
) {
let acc = getAccessType(keyserver);
let searchResult = await acc.searchKeyserver(
searchString,
keyserver,
listener
);
if (searchResult.result != 0 || searchResult.pubKeys.length != 1) {
return null;
}
return this.downloadNoImport(
searchResult.pubKeys[0].keyId,
keyserver,
listener
);
},
/**
* Refresh all keys
*

Просмотреть файл

@ -8,137 +8,36 @@
const EXPORTED_SYMBOLS = ["EnigmailKeyserverURIs"];
const supportedProtocols = {
hkps: "443",
hkp: "11371",
ldap: "389",
};
function buildUriFor(protocol, keyserver) {
return {
protocol,
domain: keyserver,
port: supportedProtocols[protocol],
};
}
function addUriOptionsForPoolKeyservers(keyserver, uris) {
if (keyserver === "hkps.pool.sks-keyservers.net") {
uris.push(buildUriFor("hkps", keyserver));
}
if (keyserver === "pool.sks-keyservers.net") {
uris.push(buildUriFor("hkps", "hkps.pool.sks-keyservers.net"));
uris.push(buildUriFor("hkp", keyserver));
}
}
function buildUriOptionsFor(keyserver) {
const uris = [];
const keyserverProtocolAndDomain = keyserver.split("://");
const protocolIncluded = keyserverProtocolAndDomain.length === 2;
const isPoolKeyserver =
["hkps.pool.sks-keyservers.net", "pool.sks-keyservers.net"].indexOf(
keyserver
) > -1;
if (isPoolKeyserver) {
addUriOptionsForPoolKeyservers(keyserver, uris);
} else if (protocolIncluded) {
uris.push(
buildUriFor(
keyserverProtocolAndDomain[0].toLowerCase(),
keyserverProtocolAndDomain[1]
)
);
} else {
uris.push(buildUriFor("hkps", keyserver));
uris.push(buildUriFor("hkp", keyserver));
}
return uris;
}
function getDefaultKeyServer() {
function getKeyServers() {
let keyservers = Services.prefs
.getCharPref("temp.openpgp.keyserver")
.getCharPref("mail.openpgp.keyserver_list")
.split(/\s*[,;]\s*/g);
let defKs = keyservers[0];
// We don't have great code yet to handle multiple results,
// or poisoned results. So avoid SKS.
// Let's start with verifying keyservers, only, which return only
// one result.
if (!defKs.startsWith("vks://")) {
console.debug("Not using " + defKs + " in getDefaultKeyServer");
return null;
return keyservers.filter(
ks =>
ks.startsWith("vks://") ||
ks.startsWith("hkp://") ||
ks.startsWith("hkps://")
);
}
function getUploadKeyServer() {
let keyservers = Services.prefs
.getCharPref("mail.openpgp.keyserver_list")
.split(/\s*[,;]\s*/g);
for (let ks of keyservers) {
if (
!ks.startsWith("vks://") &&
!ks.startsWith("hkp://") &&
!ks.startsWith("hkps://")
) {
continue;
}
return ks;
}
return defKs;
}
function getUserDefinedKeyserverURIs() {
const keyservers = Services.prefs
.getCharPref("temp.openpgp.keyserver")
.split(/\s*[,;]\s*/g);
return Services.prefs.getCharPref("temp.openpgp.autoKeyServerSelection")
? [keyservers[0]]
: keyservers;
}
function combineIntoURI(protocol, domain, port) {
return protocol + "://" + domain + ":" + port;
}
function isValidProtocol(uri) {
return uri.match(/:\/\//) === null || /^(hkps|hkp|ldap):\/\//i.test(uri);
}
function validProtocolsExist() {
const validKeyserverUris = getUserDefinedKeyserverURIs().filter(
isValidProtocol
);
return validKeyserverUris.length > 0;
}
/**
* Construct the full URIs for making gpg requests.
* This takes the specified keyservers and adds the relevant protocol and port.
* When no specific protocol is defined by the user, 2 URIs will be built, for hkps and hkp.
*
* @returns array of all URIs to try refreshing keys over
*/
function buildKeyserverUris() {
const uris = getUserDefinedKeyserverURIs()
.filter(isValidProtocol)
.map(function(keyserver) {
return buildUriOptionsFor(keyserver);
})
.reduce(function(a, b) {
return a.concat(b);
});
return uris.map(function(uri) {
return combineIntoURI(uri.protocol, uri.domain, uri.port);
});
}
/**
* Checks if the keyservers specified are valid.
* Key refreshes will not be attempted without valid keyservers.
* A valid keyserver is one that is non-empty and consists of
* - the keyserverDomain
* - may include a protocol from hkps, hkp or ldap
* - may include the port
*
* @returns true if keyservers exist and are valid, false otherwise.
*/
function validKeyserversExist() {
return (
Services.prefs.getCharPref("temp.openpgp.keyserver").trim() !== "" &&
validProtocolsExist()
);
return null;
}
var EnigmailKeyserverURIs = {
getDefaultKeyServer,
buildKeyserverUris,
validKeyserversExist,
getKeyServers,
getUploadKeyServer,
};

Просмотреть файл

@ -57,6 +57,9 @@ var { EnigmailConstants } = ChromeUtils.import(
var { EnigmailDialog } = ChromeUtils.import(
"chrome://openpgp/content/modules/dialog.jsm"
);
var { EnigmailKeyserverURIs } = ChromeUtils.import(
"chrome://openpgp/content/modules/keyserverUris.jsm"
);
const ENIG_KEY_EXPIRED = "e";
const ENIG_KEY_REVOKED = "r";
@ -117,8 +120,7 @@ function enigmailKeyManagerLoad() {
});
gUserList.addEventListener("click", onListClick, true);
document.l10n.setAttributes(
document.getElementById("statusText"),
document.getElementById("statusText").value = l10n.formatValueSync(
"key-man-loading-keys"
);
document.getElementById("progressBar").style.visibility = "visible";
@ -152,7 +154,7 @@ function loadkeyList() {
sortTree();
gKeyListView.applyFilter(0);
document.getElementById("pleaseWait").hidePopup();
document.getElementById("statusText").value = " ";
document.getElementById("statusText").value = "";
document.getElementById("progressBar").style.visibility = "collapse";
}
@ -261,6 +263,8 @@ function enigmailKeyMenu() {
}
}
let singleSecretSelected = keyList.length == 1 && haveSecretForAll;
// Make the selected key count available to translations.
for (let el of document.querySelectorAll(".enigmail-bulk-key-operation")) {
el.setAttribute(
@ -270,6 +274,7 @@ function enigmailKeyMenu() {
}
document.getElementById("backupSecretKey").disabled = !haveSecretForAll;
document.getElementById("uploadToServer").disabled = !singleSecretSelected;
document.getElementById("revokeKey").disabled =
keyList.length != 1 || !gKeyList[keyList[0]].secretAvailable;
@ -701,22 +706,27 @@ async function enigmailSearchKey() {
}
}
/*
function enigmailUploadKeys() {
accessKeyServer(EnigmailConstants.UPLOAD_KEY, enigmailUploadKeysCb);
}
function enigmailUploadKeysCb(exitCode, errorMsg, msgBox) {
if (msgBox) {
if (exitCode !== 0) {
EnigmailDialog.alert(window, "Sending of keys failed" + "\n" + errorMsg);
}
} else {
return exitCode === 0 ? "Key(s) sent successfully" : "Sending of keys failed";
async function enigmailUploadKey() {
/* Always upload to the first configured keyserver with a supported protocol */
let selKeyList = getSelectedKeys();
if (selKeyList.length != 1) {
return;
}
return "";
let keyId = gKeyList[selKeyList[0]].keyId;
let ks = EnigmailKeyserverURIs.getUploadKeyServer();
let ok = await EnigmailKeyServer.upload(keyId, ks);
document.l10n
.formatValue(ok ? "openpgp-key-publish-ok" : "openpgp-key-publish-fail", {
keyserver: ks,
})
.then(value => {
EnigmailDialog.alert(window, value);
});
}
/*
function enigmailUploadToWkd() {
let selKeyList = getSelectedKeys();
let keyList = [];
@ -871,123 +881,6 @@ function determineHiddenKeys(keyObj, showInvalidKeys, showOthersKeys) {
return show;
}
//
// ----- keyserver related functionality ----
//
function accessKeyServer(accessType, callbackFunc) {
const ioService = Services.io;
if (ioService && ioService.offline) {
document.l10n.formatValue("need-online").then(value => {
EnigmailDialog.alert(window, value);
});
return;
}
let inputObj = {};
let resultObj = {};
let selKeyList = getSelectedKeys();
let keyList = [];
for (let i = 0; i < selKeyList.length; i++) {
keyList.push(gKeyList[selKeyList[i]]);
}
if (accessType !== EnigmailConstants.REFRESH_KEY && selKeyList.length === 0) {
if (
EnigmailDialog.confirmDlg(
window,
l10n.formatValueSync("refresh-all-question"),
l10n.formatValueSync("key-man-button-refresh-all")
)
) {
accessType = EnigmailConstants.DOWNLOAD_KEY;
EnigmailDialog.alertPref(
window,
l10n.formatValueSync("refresh-key-warn"),
"warnRefreshAll"
);
} else {
return;
}
}
let keyServer = Services.prefs.getBoolPref(
"temp.openpgp.autoKeyServerSelection"
)
? Services.prefs.getCharPref("temp.openpgp.keyserver").split(/[ ,;]/g)[0]
: null;
if (!keyServer) {
switch (accessType) {
case EnigmailConstants.REFRESH_KEY:
inputObj.upload = false;
inputObj.keyId = "All keys";
break;
case EnigmailConstants.DOWNLOAD_KEY:
inputObj.upload = false;
inputObj.keyId = keyList
.map(k => {
try {
return EnigmailFuncs.stripEmail(k.userId);
} catch (x) {
return "0x" + k.fpr;
}
})
.join(", ");
break;
/*
case EnigmailConstants.UPLOAD_KEY:
inputObj.upload = true;
inputObj.keyId = keyList
.map(k => {
try {
return EnigmailFuncs.stripEmail(k.userId);
} catch (x) {
return "0x" + k.fpr;
}
})
.join(", ");
break;
*/
default:
inputObj.upload = true;
inputObj.keyId = "";
}
window.openDialog(
"chrome://openpgp/content/ui/enigmailKeyserverDlg.xhtml",
"",
"dialog,modal,centerscreen",
inputObj,
resultObj
);
keyServer = resultObj.value;
}
if (keyServer.length === 0) {
return;
}
if (accessType !== EnigmailConstants.REFRESH_KEY) {
inputObj.keyServer = keyServer;
inputObj.accessType = accessType;
inputObj.keyId = keyList.map(k => {
return "0x" + k.fpr;
});
window.openDialog(
"chrome://openpgp/content/ui/enigRetrieveProgress.xhtml",
"",
"dialog,modal,centerscreen",
inputObj,
resultObj
);
if (resultObj.result) {
callbackFunc(resultObj.exitCode, resultObj.errorMsg, false);
}
} else {
EnigmailKeyServer.refresh(keyServer);
}
}
function getSortDirection() {
return gUserList.getAttribute("sortDirection") == "ascending" ? 1 : -1;
}

Просмотреть файл

@ -159,10 +159,13 @@
<menu id="keyserverMenu"
data-l10n-id="openpgp-key-man-keyserver-menu">
<menupopup>
<menupopup onpopupshowing="enigmailKeyMenu()">
<menuitem id="importFromServer"
data-l10n-id="openpgp-key-man-discover-cmd"
oncommand="enigmailSearchKey()"/>
<menuitem id="uploadToServer"
data-l10n-id="openpgp-key-man-publish-cmd"
oncommand="enigmailUploadKey()"/>
</menupopup>
</menu>

Просмотреть файл

@ -2684,28 +2684,6 @@ Enigmail.msg = {
);
},
importKeyFromKeyserver() {
var pubKeyId = "0x" + Enigmail.msg.securityInfo.keyId;
var inputObj = {
searchList: [pubKeyId],
autoKeyServer: Services.prefs.getBoolPref(
"temp.openpgp.autoKeyServerSelection"
)
? Services.prefs
.getCharPref("temp.openpgp.keyserver")
.split(/[ ,;]/g)[0]
: null,
};
var resultObj = {};
EnigmailWindows.downloadKeys(window, inputObj, resultObj);
if (resultObj.importedKeys > 0) {
return true;
}
return false;
},
onUnloadEnigmail() {
window.removeEventListener("unload", Enigmail.msg.messengerClose);
window.removeEventListener(

Просмотреть файл

@ -44,6 +44,12 @@ include $(moztopsrcdir)/config/rules.mk
include $(moztopsrcdir)/toolkit/locales/l10n.mk
ifeq ($(VCS_CHECKOUT_TYPE),hg)
L10N_CO = $(PYTHON3) $(moztopsrcdir)/comm/python/l10n/l10n_clone/l10n_clone.py $(AB_CD) $(L10NBASEDIR)
else
L10N_CO = $(error You need to use hg)
endif
l10n-%: AB_CD=$*
l10n-%:
# merge if we're not en-US. Conditional function because

Просмотреть файл

@ -126,8 +126,13 @@ openpgp-key-man-backup-secret-keys =
openpgp-key-man-discover-cmd =
.label = Discover Keys Online
.accesskey = D
openpgp-key-man-publish-cmd =
.label = Publish
.accesskey = P
openpgp-key-man-discover-prompt = To discover OpenPGP keys online, on keyservers or using the WKD protocol, enter either an email address or a key ID.
openpgp-key-man-discover-progress = Searching…
openpgp-key-publish-ok = The request to publish your public key was sent to "{ $keyserver }". The keyserver might send email that asks for confirmation.
openpgp-key-publish-fail = Failed to send your public key to "{ $keyserver }".
openpgp-key-copy-key =
.label = Copy Public Key

Просмотреть файл

@ -2,7 +2,8 @@
* 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/. */
@import url("chrome://messenger/skin/icons.css");
@import url("chrome://messenger/skin/icons.css");
@import url("chrome://messenger/skin/colors.css");
body {
/* Override the absolute (px) font-size value in common-shared.css. */

Просмотреть файл

@ -11,8 +11,6 @@
font: message-box;
background-color: var(--color-white);
--address-book-book-label-color: var(--color-white);
--address-book-book-label-background: var(--color-gray-50);
--address-book-card-min-height: 140px;
--ab-card-line-height: 1.3em;
@ -34,13 +32,8 @@
background-color: transparent;
color: currentColor;
--address-book-books-list-bg: transparent;
--address-book-cards-list-bg: transparent;
--address-book-icons-color: currentColor;
--address-book-section-border-color: currentColor;
--address-book-section-bg: transparent;
}
}
@ -48,18 +41,8 @@
:root {
color: var(--color-gray-80);
--address-book-books-list-bg: var(--color-gray-10);
--address-book-cards-list-bg: var(--color-gray-05);
--address-book-icons-color: var(--color-ink-80);
--in-content-button-background-active: var(--grey-90-a30);
--in-content-categories-background: #ebebef;
--in-content-item-selected-unfocused: var(--grey-20);
--splitter-color: var(--in-content-border-color);
--address-book-section-border-color: var(--color-gray-30);
--address-book-section-bg: var(--color-gray-05);
}
@media (prefers-color-scheme: dark) {
@ -67,24 +50,8 @@
background: var(--color-gray-90);
color: var(--color-gray-05);
--address-book-books-list-bg: var(--color-gray-80);
--address-book-cards-list-bg: var(--color-gray-80);
--address-book-icons-color: var(--color-gray-30);
--in-content-categories-background: rgba(249, 249, 250, 0.1);
--in-content-item-selected-unfocused: rgba(249, 249, 250, 0.05);
--in-content-button-background-active: rgba(249, 249, 250, 0.2);
--in-content-primary-button-background: #45a1ff;
--in-content-primary-button-background-hover: #65c1ff;
--in-content-primary-button-background-active: #85e1ff;
--in-content-focus-outline-color: #45a1ff;
--address-book-book-label-color: var(--color-white);
--address-book-book-label-background: var(--color-gray-50);
--address-book-section-border-color: transparent;
--address-book-section-bg: var(--color-gray-80);
}
}
}
@ -168,7 +135,7 @@ body.layout-table {
display: flex;
flex-direction: column;
overflow-y: auto;
background-color: var(--address-book-books-list-bg);
background-color: var(--in-content-categories-background);
}
#booksSplitter {
@ -863,8 +830,8 @@ body:not(.is-editing) #editContactForm {
#detailsBody section {
padding: 15px;
border-radius: var(--in-content-button-border-radius);
border: 1px solid var(--address-book-section-border-color);
background-color: var(--address-book-section-bg);
border: 1px solid var(--in-content-box-info-border);
background-color: var(--in-content-box-info-background);
font-size: 1.1rem;
line-height: 1.2;
}
@ -1199,7 +1166,7 @@ input[type="number"]::-moz-number-spin-down {
#cardCount {
position: sticky;
bottom: 0;
background-color: var(--address-book-books-list-bg);
background-color: var(--in-content-categories-background);
border-top: 1px solid var(--splitter-color);
color: color-mix(in srgb, currentColor 75%, transparent);
padding: 9px;

Просмотреть файл

@ -218,6 +218,13 @@ richlistitem[is="chat-imconv-richlistitem"]:not(:hover) > .closeConversationButt
color: GrayText;
}
.convDisplayName,
.blistDisplayName,
.contactDisplayName,
richlistitem[is="chat-group-richlistitem"] > label {
display: inline-block;
}
.convUnreadCount,
.contactDisplayName,
.convDisplayName,
@ -455,12 +462,17 @@ richlistitem:not([selected]) .protoIconDimmed {
.displayName {
font-size: larger;
display: block;
}
.nameAndStatusGrid > .displayName:empty + hr {
display: none;
}
.statusMessage {
display: inline-block;
}
.statusMessage[noTopic] {
font-style: italic;
}
@ -617,6 +629,7 @@ richlistitem:not([selected]) .protoIconDimmed {
pointer-events: none;
font-weight: bold;
padding-inline-start: 1px;
display: inline-block;
}
.conv-nicklist-image {
@ -788,8 +801,13 @@ toolbar[mode="text"] #statusTypeIcon > .toolbarbutton-icon {
border-bottom-color: var(--sidebar-border-color, rgba(249,249,250,.2));
}
.conv-header-label {
display: inline-block;
}
#participantCount {
background: transparent;
width: 0;
}
:root[lwt-tree] #participantCount {
@ -894,6 +912,11 @@ toolbar[mode="text"] .badgeButton-badge {
.encryption-label {
font-weight: 600;
text-overflow: ellipsis;
display: inline-block;
white-space: nowrap;
overflow: hidden;
min-width: 0;
}
.encryption-not-private > image {

Просмотреть файл

@ -21,20 +21,25 @@
@media not (prefers-contrast) {
:host,
:root {
--in-content-box-info-background: var(--color-gray-05);
--in-content-box-info-border: var(--color-gray-30);
--in-content-button-background: var(--grey-90-a10);
--in-content-button-background-hover: var(--grey-90-a20);
--in-content-button-background-active: var(--grey-90-a30);
--in-content-categories-background: #ebebef;
--in-content-categories-background: var(--color-gray-10);
--in-content-item-selected-unfocused: var(--grey-20);
--in-content-item-hover: color-mix(in srgb, currentColor 12%, transparent);
--in-content-item-selected: color-mix(in srgb, currentColor 20%, transparent);
--in-content-item-selected-text: var(--in-content-page-color);
--splitter-color: var(--in-content-border-color);
}
@media (prefers-color-scheme: dark) {
:host,
:root {
--in-content-categories-background: rgba(249, 249, 250, 0.1);
--in-content-box-info-background: var(--color-gray-80);
--in-content-box-info-border: transparent;
--in-content-categories-background: var(--color-gray-80);
--in-content-item-selected-unfocused: rgba(249, 249, 250, 0.05);
--in-content-button-background: rgba(249, 249, 250, 0.1);
--in-content-button-background-hover: rgba(249, 249, 250, 0.15);
@ -49,6 +54,8 @@
@media (prefers-contrast) {
:root {
--in-content-box-info-background: transparent;
--in-content-box-info-border: currentColor;
--in-content-categories-background: transparent;
}
}

Просмотреть файл

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@import url("chrome://messenger/skin/shared/contextMenu.css");
@import url("chrome://messenger/skin/colors.css");
:host {
--icon-size: 16px;
@ -20,6 +21,7 @@
@media (prefers-contrast) {
:host {
--in-content-box-info-background: -moz-Dialog;
--in-content-button-color: ButtonText;
--in-content-button-border: ThreeDLightShadow;
--in-content-button-background: ButtonFace;
@ -52,6 +54,10 @@
}
@media (prefers-color-scheme: dark) {
:host {
--in-content-box-info-background: var(--color-gray-60);
}
:host([type=warning]) {
--message-bar-background-color: #ffe900;
}

Просмотреть файл

@ -452,6 +452,7 @@ checkbox {
.updateSettingCrossUserWarningContainer {
background: var(--in-content-box-info-background);
border: 1px solid var(--in-content-box-info-border);
border-radius: 5px;
padding: 2px 8px 8px;
margin-block-end: 17px;

Просмотреть файл

@ -12,15 +12,9 @@ menuitem[disabled="true"]:not(.menuitem-iconic) {
}
menupopup:not([type="arrow"]) {
--windows-panel-box-shadow: 0 0 4px hsla(0, 0%, 0%, 0.2);
margin: -4px;
}
menupopup:not([type="arrow"])::part(content) {
margin: 4px;
box-shadow: var(--windows-panel-box-shadow);
}
@media (prefers-contrast) {
menupopup > :is(menu, menuitem):not([disabled="true"])[_moz-menuactive] {
color: SelectedItemText;
@ -52,6 +46,11 @@ menupopup:not([type="arrow"])::part(content) {
border-radius: calc(2 * var(--arrowpanel-border-radius));
}
menupopup:not([type="arrow"])::part(content) {
--panel-shadow-margin: 4px;
--panel-shadow: 0 0 4px hsla(0, 0%, 0%, 0.2);
}
/* Override popup.css */
menulist > menupopup {
--panel-background: var(--arrowpanel-background);

Просмотреть файл

@ -511,8 +511,3 @@ treechildren::-moz-tree-row(dummy, selected, focus) {
background: transparent;
border: none;
}
#notification-popup::part(content) {
margin: 4px;
box-shadow: var(--windows-panel-box-shadow);
}

Просмотреть файл

@ -369,14 +369,14 @@ class ImapClient {
}
if (folder.onlineName) {
return folder.onlineName;
return folder.onlineName.replaceAll('"', '\\"');
}
let delimiter =
folder.QueryInterface(Ci.nsIMsgImapMailFolder).hierarchyDelimiter || "/";
let names = this._getAncestorFolderNames(folder);
return this._charsetManager.unicodeToMutf7(
[...names, folder.name].join(delimiter)
);
return this._charsetManager
.unicodeToMutf7([...names, folder.name].join(delimiter))
.replaceAll('"', '\\"');
}
/**
@ -669,11 +669,7 @@ class ImapClient {
* @param {Function} nextAction - Callback function after IDLE is ended.
*/
endIdle(nextAction) {
this._nextAction = res => {
if (res.status == "OK") {
nextAction();
}
};
this._nextAction = nextAction;
this._send("DONE");
this._idling = false;
}
@ -717,7 +713,6 @@ class ImapClient {
this._response = new ImapResponse();
}
this._response.parse(stringPayload);
this._logger.debug("Parsed:", this._response);
if (
!this._authenticating &&
this._response.done &&
@ -1335,7 +1330,9 @@ class ImapClient {
this._folderSink.setFolderQuotaData(VALIDATE_QUOTA, "", 0, 0);
this._actionAfterSelectFolder();
};
this._sendTagged(`GETQUOTAROOT ${this._getServerFolderName(this.folder)}`);
this._sendTagged(
`GETQUOTAROOT "${this._getServerFolderName(this.folder)}"`
);
this._folderSink.folderQuotaCommandIssued = true;
}

Просмотреть файл

@ -473,6 +473,16 @@ class ImapIncomingServer extends MsgIncomingServer {
return null;
}
/**
* Check if INBOX folder is selected in a connection.
*
* @param {ImapClient} client - The client to check.
* @returns {boolean}
*/
_isInboxConnection(client) {
return client.folder?.onlineName.toUpperCase() == "INBOX";
}
/**
* Get a free connection that can be used.
*
@ -509,16 +519,18 @@ class ImapIncomingServer extends MsgIncomingServer {
return this._waitForNextClient(folder);
}
// Reuse any free connection available.
if (this.maximumConnectionsNumber <= 1) {
// Reuse any free connection if only have one connection or IDLE not used.
if (
this.maximumConnectionsNumber <= 1 ||
!this.useIdle ||
!this._capabilities.includes("IDLE")
) {
freeConnections[0].busy = true;
return freeConnections[0];
}
// Reuse non-inbox free connection.
client = freeConnections.find(
c => c.folder?.onlineName.toUpperCase() != "INBOX"
);
client = freeConnections.find(c => !this._isInboxConnection(c));
if (client) {
client.busy = true;
return client;
@ -539,27 +551,32 @@ class ImapIncomingServer extends MsgIncomingServer {
return;
}
client.onFree = async () => {
let alreadyIdling =
client.folder &&
this._connections.find(
c => c != client && !c.busy && c.folder == client.folder
);
if (
this.useIdle &&
this._capabilities.includes("IDLE") &&
client.folder &&
!alreadyIdling
) {
// IDLE is configed and supported, use IDLE to receive server pushes.
client.idle();
} else if (alreadyIdling) {
client.folder = null;
}
client.busy = false;
let resolve = this._connectionWaitingQueue.shift();
if (resolve) {
// Resovle the first waiting in queue.
// Resolve the first waiting in queue.
resolve(true);
} else {
let hasInboxConnection = this._connections.some(c =>
this._isInboxConnection(c)
);
let alreadyIdling =
client.folder &&
this._connections.find(
c => c != client && !c.busy && c.folder == client.folder
);
if (this.useIdle && this._capabilities.includes("IDLE")) {
// IDLE is configed and supported, use IDLE to receive server pushes.
if (!hasInboxConnection) {
client.selectFolder(
this.rootFolder.getFolderWithFlags(Ci.nsMsgFolderFlags.Inbox)
);
} else if (client.folder && !alreadyIdling) {
client.idle();
} else if (alreadyIdling) {
client.folder = null;
}
}
}
};
handler(client);

Просмотреть файл

@ -0,0 +1,81 @@
# 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/.
"""
Download and combine translations from l10n-central and comm-l10n for
use by mach build installers-$AB_CD and mach build langpack-$AB_CD.
"""
import argparse
import os
import sys
import tempfile
from pathlib import Path
from mozpack.copier import FileCopier
from mozpack.files import FileFinder
from mozversioncontrol.repoupdate import update_mercurial_repo
COMM_PATH = (Path(__file__).parent / "../../..").resolve()
COMM_PYTHON_L10N = os.path.join(COMM_PATH, "python/l10n")
sys.path.insert(1, COMM_PYTHON_L10N)
from tbxchannel.l10n_merge import (
COMM_L10N,
L10N_CENTRAL,
COMM_STRINGS_PATTERNS,
GECKO_STRINGS_PATTERNS,
)
ALL_LOCALES = [
l.rstrip() for l in (COMM_PATH / "mail/locales/all-locales").open().readlines()
]
def tb_locale(locale):
if locale in ALL_LOCALES:
return locale
raise argparse.ArgumentTypeError("Locale {} invalid.".format(locale))
def get_strings_repos(locale, destination):
with tempfile.TemporaryDirectory() as tmproot:
central_url = "{}/{}".format(L10N_CENTRAL, locale)
l10n_central = Path(tmproot) / "l10n-central"
l10n_central.mkdir()
central_path = l10n_central / locale
update_mercurial_repo("hg", central_url, central_path)
comm_l10n = Path(tmproot) / "comm-l10n"
update_mercurial_repo("hg", COMM_L10N, comm_l10n)
file_copier = FileCopier()
def add_to_registry(base_path, patterns):
finder = FileFinder(base_path)
for pattern in patterns:
for _filepath, _fileobj in finder.find(pattern.format(lang=locale)):
# _filepath = os.path.join("l10n-central", _filepath)
file_copier.add(_filepath, _fileobj)
add_to_registry(l10n_central, GECKO_STRINGS_PATTERNS)
add_to_registry(comm_l10n, COMM_STRINGS_PATTERNS)
file_copier.copy(destination / locale)
def main():
parser = argparse.ArgumentParser(
description="Download translated strings from comm-l10n"
)
parser.add_argument("locale", help="The locale to download", type=tb_locale)
parser.add_argument(
"dest_path", help="Path where locale will be downloaded to.", type=Path
)
args = parser.parse_args()
get_strings_repos(args.locale, args.dest_path)
if __name__ == "__main__":
main()

Просмотреть файл

@ -22,6 +22,38 @@ def _positive_int(value):
return value
def _retry_run_process(command_context, *args, error_msg=None, **kwargs):
try:
return command_context.run_process(*args, **kwargs)
except Exception as exc:
raise Exception(error_msg or str(exc)) from exc
def _get_rev(command_context, strings_path):
result = []
def save_output(line):
result.append(line)
status = _retry_run_process(
command_context,
[
"hg",
"--cwd",
str(strings_path),
"log",
"-r",
".",
"--template",
"'{node}\n'",
],
line_handler=save_output,
)
if status == 0:
return "\n".join(result)
raise Exception(f"Failed to get head revision: {status}")
@Command(
"tb-l10n-x-channel",
category="thunderbird",
@ -75,7 +107,9 @@ def tb_cross_channel(
**kwargs,
):
"""Run Thunderbird's l10n cross-channel content generation."""
from tbxchannel import get_thunderbird_xc_config
from tbxchannel import get_thunderbird_xc_config, TB_XC_NOTIFICATION_TMPL
from tbxchannel.l10n_merge import COMM_STRINGS_QUARANTINE
from rocbuild.notify import email_notification
kwargs.update(
{
@ -90,6 +124,14 @@ def tb_cross_channel(
command_context._mach_context.commands.dispatch(
"l10n-cross-channel", command_context._mach_context, **kwargs
)
if os.path.exists(outgoing_path):
head_rev = _get_rev(command_context, strings_path)
rev_url = f"{COMM_STRINGS_QUARANTINE}/rev/{head_rev}"
notification_body = TB_XC_NOTIFICATION_TMPL.format(rev_url=rev_url)
email_notification(
"X-channel comm-strings-quarantine updated", notification_body
)
@Command(

Просмотреть файл

@ -7,6 +7,13 @@ from pathlib import Path
from .l10n_merge import COMM_STRINGS_QUARANTINE, COMM_STRINGS_QUARANTINE_PUSH
TB_XC_NOTIFICATION_TMPL = """\
**Thunderbird L10n Cross Channel**
Changes pushed to `comm-strings-quarantine`: {rev_url}
"""
def get_thunderbird_xc_config(topsrcdir, strings_path):
assert isinstance(topsrcdir, Path)
assert isinstance(strings_path, Path)

Просмотреть файл

Просмотреть файл

@ -0,0 +1,35 @@
# 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/.
"""
Notification utility functions
"""
import os
from taskcluster import Notify
from taskcluster import optionsFromEnvironment
TB_BUILD_ADDR = "tb-builds@thunderbird.net"
def email_notification(subject, content, recipients=None):
# use proxy if configured, otherwise local credentials from env vars
if recipients is None:
recipients = [TB_BUILD_ADDR]
if "TASKCLUSTER_PROXY_URL" in os.environ:
notify_options = {"rootUrl": os.environ["TASKCLUSTER_PROXY_URL"]}
else:
notify_options = optionsFromEnvironment()
notify = Notify(notify_options)
for address in recipients:
notify.email(
{
"address": address,
"subject": subject,
"content": content,
}
)

Просмотреть файл

@ -13,7 +13,7 @@ jobs:
quarantine:
description: Push strings from all shipping trains to comm-strings-quarantine
run-on-projects: []
worker-type: b-linux
worker-type: b-linux-gcp
ssh-key-secret:
by-level:
"3": project/comm/thunderbird/releng/build/level-3/l10n-cross-channel-quarantine-ssh

Просмотреть файл

@ -18,7 +18,7 @@ job-defaults:
description: bouncer check
run-on-projects: [] # to make sure this never runs as part of CI
shipping-phase: push
worker-type: b-linux
worker-type: b-linux-gcp
worker:
max-run-time: 1800
docker-image: {in-tree: "update-verify"}

Просмотреть файл

@ -17,7 +17,7 @@ transforms:
job-defaults:
name: final-verify
run-on-projects: [] # to make sure this never runs as part of CI
worker-type: b-linux
worker-type: b-linux-gcp
worker:
docker-image:
in-tree: "update-verify"

Просмотреть файл

@ -20,7 +20,7 @@ job-defaults:
description: generates checksums
run-on-projects: [] # to make sure this never runs as part of CI
shipping-phase: promote
worker-type: b-linux
worker-type: b-linux-gcp
worker:
max-run-time: 1200
artifacts:

Просмотреть файл

@ -18,7 +18,7 @@ job-defaults:
shipping-phase: promote
treeherder:
symbol: Src
worker-type: b-linux
worker-type: b-linux-gcp
worker:
max-run-time: 3600
env:

Просмотреть файл

@ -15,7 +15,7 @@ job-defaults:
run-on-projects: [] # to make sure this never runs as part of CI
run-on-releases: [release]
shipping-phase: promote
worker-type: b-linux
worker-type: b-linux-gcp
worker:
docker-image:
in-tree: "update-verify"

Просмотреть файл

@ -13,7 +13,7 @@ job-defaults:
name: update-verify-config
run-on-projects: [] # to make sure this never runs as part of CI
shipping-phase: promote
worker-type: b-linux
worker-type: b-linux-gcp
worker:
docker-image:
in-tree: "update-verify"

Просмотреть файл

@ -22,7 +22,7 @@ job-defaults:
run-on-projects: [] # to make sure this never runs as part of CI
run-on-releases: [release]
shipping-phase: promote
worker-type: b-linux
worker-type: b-linux-gcp
worker:
artifacts:
- name: 'public/build/diff-summary.log'

Просмотреть файл

@ -20,7 +20,7 @@ job-defaults:
name: update-verify
run-on-projects: [] # to make sure this never runs as part of CI
shipping-phase: promote
worker-type: b-linux
worker-type: b-linux-gcp
worker:
artifacts:
- name: 'public/build/diff-summary.log'

Просмотреть файл

@ -26,7 +26,7 @@ job-template:
attributes:
shipping_phase: promote
run-time: 900
worker-type: b-linux
worker-type: b-linux-gcp
docker-image: {in-tree: debian11-amd64-build}
treeherder:
symbol: L10n-pre

Просмотреть файл

@ -27,7 +27,7 @@ only-for-build-platforms:
job-template:
description: Upload Symbols
worker-type: b-linux
worker-type: b-linux-gcp
worker:
docker-image: {in-tree: "debian11-base"}
max-run-time: 900

Просмотреть файл

@ -10,6 +10,8 @@ from shlex import quote as shell_quote
from taskgraph.transforms.base import TransformSequence
from taskgraph.util.schema import resolve_keyed_by
from rocbuild.notify import TB_BUILD_ADDR
transforms = TransformSequence()
@ -35,6 +37,7 @@ def build_command(config, jobs):
if ssh_key_secret:
command.extend(["--ssh-secret", ssh_key_secret])
job.setdefault("scopes", []).append(f"secrets:get:{ssh_key_secret}")
job["scopes"].append(f"notify:email:{TB_BUILD_ADDR}")
command.extend(job["run"].pop("actions", []))
job.setdefault("run", {}).update(