Files
binoc-central-mirror/mail/modules/mailMigrator.js
T
2020-05-10 13:52:36 -04:00

444 lines
18 KiB
JavaScript

/* -*- Mode: JavaScript; 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/. */
/**
* This module handles migrating mail-specific preferences, etc. Migration has
* traditionally been a part of msgMail3PaneWindow.js, but separating the code
* out into a module makes unit testing much easier.
*/
var EXPORTED_SYMBOLS = ["MailMigrator"];
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/mailServices.js");
Cu.import("resource:///modules/IOUtils.js");
XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
"resource://gre/modules/LoginHelper.jsm");
var MailMigrator = {
/**
* Switch the given fonts to the given encodings, but only if the current fonts
* are defaults.
*/
_switchDefaultFonts: function MailMigrator__switchDefaultFonts(aFonts,
aEncodings) {
for (let encoding of aEncodings) {
let serifPref = "font.name.serif." + encoding;
let sansPref = "font.name.sans-serif." + encoding;
let variableSizePref = "font.size.variable." + encoding;
// This is expected to be one of sans-serif or serif, and determines what
// we'll link the variable font size to.
let isSansDefault = Services.prefs.getCharPref("font.default." + encoding) ==
"sans-serif";
if (!Services.prefs.prefHasUserValue(serifPref)) {
Services.prefs.setCharPref(serifPref, aFonts.serif);
if (!isSansDefault)
Services.prefs.setIntPref(variableSizePref, aFonts.variableSize);
}
if (!Services.prefs.prefHasUserValue(sansPref)) {
Services.prefs.setCharPref(sansPref, aFonts.sans);
if (isSansDefault)
Services.prefs.setIntPref(variableSizePref, aFonts.variableSize);
}
let monospacePref = "font.name.monospace." + encoding;
let fixedSizePref = "font.size.fixed." + encoding;
if (!Services.prefs.prefHasUserValue(monospacePref)) {
Services.prefs.setCharPref(monospacePref, aFonts.monospace);
Services.prefs.setIntPref(fixedSizePref, aFonts.fixedSize);
}
}
},
/**
* Migrate to ClearType fonts (Cambria, Calibri and Consolas) on Windows Vista
* and above.
*/
migrateToClearTypeFonts: function MailMigrator_migrateToClearTypeFonts() {
// Windows...
if ("@mozilla.org/windows-registry-key;1" in Components.classes) {
// Only migrate on Vista (Windows version 6.0) and above
if (Services.sysinfo.getPropertyAsDouble("version") >= 6.0) {
let fontPrefVersion =
Services.prefs.getIntPref("mail.font.windows.version");
if (fontPrefVersion < 2) {
let fonts = {
serif: "Cambria",
sans: "Calibri",
monospace: "Consolas",
variableSize: 17,
fixedSize: 14,
};
// Encodings to switch to the new fonts.
let encodings = [];
// (Thunderbird 3.1)
if (fontPrefVersion < 1)
encodings.push("x-unicode", "x-western");
// (Thunderbird 3.2)
encodings.push("x-cyrillic", "el");
this._switchDefaultFonts(fonts, encodings);
Services.prefs.setIntPref("mail.font.windows.version", 2);
}
}
}
},
/**
* Determine if the UI has been upgraded in a way that requires us to reset
* some user configuration. If so, performs the resets.
*/
_migrateUI: function() {
// The code for this was ported from
// mozilla/browser/components/nsBrowserGlue.js
const UI_VERSION = 17;
const MESSENGER_DOCURL = "chrome://messenger/content/messenger.xul";
const UI_VERSION_PREF = "mail.ui-rdf.version";
let currentUIVersion = 0;
try {
currentUIVersion = Services.prefs.getIntPref(UI_VERSION_PREF);
} catch(ex) {}
if (currentUIVersion >= UI_VERSION)
return;
let xulStore = Cc["@mozilla.org/xul/xulstore;1"].getService(Ci.nsIXULStore);
try {
// Initially, we checked if currentUIVersion < 1, and stripped the
// persisted "collapsed" property from folderPaneBox if it wasn't.
// However, the inital implementation of migrateUI swallowed up
// exceptions, and bumped the value of UI_VERSION_PREF regardless.
// Now, instead, we fail to bump the UI_VERSION_PREF if something goes
// wrong, and we've moved the folderPaneBox operation into
// currentUIVersion < 2 just in case the operation failed for some of
// our users the first time.
if (currentUIVersion < 2) {
// We want to remove old settings that collapse the folderPaneBox
if (xulStore.hasValue(MESSENGER_DOCURL, "folderPaneBox", "collapsed")) {
// We want to override this, and set it to false. We should really
// be ignoring this persist attribute, anyhow.
xulStore.removeValue(MESSENGER_DOCURL, "folderPaneBox", "collapsed");
}
// We want to remove the throbber from the menubar on Linux and
// Windows, and from the mail-toolbar on OSX.
let mailBarId = (Services.appinfo.OS == "Darwin") ?
"mail-bar3" : "mail-toolbar-menubar2";
let cs = xulStore.getValue(MESSENGER_DOCURL, mailBarId, "currentset");
if (cs && cs.includes("throbber-box")) {
cs = cs.replace(/(^|,)throbber-box($|,)/, "$1$2");
xulStore.setValue(MESSENGER_DOCURL, mailBarId, "currentset", cs);
}
}
// In UI version 3, we move the QFB button from the tabbar toolbar to
// to the mail toolbar.
if (currentUIVersion < 3) {
let cs = xulStore.getValue(MESSENGER_DOCURL, "tabbar-toolbar", "currentset");
if (cs && cs.includes("qfb-show-filter-bar")) {
cs = cs.replace(/(^|,)qfb-show-filter-bar($|,)/, "$1$2");
xulStore.setValue(MESSENGER_DOCURL, "tabbar-toolbar", "currentset", cs);
}
let cs3 = xulStore.getValue(MESSENGER_DOCURL, "mail-bar3", "currentset");
if (cs3 && !cs3.includes("qfb-show-filter-bar")) {
if (cs3.includes("gloda-search")) {
// Put the QFB toggle before the gloda-search and any of
// spring / spacer / separator.
cs3 = cs3.replace(/(^|,)([spring,|spacer,|separator,]*)gloda-search($|,)/,
"$1qfb-show-filter-bar,$2gloda-search$3");
} else {
// If there's no gloda-search, just put the QFB toggle at the end
cs3 += ",qfb-show-filter-bar";
}
xulStore.setValue(MESSENGER_DOCURL, "mail-bar3", "currentset", cs3);
}
}
// In UI version 4, we add the chat button to the mail toolbar.
if (currentUIVersion < 4) {
let cs = xulStore.getValue(MESSENGER_DOCURL, "mail-bar3", "currentset");
if (cs && !cs.includes("button-chat")) {
if (cs.includes("button-newmsg")) {
// Put the chat button after the newmsg button.
cs = cs.replace(/(^|,)button-newmsg($|,)/,
"$1button-newmsg,button-chat$2");
} else if (cs.includes("button-address")) {
// If there's no newmsg button, put the chat button before the address book button.
cs = cs.replace(/(^|,)button-address($|,)/,
"$1button-chat,button-address$2");
} else {
// Otherwise, just put the chat button at the end.
cs += ",button-chat";
}
xulStore.setValue(MESSENGER_DOCURL, "mail-bar3", "currentset", cs);
}
}
// In UI version 5, we add the AppMenu button to the mail toolbar and
// collapse the main menu by default if the user has no accounts
// set up (and the override pref "mail.main_menu.collapse_by_default"
// is set to true). Checking for 0 accounts is a hack, because we can't
// think of any better way of determining whether this profile is new
// or not.
if (currentUIVersion < 5) {
/**
* Helper function that attempts to add the AppMenu button to the
* end of a toolbar with ID aToolbarID. Fails silently if this is
* not possible, as is typical within our UI migration code.
*
* @param aToolbarID the ID of the toolbar to add the AppMenu to.
*/
let addButtonToEnd = function(aToolbarID, aButtonID) {
let cs = xulStore.getValue(MESSENGER_DOCURL, aToolbarID, "currentset");
if (cs && !cs.includes(aButtonID)) {
// Put the AppMenu button at the end.
cs += "," + aButtonID;
xulStore.setValue(MESSENGER_DOCURL, aToolbarID, "currentset", cs);
}
}.bind(this);
addButtonToEnd("mail-bar3", "button-appmenu");
addButtonToEnd("chat-toobar", "button-chat-appmenu");
if (Services.prefs.getBoolPref("mail.main_menu.collapse_by_default") &&
MailServices.accounts.accounts.length == 0) {
xulStore.setValue(MESSENGER_DOCURL, "mail-toolbar-menubar2", "autohide", "true");
}
}
// In UI version 6, we move the otherActionsButton button to the
// header-view-toolbar.
if (currentUIVersion < 6) {
let cs = xulStore.getValue(MESSENGER_DOCURL, "header-view-toolbar", "currentset");
if (cs && !cs.includes("otherActionsButton")) {
// Put the otherActionsButton button at the end.
cs = cs + "," + "otherActionsButton";
xulStore.setValue(MESSENGER_DOCURL, "header-view-toolbar", "currentset", cs);
}
}
// In UI version 7, the three-state doNotTrack setting was reverted back
// to two-state. This reverts a (no longer supported) setting of "please
// track me" to the default "don't say anything".
if (currentUIVersion < 7) {
try {
if (Services.prefs.getBoolPref("privacy.donottrackheader.enabled") &&
Services.prefs.getIntPref("privacy.donottrackheader.value") != 1) {
Services.prefs.clearUserPref("privacy.donottrackheader.enabled");
Services.prefs.clearUserPref("privacy.donottrackheader.value");
}
}
catch (ex) {}
}
// In UI version 8, we change from boolean browser.display.use_document_colors
// to the tri-state browser.display.document_color_use.
if (currentUIVersion < 8) {
const kOldColorPref = "browser.display.use_document_colors";
if (Services.prefs.prefHasUserValue(kOldColorPref) &&
!Services.prefs.getBoolPref(kOldColorPref)) {
Services.prefs.setIntPref("browser.display.document_color_use", 2);
}
}
// Limit the charset detector pref to values (now) available from the UI.
if (currentUIVersion < 9) {
let detector = null;
try {
detector = Services.prefs.getComplexValue("intl.charset.detector",
Ci.nsIPrefLocalizedString).data;
} catch (ex) { }
if (!(detector == "" ||
detector == "ja_parallel_state_machine" ||
detector == "ruprob" ||
detector == "ukprob")) {
// If the encoding detector pref value is not reachable from the UI,
// reset to default (varies by localization).
Services.prefs.clearUserPref("intl.charset.detector");
}
}
// Add an expanded entry for All Address Books.
if (currentUIVersion < 10) {
const DIR_TREE_FILE = "directoryTree.json";
// If the file exists, read its contents, prepend the "All ABs" URI
// and save it, else, just write the "All ABs" URI to the file.
let data = IOUtils.loadFileToString(DIR_TREE_FILE);
if (!data || data == "[]") {
data = "";
} else if (data.length > 0) {
data = data.substring(1, data.length - 1);
}
data = "[" + "\"moz-abdirectory://?\"" +
((data.length > 0) ? ("," + data) : "") + "]";
IOUtils.saveStringToFile(DIR_TREE_FILE, data);
}
// Several Latin language groups were consolidated into x-western.
if (currentUIVersion < 11) {
let group = null;
try {
group = Services.prefs.getComplexValue("font.language.group",
Ci.nsIPrefLocalizedString);
} catch (ex) {}
if (group &&
["tr", "x-baltic", "x-central-euro"].some(g => g == group.data)) {
group.data = "x-western";
Services.prefs.setComplexValue("font.language.group",
Ci.nsIPrefLocalizedString, group);
}
}
// The obsolete files signons.txt, signons2.txt and signons3.txt got
// removed from the profile directory.
if (currentUIVersion < 12) {
LoginHelper.removeLegacySignonFiles();
}
// Untangled starting in Paragraph mode from Enter key preference
if (currentUIVersion < 13) {
Services.prefs.setBoolPref("mail.compose.default_to_paragraph",
Services.prefs.getBoolPref("editor.CR_creates_new_p"));
Services.prefs.clearUserPref("editor.CR_creates_new_p");
}
// Migrate remote content exceptions for email addresses which are
// encoded as chrome URIs.
if (currentUIVersion < 14) {
let permissionsDB =
Services.dirsvc.get("ProfD",Components.interfaces.nsILocalFile);
permissionsDB.append("permissions.sqlite");
let db = Services.storage.openDatabase(permissionsDB);
try {
let statement = db.createStatement(
"select origin,permission from moz_perms where " +
// Avoid 'like' here which needs to be escaped.
"substr(origin, 1, 28)='chrome://messenger/content/?';");
try {
while (statement.executeStep()) {
let origin = statement.getUTF8String(0);
let permission = statement.getInt32(1);
Services.perms.remove(
Services.io.newURI(origin), "image");
origin = origin.replace("chrome://messenger/content/?",
"chrome://messenger/content/");
Services.perms.add(
Services.io.newURI(origin), "image", permission);
}
} finally {
statement.finalize();
}
// Sadly we still need to clear the database manually. Experiments
// showed that the permissions manager deleted only one record.
db.beginTransactionAs(Components.interfaces.mozIStorageConnection
.TRANSACTION_EXCLUSIVE);
try {
db.executeSimpleSQL("delete from moz_perms where " +
"substr(origin, 1, 28)='chrome://messenger/content/?';");
db.commitTransaction();
} catch (ex) {
db.rollbackTransaction();
throw ex;
}
} finally {
db.close();
}
}
// Changed notification sound behaviour on OS X.
if (currentUIVersion < 15) {
Cu.import("resource://gre/modules/AppConstants.jsm");
if (AppConstants.platform == "macosx") {
// For people updating from versions < 52 who had "Play system sound"
// selected for notifications. As TB no longer plays system sounds,
// uncheck the pref to match the new behaviour.
const soundPref = "mail.biff.play_sound";
if (Services.prefs.getBoolPref(soundPref) &&
Services.prefs.getIntPref(soundPref + ".type") == 0) {
Services.prefs.setBoolPref(soundPref, false);
}
}
}
// Interlink doesn't support langpacks so we need to reset the UI lang pref
if (currentUIVersion < 16) {
Services.prefs.clearUserPref("general.useragent.locale");
var disableLangPacks16 = function() {
Cu.import("resource://gre/modules/AddonManager.jsm");
function disableAddons(aAddons) {
for each(let addon in aAddons) {
addon.userDisabled = true;
}
}
AddonManager.getAddonsByTypes(['locale'], disableAddons);
}
disableLangPacks16();
}
// UXP Milestone NOT-29 changed the prefs regarding HWA so in true comm style
// steal the UI migration code from the defacto browser and proofread it for
// god damned fucking typos that kill the everything
if (currentUIVersion < 17) {
if (Services.prefs.prefHasUserValue("layers.acceleration.disabled")) {
let HWADisabled = Services.prefs.getBoolPref("layers.acceleration.disabled");
Services.prefs.setBoolPref("layers.acceleration.enabled", !HWADisabled);
Services.prefs.setBoolPref("gfx.direct2d.disabled", HWADisabled);
}
if (Services.prefs.getBoolPref("layers.acceleration.force-enabled", false)) {
Services.prefs.setBoolPref("layers.acceleration.force", true);
}
Services.prefs.clearUserPref("layers.acceleration.disabled");
Services.prefs.clearUserPref("layers.acceleration.force-enabled");
}
// Update the migration version.
Services.prefs.setIntPref(UI_VERSION_PREF, UI_VERSION);
} catch(e) {
Cu.reportError("Migrating from UI version " + currentUIVersion + " to " +
UI_VERSION + " failed. Error message was: " + e + " -- " +
"Will reattempt on next start.");
}
},
/**
* Perform any migration work that needs to occur after the Account Wizard
* has had a chance to appear.
*/
migratePostAccountWizard: function MailMigrator_migratePostAccountWizard() {
this.migrateToClearTypeFonts();
},
/**
* Perform any migration work that needs to occur once the user profile has
* been loaded.
*/
migrateAtProfileStartup: function MailMigrator_migrateAtProfileStartup() {
this._migrateUI();
},
};