diff options
Diffstat (limited to 'comm/mailnews/base/prefs/content/converterDialog.js')
-rw-r--r-- | comm/mailnews/base/prefs/content/converterDialog.js | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/comm/mailnews/base/prefs/content/converterDialog.js b/comm/mailnews/base/prefs/content/converterDialog.js new file mode 100644 index 0000000000..e0ac74fd5b --- /dev/null +++ b/comm/mailnews/base/prefs/content/converterDialog.js @@ -0,0 +1,385 @@ +/* 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 file contains functionality for the front-end part of the mail store + * type conversion. + */ + +var { MailUtils } = ChromeUtils.import("resource:///modules/MailUtils.jsm"); +var { FileUtils } = ChromeUtils.importESModule( + "resource://gre/modules/FileUtils.sys.mjs" +); +ChromeUtils.defineModuleGetter( + this, + "FolderUtils", + "resource:///modules/FolderUtils.jsm" +); +var MailstoreConverter = ChromeUtils.import( + "resource:///modules/mailstoreConverter.jsm" +); +var { AppConstants } = ChromeUtils.importESModule( + "resource://gre/modules/AppConstants.sys.mjs" +); + +window.addEventListener("DOMContentLoaded", () => { + for (let img of document.querySelectorAll(".infoIcon")) { + img.setAttribute( + "src", + "chrome://messenger/skin/icons/new/activity/warning.svg" + ); + } +}); + +var log = console.createInstance({ + prefix: "mail.mailstoreconverter", + maxLogLevel: "Warn", + maxLogLevelPref: "mail.mailstoreconverter.loglevel", +}); +// {nsIMsgIncomingServer} server for the account to be migrated. +var gServer; +// {nsIMsgFolder} account root folder. +var gFolder; +// 'gResponse.newRootFolder' is path to the new account root folder if migration +// is complete, else null. +// 'gResponse' is set to the modified response parameter received from +// am-server.js. +var gResponse; +// Array to hold deferred accounts. +var gDeferredAccounts = []; +// Value of Services.io.offline before migration. +var gOriginalOffline; +/** + * Place account name in migration dialog modal. + * + * @param {nsIMsgIncomingServer} aServer - account server. + */ +function placeAccountName(aServer) { + gOriginalOffline = Services.io.offline; + + let bundle = Services.strings.createBundle( + "chrome://messenger/locale/converterDialog.properties" + ); + + let brandShortName = Services.strings + .createBundle("chrome://branding/locale/brand.properties") + .GetStringFromName("brandShortName"); + + // 'deferredToRootFolder' holds path of rootMsgFolder of account to which + // other accounts have been deferred. + let deferredToRootFolder = aServer.rootMsgFolder.filePath.path; + // String to hold names of deferred accounts separated by commas. + let deferredAccountsString = ""; + // Account to which other accounts have been deferred. + let deferredToAccount; + // Array of all accounts. + let accounts = FolderUtils.allAccountsSorted(true); + + for (let account of accounts) { + if ( + account.incomingServer.rootFolder.filePath.path == deferredToRootFolder + ) { + // Other accounts may be deferred to this account. + deferredToAccount = account; + } else if ( + account.incomingServer.rootMsgFolder.filePath.path == deferredToRootFolder + ) { + // This is a deferred account. + gDeferredAccounts.push(account); + } + } + + // String to hold the names of accounts to be converted separated by commas. + let accountsToConvert = ""; + + if (gDeferredAccounts.length >= 1) { + // Add account names to 'accountsToConvert' and 'deferredAccountsString'. + for (let i = 0; i < gDeferredAccounts.length; i++) { + if (i < gDeferredAccounts.length - 1) { + accountsToConvert += + gDeferredAccounts[i].incomingServer.username + ", "; + deferredAccountsString += + gDeferredAccounts[i].incomingServer.username + ", "; + } else { + accountsToConvert += gDeferredAccounts[i].incomingServer.username; + deferredAccountsString += gDeferredAccounts[i].incomingServer.username; + } + } + + // Username of Local Folders is "nobody". So it's better to use + // its hostname which is "Local Folders". + // TODO: maybe test against .key == MailServices.accounts.localFoldersServer.key ? + if (deferredToAccount.incomingServer.hostName == "Local Folders") { + accountsToConvert += ", " + deferredToAccount.incomingServer.prettyName; + } else { + accountsToConvert += ", " + deferredToAccount.incomingServer.prettyName; + } + log.info(accountsToConvert + " will be converted"); + let storeContractId = Services.prefs.getCharPref( + "mail.server." + deferredToAccount.incomingServer.key + ".storeContractID" + ); + + if (storeContractId == "@mozilla.org/msgstore/berkeleystore;1") { + storeContractId = "maildir"; + } else { + storeContractId = "mbox"; + } + + // Username of Local Folders is "nobody". So it's better to use + // its hostname which is "Local Folders". + // TODO: maybe test against .key != MailServices.accounts.localFoldersServer.key ? + let deferredToAccountName = deferredToAccount.incomingServer.hostName; + if (deferredToAccountName != "Local Folders") { + deferredToAccountName = deferredToAccount.incomingServer.username; + } + + if (aServer.rootFolder.filePath.path != deferredToRootFolder) { + document.getElementById("warningSpan").textContent = + bundle.formatStringFromName( + "converterDialog.warningForDeferredAccount", + [ + aServer.username, + deferredToAccountName, + deferredToAccountName, + deferredAccountsString, + accountsToConvert, + storeContractId, + brandShortName, + ] + ); + } else { + document.getElementById("warningSpan").textContent = + bundle.formatStringFromName( + "converterDialog.warningForDeferredToAccount", + [ + deferredToAccountName, + deferredAccountsString, + accountsToConvert, + storeContractId, + brandShortName, + ] + ); + } + + document.getElementById("messageSpan").textContent = + bundle.formatStringFromName("converterDialog.messageForDeferredAccount", [ + accountsToConvert, + storeContractId, + ]); + gServer = deferredToAccount.incomingServer; + } else { + // No account is deferred. + let storeContractId = Services.prefs.getCharPref( + "mail.server." + aServer.key + ".storeContractID" + ); + if (storeContractId == "@mozilla.org/msgstore/berkeleystore;1") { + storeContractId = "maildir"; + } else { + storeContractId = "mbox"; + } + + let tempName = aServer.username; + if (tempName == "nobody") { + tempName = "Local Folders"; + } else if (!tempName) { + tempName = aServer.hostName; + } + + document.getElementById("warningSpan").textContent = + bundle.formatStringFromName("converterDialog.warning", [ + tempName, + storeContractId, + brandShortName, + ]); + document.getElementById("messageSpan").textContent = + bundle.formatStringFromName("converterDialog.message", [ + tempName, + storeContractId, + ]); + gServer = aServer; + } + + // Forces the resize of the dialog to the actual content + window.sizeToContent(); +} + +/** + * Start the conversion process. + * + * @param {string} aSelectedStoreType - mailstore type selected by user. + * @param {object} aResponse - response from the migration dialog modal. + */ +function startContinue(aSelectedStoreType, aResponse) { + gResponse = aResponse; + gFolder = gServer.rootFolder.filePath; + + let bundle = Services.strings.createBundle( + "chrome://messenger/locale/converterDialog.properties" + ); + + document + .getElementById("progress") + .addEventListener("progress", function (e) { + document.getElementById("progress").value = e.detail; + document.getElementById("progressPercent").textContent = + bundle.formatStringFromName("converterDialog.percentDone", [e.detail]); + }); + + document.getElementById("warningArea").hidden = true; + document.getElementById("progressArea").hidden = false; + + // Storing original prefs and root folder path + // to revert changes in case of error. + let p1 = "mail.server." + gServer.key + ".directory"; + let p2 = "mail.server." + gServer.key + ".directory-rel"; + let p3 = "mail.server." + gServer.key + ".newsrc.file"; + let p4 = "mail.server." + gServer.key + ".newsrc.file-rel"; + let p5 = "mail.server." + gServer.key + ".storeContractID"; + + let originalDirectoryPref = Services.prefs.getCharPref(p1); + let originalDirectoryRelPref = Services.prefs.getCharPref(p2); + let originalNewsrcFilePref; + let originalNewsrcFileRelPref; + if (gServer.type == "nntp") { + originalNewsrcFilePref = Services.prefs.getCharPref(p3); + originalNewsrcFileRelPref = Services.prefs.getCharPref(p4); + } + let originalStoreContractID = Services.prefs.getCharPref(p5); + let originalRootFolderPath = gServer.rootFolder.filePath.path; + + /** + * Called when promise returned by convertMailStoreTo() is rejected. + * + * @param {string} aReason - error because of which the promise was rejected. + */ + function promiseRejected(aReason) { + log.error("Conversion to '" + aSelectedStoreType + "' failed: " + aReason); + document.getElementById("messageSpan").hidden = true; + + document.getElementById("errorSpan").hidden = false; + gResponse.newRootFolder = null; + + // Revert prefs. + Services.prefs.setCharPref(p1, originalDirectoryPref); + Services.prefs.setCharPref(p2, originalDirectoryRelPref); + if (gServer.type == "nntp") { + Services.prefs.setCharPref(p3, originalNewsrcFilePref); + Services.prefs.setCharPref(p4, originalNewsrcFileRelPref); + } + Services.prefs.setCharPref(p5, originalStoreContractID); + Services.prefs.savePrefFile(null); + if (gServer.rootFolder.filePath.path != originalRootFolderPath) { + gServer.rootFolder.filePath = new FileUtils.File(originalRootFolderPath); + } + Services.io.offline = gOriginalOffline; + } + + /** + * Called when promise returned by convertMailStoreTo() is resolved. + * + * @param {string} aVal - path of the new account root folder with which the + * promise returned by convertMailStoreTo() is resolved. + */ + function promiseResolved(aVal) { + log.info("Converted to '" + aSelectedStoreType + "' - " + aVal); + + gResponse.newRootFolder = aVal; + for (let deferredAccount of gDeferredAccounts) { + let defServer = deferredAccount.incomingServer; + defServer.rootMsgFolder.filePath = new FileUtils.File(aVal); + Services.prefs.setCharPref( + "mail.server." + defServer.key + ".storeContractID", + aSelectedStoreType + ); + } + + Services.io.offline = gOriginalOffline; + document.getElementById("cancel").hidden = true; + document.getElementById("finish").hidden = false; + document.getElementById("messageSpan").hidden = true; + document.getElementById("completeSpan").hidden = false; + } + + /** + * Check whether an mbox folder can be compacted or not. + * + * @param {nsIMsgFolder} aFolder - mbox folder that is to be checked. + */ + function canCompact(aFolder) { + if (aFolder.expungedBytes != 0) { + return true; + } + if (aFolder.hasSubFolders) { + for (let subFolder of aFolder.subFolders) { + if (canCompact(subFolder)) { + return true; + } + } + } + return false; + } + + // Compaction (compactAll()) works only for mbox folders which satisfy one of + // the following 2 conditions - + // 1. Messages are moved out of the folder. + // 2. Messages are moved out of some descendant folder of the folder. + // If the account root folder can be compacted, start the conversion after + // compacting it. + if ( + originalStoreContractID == "@mozilla.org/msgstore/berkeleystore;1" && + canCompact(gServer.rootFolder) + ) { + let urlListener = { + OnStartRunningUrl(aUrl) {}, + OnStopRunningUrl(aUrl, aExitCode) { + let pConvert = MailstoreConverter.convertMailStoreTo( + originalStoreContractID, + gServer, + document.getElementById("progress") + ); + pConvert + .then(function (val) { + promiseResolved(val); + }) + .catch(function (reason) { + promiseRejected(reason); + }); + }, + }; + gServer.rootFolder.compactAll(urlListener, null); + } else { + let pConvert = MailstoreConverter.convertMailStoreTo( + originalStoreContractID, + gServer, + document.getElementById("progress") + ); + pConvert + .then(function (val) { + promiseResolved(val); + }) + .catch(function (reason) { + promiseRejected(reason); + }); + } +} + +/** + * Cancel the conversion. + * + * @param {object} aResponse - response param from the migration dialog modal. + */ +function cancelConversion(aResponse) { + gResponse = aResponse; + gResponse.newRootFolder = null; + MailstoreConverter.terminateWorkers(); + Services.io.offline = gOriginalOffline; + window.close(); +} + +/** + * Called when "finish" button is clicked. + */ +function finishConversion() { + window.close(); +} |