diff options
Diffstat (limited to 'comm/mailnews/base/src/MailnewsMigrator.jsm')
-rw-r--r-- | comm/mailnews/base/src/MailnewsMigrator.jsm | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/comm/mailnews/base/src/MailnewsMigrator.jsm b/comm/mailnews/base/src/MailnewsMigrator.jsm new file mode 100644 index 0000000000..bc6ad9c3ef --- /dev/null +++ b/comm/mailnews/base/src/MailnewsMigrator.jsm @@ -0,0 +1,352 @@ +/* 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/. */ + +/** + * Migrate profile (prefs and other files) from older versions of Mailnews to + * current. + * This should be run at startup. It migrates as needed: each migration + * function should be written to be a no-op when the value is already migrated + * or was never used in the old version. + */ + +const EXPORTED_SYMBOLS = ["migrateMailnews"]; + +const { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); +const lazy = {}; +ChromeUtils.defineModuleGetter( + lazy, + "migrateServerUris", + "resource:///modules/MsgIncomingServer.jsm" +); + +var kServerPrefVersion = 1; +var kSmtpPrefVersion = 1; +var kABRemoteContentPrefVersion = 1; + +function migrateMailnews() { + let migrations = [ + migrateProfileClientid, + migrateServerAuthPref, + migrateServerAndUserName, + migrateABRemoteContentSettings, + ]; + + for (let fn of migrations) { + try { + fn(); + } catch (e) { + console.error(e); + } + } +} + +/** + * Creates the server specific 'CLIENTID' prefs and tries to pair up any imap + * services with smtp services which are using the same username and hostname. + */ +function migrateProfileClientid() { + // Comma-separated list of all account ids. + let accounts = Services.prefs.getCharPref("mail.accountmanager.accounts", ""); + // Comma-separated list of all smtp servers. + let smtpServers = Services.prefs.getCharPref("mail.smtpservers", ""); + // If both accounts and smtpservers are empty then there is nothing to do. + if (accounts.length == 0 && smtpServers.length == 0) { + return; + } + // A cache to allow CLIENTIDs to be stored and shared across services that + // share a username and hostname. + let clientidCache = new Map(); + // There may be accounts but no smtpservers so check the length before + // trying to split the smtp servers and iterate in the loop below. + if (smtpServers.length > 0) { + // Now walk all smtp servers and generate any missing CLIENTIDS, caching + // all CLIENTIDS along the way to be reused for matching imap servers + // if possible. + + // Since the length of the smtpServers string is non-zero then we can split + // the string by comma and iterate each entry in the comma-separated list. + for (let key of smtpServers.split(",")) { + let server = "mail.smtpserver." + key + "."; + if ( + !Services.prefs.prefHasUserValue(server + "clientid") || + !Services.prefs.getCharPref(server + "clientid", "") + ) { + // Always give outgoing servers a new unique CLIENTID. + let newClientid = Services.uuid + .generateUUID() + .toString() + .replace(/[{}]/g, ""); + Services.prefs.setCharPref(server + "clientid", newClientid); + } + let username = Services.prefs.getCharPref(server + "username", ""); + if (!username) { + // Not all SMTP servers require a username. + continue; + } + + // Cache all CLIENTIDs from all outgoing servers to reuse them for any + // incoming servers which have a matching username and hostname. + let hostname = Services.prefs.getCharPref(server + "hostname"); + let combinedKey; + try { + combinedKey = + username + "@" + Services.eTLD.getBaseDomainFromHost(hostname); + } catch (e) { + combinedKey = username + "@" + hostname; + } + clientidCache.set( + combinedKey, + Services.prefs.getCharPref(server + "clientid") + ); + } + } + + // Now walk all imap accounts and generate any missing CLIENTIDS, reusing + // cached CLIENTIDS if possible. + for (let key of accounts.split(",")) { + let serverKey = Services.prefs.getCharPref( + "mail.account." + key + ".server" + ); + let server = "mail.server." + serverKey + "."; + // Check if this imap server needs the CLIENTID preference to be populated. + if ( + !Services.prefs.prefHasUserValue(server + "clientid") || + !Services.prefs.getCharPref(server + "clientid", "") + ) { + // Clientid should only be provisioned for imap accounts. + if (Services.prefs.getCharPref(server + "type", "") != "imap") { + continue; + } + // Grab username + hostname to check if a CLIENTID is cached. + let username = Services.prefs.getCharPref(server + "userName", ""); + if (!username) { + continue; + } + let hostname = Services.prefs.getCharPref(server + "hostname"); + let combinedKey; + try { + combinedKey = + username + "@" + Services.eTLD.getBaseDomainFromHost(hostname); + } catch (e) { + combinedKey = username + "@" + hostname; + } + if (!clientidCache.has(combinedKey)) { + // Generate a new CLIENTID if no matches were found from smtp servers. + let newClientid = Services.uuid + .generateUUID() + .toString() + .replace(/[{}]/g, ""); + Services.prefs.setCharPref(server + "clientid", newClientid); + } else { + // Otherwise if a cached CLIENTID was found for this username + hostname + // then we can just use the outgoing CLIENTID which was matching. + Services.prefs.setCharPref( + server + "clientid", + clientidCache.get(combinedKey) + ); + } + } + } +} + +/** + * Migrates from pref useSecAuth to pref authMethod + */ +function migrateServerAuthPref() { + // comma-separated list of all accounts. + var accounts = Services.prefs + .getCharPref("mail.accountmanager.accounts") + .split(","); + for (let i = 0; i < accounts.length; i++) { + let accountKey = accounts[i]; // e.g. "account1" + if (!accountKey) { + continue; + } + let serverKey = Services.prefs.getCharPref( + "mail.account." + accountKey + ".server" + ); + let server = "mail.server." + serverKey + "."; + if (Services.prefs.prefHasUserValue(server + "authMethod")) { + continue; + } + if ( + !Services.prefs.prefHasUserValue(server + "useSecAuth") && + !Services.prefs.prefHasUserValue(server + "auth_login") + ) { + continue; + } + if (Services.prefs.prefHasUserValue(server + "migrated")) { + continue; + } + // auth_login = false => old-style auth + // else: useSecAuth = true => "secure auth" + // else: cleartext pw + let auth_login = Services.prefs.getBoolPref(server + "auth_login", true); + // old default, default pref now removed + let useSecAuth = Services.prefs.getBoolPref(server + "useSecAuth", false); + + if (auth_login) { + if (useSecAuth) { + Services.prefs.setIntPref( + server + "authMethod", + Ci.nsMsgAuthMethod.secure + ); + } else { + Services.prefs.setIntPref( + server + "authMethod", + Ci.nsMsgAuthMethod.passwordCleartext + ); + } + } else { + Services.prefs.setIntPref(server + "authMethod", Ci.nsMsgAuthMethod.old); + } + Services.prefs.setIntPref(server + "migrated", kServerPrefVersion); + } + + // same again for SMTP servers + var smtpservers = Services.prefs.getCharPref("mail.smtpservers").split(","); + for (let i = 0; i < smtpservers.length; i++) { + if (!smtpservers[i]) { + continue; + } + let server = "mail.smtpserver." + smtpservers[i] + "."; + if (Services.prefs.prefHasUserValue(server + "authMethod")) { + continue; + } + if ( + !Services.prefs.prefHasUserValue(server + "useSecAuth") && + !Services.prefs.prefHasUserValue(server + "auth_method") + ) { + continue; + } + if (Services.prefs.prefHasUserValue(server + "migrated")) { + continue; + } + // auth_method = 0 => no auth + // else: useSecAuth = true => "secure auth" + // else: cleartext pw + let auth_method = Services.prefs.getIntPref(server + "auth_method", 1); + let useSecAuth = Services.prefs.getBoolPref(server + "useSecAuth", false); + + if (auth_method) { + if (useSecAuth) { + Services.prefs.setIntPref( + server + "authMethod", + Ci.nsMsgAuthMethod.secure + ); + } else { + Services.prefs.setIntPref( + server + "authMethod", + Ci.nsMsgAuthMethod.passwordCleartext + ); + } + } else { + Services.prefs.setIntPref(server + "authMethod", Ci.nsMsgAuthMethod.none); + } + Services.prefs.setIntPref(server + "migrated", kSmtpPrefVersion); + } +} + +/** + * For each mail.server.key. branch, + * - migrate realhostname to hostname + * - migrate realuserName to userName + */ +function migrateServerAndUserName() { + let branch = Services.prefs.getBranch("mail.server."); + + // Collect all the server keys. + let keySet = new Set(); + for (let name of branch.getChildList("")) { + keySet.add(name.split(".")[0]); + } + keySet.delete("default"); + + for (let key of keySet) { + let type = branch.getCharPref(`${key}.type`, ""); + let hostname = branch.getCharPref(`${key}.hostname`, ""); + let username = branch.getCharPref(`${key}.userName`, ""); + let realHostname = branch.getCharPref(`${key}.realhostname`, ""); + if (realHostname) { + branch.setCharPref(`${key}.hostname`, realHostname); + branch.clearUserPref(`${key}.realhostname`); + } + let realUsername = branch.getCharPref(`${key}.realuserName`, ""); + if (realUsername) { + branch.setCharPref(`${key}.userName`, realUsername); + branch.clearUserPref(`${key}.realuserName`); + } + // Previously, when hostname/username changed, LoginManager and many prefs + // still contain the old hostname/username, try to migrate them to use the + // new hostname/username. + if ( + ["imap", "pop3", "nntp"].includes(type) && + (realHostname || realUsername) + ) { + let localStoreType = { imap: "imap", pop3: "mailbox", nntp: "news" }[ + type + ]; + lazy.migrateServerUris( + localStoreType, + hostname, + username, + realHostname || hostname, + realUsername || username + ); + } + } +} + +/** + * The address book used to contain information about whether to allow remote + * content for a given contact. Now we use the permission manager for that. + * Do a one-time migration for it. + */ +function migrateABRemoteContentSettings() { + if (Services.prefs.prefHasUserValue("mail.ab_remote_content.migrated")) { + return; + } + + // Search through all of our local address books looking for a match. + for (let addrbook of MailServices.ab.directories) { + let migrateAddress = function (aEmail) { + let uri = Services.io.newURI( + "chrome://messenger/content/email=" + aEmail + ); + Services.perms.addFromPrincipal( + Services.scriptSecurityManager.createContentPrincipal(uri, {}), + "image", + Services.perms.ALLOW_ACTION + ); + }; + + try { + // If it's a read-only book, don't try to find a card as we we could never + // have set the AllowRemoteContent property. + if (addrbook.readOnly) { + continue; + } + + for (let card of addrbook.childCards) { + if (card.getProperty("AllowRemoteContent", "0") == "0") { + // Not allowed for this contact. + continue; + } + + for (let emailAddress of card.emailAddresses) { + migrateAddress(emailAddress); + } + } + } catch (e) { + console.error(e); + } + } + + Services.prefs.setIntPref( + "mail.ab_remote_content.migrated", + kABRemoteContentPrefVersion + ); +} |