/* 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 ); }