summaryrefslogtreecommitdiffstats
path: root/comm/suite/components/migration
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /comm/suite/components/migration
parentInitial commit. (diff)
downloadthunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz
thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--comm/suite/components/migration/SuiteProfileMigrator.js149
-rw-r--r--comm/suite/components/migration/SuiteProfileMigrator.manifest2
-rw-r--r--comm/suite/components/migration/content/migration.js413
-rw-r--r--comm/suite/components/migration/content/migration.xul95
-rw-r--r--comm/suite/components/migration/jar.mn7
-rw-r--r--comm/suite/components/migration/moz.build19
-rw-r--r--comm/suite/components/migration/public/moz.build15
-rw-r--r--comm/suite/components/migration/public/nsISuiteProfileMigrator.idl76
-rw-r--r--comm/suite/components/migration/public/nsSuiteMigrationCID.h8
-rw-r--r--comm/suite/components/migration/src/moz.build13
-rw-r--r--comm/suite/components/migration/src/nsSuiteProfileMigratorBase.cpp844
-rw-r--r--comm/suite/components/migration/src/nsSuiteProfileMigratorBase.h147
-rw-r--r--comm/suite/components/migration/src/nsSuiteProfileMigratorUtils.cpp66
-rw-r--r--comm/suite/components/migration/src/nsSuiteProfileMigratorUtils.h60
-rw-r--r--comm/suite/components/migration/src/nsThunderbirdProfileMigrator.cpp571
-rw-r--r--comm/suite/components/migration/src/nsThunderbirdProfileMigrator.h44
16 files changed, 2529 insertions, 0 deletions
diff --git a/comm/suite/components/migration/SuiteProfileMigrator.js b/comm/suite/components/migration/SuiteProfileMigrator.js
new file mode 100644
index 0000000000..0ad4dfcca3
--- /dev/null
+++ b/comm/suite/components/migration/SuiteProfileMigrator.js
@@ -0,0 +1,149 @@
+/* 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/. */
+
+"use strict";
+
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { XPCOMUtils } =
+ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+const { FileUtils } =
+ ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
+const { AppConstants } =
+ ChromeUtils.import('resource://gre/modules/AppConstants.jsm');
+
+ChromeUtils.defineModuleGetter(this, "FileUtils",
+ "resource://gre/modules/FileUtils.jsm");
+
+function ProfileMigrator() {
+}
+
+ProfileMigrator.prototype = {
+ migrate: function PM_migrate(aStartup) {
+ // By opening the wizard with a supplied migrator, it will automatically
+ // migrate from it.
+ let [key, migrator] = this._getDefaultMigrator();
+ if (!key)
+ return;
+
+ let params = Cc["@mozilla.org/array;1"]
+ .createInstance(Ci.nsIMutableArray);
+ params.appendElement(this._toString(key));
+ params.appendElement(migrator);
+ params.appendElement(aStartup);
+
+ Services.ww.openWindow(null,
+ "chrome://communicator/content/migration/migration.xul",
+ "_blank",
+ "chrome,dialog,modal,centerscreen,titlebar",
+ params);
+ },
+
+ _toString: function PM__toString(aStr) {
+ let str = Cc["@mozilla.org/supports-string;1"]
+ .createInstance(Ci.nsISupportsString);
+ str.data = aStr;
+ return str;
+ },
+
+ _getMigratorIfSourceExists: function PM__getMigratorIfSourceExists(aKey) {
+ let cid = "@mozilla.org/profile/migrator;1?app=suite&type=" + aKey;
+ let migrator = Cc[cid].createInstance(Ci.nsISuiteProfileMigrator);
+ if (migrator.sourceExists)
+ return migrator;
+ return null;
+ },
+
+ // We don't yet support checking for the default browser on all platforms,
+ // needless to say we don't have migrators for all browsers. Thus, for each
+ // platform, there's a fallback list of migrators used in these cases.
+ _PLATFORM_FALLBACK_LIST:
+ ["thunderbird"],
+
+ _getDefaultMigrator: function PM__getDefaultMigrator() {
+
+ let migratorsOrdered = Array.from(this._PLATFORM_FALLBACK_LIST);
+
+ // FIXME This is all so not working currently.
+ // There are currently no migrators for browsers available.
+ // See Bug 739056.
+ if (false) {
+ let defaultBrowser = "";
+
+ if (AppConstants.platform == "win") {
+ try {
+ const REG_KEY = "SOFTWARE\\Classes\\HTTP\\shell\\open\\command";
+ let regKey = Cc["@mozilla.org/windows-registry-key;1"]
+ .createInstance(Ci.nsIWindowsRegKey);
+ regKey.open(regKey.ROOT_KEY_LOCAL_MACHINE, REG_KEY,
+ regKey.ACCESS_READ);
+ let value = regKey.readStringValue("").toLowerCase();
+ let pathMatches = value.match(/^"?(.+?\.exe)"?/);
+ if (!pathMatches) {
+ throw new Error("Could not extract path from " +
+ REG_KEY + "(" + value + ")");
+ }
+
+ // We want to find out what the default browser is but the path in and of
+ // itself isn't enough. Why? Because sometimes on Windows paths get
+ // truncated like so: C:\PROGRA~1\MOZILL~2\MOZILL~1.EXE. How do we know
+ // what product that is? Mozilla's file objects do nothing to 'normalize'
+ // the path so we need to attain an actual product descriptor from the
+ // file somehow, and in this case it means getting the "InternalName"
+ // field of the file's VERSIONINFO resource.
+ //
+ // In the file's resource segment there is a VERSIONINFO section that is
+ // laid out like this:
+ //
+ // VERSIONINFO
+ // StringFileInfo
+ // <TranslationID>
+ // InternalName "iexplore"
+ // VarFileInfo
+ // Translation <TranslationID>
+ //
+ // By Querying the VERSIONINFO section for its Tranlations, we can find
+ // out where the InternalName lives (A file can have more than one
+ // translation of its VERSIONINFO segment, but we just assume the first
+ // one).
+ let file = FileUtils.File(pathMatches[1])
+ .QueryInterface(Ci.nsILocalFileWin);
+ switch (file.getVersionInfoField("InternalName").toLowerCase()) {
+ case "iexplore":
+ defaultBrowser = "ie";
+ break;
+ case "chrome":
+ defaultBrowser = "chrome";
+ break;
+ }
+ }
+ catch (ex) {
+ Cu.reportError("Could not retrieve default browser: " + ex);
+ }
+ }
+
+ // If we found the default browser and we have support for that browser,
+ // make sure to check it before any other browser, by moving it to the head
+ // of the array.
+ if (defaultBrowser) {
+ migratorsOrdered.sort((a, b) => b == defaultBrowser ? 1 : 0);
+ }
+ }
+
+ for (let key of migratorsOrdered) {
+ let migrator = this._getMigratorIfSourceExists(key);
+ if (migrator) {
+ return [key, migrator];
+ }
+ }
+
+ return ["", null];
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIProfileMigrator]),
+ classDescription: "Profile Migrator",
+ contractID: "@mozilla.org/toolkit/profile-migrator;1",
+ classID: Components.ID("{d5148b7c-ba4e-4f7a-a80b-1ae48b90b910}"),
+};
+
+var NSGetFactory = XPCOMUtils.generateNSGetFactory([ProfileMigrator]);
diff --git a/comm/suite/components/migration/SuiteProfileMigrator.manifest b/comm/suite/components/migration/SuiteProfileMigrator.manifest
new file mode 100644
index 0000000000..a57376b855
--- /dev/null
+++ b/comm/suite/components/migration/SuiteProfileMigrator.manifest
@@ -0,0 +1,2 @@
+component {d5148b7c-ba4e-4f7a-a80b-1ae48b90b910} SuiteProfileMigrator.js
+contract @mozilla.org/toolkit/profile-migrator;1 {d5148b7c-ba4e-4f7a-a80b-1ae48b90b910}
diff --git a/comm/suite/components/migration/content/migration.js b/comm/suite/components/migration/content/migration.js
new file mode 100644
index 0000000000..b106e51e22
--- /dev/null
+++ b/comm/suite/components/migration/content/migration.js
@@ -0,0 +1,413 @@
+/* -*- Mode: Java; 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/. */
+
+var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+const NS_PROFILE_MIGRATOR_CONTRACTID =
+ "@mozilla.org/profile/migrator;1?app=suite&type=";
+
+var MigrationWizard = {
+ _source: "", // Source Profile Migrator ContractID suffix
+ _itemsFlags: Ci.nsISuiteProfileMigrator.ALL, // Selected Import Data Sources
+ _selectedProfile: null, // Selected Profile name to import from
+ _wiz: null, // Shortcut to the wizard
+ _migrator: null, // The actual profile migrator.
+ _autoMigrate: null, // Whether or not we are actually migrating.
+ _singleItem: false, // Are we choosing just to import a single
+ // item into the current profile?
+ _newHomePage: null, // Are we setting a new home page - what to?
+
+ init: function() {
+ Services.obs.addObserver(this, "Migration:Started");
+ Services.obs.addObserver(this, "Migration:ItemBeforeMigrate");
+ Services.obs.addObserver(this, "Migration:ItemAfterMigrate");
+ Services.obs.addObserver(this, "Migration:Ended");
+ Services.obs.addObserver(this, "Migration:Progress");
+
+ this._wiz = document.documentElement;
+ this._wiz.canRewind = false;
+
+ if ("arguments" in window) {
+ if ("arguments" in window && window.arguments[0] == "bookmarks") {
+ this._singleItem = true;
+ this._itemsFlags = Ci.nsISuiteProfileMigrator.BOOKMARKS;
+ document.getElementById("fromFile").hidden = false;
+ document.getElementById("importBookmarks").hidden = false;
+ document.getElementById("importAll").hidden = true;
+ }
+ else if (window.arguments.length > 1) {
+ this._source = window.arguments[0];
+ this._migrator =
+ window.arguments[1] instanceof Ci.nsISuiteProfileMigrator ?
+ window.arguments[1] : null;
+ this._autoMigrate = window.arguments[2]
+ .QueryInterface(Ci.nsIProfileStartup);
+ // Show the "nothing" option in the automigrate case to provide an
+ // easily identifiable way to avoid migration and create a new profile.
+ document.getElementById("nothing").hidden = false;
+ }
+ }
+
+ this.onImportSourcePageShow();
+ },
+
+ uninit: function() {
+ Services.obs.removeObserver(this, "Migration:Started");
+ Services.obs.removeObserver(this, "Migration:ItemBeforeMigrate");
+ Services.obs.removeObserver(this, "Migration:ItemAfterMigrate");
+ Services.obs.removeObserver(this, "Migration:Ended");
+ Services.obs.removeObserver(this, "Migration:Progress");
+ },
+
+ // 1 - Import Source
+ onImportSourcePageShow: function() {
+ // Figure out what source apps are are available to import from:
+ var group = document.getElementById("importSourceGroup");
+ var firstSelectable = null;
+ for (var i = 0; i < group.childNodes.length; ++i) {
+ var suffix = group.childNodes[i].id;
+ if (suffix != "nothing" && suffix != "fromFile") {
+ var contractID = NS_PROFILE_MIGRATOR_CONTRACTID + suffix;
+ var migrator = null;
+ if (contractID in Cc) {
+ migrator = Cc[contractID]
+ .createInstance(Ci.nsISuiteProfileMigrator);
+ } else {
+ dump("*** invalid contractID =" + contractID + "\n");
+ // This is an invalid contract id, therefore hide this element
+ // and allow things to continue - that way we should be able to
+ // copy with anything happening.
+ group.childNodes[i].hidden = true;
+ break;
+ }
+
+ // Ensure that we only allow import selections for profile
+ // migrators that support the requested action.
+ if (!migrator.sourceExists ||
+ !(migrator.supportedItems & this._itemsFlags)) {
+ group.childNodes[i].hidden = true;
+ break;
+ }
+
+ if (!firstSelectable && !group.childNodes[i].disabled &&
+ !group.childNodes[i].hidden) {
+ firstSelectable = group.childNodes[i];
+ }
+ }
+ }
+
+ if (this._source) {
+ // Somehow the Profile Migrator got confused, and gave us a migrate source
+ // that doesn't actually exist. This could be because of a bogus registry
+ // state. Set the _source property to null so the first visible item in
+ // the list is selected instead.
+ if (document.getElementById(this._source).hidden)
+ this._source = null;
+ }
+ group.selectedItem = this._source ?
+ document.getElementById(this._source) : firstSelectable;
+ },
+
+ onImportSourcePageAdvanced: function() {
+ var newSource = document.getElementById("importSourceGroup").value;
+
+ if (newSource == "nothing" || newSource == "fromFile") {
+ if (newSource == "fromFile") {
+ window.opener.fromFile = true;
+ }
+ document.documentElement.cancel();
+ // Don't let the wizard migrate to the next page event though we've
+ // called cancel - cancel may not get processed first.
+ return false;
+ }
+
+ if (!this._migrator || newSource != this._source) {
+ // Create the migrator for the selected source.
+ var contractID = NS_PROFILE_MIGRATOR_CONTRACTID + newSource;
+ this._migrator = Cc[contractID]
+ .createInstance(Ci.nsISuiteProfileMigrator);
+
+ this._selectedProfile = null;
+ }
+ this._source = newSource;
+
+ // check for more than one source profile
+ if (this._migrator.sourceHasMultipleProfiles)
+ this._wiz.currentPage.next = "selectProfile";
+ else {
+ if (this._autoMigrate)
+ this._wiz.currentPage.next = "homePageImport";
+ else if (this._singleItem)
+ this._wiz.currentPage.next = "migrating";
+ else
+ this._wiz.currentPage.next = "importItems";
+
+ var sourceProfiles = this._migrator.sourceProfiles;
+ if (sourceProfiles && sourceProfiles.length == 1) {
+ this._selectedProfile = sourceProfiles
+ .queryElementAt(0, Ci.nsISupportsString).data;
+ }
+ else
+ this._selectedProfile = "";
+ }
+ return true;
+ },
+
+ // 2 - [Profile Selection]
+ onSelectProfilePageShow: function() {
+ var profiles = document.getElementById("profiles");
+ while (profiles.hasChildNodes())
+ profiles.lastChild.remove();
+
+ var sourceProfiles = this._migrator.sourceProfiles;
+ var count = sourceProfiles.length;
+ for (var i = 0; i < count; ++i) {
+ var item = document.createElement("radio");
+ item.id = sourceProfiles.queryElementAt(i, Ci.nsISupportsString).data;
+ item.setAttribute("label", item.id);
+ profiles.appendChild(item);
+ }
+
+ profiles.selectedItem = this._selectedProfile ?
+ document.getElementById(this._selectedProfile) : profiles.firstChild;
+ },
+
+ onSelectProfilePageAdvanced: function() {
+ this._selectedProfile = document.getElementById("profiles").selectedItem.id;
+
+ // If we're automigrating or just doing bookmarks don't show the item
+ // selection page
+ if (this._autoMigrate)
+ this._wiz.currentPage.next = "homePageImport";
+ else if (this._singleItem)
+ this._wiz.currentPage.next = "migrating"
+ },
+
+ // 3 - ImportItems
+ onImportItemsPageShow: function() {
+ var dataSources = document.getElementById("dataSources");
+ while (dataSources.hasChildNodes())
+ dataSources.lastChild.remove();
+
+ var bundle = document.getElementById("bundle");
+
+ var items = this._migrator.getMigrateData(this._selectedProfile,
+ this._autoMigrate);
+
+ for (var i = 0; i < 16; ++i) {
+ var itemID = items & (1 << i);
+ if (itemID) {
+ var checkbox = document.createElement("checkbox");
+ checkbox.id = itemID;
+ try {
+ checkbox.setAttribute("label",
+ bundle.getString(itemID + "_" + this._source));
+ }
+ catch (ex) {
+ checkbox.setAttribute("label",
+ bundle.getString(itemID + "_generic"));
+ }
+ dataSources.appendChild(checkbox);
+ if (this._itemsFlags & itemID)
+ checkbox.setAttribute("checked", true);
+ }
+ }
+ },
+
+ onImportItemsPageRewound: function() {
+ this._wiz.canAdvance = true;
+ this.onImportItemsPageAdvanced();
+ },
+
+ onImportItemsPageAdvanced: function() {
+ var dataSources = document.getElementById("dataSources");
+ this._itemsFlags = 0;
+ for (var i = 0; i < dataSources.childNodes.length; ++i) {
+ var checkbox = dataSources.childNodes[i];
+ if (checkbox.checked)
+ this._itemsFlags |= checkbox.id;
+ }
+ },
+
+ onImportItemCommand: function(aEvent) {
+ this._wiz.canAdvance = document
+ .getElementById("dataSources")
+ .getElementsByAttribute("checked", "true").item(0) != null;
+ },
+
+ // 4 - Home Page Selection
+ onHomePageMigrationPageShow: function() {
+ // only want this on the first run
+ if (!this._autoMigrate) {
+ this._wiz.advance();
+ return;
+ }
+
+ var bundle = document.getElementById("bundle");
+ var pageTitle = bundle.getString("homePageMigrationPageTitle");
+ var pageDesc = bundle.getString("homePageMigrationDescription");
+
+ document.getElementById("homePageImport").setAttribute("label", pageTitle);
+ document.getElementById("homePageImportDesc")
+ .setAttribute("value", pageDesc);
+
+ this._wiz._adjustWizardHeader();
+
+ var homePageStart = document.getElementById("homePageStart");
+
+ // Find out if the target profile already has a homepage or not
+ var mainStr = this.targetHasHomePageURL() ?
+ bundle.getString("homePageStartCurrent") :
+ bundle.getString("homePageStartDefault");
+
+ homePageStart.setAttribute("label", mainStr);
+
+ var source = null;
+ if (this._source != "") {
+ source = "sourceName" + this._source;
+ }
+
+ var availableItems = this._migrator.getMigrateData(this._selectedProfile,
+ this._autoMigrate);
+
+ if (source && (availableItems & Ci.nsISuiteProfileMigrator.HOMEPAGEDATA)) {
+ var appName = document.getElementById("bundle").getString(source);
+ var oldHomePageLabel = bundle.getFormattedString("homePageImport",
+ [appName]);
+ var oldHomePage = document.getElementById("oldHomePage");
+ oldHomePage.setAttribute("label", oldHomePageLabel);
+ oldHomePage.setAttribute("value", "source");
+ oldHomePage.removeAttribute("hidden");
+ oldHomePage.focus();
+
+ document.getElementById("homePageRadioGroup").selectedItem = oldHomePage;
+ }
+ else {
+ // if we don't have at least two options, just advance
+ this._wiz.advance();
+ }
+ },
+
+ onHomePageMigrationPageAdvanced: function() {
+ // we might not have a selectedItem if we're in fallback mode
+ try {
+ this._newHomePage = document.getElementById("homePageRadioGroup")
+ .value;
+ } catch(ex) {}
+ },
+
+ // 5 - Migrating
+ onMigratingPageShow: function() {
+ this._wiz.getButton("cancel").disabled = true;
+ this._wiz.canRewind = false;
+ this._wiz.canAdvance = false;
+
+ // When migrating a profile on startup, show all of the data that can be
+ // received from this source, but exclude home pages if the user didn't
+ // want to migrate it.
+ if (this._autoMigrate) {
+ this._itemsFlags = this._migrator.getMigrateData(this._selectedProfile,
+ this._autoMigrate);
+ if (!this._newHomePage)
+ this._itemsFlags &= ~Ci.nsISuiteProfileMigrator.HOMEPAGEDATA;
+ }
+
+ this._listItems("migratingItems");
+ setTimeout(this.onMigratingMigrate, 0, this);
+ },
+
+ onMigratingMigrate: function(aOuter) {
+ aOuter._migrator.migrate(aOuter._itemsFlags,
+ aOuter._autoMigrate,
+ aOuter._selectedProfile);
+ },
+
+ _listItems: function(aID) {
+ var items = document.getElementById(aID);
+ while (items.hasChildNodes())
+ items.lastChild.remove();
+
+ var bundle = document.getElementById("bundle");
+ var itemID;
+ for (var x = 1; x < Ci.nsISuiteProfileMigrator.ALL;
+ x = x << 1) {
+ if (x & this._itemsFlags) {
+ var label = document.createElement("label");
+ label.id = x + "_migrated";
+ try {
+ label.setAttribute("value",
+ bundle.stringBundle
+ .GetStringFromName(x + "_"+ this._source));
+ label.setAttribute("class", "migration-pending");
+ items.appendChild(label);
+ }
+ catch (ex) {
+ try {
+ label.setAttribute("value", bundle.getString(x + "_generic"));
+ label.setAttribute("class", "migration-pending");
+ items.appendChild(label);
+ }
+ catch (e) {
+ // if the block above throws, we've enumerated all the import
+ // data types we currently support and are now just wasting time.
+ break;
+ }
+ }
+ }
+ }
+ },
+
+ observe: function(aSubject, aTopic, aData) {
+ switch (aTopic) {
+ case "Migration:Progress":
+ document.getElementById("progressBar").value = aData;
+ break;
+ case "Migration:Started":
+ break;
+ case "Migration:ItemBeforeMigrate":
+ var label = document.getElementById(aData + "_migrated");
+ if (label)
+ label.setAttribute("class", "migration-in-progress");
+ break;
+ case "Migration:ItemAfterMigrate":
+ var label = document.getElementById(aData + "_migrated");
+ if (label)
+ label.setAttribute("class", "migration-finished");
+ break;
+ case "Migration:Ended":
+ // We're done now.
+ this._wiz.canAdvance = true;
+ this._wiz.advance();
+
+ if (this._autoMigrate)
+ setTimeout(close, 5000);
+
+ break;
+ }
+ },
+
+ onDonePageShow: function() {
+ this._wiz.getButton("cancel").disabled = true;
+ this._wiz.canRewind = false;
+ this._listItems("doneItems");
+ },
+
+ targetHasHomePageURL: function() {
+ var targetPrefsFile = this._autoMigrate.directory;
+
+ targetPrefsFile.append("prefs.js");
+
+ // If the target prefs file doesn't exist, then we can't have a
+ // homepage set in the target profile.
+ if (!targetPrefsFile.exists())
+ return false;
+
+ Services.prefs.resetPrefs();
+
+ Services.prefs.readUserPrefsFromFile(targetPrefsFile);
+
+ return Services.prefs.prefHasUserValue("browser.startup.homepage");
+ }
+};
diff --git a/comm/suite/components/migration/content/migration.xul b/comm/suite/components/migration/content/migration.xul
new file mode 100644
index 0000000000..ad8b279361
--- /dev/null
+++ b/comm/suite/components/migration/content/migration.xul
@@ -0,0 +1,95 @@
+<?xml version="1.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/. -->
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://communicator/locale/migration/migration.dtd" >
+
+<wizard id="migrationWizard"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ title="&migrationWizard.title;"
+ onload="MigrationWizard.init()"
+ onunload="MigrationWizard.uninit()"
+ style="width: 40em; height: 32em;"
+ branded="true"
+ buttons="accept,cancel"
+ xmlns:xhtml="http://www.w3.org/1999/xhtml">
+
+ <script src="chrome://communicator/content/migration/migration.js"/>
+
+ <stringbundle id="bundle"
+ src="chrome://communicator/locale/migration/migration.properties"/>
+
+ <wizardpage id="importSource" pageid="importSource" next="selectProfile"
+ label="&importSource.title;"
+ onpageadvanced="return MigrationWizard.onImportSourcePageAdvanced();">
+ <label id="importAll"
+ control="importSourceGroup">&importAllFrom.label;</label>
+ <label id="importBookmarks" control="importSourceGroup"
+ hidden="true">&importBookmarksFrom.label;</label>
+
+ <radiogroup id="importSourceGroup" align="start">
+ <radio id="thunderbird" label="&importFromThunderbird.label;"
+ accesskey="&importFromThunderbird.accesskey;"
+ value="thunderbird"/>
+ <!-- fromfile is used for bookmark importing -->
+ <radio id="fromFile" label="&importFromFile.label;" value="fromFile"
+ accesskey="&importFromFile.accesskey;" hidden="true"/>
+ <radio id="nothing" label="&importFromNothing.label;" value="nothing"
+ accesskey="&importFromNothing.accesskey;" hidden="true"/>
+ </radiogroup>
+ </wizardpage>
+
+ <wizardpage id="selectProfile" pageid="selectProfile"
+ label="&selectProfile.title;" next="importItems"
+ onpageshow="return MigrationWizard.onSelectProfilePageShow();"
+ onpageadvanced="return MigrationWizard.onSelectProfilePageAdvanced();">
+ <label control="profiles">&selectProfile.label;</label>
+
+ <radiogroup id="profiles" align="left"/>
+ </wizardpage>
+
+ <wizardpage id="importItems" pageid="importItems" label="&importItems.title;"
+ next="homePageImport"
+ onpageshow="return MigrationWizard.onImportItemsPageShow();"
+ onpageadvanced="return MigrationWizard.onImportItemsPageAdvanced();"
+ oncommand="MigrationWizard.onImportItemCommand();">
+ <label control="dataSources">&importItems.label;</label>
+
+ <vbox id="dataSources" style="overflow-y: auto;"
+ align="left" flex="1" role="group"/>
+ </wizardpage>
+
+ <wizardpage id="homePageImport" pageid="homePageImport"
+ next="migrating"
+ onpageshow="return MigrationWizard.onHomePageMigrationPageShow();"
+ onpageadvanced="return MigrationWizard.onHomePageMigrationPageAdvanced();">
+
+ <label id="homePageImportDesc" control="homePageRadioGroup"/>
+ <radiogroup id="homePageRadioGroup" align="start">
+ <radio id="oldHomePage" hidden="true"/>
+ <radio id="homePageStart" selected="true"/>
+ </radiogroup>
+ </wizardpage>
+
+ <wizardpage id="migrating" pageid="migrating" label="&migrating.title;"
+ next="done" onpageshow="MigrationWizard.onMigratingPageShow();">
+ <label control="migratingItems">&migrating.label;</label>
+
+ <vbox id="migratingItems" style="overflow-y: auto;" align="left" role="group"/>
+
+ <hbox>
+ <progressmeter class="progressmeter-statusbar" id="progressBar"
+ flex="1" mode="normal" value="0"/>
+ </hbox>
+ </wizardpage>
+
+ <wizardpage id="done" pageid="done" label="&done.title;"
+ onpageshow="MigrationWizard.onDonePageShow();">
+ <label control="doneItems">&done.label;</label>
+
+ <vbox id="doneItems" style="overflow-y: auto;" align="left" role="group"/>
+ </wizardpage>
+</wizard>
diff --git a/comm/suite/components/migration/jar.mn b/comm/suite/components/migration/jar.mn
new file mode 100644
index 0000000000..a202ce87a1
--- /dev/null
+++ b/comm/suite/components/migration/jar.mn
@@ -0,0 +1,7 @@
+# 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/.
+
+comm.jar:
+ content/communicator/migration/migration.xul (content/migration.xul)
+ content/communicator/migration/migration.js (content/migration.js)
diff --git a/comm/suite/components/migration/moz.build b/comm/suite/components/migration/moz.build
new file mode 100644
index 0000000000..ef93d7617a
--- /dev/null
+++ b/comm/suite/components/migration/moz.build
@@ -0,0 +1,19 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+DIRS += [
+ "public",
+ "src",
+]
+
+EXTRA_COMPONENTS += [
+ "SuiteProfileMigrator.js",
+ "SuiteProfileMigrator.manifest",
+]
+
+FINAL_LIBRARY = "suite"
+
+JAR_MANIFESTS += ["jar.mn"]
diff --git a/comm/suite/components/migration/public/moz.build b/comm/suite/components/migration/public/moz.build
new file mode 100644
index 0000000000..a25b10157b
--- /dev/null
+++ b/comm/suite/components/migration/public/moz.build
@@ -0,0 +1,15 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+XPIDL_SOURCES += [
+ "nsISuiteProfileMigrator.idl",
+]
+
+XPIDL_MODULE = "suitemigration"
+
+EXPORTS += [
+ "nsSuiteMigrationCID.h",
+]
diff --git a/comm/suite/components/migration/public/nsISuiteProfileMigrator.idl b/comm/suite/components/migration/public/nsISuiteProfileMigrator.idl
new file mode 100644
index 0000000000..ca0bd98413
--- /dev/null
+++ b/comm/suite/components/migration/public/nsISuiteProfileMigrator.idl
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; 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/. */
+
+#include "nsISupports.idl"
+
+interface nsIArray;
+interface nsIProfileStartup;
+
+[scriptable, uuid(b6adb2b8-5e3b-4fdd-b085-d58998b5c21a)]
+interface nsISuiteProfileMigrator : nsISupports
+{
+ /**
+ * profile items to migrate. use with migrate().
+ */
+ const unsigned short SETTINGS = 0x0001;
+ const unsigned short COOKIES = 0x0002;
+ const unsigned short HISTORY = 0x0004;
+ const unsigned short HOMEPAGEDATA = 0x0008;
+ const unsigned short PASSWORDS = 0x0010;
+ const unsigned short BOOKMARKS = 0x0020;
+ const unsigned short OTHERDATA = 0x0040;
+ const unsigned short ACCOUNT_SETTINGS = 0x0080;
+ const unsigned short ADDRESSBOOK_DATA = 0x0100;
+ const unsigned short JUNKTRAINING = 0x0200;
+ const unsigned short NEWSDATA = 0x0400;
+ const unsigned short MAILDATA = 0x0800;
+ const unsigned short ALL = 0x0FFF;
+
+ /**
+ * Copy user profile information to the current active profile.
+ *
+ * @param aItems list of data items to migrate. see above for values.
+ * @param aReplace replace or append current data where applicable.
+ * @param aProfile profile to migrate from, if there is more than one.
+ */
+ void migrate(in unsigned short aItems, in nsIProfileStartup aStartup,
+ in wstring aProfile);
+
+ /**
+ * A bit field containing profile items that this migrator is able
+ * to import for a specified source profile.
+ *
+ * @param aProfile the profile that we are looking for available data
+ * to import
+ * @param aStarting "true" if the profile is not currently being used.
+ * @returns bit field containing profile items (see above)
+ */
+ unsigned short getMigrateData(in wstring aProfile, in boolean aDoingStartup);
+
+ /**
+ * A bit field containing profile items that this migrator may be able
+ * to import for any source profile of its type.
+ */
+ readonly attribute unsigned short supportedItems;
+
+ /**
+ * Whether or not there is any data that can be imported from this
+ * browser (i.e. whether or not it is installed, and there exists
+ * a user profile)
+ */
+ readonly attribute boolean sourceExists;
+
+ /**
+ * Whether or not the import source implementing this interface
+ * has multiple user profiles configured.
+ */
+ readonly attribute boolean sourceHasMultipleProfiles;
+
+ /**
+ * An enumeration of available profiles. If the import source does
+ * not support profiles, this attribute is null.
+ */
+ readonly attribute nsIArray sourceProfiles;
+};
diff --git a/comm/suite/components/migration/public/nsSuiteMigrationCID.h b/comm/suite/components/migration/public/nsSuiteMigrationCID.h
new file mode 100644
index 0000000000..252f5ed9df
--- /dev/null
+++ b/comm/suite/components/migration/public/nsSuiteMigrationCID.h
@@ -0,0 +1,8 @@
+/* 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/. */
+
+#define NS_SUITEPROFILEMIGRATOR_CONTRACTID_PREFIX "@mozilla.org/profile/migrator;1?app=suite&type="
+
+#define NS_THUNDERBIRDPROFILEMIGRATOR_CID \
+{ 0x6ba91adb, 0xa4ed, 0x405f, { 0xbd, 0x6c, 0xe9, 0x04, 0xa9, 0x9d, 0x9a, 0xd8 } }
diff --git a/comm/suite/components/migration/src/moz.build b/comm/suite/components/migration/src/moz.build
new file mode 100644
index 0000000000..367fecf45e
--- /dev/null
+++ b/comm/suite/components/migration/src/moz.build
@@ -0,0 +1,13 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+SOURCES += [
+ "nsSuiteProfileMigratorBase.cpp",
+ "nsSuiteProfileMigratorUtils.cpp",
+ "nsThunderbirdProfileMigrator.cpp",
+]
+
+FINAL_LIBRARY = "suite"
diff --git a/comm/suite/components/migration/src/nsSuiteProfileMigratorBase.cpp b/comm/suite/components/migration/src/nsSuiteProfileMigratorBase.cpp
new file mode 100644
index 0000000000..521fa32215
--- /dev/null
+++ b/comm/suite/components/migration/src/nsSuiteProfileMigratorBase.cpp
@@ -0,0 +1,844 @@
+/* -*- Mode: C++; 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/. */
+
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsSuiteProfileMigratorUtils.h"
+#include "nsCRT.h"
+#include "nsIFile.h"
+#include "nsILineInputStream.h"
+#include "nsIOutputStream.h"
+#include "nsIPrefBranch.h"
+#include "nsIPrefLocalizedString.h"
+#include "nsIPrefService.h"
+#include "nsIServiceManager.h"
+#include "nsISupportsPrimitives.h"
+#include "nsIURL.h"
+#include "nsSuiteProfileMigratorBase.h"
+#include "nsNetUtil.h"
+#include "nsIDirectoryEnumerator.h"
+#include "nsIFileProtocolHandler.h"
+#include "nsServiceManagerUtils.h"
+#include "prtime.h"
+#include "nsINIParser.h"
+#include "nsArrayUtils.h"
+
+#define MAIL_DIR_50_NAME u"Mail"_ns
+#define IMAP_MAIL_DIR_50_NAME u"ImapMail"_ns
+#define NEWS_DIR_50_NAME u"News"_ns
+#define DIR_NAME_CHROME u"chrome"_ns
+
+NS_IMPL_ISUPPORTS(nsSuiteProfileMigratorBase, nsISuiteProfileMigrator,
+ nsITimerCallback)
+
+using namespace mozilla;
+
+///////////////////////////////////////////////////////////////////////////////
+// nsITimerCallback
+
+NS_IMETHODIMP
+nsSuiteProfileMigratorBase::Notify(nsITimer *timer) {
+ CopyNextFolder();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSuiteProfileMigratorBase::GetName(nsACString& aName) {
+ aName.AssignLiteral("nsSuiteProfileMigratorBase");
+ return NS_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// nsSuiteProfileMigratorBase
+
+nsSuiteProfileMigratorBase::nsSuiteProfileMigratorBase() {
+ mFileCopyTransactionIndex = 0;
+ mObserverService = do_GetService("@mozilla.org/observer-service;1");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// nsISuiteProfileMigrator methods
+
+NS_IMETHODIMP
+nsSuiteProfileMigratorBase::GetSourceExists(bool* aResult) {
+ nsCOMPtr<nsIArray> profiles;
+ GetSourceProfiles(getter_AddRefs(profiles));
+
+ if (profiles) {
+ uint32_t count;
+ profiles->GetLength(&count);
+ *aResult = count > 0;
+ }
+ else
+ *aResult = false;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSuiteProfileMigratorBase::GetSourceHasMultipleProfiles(bool* aResult) {
+ nsCOMPtr<nsIArray> profiles;
+ GetSourceProfiles(getter_AddRefs(profiles));
+
+ if (profiles) {
+ uint32_t count;
+ profiles->GetLength(&count);
+ *aResult = count > 1;
+ }
+ else
+ *aResult = false;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSuiteProfileMigratorBase::GetSourceProfiles(nsIArray** aResult) {
+ if (!mProfileNames && !mProfileLocations) {
+ nsresult rv;
+ mProfileNames = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ mProfileLocations = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ // Fills mProfileNames and mProfileLocations
+ FillProfileDataFromRegistry();
+ }
+
+ NS_IF_ADDREF(*aResult = mProfileNames);
+ return NS_OK;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Pref Transform methods
+
+#define GETPREF(xform, method, value) \
+ xform->prefHasValue = NS_SUCCEEDED(aBranch->method(xform->sourcePrefName, value)); \
+ return NS_OK;
+
+#define SETPREF(xform, method, value) \
+ if (xform->prefHasValue) { \
+ return aBranch->method(xform->targetPrefName ? \
+ xform->targetPrefName : \
+ xform->sourcePrefName, value); \
+ } \
+ return NS_OK;
+
+nsresult
+nsSuiteProfileMigratorBase::GetString(PrefTransform* aTransform,
+ nsIPrefBranch* aBranch) {
+ PrefTransform* xform = (PrefTransform*)aTransform;
+ nsCString str;
+ nsresult rv = aBranch->GetCharPref(xform->sourcePrefName, str);
+ if (NS_SUCCEEDED(rv)) {
+ xform->prefHasValue = true;
+ xform->stringValue = moz_xstrdup(str.get());
+ }
+ return rv;
+}
+
+nsresult
+nsSuiteProfileMigratorBase::SetString(PrefTransform* aTransform,
+ nsIPrefBranch* aBranch) {
+ PrefTransform* xform = (PrefTransform*) aTransform;
+ SETPREF(aTransform, SetCharPref,
+ nsDependentCString(xform->stringValue));
+}
+
+nsresult
+nsSuiteProfileMigratorBase::GetBool(PrefTransform* aTransform,
+ nsIPrefBranch* aBranch) {
+ GETPREF(aTransform, GetBoolPref, &aTransform->boolValue)
+}
+
+nsresult
+nsSuiteProfileMigratorBase::SetBool(PrefTransform* aTransform,
+ nsIPrefBranch* aBranch) {
+ SETPREF(aTransform, SetBoolPref, aTransform->boolValue)
+}
+
+nsresult
+nsSuiteProfileMigratorBase::GetInt(PrefTransform* aTransform,
+ nsIPrefBranch* aBranch) {
+ GETPREF(aTransform, GetIntPref, &aTransform->intValue)
+}
+
+nsresult
+nsSuiteProfileMigratorBase::SetInt(PrefTransform* aTransform,
+ nsIPrefBranch* aBranch) {
+ SETPREF(aTransform, SetIntPref, aTransform->intValue)
+}
+
+nsresult
+nsSuiteProfileMigratorBase::SetFile(PrefTransform* aTransform,
+ nsIPrefBranch* aBranch) {
+ // In this case targetPrefName is just an additional preference
+ // that needs to be modified and not what the sourcePrefName is
+ // going to be saved to once it is modified.
+ nsresult rv = NS_OK;
+ if (aTransform->prefHasValue) {
+ nsCOMPtr<nsIProtocolHandler> handler;
+ nsCOMPtr<nsIIOService> ioService(do_GetIOService());
+ if (!ioService)
+ return NS_OK;
+ rv = ioService->GetProtocolHandler("file", getter_AddRefs(handler));
+ if (NS_FAILED(rv))
+ return NS_OK;
+ nsCOMPtr<nsIFileProtocolHandler> fileHandler(do_QueryInterface(handler));
+ if (!fileHandler)
+ return NS_OK;
+
+ nsCString fileURL(aTransform->stringValue);
+ nsCOMPtr<nsIFile> file;
+ // Start off by assuming fileURL is a URL spec and
+ // try and get a File from it.
+ rv = fileHandler->GetFileFromURLSpec(fileURL, getter_AddRefs(file));
+ if (NS_FAILED(rv)) {
+ // Okay it wasn't a URL spec so assume it is a localfile,
+ // if this fails then just don't set anything.
+ rv = NS_NewNativeLocalFile(fileURL, false, getter_AddRefs(file));
+ if (NS_FAILED(rv))
+ return NS_OK;
+ }
+ // Now test to see if File exists and is an actual file.
+ bool exists = false;
+ rv = file->Exists(&exists);
+ if (NS_SUCCEEDED(rv) && exists)
+ rv = file->IsFile(&exists);
+
+ if (NS_SUCCEEDED(rv) && exists) {
+ // After all that let's just get the URL spec and set the pref to it.
+ rv = fileHandler->GetURLSpecFromFile(file, fileURL);
+ if (NS_FAILED(rv))
+ return NS_OK;
+ rv = aBranch->SetCharPref(aTransform->sourcePrefName, fileURL);
+ if (NS_SUCCEEDED(rv) && aTransform->targetPrefName)
+ rv = aBranch->SetIntPref(aTransform->targetPrefName, 1);
+ }
+ }
+ return rv;
+}
+
+nsresult
+nsSuiteProfileMigratorBase::SetImage(PrefTransform* aTransform,
+ nsIPrefBranch* aBranch) {
+ if (aTransform->prefHasValue)
+ // This transforms network.image.imageBehavior into
+ // permissions.default.image
+ return aBranch->SetIntPref("permissions.default.image",
+ aTransform->intValue == 1 ? 3 :
+ aTransform->intValue == 2 ? 2 : 1);
+ return NS_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// General Utility Methods
+
+nsresult
+nsSuiteProfileMigratorBase::GetSourceProfile(const char16_t* aProfile) {
+ uint32_t count;
+ mProfileNames->GetLength(&count);
+ for (uint32_t i = 0; i < count; ++i) {
+ nsCOMPtr<nsISupportsString> str(do_QueryElementAt(mProfileNames, i));
+ nsString profileName;
+ str->GetData(profileName);
+ if (profileName.Equals(aProfile))
+ {
+ mSourceProfile = do_QueryElementAt(mProfileLocations, i);
+ break;
+ }
+ }
+
+ return NS_OK;
+}
+
+nsresult
+nsSuiteProfileMigratorBase::GetProfileDataFromProfilesIni(nsIFile* aDataDir,
+ nsIMutableArray* aProfileNames,
+ nsIMutableArray* aProfileLocations) {
+ nsresult rv;
+ nsCOMPtr<nsIFile> profileIni;
+ rv = aDataDir->Clone(getter_AddRefs(profileIni));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ profileIni->Append(u"profiles.ini"_ns);
+
+ // Does it exist?
+ bool profileFileExists = false;
+ rv = profileIni->Exists(&profileFileExists);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!profileFileExists)
+ return NS_ERROR_FILE_NOT_FOUND;
+
+ nsINIParser parser;
+ rv = parser.Init(profileIni);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoCString buffer, filePath;
+ bool isRelative;
+
+ unsigned int c = 0;
+ for (c = 0; true; ++c) {
+ nsAutoCString profileID("Profile");
+ profileID.AppendInt(c);
+
+ rv = parser.GetString(profileID.get(), "IsRelative", buffer);
+ if (NS_FAILED(rv))
+ break;
+
+ isRelative = buffer.EqualsLiteral("1");
+
+ rv = parser.GetString(profileID.get(), "Path", filePath);
+ if (NS_FAILED(rv)) {
+ NS_ERROR("Malformed profiles.ini: Path= not found");
+ continue;
+ }
+
+ rv = parser.GetString(profileID.get(), "Name", buffer);
+ if (NS_FAILED(rv)) {
+ NS_ERROR("Malformed profiles.ini: Name= not found");
+ continue;
+ }
+
+ nsCOMPtr<nsIFile> rootDir;
+ rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(rootDir));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (isRelative)
+ rv = rootDir->SetRelativeDescriptor(aDataDir, filePath);
+ else
+ rv = rootDir->SetPersistentDescriptor(filePath);
+
+ if (NS_FAILED(rv)) continue;
+
+ bool exists;
+ rootDir->Exists(&exists);
+
+ if (exists) {
+ aProfileLocations->AppendElement(rootDir);
+
+ nsCOMPtr<nsISupportsString> profileNameString(
+ do_CreateInstance("@mozilla.org/supports-string;1"));
+
+ profileNameString->SetData(NS_ConvertUTF8toUTF16(buffer));
+ aProfileNames->AppendElement(profileNameString);
+ }
+ }
+ return NS_OK;
+}
+
+nsresult
+nsSuiteProfileMigratorBase::CopyFile(const char* aSourceFileName,
+ const char* aTargetFileName) {
+ nsCOMPtr<nsIFile> sourceFile;
+ mSourceProfile->Clone(getter_AddRefs(sourceFile));
+
+ sourceFile->AppendNative(nsDependentCString(aSourceFileName));
+ bool exists = false;
+ sourceFile->Exists(&exists);
+ if (!exists)
+ return NS_OK;
+
+ nsCOMPtr<nsIFile> targetFile;
+ mTargetProfile->Clone(getter_AddRefs(targetFile));
+
+ targetFile->AppendNative(nsDependentCString(aTargetFileName));
+ targetFile->Exists(&exists);
+ if (exists)
+ targetFile->Remove(false);
+
+ return sourceFile->CopyToNative(mTargetProfile,
+ nsDependentCString(aTargetFileName));
+}
+
+// helper function, copies the contents of srcDir into destDir.
+// destDir will be created if it doesn't exist.
+nsresult
+nsSuiteProfileMigratorBase::RecursiveCopy(nsIFile* srcDir,
+ nsIFile* destDir) {
+ bool exists;
+ nsresult rv = srcDir->Exists(&exists);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!exists)
+ // We do not want to fail if the source folder does not exist because then
+ // parts of the migration process following this would not get executed
+ return NS_OK;
+
+ bool isDir;
+
+ rv = srcDir->IsDirectory(&isDir);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!isDir)
+ return NS_ERROR_INVALID_ARG;
+
+ rv = destDir->Exists(&exists);
+ if (NS_SUCCEEDED(rv) && !exists)
+ rv = destDir->Create(nsIFile::DIRECTORY_TYPE, 0775);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIDirectoryEnumerator> dirIterator;
+ rv = srcDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ bool hasMore = false;
+ while (NS_SUCCEEDED(dirIterator->HasMoreElements(&hasMore)) && hasMore) {
+ nsCOMPtr<nsIFile> dirEntry;
+ rv = dirIterator->GetNextFile(getter_AddRefs(dirEntry));
+ if (NS_SUCCEEDED(rv) && dirEntry) {
+ rv = dirEntry->IsDirectory(&isDir);
+ if (NS_SUCCEEDED(rv)) {
+ if (isDir) {
+ nsCOMPtr<nsIFile> newChild;
+ rv = destDir->Clone(getter_AddRefs(newChild));
+ if (NS_SUCCEEDED(rv)) {
+ nsAutoString leafName;
+ dirEntry->GetLeafName(leafName);
+
+ newChild->AppendRelativePath(leafName);
+ rv = newChild->Exists(&exists);
+ if (NS_SUCCEEDED(rv) && !exists)
+ rv = newChild->Create(nsIFile::DIRECTORY_TYPE, 0775);
+
+ rv = RecursiveCopy(dirEntry, newChild);
+ }
+ }
+ else {
+ // we aren't going to do any actual file copying here. Instead,
+ // add this to our file transaction list so we can copy files
+ // asynchronously...
+ fileTransactionEntry fileEntry;
+
+ fileEntry.srcFile = dirEntry;
+ fileEntry.destFile = destDir;
+
+ mFileCopyTransactions.AppendElement(fileEntry);
+ }
+ }
+ }
+ }
+
+ return rv;
+}
+
+void
+nsSuiteProfileMigratorBase::ReadBranch(const char * branchName,
+ nsIPrefService* aPrefService,
+ PBStructArray &aPrefs) {
+ // Enumerate the branch
+ nsCOMPtr<nsIPrefBranch> branch;
+ aPrefService->GetBranch(branchName, getter_AddRefs(branch));
+
+ nsTArray<nsCString> prefs;
+
+ nsresult rv = branch->GetChildList("", prefs);
+ if (NS_FAILED(rv))
+ return;
+
+ for (auto& pref : prefs) {
+ // Save each pref's value into an array
+ char* currPref = moz_xstrdup(pref.get());
+ int32_t type;
+ branch->GetPrefType(currPref, &type);
+
+ PrefBranchStruct* prefBranch = new PrefBranchStruct;
+ if (!prefBranch) {
+ NS_WARNING("Could not create new PrefBranchStruct");
+ free(currPref);
+ return;
+ }
+ prefBranch->prefName = currPref;
+ prefBranch->type = type;
+
+ switch (type) {
+ case nsIPrefBranch::PREF_STRING: {
+ nsCString str;
+ rv = branch->GetCharPref(currPref, str);
+ prefBranch->stringValue = moz_xstrdup(str.get());
+ break;
+ }
+ case nsIPrefBranch::PREF_BOOL:
+ rv = branch->GetBoolPref(currPref, &prefBranch->boolValue);
+ break;
+ case nsIPrefBranch::PREF_INT:
+ rv = branch->GetIntPref(currPref, &prefBranch->intValue);
+ break;
+ default:
+ NS_WARNING("Invalid prefBranch Type in "
+ "nsSuiteProfileMigratorBase::ReadBranch\n");
+ break;
+ }
+
+ if (NS_SUCCEEDED(rv))
+ aPrefs.AppendElement(prefBranch);
+ }
+}
+
+void
+nsSuiteProfileMigratorBase::WriteBranch(const char * branchName,
+ nsIPrefService* aPrefService,
+ PBStructArray &aPrefs) {
+ // Enumerate the branch
+ nsCOMPtr<nsIPrefBranch> branch;
+ aPrefService->GetBranch(branchName, getter_AddRefs(branch));
+
+ uint32_t count = aPrefs.Length();
+ for (uint32_t i = 0; i < count; ++i) {
+ PrefBranchStruct* pref = aPrefs.ElementAt(i);
+
+ switch (pref->type) {
+ case nsIPrefBranch::PREF_STRING: {
+ branch->SetCharPref(pref->prefName,
+ nsDependentCString(pref->stringValue));
+ free(pref->stringValue);
+ pref->stringValue = nullptr;
+ break;
+ }
+ case nsIPrefBranch::PREF_BOOL:
+ branch->SetBoolPref(pref->prefName, pref->boolValue);
+ break;
+ case nsIPrefBranch::PREF_INT:
+ branch->SetIntPref(pref->prefName, pref->intValue);
+ break;
+ default:
+ NS_WARNING("Invalid Pref Type in "
+ "nsSuiteProfileMigratorBase::WriteBranch\n");
+ break;
+ }
+ free(pref->prefName);
+ pref->prefName = nullptr;
+ delete pref;
+ pref = nullptr;
+ }
+ aPrefs.Clear();
+}
+
+nsresult
+nsSuiteProfileMigratorBase::GetFileValue(nsIPrefBranch* aPrefBranch,
+ const char* aRelPrefName,
+ const char* aPrefName,
+ nsIFile** aReturnFile) {
+ nsCString prefValue;
+ nsCOMPtr<nsIFile> theFile;
+ nsresult rv = aPrefBranch->GetCharPref(aRelPrefName, prefValue);
+ if (NS_SUCCEEDED(rv)) {
+ // The pref has the format: [ProfD]a/b/c
+ if (!StringBeginsWith(prefValue, "[ProfD]"_ns))
+ return NS_ERROR_FILE_NOT_FOUND;
+
+ rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(theFile));
+ if (NS_FAILED(rv))
+ return rv;
+
+ rv = theFile->SetRelativeDescriptor(mSourceProfile, Substring(prefValue, 7));
+ if (NS_FAILED(rv))
+ return rv;
+ } else {
+ rv = aPrefBranch->GetComplexValue(aPrefName,
+ NS_GET_IID(nsIFile),
+ getter_AddRefs(theFile));
+ }
+
+ theFile.forget(aReturnFile);
+ return rv;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Mail Import Functions
+
+nsresult
+nsSuiteProfileMigratorBase::CopyAddressBookDirectories(PBStructArray &aLdapServers,
+ nsIPrefService* aPrefService) {
+ // each server has a pref ending with .filename. The value of that pref
+ // points to a profile which we need to migrate.
+ nsAutoString index;
+ index.AppendInt(nsISuiteProfileMigrator::ADDRESSBOOK_DATA);
+ NOTIFY_OBSERVERS(MIGRATION_ITEMBEFOREMIGRATE, index.get());
+
+ uint32_t count = aLdapServers.Length();
+ for (uint32_t i = 0; i < count; ++i) {
+ PrefBranchStruct* pref = aLdapServers.ElementAt(i);
+ nsDependentCString prefName(pref->prefName);
+
+ if (StringEndsWith(prefName, ".filename"_ns)) {
+ CopyFile(pref->stringValue, pref->stringValue);
+ }
+
+ // we don't need to do anything to the fileName pref itself
+ }
+
+ NOTIFY_OBSERVERS(MIGRATION_ITEMAFTERMIGRATE, index.get());
+
+ return NS_OK;
+}
+
+nsresult
+nsSuiteProfileMigratorBase::CopySignatureFiles(PBStructArray &aIdentities,
+ nsIPrefService* aPrefService) {
+ nsresult rv = NS_OK;
+
+ uint32_t count = aIdentities.Length();
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ PrefBranchStruct* pref = aIdentities.ElementAt(i);
+ nsDependentCString prefName(pref->prefName);
+
+ // a partial fix for bug #255043
+ // if the user's signature file from seamonkey lives in the
+ // old profile root, we'll copy it over to the new profile root and
+ // then set the pref to the new value. Note, this doesn't work for
+ // multiple signatures that live below the seamonkey profile root
+ if (StringEndsWith(prefName, ".sig_file"_ns))
+ {
+ // turn the pref into a nsIFile
+ nsCOMPtr<nsIFile> srcSigFile =
+ do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
+ rv = srcSigFile->SetPersistentDescriptor(nsDependentCString(pref->stringValue));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIFile> targetSigFile;
+ rv = mTargetProfile->Clone(getter_AddRefs(targetSigFile));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // now make the copy
+ bool exists;
+ srcSigFile->Exists(&exists);
+ if (exists)
+ {
+ nsAutoString leafName;
+ srcSigFile->GetLeafName(leafName);
+ // will fail if we've already copied a sig file here
+ srcSigFile->CopyTo(targetSigFile, leafName);
+ targetSigFile->Append(leafName);
+
+ // now write out the new descriptor
+ nsAutoCString descriptorString;
+ rv = targetSigFile->GetPersistentDescriptor(descriptorString);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ free(pref->stringValue);
+ pref->stringValue = ToNewCString(descriptorString);
+ }
+ }
+ }
+ return NS_OK;
+}
+
+nsresult
+nsSuiteProfileMigratorBase::CopyJunkTraining(bool aReplace)
+{
+ return aReplace ? CopyFile(FILE_NAME_JUNKTRAINING,
+ FILE_NAME_JUNKTRAINING) : NS_OK;
+}
+
+nsresult
+nsSuiteProfileMigratorBase::CopyMailFolderPrefs(PBStructArray &aMailServers,
+ nsIPrefService* aPrefService) {
+ // Each server has a .directory pref which points to the location of the
+ // mail data for that server. We need to do two things for that case...
+ // (1) Fix up the directory path for the new profile
+ // (2) copy the mail folder data from the source directory pref to the
+ // destination directory pref
+ CopyFile(FILE_NAME_VIRTUALFOLDERS, FILE_NAME_VIRTUALFOLDERS);
+
+ int32_t count = aMailServers.Length();
+ for (int32_t i = 0; i < count; ++i) {
+ PrefBranchStruct* pref = aMailServers.ElementAt(i);
+ nsDependentCString prefName(pref->prefName);
+
+ if (StringEndsWith(prefName, ".directory"_ns)) {
+ // let's try to get a branch for this particular server to simplify things
+ prefName.Cut(prefName.Length() - strlen("directory"),
+ strlen("directory"));
+ prefName.Insert("mail.server.", 0);
+
+ nsCOMPtr<nsIPrefBranch> serverBranch;
+ aPrefService->GetBranch(prefName.get(), getter_AddRefs(serverBranch));
+
+ if (!serverBranch)
+ break; // should we clear out this server pref from aMailServers?
+
+ nsCString serverType;
+ serverBranch->GetCharPref("type", serverType);
+
+ nsCOMPtr<nsIFile> sourceMailFolder;
+ nsresult rv = GetFileValue(serverBranch, "directory-rel", "directory",
+ getter_AddRefs(sourceMailFolder));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // now based on type, we need to build a new destination path for the
+ // mail folders for this server
+ nsCOMPtr<nsIFile> targetMailFolder;
+ if (serverType.Equals("imap")) {
+ mTargetProfile->Clone(getter_AddRefs(targetMailFolder));
+ targetMailFolder->Append(IMAP_MAIL_DIR_50_NAME);
+ }
+ else if (serverType.Equals("none") || serverType.Equals("pop3")) {
+ // local folders and POP3 servers go under <profile>\Mail
+ mTargetProfile->Clone(getter_AddRefs(targetMailFolder));
+ targetMailFolder->Append(MAIL_DIR_50_NAME);
+ }
+ else if (serverType.Equals("nntp")) {
+ mTargetProfile->Clone(getter_AddRefs(targetMailFolder));
+ targetMailFolder->Append(NEWS_DIR_50_NAME);
+ }
+
+ if (targetMailFolder) {
+ // for all of our server types, append the host name to the directory
+ // as part of the new location
+ nsCString hostName;
+ serverBranch->GetCharPref("hostname", hostName);
+ targetMailFolder->Append(NS_ConvertASCIItoUTF16(hostName));
+
+ // we should make sure the host name based directory we are going to
+ // migrate the accounts into is unique. This protects against the
+ // case where the user has multiple servers with the same host name.
+ rv = targetMailFolder->CreateUnique(nsIFile::DIRECTORY_TYPE, 0777);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ RecursiveCopy(sourceMailFolder, targetMailFolder);
+ // now we want to make sure the actual directory pref that gets
+ // transformed into the new profile's pref.js has the right file
+ // location.
+ nsAutoCString descriptorString;
+ rv = targetMailFolder->GetPersistentDescriptor(descriptorString);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ free(pref->stringValue);
+ pref->stringValue = ToNewCString(descriptorString);
+ }
+ }
+ else if (StringEndsWith(prefName, ".newsrc.file"_ns)) {
+ // copy the news RC file into \News. this won't work if the user has
+ // different newsrc files for each account I don't know what to do in
+ // that situation.
+ nsCOMPtr<nsIFile> targetNewsRCFile;
+ mTargetProfile->Clone(getter_AddRefs(targetNewsRCFile));
+ targetNewsRCFile->Append(NEWS_DIR_50_NAME);
+
+ // turn the pref into a nsIFile
+ nsCOMPtr<nsIFile> srcNewsRCFile =
+ do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
+ nsresult rv = srcNewsRCFile->SetPersistentDescriptor(
+ nsDependentCString(pref->stringValue));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // now make the copy
+ bool exists;
+ srcNewsRCFile->Exists(&exists);
+ if (exists) {
+ nsAutoString leafName;
+ srcNewsRCFile->GetLeafName(leafName);
+ // will fail if we've already copied a newsrc file here
+ srcNewsRCFile->CopyTo(targetNewsRCFile,leafName);
+ targetNewsRCFile->Append(leafName);
+
+ // now write out the new descriptor
+ nsAutoCString descriptorString;
+ rv = targetNewsRCFile->GetPersistentDescriptor(descriptorString);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ free(pref->stringValue);
+ pref->stringValue = ToNewCString(descriptorString);
+ }
+ }
+ }
+
+ // Remove all .directory-rel prefs as those might have changed; MailNews
+ // will create those prefs again on first use
+ for (int32_t i = count; i-- > 0; ) {
+ PrefBranchStruct* pref = aMailServers.ElementAt(i);
+ nsDependentCString prefName(pref->prefName);
+
+ if (StringEndsWith(prefName, ".directory-rel"_ns)) {
+ if (pref->type == nsIPrefBranch::PREF_STRING)
+ free(pref->stringValue);
+
+ aMailServers.RemoveElementAt(i);
+ }
+ }
+
+ return NS_OK;
+}
+
+void
+nsSuiteProfileMigratorBase::CopyMailFolders() {
+ nsAutoString index;
+ index.AppendInt(nsISuiteProfileMigrator::MAILDATA);
+ NOTIFY_OBSERVERS(MIGRATION_ITEMBEFOREMIGRATE, index.get());
+
+ // Generate the max progress value now that we know all of the files we
+ // need to copy
+ uint32_t count = mFileCopyTransactions.Length();
+ mMaxProgress = 0;
+ mCurrentProgress = 0;
+
+ for (uint32_t i = 0; i < count; ++i) {
+ fileTransactionEntry fileTransaction = mFileCopyTransactions[i];
+ int64_t fileSize;
+ fileTransaction.srcFile->GetFileSize(&fileSize);
+ mMaxProgress += fileSize;
+ }
+
+ CopyNextFolder();
+}
+
+void
+nsSuiteProfileMigratorBase::CopyNextFolder() {
+ if (mFileCopyTransactionIndex < mFileCopyTransactions.Length()) {
+ fileTransactionEntry fileTransaction =
+ mFileCopyTransactions.ElementAt(mFileCopyTransactionIndex++);
+
+ // copy the file
+ fileTransaction.srcFile->CopyTo(fileTransaction.destFile,
+ EmptyString());
+
+ // add to our current progress
+ int64_t fileSize;
+ fileTransaction.srcFile->GetFileSize(&fileSize);
+ mCurrentProgress += fileSize;
+
+ uint32_t percentage = (uint32_t)(mCurrentProgress * 100 / mMaxProgress);
+
+ nsAutoString index;
+ index.AppendInt(percentage);
+
+ NOTIFY_OBSERVERS(MIGRATION_PROGRESS, index.get());
+
+ if (mFileCopyTransactionIndex == mFileCopyTransactions.Length())
+ {
+ EndCopyFolders();
+ return;
+ }
+
+ // fire a timer to handle the next one.
+ mFileIOTimer = do_CreateInstance("@mozilla.org/timer;1");
+
+ if (mFileIOTimer)
+ mFileIOTimer->InitWithCallback(static_cast<nsITimerCallback *>(this),
+ 1, nsITimer::TYPE_ONE_SHOT);
+ }
+ else
+ EndCopyFolders();
+
+ return;
+}
+
+void
+nsSuiteProfileMigratorBase::EndCopyFolders() {
+ mFileCopyTransactions.Clear();
+ mFileCopyTransactionIndex = 0;
+
+ // notify the UI that we are done with the migration process
+ nsAutoString index;
+ index.AppendInt(nsISuiteProfileMigrator::MAILDATA);
+ NOTIFY_OBSERVERS(MIGRATION_ITEMAFTERMIGRATE, index.get());
+
+ NOTIFY_OBSERVERS(MIGRATION_ENDED, nullptr);
+}
diff --git a/comm/suite/components/migration/src/nsSuiteProfileMigratorBase.h b/comm/suite/components/migration/src/nsSuiteProfileMigratorBase.h
new file mode 100644
index 0000000000..6a4d40e3df
--- /dev/null
+++ b/comm/suite/components/migration/src/nsSuiteProfileMigratorBase.h
@@ -0,0 +1,147 @@
+/* -*- Mode: C++; 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/. */
+
+#ifndef nsSuiteProfileMigratorBase___h___
+#define nsSuiteProfileMigratorBase___h___
+
+#include "nsAttrValue.h"
+#include "nsIFile.h"
+#include "nsIMutableArray.h"
+#include "nsTArray.h"
+#include "nsITimer.h"
+#include "nsIObserverService.h"
+#include "nsISuiteProfileMigrator.h"
+#include "nsSuiteMigrationCID.h"
+
+class nsIPrefBranch;
+class nsIPrefService;
+
+struct fileTransactionEntry {
+ nsCOMPtr<nsIFile> srcFile; // the src path including leaf name
+ nsCOMPtr<nsIFile> destFile; // the destination path
+ nsString newName; // only valid if the file should be renamed after
+ // getting copied
+};
+
+#define FILE_NAME_PREFS "prefs.js"
+#define FILE_NAME_JUNKTRAINING "training.dat"
+#define FILE_NAME_VIRTUALFOLDERS "virtualFolders.dat"
+
+#define F(a) nsSuiteProfileMigratorBase::a
+
+#define MAKEPREFTRANSFORM(pref, newpref, getmethod, setmethod) \
+ { pref, newpref, F(Get##getmethod), F(Set##setmethod), false, { -1 } }
+
+#define MAKESAMETYPEPREFTRANSFORM(pref, method) \
+ { pref, 0, F(Get##method), F(Set##method), false, { -1 } }
+
+class nsSuiteProfileMigratorBase : public nsISuiteProfileMigrator,
+ public nsITimerCallback,
+ public nsINamed
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSITIMERCALLBACK
+ NS_DECL_NSINAMED
+
+ nsSuiteProfileMigratorBase();
+
+ struct PrefTransform;
+ typedef nsresult(*prefConverter)(PrefTransform*, nsIPrefBranch*);
+
+ struct PrefTransform {
+ const char* sourcePrefName;
+ const char* targetPrefName;
+ prefConverter prefGetterFunc;
+ prefConverter prefSetterFunc;
+ bool prefHasValue;
+ union {
+ int32_t intValue;
+ bool boolValue;
+ char* stringValue;
+ };
+ };
+
+ struct PrefBranchStruct {
+ char* prefName;
+ int32_t type;
+ union {
+ char* stringValue;
+ int32_t intValue;
+ bool boolValue;
+ };
+ };
+
+ typedef nsTArray<PrefBranchStruct*> PBStructArray;
+
+ // nsISuiteProfileMigrator methods
+ NS_IMETHOD GetSourceExists(bool* aSourceExists) override;
+ NS_IMETHOD GetSourceHasMultipleProfiles(bool* aSourceHasMultipleProfiles) override;
+ NS_IMETHOD GetSourceProfiles(nsIArray** aResult) override;
+
+ // Pref Transform Methods
+ static nsresult GetString(PrefTransform* aTransform, nsIPrefBranch* aBranch);
+ static nsresult SetString(PrefTransform* aTransform, nsIPrefBranch* aBranch);
+ static nsresult GetBool(PrefTransform* aTransform, nsIPrefBranch* aBranch);
+ static nsresult SetBool(PrefTransform* aTransform, nsIPrefBranch* aBranch);
+ static nsresult GetInt(PrefTransform* aTransform, nsIPrefBranch* aBranch);
+ static nsresult SetInt(PrefTransform* aTransform, nsIPrefBranch* aBranch);
+ static nsresult SetFile(PrefTransform* aTransform, nsIPrefBranch* aBranch);
+ static nsresult SetImage(PrefTransform* aTransform, nsIPrefBranch* aBranch);
+ static nsresult SetCookie(PrefTransform* aTransform, nsIPrefBranch* aBranch);
+
+protected:
+ virtual ~nsSuiteProfileMigratorBase() {}
+ // This function is designed to be overriden by derived classes so that
+ // the required profile data for the specific application can be obtained.
+ virtual nsresult FillProfileDataFromRegistry() = 0;
+
+ // General Utility Methods
+ nsresult GetSourceProfile(const char16_t* aProfile);
+ nsresult GetProfileDataFromProfilesIni(nsIFile* aDataDir,
+ nsIMutableArray* aProfileNames,
+ nsIMutableArray* aProfileLocations);
+ nsresult GetFileValue(nsIPrefBranch* aPrefBranch, const char* aRelPrefName,
+ const char* aPrefName, nsIFile** aReturnFile);
+ nsresult CopyFile(const char* aSourceFileName,
+ const char* aTargetFileName);
+ nsresult RecursiveCopy(nsIFile* srcDir, nsIFile* destDir);
+ void ReadBranch(const char * branchName, nsIPrefService* aPrefService,
+ PBStructArray &aPrefs);
+ void WriteBranch(const char * branchName, nsIPrefService* aPrefService,
+ PBStructArray &aPrefs);
+
+ // Mail Import Functions
+ nsresult CopyAddressBookDirectories(PBStructArray &aLdapServers,
+ nsIPrefService* aPrefService);
+ nsresult CopySignatureFiles(PBStructArray &aIdentities,
+ nsIPrefService* aPrefService);
+ nsresult CopyJunkTraining(bool aReplace);
+ nsresult CopyMailFolderPrefs(PBStructArray &aMailServers,
+ nsIPrefService* aPrefService);
+ void CopyMailFolders();
+ void CopyNextFolder();
+ void EndCopyFolders();
+
+ // Source & Target profiles
+ nsCOMPtr<nsIFile> mSourceProfile;
+ nsCOMPtr<nsIFile> mTargetProfile;
+
+ // list of src/destination files we still have to copy into the new profile
+ // directory
+ nsTArray<fileTransactionEntry> mFileCopyTransactions;
+ uint32_t mFileCopyTransactionIndex;
+
+ nsCOMPtr<nsIObserverService> mObserverService;
+ int64_t mMaxProgress;
+ int64_t mCurrentProgress;
+
+ nsCOMPtr<nsIMutableArray> mProfileNames;
+ nsCOMPtr<nsIMutableArray> mProfileLocations;
+
+ nsCOMPtr<nsITimer> mFileIOTimer;
+};
+
+#endif
diff --git a/comm/suite/components/migration/src/nsSuiteProfileMigratorUtils.cpp b/comm/suite/components/migration/src/nsSuiteProfileMigratorUtils.cpp
new file mode 100644
index 0000000000..091a96540d
--- /dev/null
+++ b/comm/suite/components/migration/src/nsSuiteProfileMigratorUtils.cpp
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; 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/. */
+
+#include "nsSuiteProfileMigratorUtils.h"
+#include "nsIPrefBranch.h"
+#include "nsIFile.h"
+#include "nsIInputStream.h"
+#include "nsILineInputStream.h"
+#include "nsIProfileMigrator.h"
+
+#include "nsIURI.h"
+#include "nsNetUtil.h"
+#include "nsIProperties.h"
+#include "nsServiceManagerUtils.h"
+#include "nsISupportsPrimitives.h"
+
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsIStringBundle.h"
+#include "nsCRT.h"
+
+#define MIGRATION_BUNDLE "chrome://communicator/migration/locale/migration.properties"
+
+using namespace mozilla;
+
+void GetMigrateDataFromArray(MigrationData* aDataArray,
+ int32_t aDataArrayLength,
+ bool aReplace, nsIFile* aSourceProfile,
+ uint16_t* aResult)
+{
+ nsCOMPtr<nsIFile> sourceFile;
+ bool exists;
+ MigrationData* cursor;
+ MigrationData* end = aDataArray + aDataArrayLength;
+ for (cursor = aDataArray; cursor < end; ++cursor) {
+ // When in replace mode, all items can be imported.
+ // When in non-replace mode, only items that do not require file
+ // replacement can be imported.
+ if (aReplace || !cursor->replaceOnly) {
+ aSourceProfile->Clone(getter_AddRefs(sourceFile));
+ sourceFile->AppendNative(nsDependentCString(cursor->fileName));
+ sourceFile->Exists(&exists);
+ if (exists)
+ *aResult |= cursor->sourceFlag;
+ }
+ }
+}
+
+void
+GetProfilePath(nsIProfileStartup* aStartup, nsIFile** aProfileDir)
+{
+ *aProfileDir = nullptr;
+
+ if (aStartup) {
+ aStartup->GetDirectory(aProfileDir);
+ }
+ else {
+ nsCOMPtr<nsIProperties> dirSvc
+ (do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
+ if (dirSvc) {
+ dirSvc->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
+ (void**)aProfileDir);
+ }
+ }
+}
diff --git a/comm/suite/components/migration/src/nsSuiteProfileMigratorUtils.h b/comm/suite/components/migration/src/nsSuiteProfileMigratorUtils.h
new file mode 100644
index 0000000000..e469f5723d
--- /dev/null
+++ b/comm/suite/components/migration/src/nsSuiteProfileMigratorUtils.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; 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/. */
+
+#ifndef SuiteProfileMigratorUtils_h__
+#define SuiteProfileMigratorUtils_h__
+
+#define MIGRATION_ITEMBEFOREMIGRATE "Migration:ItemBeforeMigrate"
+#define MIGRATION_ITEMAFTERMIGRATE "Migration:ItemAfterMigrate"
+#define MIGRATION_STARTED "Migration:Started"
+#define MIGRATION_ENDED "Migration:Ended"
+#define MIGRATION_PROGRESS "Migration:Progress"
+
+#define NOTIFY_OBSERVERS(message, item) \
+ mObserverService->NotifyObservers(nullptr, message, item)
+
+#define COPY_DATA(func, replace, itemIndex) \
+ if (NS_SUCCEEDED(rv) && (aItems & itemIndex || !aItems)) { \
+ nsAutoString index; \
+ index.AppendInt(itemIndex); \
+ NOTIFY_OBSERVERS(MIGRATION_ITEMBEFOREMIGRATE, index.get()); \
+ rv = func(replace); \
+ NOTIFY_OBSERVERS(MIGRATION_ITEMAFTERMIGRATE, index.get()); \
+ }
+
+#define MAKEPREFTRANSFORM(pref, newpref, getmethod, setmethod) \
+ { pref, newpref, F(Get##getmethod), F(Set##setmethod), false, { -1 } }
+
+#define MAKESAMETYPEPREFTRANSFORM(pref, method) \
+ { pref, 0, F(Get##method), F(Set##method), false, { -1 } }
+
+#include "nsString.h"
+#include "nscore.h"
+#include "nsCOMPtr.h"
+
+class nsIPrefBranch;
+class nsIProfileStartup;
+class nsIFile;
+
+struct MigrationData {
+ const char* fileName;
+ uint32_t sourceFlag;
+ bool replaceOnly;
+};
+
+class nsIFile;
+void GetMigrateDataFromArray(MigrationData* aDataArray,
+ int32_t aDataArrayLength,
+ bool aReplace,
+ nsIFile* aSourceProfile,
+ uint16_t* aResult);
+
+
+// get the base directory of the *target* profile
+// this is already cloned, modify it to your heart's content
+void GetProfilePath(nsIProfileStartup* aStartup,
+ nsIFile** aProfileDir);
+
+#endif
diff --git a/comm/suite/components/migration/src/nsThunderbirdProfileMigrator.cpp b/comm/suite/components/migration/src/nsThunderbirdProfileMigrator.cpp
new file mode 100644
index 0000000000..3f5365f12a
--- /dev/null
+++ b/comm/suite/components/migration/src/nsThunderbirdProfileMigrator.cpp
@@ -0,0 +1,571 @@
+/* -*- Mode: C++; 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/. */
+
+#include "nsSuiteProfileMigratorUtils.h"
+#include "mozilla/ArrayUtils.h"
+#include "nsCRT.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsIObserverService.h"
+#include "nsIPrefLocalizedString.h"
+#include "nsIPrefService.h"
+#include "nsIServiceManager.h"
+#include "nsISupportsPrimitives.h"
+#include "nsNetCID.h"
+#include "nsNetUtil.h"
+#include "nsIProperties.h"
+#include "nsServiceManagerUtils.h"
+#include "nsThunderbirdProfileMigrator.h"
+#include "prprf.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// nsThunderbirdProfileMigrator
+
+#define FILE_NAME_SITEPERM_OLD "cookperm.txt"
+#define FILE_NAME_SITEPERM_NEW "hostperm.1"
+#define FILE_NAME_CERT8DB "cert8.db"
+#define FILE_NAME_KEY3DB "key3.db"
+#define FILE_NAME_SECMODDB "secmod.db"
+#define FILE_NAME_HISTORY "history.dat"
+#define FILE_NAME_SIGNONS "signons.sqlite"
+#define FILE_NAME_MIMETYPES "mimeTypes.rdf"
+#define FILE_NAME_USER_PREFS "user.js"
+#define FILE_NAME_PERSONALDICTIONARY "persdict.dat"
+#define FILE_NAME_MAILVIEWS "mailViews.dat"
+
+NS_IMPL_ISUPPORTS(nsThunderbirdProfileMigrator, nsISuiteProfileMigrator,
+ nsITimerCallback)
+
+nsThunderbirdProfileMigrator::nsThunderbirdProfileMigrator()
+{
+}
+
+nsThunderbirdProfileMigrator::~nsThunderbirdProfileMigrator()
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// nsISuiteProfileMigrator
+
+NS_IMETHODIMP
+nsThunderbirdProfileMigrator::Migrate(uint16_t aItems,
+ nsIProfileStartup* aStartup,
+ const char16_t* aProfile)
+{
+ nsresult rv = NS_OK;
+ bool aReplace = aStartup ? true : false;
+
+ if (!mTargetProfile) {
+ GetProfilePath(aStartup, getter_AddRefs(mTargetProfile));
+ if (!mTargetProfile)
+ return NS_ERROR_FILE_NOT_FOUND;
+ }
+ if (!mSourceProfile) {
+ GetSourceProfile(aProfile);
+ if (!mSourceProfile)
+ return NS_ERROR_FILE_NOT_FOUND;
+ }
+
+ NOTIFY_OBSERVERS(MIGRATION_STARTED, nullptr);
+
+ COPY_DATA(CopyPreferences, aReplace, nsISuiteProfileMigrator::SETTINGS);
+ COPY_DATA(CopyHistory, aReplace, nsISuiteProfileMigrator::HISTORY);
+ COPY_DATA(CopyPasswords, aReplace, nsISuiteProfileMigrator::PASSWORDS);
+
+ // fake notifications for things we've already imported as part of
+ // CopyPreferences
+ nsAutoString index;
+ index.AppendInt(nsISuiteProfileMigrator::ACCOUNT_SETTINGS);
+ NOTIFY_OBSERVERS(MIGRATION_ITEMBEFOREMIGRATE, index.get());
+ NOTIFY_OBSERVERS(MIGRATION_ITEMAFTERMIGRATE, index.get());
+
+ index.Truncate();
+ index.AppendInt(nsISuiteProfileMigrator::NEWSDATA);
+ NOTIFY_OBSERVERS(MIGRATION_ITEMBEFOREMIGRATE, index.get());
+ NOTIFY_OBSERVERS(MIGRATION_ITEMAFTERMIGRATE, index.get());
+
+ // copy junk mail training file
+ COPY_DATA(CopyJunkTraining, aReplace, nsISuiteProfileMigrator::JUNKTRAINING);
+
+ if (aReplace &&
+ (aItems & nsISuiteProfileMigrator::SETTINGS ||
+ aItems & nsISuiteProfileMigrator::PASSWORDS ||
+ !aItems)) {
+ // Permissions (Images)
+ if (NS_SUCCEEDED(rv))
+ rv = CopyFile(FILE_NAME_SITEPERM_NEW, FILE_NAME_SITEPERM_NEW);
+ if (NS_SUCCEEDED(rv))
+ rv = CopyFile(FILE_NAME_SITEPERM_OLD, FILE_NAME_SITEPERM_OLD);
+ }
+
+ // the last thing to do is to actually copy over any mail folders
+ // we have marked for copying we want to do this last and it will be
+ // asynchronous so the UI doesn't freeze up while we perform
+ // this potentially very long operation.
+ CopyMailFolders();
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsThunderbirdProfileMigrator::GetMigrateData(const char16_t* aProfile,
+ bool aReplace,
+ uint16_t* aResult)
+{
+ *aResult = 0;
+
+ if (!mSourceProfile) {
+ GetSourceProfile(aProfile);
+ if (!mSourceProfile)
+ return NS_ERROR_FILE_NOT_FOUND;
+ }
+
+ // migration fields for things we always migrate
+ *aResult =
+ nsISuiteProfileMigrator::ACCOUNT_SETTINGS |
+ nsISuiteProfileMigrator::MAILDATA |
+ nsISuiteProfileMigrator::NEWSDATA |
+ nsISuiteProfileMigrator::ADDRESSBOOK_DATA;
+
+ MigrationData data[] = { { FILE_NAME_PREFS,
+ nsISuiteProfileMigrator::SETTINGS,
+ true },
+ { FILE_NAME_USER_PREFS,
+ nsISuiteProfileMigrator::SETTINGS,
+ true },
+ { FILE_NAME_HISTORY,
+ nsISuiteProfileMigrator::HISTORY,
+ true },
+ { FILE_NAME_SIGNONS,
+ nsISuiteProfileMigrator::PASSWORDS,
+ true },
+ { FILE_NAME_JUNKTRAINING,
+ nsISuiteProfileMigrator::JUNKTRAINING,
+ true } };
+
+ GetMigrateDataFromArray(data, sizeof(data)/sizeof(MigrationData),
+ aReplace, mSourceProfile, aResult);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsThunderbirdProfileMigrator::GetSupportedItems(uint16_t *aSupportedItems)
+{
+ NS_ENSURE_ARG_POINTER(aSupportedItems);
+
+ *aSupportedItems = nsISuiteProfileMigrator::SETTINGS |
+ nsISuiteProfileMigrator::HISTORY |
+ nsISuiteProfileMigrator::JUNKTRAINING |
+ nsISuiteProfileMigrator::PASSWORDS |
+ nsISuiteProfileMigrator::ACCOUNT_SETTINGS |
+ nsISuiteProfileMigrator::MAILDATA |
+ nsISuiteProfileMigrator::NEWSDATA |
+ nsISuiteProfileMigrator::ADDRESSBOOK_DATA;
+
+ return NS_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// nsThunderbirdProfileMigrator
+
+nsresult
+nsThunderbirdProfileMigrator::FillProfileDataFromRegistry()
+{
+ // Find the Thunderbird Registry
+ nsCOMPtr<nsIProperties> fileLocator(
+ do_GetService("@mozilla.org/file/directory_service;1"));
+ nsCOMPtr<nsIFile> thunderbirdData;
+#ifdef XP_WIN
+ fileLocator->Get(NS_WIN_APPDATA_DIR, NS_GET_IID(nsIFile),
+ getter_AddRefs(thunderbirdData));
+
+ thunderbirdData->Append(u"Thunderbird"_ns);
+
+#elif defined(XP_MACOSX)
+ fileLocator->Get(NS_MAC_USER_LIB_DIR, NS_GET_IID(nsIFile),
+ getter_AddRefs(thunderbirdData));
+
+ thunderbirdData->Append(u"Thunderbird"_ns);
+
+#elif defined(XP_UNIX)
+ fileLocator->Get(NS_UNIX_HOME_DIR, NS_GET_IID(nsIFile),
+ getter_AddRefs(thunderbirdData));
+
+ thunderbirdData->Append(u".thunderbird"_ns);
+
+#else
+ // On other OS just abort
+ return NS_ERROR_FILE_NOT_FOUND;
+#endif
+
+ // Try profiles.ini first
+ return GetProfileDataFromProfilesIni(thunderbirdData,
+ mProfileNames,
+ mProfileLocations);
+}
+
+static
+nsThunderbirdProfileMigrator::PrefTransform gTransforms[] = {
+ MAKESAMETYPEPREFTRANSFORM("accessibility.typeaheadfind.autostart", Bool),
+ MAKESAMETYPEPREFTRANSFORM("accessibility.typeaheadfind.linksonly", Bool),
+
+ MAKESAMETYPEPREFTRANSFORM("browser.anchor_color", String),
+ MAKESAMETYPEPREFTRANSFORM("browser.active_color", String),
+ MAKESAMETYPEPREFTRANSFORM("browser.display.background_color", String),
+ MAKESAMETYPEPREFTRANSFORM("browser.display.foreground_color", String),
+ MAKESAMETYPEPREFTRANSFORM("browser.display.use_system_colors", Bool),
+ MAKESAMETYPEPREFTRANSFORM("browser.display.document_color_use", Int),
+ MAKESAMETYPEPREFTRANSFORM("browser.display.use_document_fonts", Bool),
+ MAKESAMETYPEPREFTRANSFORM("browser.enable_automatic_image_resizing", Bool),
+ MAKESAMETYPEPREFTRANSFORM("browser.tabs.autoHide", Bool),
+ MAKESAMETYPEPREFTRANSFORM("browser.tabs.loadInBackground", Bool),
+ MAKESAMETYPEPREFTRANSFORM("browser.underline_anchors", Bool),
+ MAKESAMETYPEPREFTRANSFORM("browser.visited_color", String),
+
+ MAKESAMETYPEPREFTRANSFORM("dom.disable_open_during_load", Bool),
+ MAKESAMETYPEPREFTRANSFORM("dom.disable_window_move_resize", Bool),
+ MAKESAMETYPEPREFTRANSFORM("dom.disable_window_flip", Bool),
+ MAKESAMETYPEPREFTRANSFORM("dom.disable_window_open_feature.status", Bool),
+ MAKESAMETYPEPREFTRANSFORM("dom.disable_window_status_change", Bool),
+
+ MAKESAMETYPEPREFTRANSFORM("extensions.spellcheck.inline.max-misspellings",Int),
+
+ MAKESAMETYPEPREFTRANSFORM("general.warnOnAboutConfig", Bool),
+
+ MAKESAMETYPEPREFTRANSFORM("intl.accept_charsets", String),
+ MAKESAMETYPEPREFTRANSFORM("intl.accept_languages", String),
+ MAKESAMETYPEPREFTRANSFORM("intl.charset.fallback.override", String),
+
+ MAKESAMETYPEPREFTRANSFORM("javascript.enabled", Bool),
+ MAKESAMETYPEPREFTRANSFORM("javascript.options.relimit", Bool),
+ MAKESAMETYPEPREFTRANSFORM("javascript.options.showInConsole", Bool),
+ MAKESAMETYPEPREFTRANSFORM("javascript.options.strict", Bool),
+
+ MAKESAMETYPEPREFTRANSFORM("layout.spellcheckDefault", Int),
+
+ MAKESAMETYPEPREFTRANSFORM("mail.accountmanager.accounts", String),
+ MAKESAMETYPEPREFTRANSFORM("mail.accountmanager.defaultaccount", String),
+ MAKESAMETYPEPREFTRANSFORM("mail.accountmanager.localfoldersserver", String),
+ MAKESAMETYPEPREFTRANSFORM("mail.accountwizard.deferstorage", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.adaptivefilters.junk_threshold", Int),
+ MAKESAMETYPEPREFTRANSFORM("mail.autoComplete.highlightNonMatches", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.biff.animate_doc_icon", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.biff.play_sound", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.biff.play_sound.type", Int),
+ MAKESAMETYPEPREFTRANSFORM("mail.biff.play_sound.url", String),
+ MAKESAMETYPEPREFTRANSFORM("mail.biff.show_alert", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.biff.show_tray_icon", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.check_all_imap_folders_for_new", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.citation_color", String),
+ MAKESAMETYPEPREFTRANSFORM("mail.collect_addressbook", String),
+ MAKESAMETYPEPREFTRANSFORM("mail.collect_email_address_incoming", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.collect_email_address_newsgroup", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.collect_email_address_outgoing", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.compose.add_undisclosed_recipients", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.compose.autosave", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.compose.autosaveinterval", Int),
+ MAKESAMETYPEPREFTRANSFORM("mail.compose.dontWarnMail2Newsgroup", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.compose.other.header", String),
+ MAKESAMETYPEPREFTRANSFORM("mail.content_disposition_type", Int),
+
+ MAKESAMETYPEPREFTRANSFORM("mail.default_html_action", Int),
+ MAKESAMETYPEPREFTRANSFORM("mail.default_sendlater_uri", String),
+ MAKESAMETYPEPREFTRANSFORM("mail.delete_matches_sort_order", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.display_glyph", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.display_struct", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.enable_autocomplete", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.fcc_folder", String),
+ MAKESAMETYPEPREFTRANSFORM("mail.file_attach_binary", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.fixed_width_messages", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.forward_message_mode", Int),
+
+ MAKESAMETYPEPREFTRANSFORM("mail.incorporate.return_receipt", Int),
+ MAKESAMETYPEPREFTRANSFORM("mail.inline_attachments", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.label_ascii_only_mail_as_us_ascii", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.notification.sound", String),
+
+ MAKESAMETYPEPREFTRANSFORM("mail.pane_config.dynamic", Int),
+ MAKESAMETYPEPREFTRANSFORM("mail.password_protect_local_cache", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.phishing.detection.enabled", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.pop3.deleteFromServerOnMove", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.prompt_purge_threshhold", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.purge_threshhold", Int),
+ MAKESAMETYPEPREFTRANSFORM("mail.purge.ask", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.purge.min_delay", Int),
+ MAKESAMETYPEPREFTRANSFORM("mail.purge.timer_interval", Int),
+
+ MAKESAMETYPEPREFTRANSFORM("mail.quoteasblock", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.quoted_graphical", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.quoted_size", Int),
+ MAKESAMETYPEPREFTRANSFORM("mail.quoted_style", Int),
+
+ MAKESAMETYPEPREFTRANSFORM("mail.receipt.request_header_type", Int),
+ MAKESAMETYPEPREFTRANSFORM("mail.receipt.request_return_receipt_on", Bool),
+
+ MAKESAMETYPEPREFTRANSFORM("mail.send_struct", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.show_headers", Int),
+ MAKESAMETYPEPREFTRANSFORM("mail.smtp.useMatchingDomainServer", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.smtp.useMatchingHostNameServer", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.smtp.defaultserver", String),
+ MAKESAMETYPEPREFTRANSFORM("mail.smtpservers", String),
+ MAKESAMETYPEPREFTRANSFORM("mail.spellcheck.inline", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.SpellCheckBeforeSend", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.startup.enabledMailCheckOnce", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.strict_threading", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.strictly_mime", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.strictly_mime_headers", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.strictly_mime.parm_folding", Bool),
+
+ MAKESAMETYPEPREFTRANSFORM("mail.thread_without_re", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.trusteddomains", String),
+ MAKESAMETYPEPREFTRANSFORM("mail.warn_on_send_accel_key", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.warn_filter_changed", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mail.wrap_long_lines", Bool),
+
+ MAKESAMETYPEPREFTRANSFORM("mailnews.account_central_page.url", String),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.confirm.moveFoldersToTrash", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.customDBHeaders", String),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.customHeaders", String),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.default_sort_order", Int),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.default_sort_type", Int),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.default_news_sort_order", Int),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.default_news_sort_type", Int),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.display.disable_format_flowed_support", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.display.disallow_mime_handlers", Int),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.display.html_as", Int),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.display_html_sanitzer.allowed_tags", String),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.display.original_date", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.display.prefer_plaintext", Bool),
+
+ MAKESAMETYPEPREFTRANSFORM("mailnews.force_ascii_search", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.force_charset_override", Bool),
+
+ MAKESAMETYPEPREFTRANSFORM("mailnews.headers.showOrganization", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.headers.showUserAgent", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.headers.extraExpandedHeaders", String),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.html_domains", String),
+
+ MAKESAMETYPEPREFTRANSFORM("mailnews.mark_message_read.delay", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.mark_message_read.delay.interval", Int),
+
+ MAKESAMETYPEPREFTRANSFORM("mailnews.message_display.disable_remote_image", Bool),
+
+ MAKESAMETYPEPREFTRANSFORM("mailnews.nav_crosses_folders", Int),
+
+ MAKESAMETYPEPREFTRANSFORM("mailnews.offline_sync_mail", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.offline_sych_news", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.offline_sync_send_unsent", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.offline_sync_work_offline", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.open_window_warning", Int),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.plaintext_domains", String),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.remember_selected_message", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.reply_in_default_charset", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.reuse_message_window", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.scroll_to_new_message", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.search_date_format", String),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.search_date_leading_zeros", String),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.search_date_separator", String),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.send_default_charset", String),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.send_plaintext_flowed", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.show_send_progress", String),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.start_page.enabled", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.start_page.url", String),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.tcptimeout", Int),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.thread_pane_column_unthreads", Bool),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.view_default_charset", String),
+ MAKESAMETYPEPREFTRANSFORM("mailnews.wraplength", Int),
+
+ MAKESAMETYPEPREFTRANSFORM("messenger.save.dir", String),
+
+ MAKESAMETYPEPREFTRANSFORM("msgcompose.background_color", String),
+ MAKESAMETYPEPREFTRANSFORM("msgcompose.font_face", String),
+ MAKESAMETYPEPREFTRANSFORM("msgcompose.font_size", String),
+ MAKESAMETYPEPREFTRANSFORM("msgcompose.text_color", String),
+
+ MAKESAMETYPEPREFTRANSFORM("news.get_messages_on_select", Bool),
+ MAKESAMETYPEPREFTRANSFORM("news.show_size_in_lines", Bool),
+ MAKESAMETYPEPREFTRANSFORM("news.update_unread_on_expand", Bool),
+
+ // pdi is the new preference, but nii is the old one - so do nii first, and
+ // then do pdi to account for both situations
+ MAKEPREFTRANSFORM("network.image.imageBehavior", 0, Int, Image),
+ MAKESAMETYPEPREFTRANSFORM("permissions.default.image", Int),
+
+ MAKESAMETYPEPREFTRANSFORM("network.proxy.autoconfig_url", String),
+ MAKESAMETYPEPREFTRANSFORM("network.proxy.ftp", String),
+ MAKESAMETYPEPREFTRANSFORM("network.proxy.ftp_port", Int),
+ MAKESAMETYPEPREFTRANSFORM("network.proxy.http", String),
+ MAKESAMETYPEPREFTRANSFORM("network.proxy.http_port", Int),
+ MAKESAMETYPEPREFTRANSFORM("network.proxy.no_proxies_on", String),
+ MAKESAMETYPEPREFTRANSFORM("network.proxy.socks", String),
+ MAKESAMETYPEPREFTRANSFORM("network.proxy.socks_port", Int),
+ MAKESAMETYPEPREFTRANSFORM("network.proxy.ssl", String),
+ MAKESAMETYPEPREFTRANSFORM("network.proxy.ssl_port", Int),
+ MAKESAMETYPEPREFTRANSFORM("network.proxy.type", Int),
+
+ MAKESAMETYPEPREFTRANSFORM("offline.autodetect", Bool),
+ MAKESAMETYPEPREFTRANSFORM("offline.download.download_messages", Int),
+ MAKESAMETYPEPREFTRANSFORM("offline.send.unsent_messages", Int),
+ MAKESAMETYPEPREFTRANSFORM("offline.startup_state", Int),
+ MAKESAMETYPEPREFTRANSFORM("security.default_personal_cert", String),
+ MAKESAMETYPEPREFTRANSFORM("security.password_lifetime", Int),
+ MAKESAMETYPEPREFTRANSFORM("security.tls.version.min", Int),
+ MAKESAMETYPEPREFTRANSFORM("security.tls.version.max", Int),
+ MAKESAMETYPEPREFTRANSFORM("security.warn_entering_secure", Bool),
+ MAKESAMETYPEPREFTRANSFORM("security.warn_leaving_secure", Bool),
+ MAKESAMETYPEPREFTRANSFORM("security.warn_submit_insecure", Bool),
+ MAKESAMETYPEPREFTRANSFORM("security.warn_viewing_mixed", Bool),
+
+ MAKESAMETYPEPREFTRANSFORM("signon.rememberSignons", Bool),
+
+ MAKESAMETYPEPREFTRANSFORM("slider.snapMultiplier", Int),
+ MAKESAMETYPEPREFTRANSFORM("startup.homepage_override_url", String),
+
+#ifdef XP_UNIX
+ MAKESAMETYPEPREFTRANSFORM("ui.allow_platform_file_picker", Bool),
+#endif
+ MAKESAMETYPEPREFTRANSFORM("ui.click_hold_context_menus", Bool)
+};
+
+nsresult
+nsThunderbirdProfileMigrator::TransformPreferences(
+ const char* aSourcePrefFileName,
+ const char* aTargetPrefFileName)
+{
+ PrefTransform* transform;
+ PrefTransform* end = gTransforms + sizeof(gTransforms)/sizeof(PrefTransform);
+
+ // Load the source pref file
+ nsCOMPtr<nsIPrefService> psvc(do_GetService(NS_PREFSERVICE_CONTRACTID));
+ psvc->ResetPrefs();
+
+ nsCOMPtr<nsIFile> sourcePrefsFile;
+ mSourceProfile->Clone(getter_AddRefs(sourcePrefsFile));
+ sourcePrefsFile->AppendNative(nsDependentCString(aSourcePrefFileName));
+ psvc->ReadUserPrefsFromFile(sourcePrefsFile);
+
+ nsCOMPtr<nsIPrefBranch> branch(do_QueryInterface(psvc));
+ for (transform = gTransforms; transform < end; ++transform)
+ transform->prefGetterFunc(transform, branch);
+
+ // read in the various pref branch trees for accounts, identities, servers,
+ // etc.
+ static const char* branchNames[] =
+ {
+ // Keep the three below first, or change the indexes below
+ "mail.identity.",
+ "mail.server.",
+ "ldap_2.",
+ "accessibility.",
+ "applications.",
+ "bidi.",
+ "dom.",
+ "editor.",
+ "font.",
+ "helpers.",
+ "mail.account.",
+ "mail.addr_book.",
+ "mail.imap.",
+ "mail.mdn.",
+ "mail.smtpserver.",
+ "mail.spam.",
+ "mail.toolbars.",
+ "mailnews.labels.",
+ "mailnews.reply_",
+ "mailnews.tags.",
+ "middlemouse.",
+ "mousewheel.",
+ "network.http.",
+ "print.",
+ "privacy.",
+ "security.OSCP.",
+ "security.crl.",
+ "ui.key.",
+ "wallet."
+ };
+
+ PBStructArray branches[MOZ_ARRAY_LENGTH(branchNames)];
+ uint32_t i;
+ for (i = 0; i < MOZ_ARRAY_LENGTH(branchNames); ++i)
+ ReadBranch(branchNames[i], psvc, branches[i]);
+
+ // the signature file prefs may be paths to files in the thunderbird profile
+ // path so we need to copy them over and fix these paths up before we write
+ // them out to the new prefs.js
+ CopySignatureFiles(branches[0], psvc);
+
+ // certain mail prefs may actually be absolute paths instead of profile
+ // relative paths we need to fix these paths up before we write them out to
+ // the new prefs.js
+ CopyMailFolderPrefs(branches[1], psvc);
+
+ CopyAddressBookDirectories(branches[2], psvc);
+
+ // Now that we have all the pref data in memory, load the target pref file,
+ // and write it back out
+ psvc->ResetPrefs();
+
+ nsCOMPtr<nsIFile> targetPrefsFile;
+ mTargetProfile->Clone(getter_AddRefs(targetPrefsFile));
+ targetPrefsFile->AppendNative(nsDependentCString(aTargetPrefFileName));
+
+ // Don't use nullptr here as we're too early in the cycle for the prefs
+ // service to get its default file (because the NS_GetDirectoryService items
+ // aren't fully set up yet).
+ psvc->ReadUserPrefsFromFile(targetPrefsFile);
+
+ for (transform = gTransforms; transform < end; ++transform)
+ transform->prefSetterFunc(transform, branch);
+
+ for (i = 0; i < MOZ_ARRAY_LENGTH(branchNames); ++i)
+ WriteBranch(branchNames[i], psvc, branches[i]);
+
+ psvc->SavePrefFile(targetPrefsFile);
+
+ return NS_OK;
+}
+
+nsresult
+nsThunderbirdProfileMigrator::CopyPreferences(bool aReplace)
+{
+ nsresult rv = NS_OK;
+ if (!aReplace)
+ return rv;
+
+ if (NS_SUCCEEDED(rv))
+ rv = TransformPreferences(FILE_NAME_PREFS, FILE_NAME_PREFS);
+ if (NS_SUCCEEDED(rv))
+ rv = CopyFile(FILE_NAME_USER_PREFS, FILE_NAME_USER_PREFS);
+
+ // Security Stuff
+ if (NS_SUCCEEDED(rv))
+ rv = CopyFile(FILE_NAME_CERT8DB, FILE_NAME_CERT8DB);
+ if (NS_SUCCEEDED(rv))
+ rv = CopyFile(FILE_NAME_KEY3DB, FILE_NAME_KEY3DB);
+ if (NS_SUCCEEDED(rv))
+ rv = CopyFile(FILE_NAME_SECMODDB, FILE_NAME_SECMODDB);
+
+ // User MIME Type overrides
+ if (NS_SUCCEEDED(rv))
+ rv = CopyFile(FILE_NAME_MIMETYPES, FILE_NAME_MIMETYPES);
+ if (NS_SUCCEEDED(rv))
+ rv = CopyFile(FILE_NAME_PERSONALDICTIONARY, FILE_NAME_PERSONALDICTIONARY);
+ if (NS_SUCCEEDED(rv))
+ rv = CopyFile(FILE_NAME_MAILVIEWS, FILE_NAME_MAILVIEWS);
+
+ return rv;
+}
+
+nsresult
+nsThunderbirdProfileMigrator::CopyHistory(bool aReplace)
+{
+ return aReplace ? CopyFile(FILE_NAME_HISTORY, FILE_NAME_HISTORY) : NS_OK;
+}
+
+nsresult
+nsThunderbirdProfileMigrator::CopyPasswords(bool aReplace)
+{
+ return aReplace ? CopyFile(FILE_NAME_SIGNONS, FILE_NAME_SIGNONS) : NS_OK;
+}
diff --git a/comm/suite/components/migration/src/nsThunderbirdProfileMigrator.h b/comm/suite/components/migration/src/nsThunderbirdProfileMigrator.h
new file mode 100644
index 0000000000..2b3bbf87ec
--- /dev/null
+++ b/comm/suite/components/migration/src/nsThunderbirdProfileMigrator.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; 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/. */
+
+#ifndef ThunderbirdProfileMigrator_h__
+#define ThunderbirdProfileMigrator_h__
+
+#include "nsISuiteProfileMigrator.h"
+#include "nsIFile.h"
+#include "nsIObserverService.h"
+#include "nsSuiteProfileMigratorBase.h"
+#include "nsITimer.h"
+#include "mozilla/Attributes.h"
+
+class nsIFile;
+class nsIPrefBranch;
+class nsIPrefService;
+
+class nsThunderbirdProfileMigrator final : public nsSuiteProfileMigratorBase
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+
+ nsThunderbirdProfileMigrator();
+
+ // nsISuiteProfileMigrator methods
+ NS_IMETHOD Migrate(uint16_t aItems, nsIProfileStartup *aStartup,
+ const char16_t *aProfile) override;
+ NS_IMETHOD GetMigrateData(const char16_t *aProfile, bool aDoingStartup,
+ uint16_t *_retval) override;
+ NS_IMETHOD GetSupportedItems(uint16_t *aSupportedItems) override;
+
+protected:
+ virtual ~nsThunderbirdProfileMigrator();
+ nsresult FillProfileDataFromRegistry() override;
+ nsresult CopyPreferences(bool aReplace);
+ nsresult TransformPreferences(const char* aSourcePrefFileName,
+ const char* aTargetPrefFileName);
+ nsresult CopyHistory(bool aReplace);
+ nsresult CopyPasswords(bool aReplace);
+};
+
+#endif