diff options
author | janekptacijarabaci <janekptacijarabaci@seznam.cz> | 2018-04-20 08:28:12 +0200 |
---|---|---|
committer | janekptacijarabaci <janekptacijarabaci@seznam.cz> | 2018-04-20 08:28:12 +0200 |
commit | 4e7e4c2cbed8209974691f18180fa7ea8f00e785 (patch) | |
tree | e819b05bad4189d06a0ab87626a010e93849e0a0 | |
parent | 8b960b23ac31d4dd0763f91ab5f494251467eeb1 (diff) | |
download | UXP-4e7e4c2cbed8209974691f18180fa7ea8f00e785.tar UXP-4e7e4c2cbed8209974691f18180fa7ea8f00e785.tar.gz UXP-4e7e4c2cbed8209974691f18180fa7ea8f00e785.tar.lz UXP-4e7e4c2cbed8209974691f18180fa7ea8f00e785.tar.xz UXP-4e7e4c2cbed8209974691f18180fa7ea8f00e785.zip |
[PALEMOON] Fix: The profile resseting - partially
https://github.com/MoonchildProductions/UXP/commit/aaf3409c46a5e472bc539a6ad5902f886c980e1f
- Revert migration
- Partially
- no manual migration from Places
- no migration from other browsers
- no the cmd `-migration`
- Fix migration files (`// Tycho:`)
- Something in the last commit (a typo)
15 files changed, 1164 insertions, 20 deletions
diff --git a/application/palemoon/components/migration/BrowserProfileMigrators.manifest b/application/palemoon/components/migration/BrowserProfileMigrators.manifest new file mode 100644 index 000000000..d2bf0901d --- /dev/null +++ b/application/palemoon/components/migration/BrowserProfileMigrators.manifest @@ -0,0 +1,4 @@ +component {6F8BB968-C14F-4D6F-9733-6C6737B35DCE} ProfileMigrator.js +contract @mozilla.org/toolkit/profile-migrator;1 {6F8BB968-C14F-4D6F-9733-6C6737B35DCE} +component {91185366-ba97-4438-acba-48deaca63386} FirefoxProfileMigrator.js +contract @mozilla.org/profile/migrator;1?app=browser&type=firefox {91185366-ba97-4438-acba-48deaca63386} diff --git a/application/palemoon/components/migration/FirefoxProfileMigrator.js b/application/palemoon/components/migration/FirefoxProfileMigrator.js new file mode 100644 index 000000000..9101974cf --- /dev/null +++ b/application/palemoon/components/migration/FirefoxProfileMigrator.js @@ -0,0 +1,126 @@ +/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=2 sts=2 et */ + /* 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"; + +/* + * Migrates from a Pale Moon profile in a lossy manner in order to clean up a + * user's profile. Data is only migrated where the benefits outweigh the + * potential problems caused by importing undesired/invalid configurations + * from the source profile. + */ + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Components.utils.import("resource:///modules/MigrationUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PlacesBackups", + "resource://gre/modules/PlacesBackups.jsm"); + +function FirefoxProfileMigrator() { } + +FirefoxProfileMigrator.prototype = Object.create(MigratorPrototype); + +FirefoxProfileMigrator.prototype._getAllProfiles = function () { + let allProfiles = new Map(); + let profiles = + Components.classes["@mozilla.org/toolkit/profile-service;1"] + .getService(Components.interfaces.nsIToolkitProfileService) + .profiles; + while (profiles.hasMoreElements()) { + let profile = profiles.getNext().QueryInterface(Components.interfaces.nsIToolkitProfile); + let rootDir = profile.rootDir; + + if (rootDir.exists() && rootDir.isReadable() && + !rootDir.equals(MigrationUtils.profileStartup.directory)) { + allProfiles.set(profile.name, rootDir); + } + } + return allProfiles; +}; + +function sorter(a, b) { + return a.id.toLocaleLowerCase().localeCompare(b.id.toLocaleLowerCase()); +} + +Object.defineProperty(FirefoxProfileMigrator.prototype, "sourceProfiles", { + get: function() { + // Tycho: return [{id: x, name: x} for (x of this._getAllProfiles().keys())].sort(sorter); + let items = []; + for (let x of this._getAllProfiles().keys()) { + items.push({id: x, name: x}); + } + return items.sort(sorter); + } +}); + +FirefoxProfileMigrator.prototype.getResources = function(aProfile) { + let sourceProfileDir = aProfile ? this._getAllProfiles().get(aProfile.id) : + Components.classes["@mozilla.org/toolkit/profile-service;1"] + .getService(Components.interfaces.nsIToolkitProfileService) + .selectedProfile.rootDir; + if (!sourceProfileDir || !sourceProfileDir.exists() || + !sourceProfileDir.isReadable()) + return null; + + // Being a startup-only migrator, we can rely on + // MigrationUtils.profileStartup being set. + let currentProfileDir = MigrationUtils.profileStartup.directory; + + // Surely data cannot be imported from the current profile. + if (sourceProfileDir.equals(currentProfileDir)) + return null; + + let getFileResource = function(aMigrationType, aFileNames) { + let files = []; + for (let fileName of aFileNames) { + let file = sourceProfileDir.clone(); + file.append(fileName); + + if (file.exists()) { + files.push(file); + } + } + if (!files.length) { + return null; + } + return { + type: aMigrationType, + migrate: function(aCallback) { + for (let file of files) { + file.copyTo(currentProfileDir, ""); + } + aCallback(true); + } + }; + }; + + let types = MigrationUtils.resourceTypes; + let places = getFileResource(types.HISTORY, ["places.sqlite", "places.sqlite-wal"]); + let cookies = getFileResource(types.COOKIES, ["cookies.sqlite", "cookies.sqlite-wal"]); + let passwords = getFileResource(types.PASSWORDS, + ["signons.sqlite", "logins.json", "key3.db"]); + let formData = getFileResource(types.FORMDATA, ["formhistory.sqlite"]); + let bookmarksBackups = getFileResource(types.OTHERDATA, + [PlacesBackups.profileRelativeFolderPath]); + let dictionary = getFileResource(types.OTHERDATA, ["persdict.dat"]); + + /* Tycho: + return [r for each (r in [places, cookies, passwords, formData, + dictionary, bookmarksBackups]) if (r)]; + */ + return [places, cookies, passwords, formData, dictionary, bookmarksBackups] + .filter(r => r); +} + +Object.defineProperty(FirefoxProfileMigrator.prototype, "startupOnlyMigrator", { + get: function() true +}); + + +FirefoxProfileMigrator.prototype.classDescription = "Firefox Profile Migrator"; +FirefoxProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=firefox"; +FirefoxProfileMigrator.prototype.classID = Components.ID("{91185366-ba97-4438-acba-48deaca63386}"); + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([FirefoxProfileMigrator]); diff --git a/application/palemoon/components/migration/MigrationUtils.jsm b/application/palemoon/components/migration/MigrationUtils.jsm index 4461b8af0..243bf098a 100644 --- a/application/palemoon/components/migration/MigrationUtils.jsm +++ b/application/palemoon/components/migration/MigrationUtils.jsm @@ -177,12 +177,11 @@ this.MigratorPrototype = { */ getMigrateData: function MP_getMigrateData(aProfile) { // Tycho: let types = [r.type for each (r in this._getMaybeCachedResources(aProfile))]; - let types = []; - - for each (r in this._getMaybeCachedResources(aProfile)) { - types.push(r.type); + let resources = this._getMaybeCachedResources(aProfile); + if (!resources) { + return []; } - + let types = resources.map(r => r.type); return types.reduce(function(a, b) a |= b, 0); }, @@ -197,15 +196,10 @@ this.MigratorPrototype = { if (resources.length == 0) throw new Error("migrate called for a non-existent source"); - if (aItems != Ci.nsIBrowserProfileMigrator.ALL) + if (aItems != Ci.nsIBrowserProfileMigrator.ALL) { // Tycho: resources = [r for each (r in resources) if (aItems & r.type)]; - resources = []; - - for each (r in resources) { - if (aItems & r.type) { - resources.push(r); - } - } + resources = resources.filter(r => aItems & r.type); + } // Called either directly or through the bookmarks import callback. function doMigrate() { diff --git a/application/palemoon/components/migration/ProfileMigrator.js b/application/palemoon/components/migration/ProfileMigrator.js new file mode 100644 index 000000000..f67823bae --- /dev/null +++ b/application/palemoon/components/migration/ProfileMigrator.js @@ -0,0 +1,21 @@ +/* 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"; + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Components.utils.import("resource:///modules/MigrationUtils.jsm"); + +function ProfileMigrator() { +} + +ProfileMigrator.prototype = { + migrate: MigrationUtils.startupMigration.bind(MigrationUtils), + QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIProfileMigrator]), + classDescription: "Profile Migrator", + contractID: "@mozilla.org/toolkit/profile-migrator;1", + classID: Components.ID("6F8BB968-C14F-4D6F-9733-6C6737B35DCE") +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ProfileMigrator]); diff --git a/application/palemoon/components/migration/content/migration.js b/application/palemoon/components/migration/content/migration.js new file mode 100644 index 000000000..908354d72 --- /dev/null +++ b/application/palemoon/components/migration/content/migration.js @@ -0,0 +1,465 @@ +/* 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/. */ + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +const kIMig = Ci.nsIBrowserProfileMigrator; +const kIPStartup = Ci.nsIProfileStartup; + +Cu.import("resource:///modules/MigrationUtils.jsm"); + +var MigrationWizard = { + _source: "", // Source Profile Migrator ContractID suffix + _itemsFlags: kIMig.ALL, // Selected Import Data Sources (16-bit bitfield) + _selectedProfile: null, // Selected Profile name to import from + _wiz: null, + _migrator: null, + _autoMigrate: null, + + init: function () + { + var os = Components.classes["@mozilla.org/observer-service;1"] + .getService(Components.interfaces.nsIObserverService); + os.addObserver(this, "Migration:Started", false); + os.addObserver(this, "Migration:ItemBeforeMigrate", false); + os.addObserver(this, "Migration:ItemAfterMigrate", false); + os.addObserver(this, "Migration:ItemError", false); + os.addObserver(this, "Migration:Ended", false); + + this._wiz = document.documentElement; + + if ("arguments" in window && window.arguments.length > 1) { + this._source = window.arguments[0]; + this._migrator = window.arguments[1] instanceof kIMig ? + window.arguments[1] : null; + this._autoMigrate = window.arguments[2].QueryInterface(kIPStartup); + this._skipImportSourcePage = window.arguments[3]; + if (this._migrator && window.arguments[4]) { + let sourceProfiles = this._migrator.sourceProfiles; + this._selectedProfile = sourceProfiles.find(profile => profile.id == window.arguments[4]); + } + + if (this._autoMigrate) { + // Show the "nothing" option in the automigrate case to provide an + // easily identifiable way to avoid migration and create a new profile. + var nothing = document.getElementById("nothing"); + nothing.hidden = false; + } + } + + this.onImportSourcePageShow(); + }, + + uninit: function () + { + var os = Components.classes["@mozilla.org/observer-service;1"] + .getService(Components.interfaces.nsIObserverService); + os.removeObserver(this, "Migration:Started"); + os.removeObserver(this, "Migration:ItemBeforeMigrate"); + os.removeObserver(this, "Migration:ItemAfterMigrate"); + os.removeObserver(this, "Migration:ItemError"); + os.removeObserver(this, "Migration:Ended"); + MigrationUtils.finishMigration(); + }, + + // 1 - Import Source + onImportSourcePageShow: function () + { + this._wiz.canRewind = false; + + var selectedMigrator = null; + + // Figure out what source apps are are available to import from: + var group = document.getElementById("importSourceGroup"); + for (var i = 0; i < group.childNodes.length; ++i) { + var migratorKey = group.childNodes[i].id; + if (migratorKey != "nothing") { + var migrator = MigrationUtils.getMigrator(migratorKey); + if (migrator) { + // Save this as the first selectable item, if we don't already have + // one, or if it is the migrator that was passed to us. + if (!selectedMigrator || this._source == migratorKey) + selectedMigrator = group.childNodes[i]; + } else { + // Hide this option + group.childNodes[i].hidden = true; + } + } + } + + if (selectedMigrator) + group.selectedItem = selectedMigrator; + else { + // We didn't find a migrator, notify the user + document.getElementById("noSources").hidden = false; + + this._wiz.canAdvance = false; + + document.getElementById("importBookmarks").hidden = true; + document.getElementById("importAll").hidden = true; + } + + // Advance to the next page if the caller told us to. + if (this._migrator && this._skipImportSourcePage) { + this._wiz.advance(); + this._wiz.canRewind = false; + } + }, + + onImportSourcePageAdvanced: function () + { + var newSource = document.getElementById("importSourceGroup").selectedItem.id; + + if (newSource == "nothing") { + document.documentElement.cancel(); + return false; + } + + if (!this._migrator || (newSource != this._source)) { + // Create the migrator for the selected source. + this._migrator = MigrationUtils.getMigrator(newSource); + + this._itemsFlags = kIMig.ALL; + this._selectedProfile = null; + } + this._source = newSource; + + // check for more than one source profile + var sourceProfiles = this._migrator.sourceProfiles; + if (this._skipImportSourcePage) { + this._wiz.currentPage.next = "homePageImport"; + } + else if (sourceProfiles && sourceProfiles.length > 1) { + this._wiz.currentPage.next = "selectProfile"; + } + else { + if (this._autoMigrate) + this._wiz.currentPage.next = "homePageImport"; + else + this._wiz.currentPage.next = "importItems"; + + if (sourceProfiles && sourceProfiles.length == 1) + this._selectedProfile = sourceProfiles[0]; + else + this._selectedProfile = null; + } + }, + + // 2 - [Profile Selection] + onSelectProfilePageShow: function () + { + // Disabling this for now, since we ask about import sources in automigration + // too and don't want to disable the back button + // if (this._autoMigrate) + // document.documentElement.getButton("back").disabled = true; + + var profiles = document.getElementById("profiles"); + while (profiles.hasChildNodes()) + profiles.removeChild(profiles.firstChild); + + // Note that this block is still reached even if the user chose 'From File' + // and we canceled the dialog. When that happens, _migrator will be null. + if (this._migrator) { + var sourceProfiles = this._migrator.sourceProfiles; + + for (let profile of sourceProfiles) { + var item = document.createElement("radio"); + item.id = profile.id; + item.setAttribute("label", profile.name); + profiles.appendChild(item); + } + } + + profiles.selectedItem = this._selectedProfile ? document.getElementById(this._selectedProfile.id) : profiles.firstChild; + }, + + onSelectProfilePageRewound: function () + { + var profiles = document.getElementById("profiles"); + this._selectedProfile = this._migrator.sourceProfiles.find( + profile => profile.id == profiles.selectedItem.id + ) || null; + }, + + onSelectProfilePageAdvanced: function () + { + var profiles = document.getElementById("profiles"); + this._selectedProfile = this._migrator.sourceProfiles.find( + profile => profile.id == profiles.selectedItem.id + ) || null; + + // If we're automigrating or just doing bookmarks don't show the item selection page + if (this._autoMigrate) + this._wiz.currentPage.next = "homePageImport"; + }, + + // 3 - ImportItems + onImportItemsPageShow: function () + { + var dataSources = document.getElementById("dataSources"); + while (dataSources.hasChildNodes()) + dataSources.removeChild(dataSources.firstChild); + + var items = this._migrator.getMigrateData(this._selectedProfile, this._autoMigrate); + for (var i = 0; i < 16; ++i) { + var itemID = (items >> i) & 0x1 ? Math.pow(2, i) : 0; + if (itemID > 0) { + var checkbox = document.createElement("checkbox"); + checkbox.id = itemID; + checkbox.setAttribute("label", + MigrationUtils.getLocalizedString(itemID + "_" + this._source)); + dataSources.appendChild(checkbox); + if (!this._itemsFlags || this._itemsFlags & itemID) + checkbox.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.localName == "checkbox" && checkbox.checked) + this._itemsFlags |= parseInt(checkbox.id); + } + }, + + onImportItemCommand: function (aEvent) + { + var items = document.getElementById("dataSources"); + var checkboxes = items.getElementsByTagName("checkbox"); + + var oneChecked = false; + for (var i = 0; i < checkboxes.length; ++i) { + if (checkboxes[i].checked) { + oneChecked = true; + break; + } + } + + this._wiz.canAdvance = oneChecked; + }, + + // 4 - Home Page Selection + onHomePageMigrationPageShow: function () + { + // only want this on the first run + if (!this._autoMigrate) { + this._wiz.advance(); + return; + } + + var brandBundle = document.getElementById("brandBundle"); + // These strings don't exist when not using official branding. If that's + // the case, just skip this page. + try { + var pageTitle = brandBundle.getString("homePageMigrationPageTitle"); + var pageDesc = brandBundle.getString("homePageMigrationDescription"); + var mainStr = brandBundle.getString("homePageSingleStartMain"); + } + catch (e) { + this._wiz.advance(); + return; + } + + document.getElementById("homePageImport").setAttribute("label", pageTitle); + document.getElementById("homePageImportDesc").setAttribute("value", pageDesc); + + this._wiz._adjustWizardHeader(); + + var singleStart = document.getElementById("homePageSingleStart"); + singleStart.setAttribute("label", mainStr); + singleStart.setAttribute("value", "DEFAULT"); + + var source = null; + switch (this._source) { + case "firefox": + source = "sourceNameFirefox"; + break; + } + + // semi-wallpaper for crash when multiple profiles exist, since we haven't initialized mSourceProfile in places + this._migrator.getMigrateData(this._selectedProfile, this._autoMigrate); + + var oldHomePageURL = this._migrator.sourceHomePageURL; + + if (oldHomePageURL && source) { + var appName = MigrationUtils.getLocalizedString(source); + var oldHomePageLabel = + brandBundle.getFormattedString("homePageImport", [appName]); + var oldHomePage = document.getElementById("oldHomePage"); + oldHomePage.setAttribute("label", oldHomePageLabel); + oldHomePage.setAttribute("value", oldHomePageURL); + oldHomePage.removeAttribute("hidden"); + } + 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 { + var radioGroup = document.getElementById("homePageRadiogroup"); + + this._newHomePage = radioGroup.selectedItem.value; + } catch(ex) {} + }, + + // 5 - Migrating + onMigratingPageShow: function () + { + this._wiz.getButton("cancel").disabled = true; + this._wiz.canRewind = false; + this._wiz.canAdvance = false; + + // When automigrating, show all of the data that can be received from this source. + if (this._autoMigrate) + this._itemsFlags = this._migrator.getMigrateData(this._selectedProfile, this._autoMigrate); + + 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.removeChild(items.firstChild); + + var brandBundle = document.getElementById("brandBundle"); + var itemID; + for (var i = 0; i < 16; ++i) { + var itemID = (this._itemsFlags >> i) & 0x1 ? Math.pow(2, i) : 0; + if (itemID > 0) { + var label = document.createElement("label"); + label.id = itemID + "_migrated"; + try { + label.setAttribute("value", + MigrationUtils.getLocalizedString(itemID + "_" + this._source)); + 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. + break; + } + } + } + }, + + observe: function (aSubject, aTopic, aData) + { + switch (aTopic) { + case "Migration:Started": + break; + case "Migration:ItemBeforeMigrate": + var label = document.getElementById(aData + "_migrated"); + if (label) + label.setAttribute("style", "font-weight: bold"); + break; + case "Migration:ItemAfterMigrate": + var label = document.getElementById(aData + "_migrated"); + if (label) + label.removeAttribute("style"); + break; + case "Migration:Ended": + if (this._autoMigrate) { + if (this._newHomePage) { + try { + // set homepage properly + var prefSvc = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefService); + var prefBranch = prefSvc.getBranch(null); + + if (this._newHomePage == "DEFAULT") { + prefBranch.clearUserPref("browser.startup.homepage"); + } + else { + var str = Components.classes["@mozilla.org/supports-string;1"] + .createInstance(Components.interfaces.nsISupportsString); + str.data = this._newHomePage; + prefBranch.setComplexValue("browser.startup.homepage", + Components.interfaces.nsISupportsString, + str); + } + + var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties); + var prefFile = dirSvc.get("ProfDS", Components.interfaces.nsIFile); + prefFile.append("prefs.js"); + prefSvc.savePrefFile(prefFile); + } catch(ex) { + dump(ex); + } + } + + // We're done now. + this._wiz.canAdvance = true; + this._wiz.advance(); + + setTimeout(close, 5000); + } + else { + this._wiz.canAdvance = true; + var nextButton = this._wiz.getButton("next"); + nextButton.click(); + } + break; + case "Migration:ItemError": + var type = "undefined"; + switch (parseInt(aData)) { + case Ci.nsIBrowserProfileMigrator.SETTINGS: + type = "settings"; + break; + case Ci.nsIBrowserProfileMigrator.COOKIES: + type = "cookies"; + break; + case Ci.nsIBrowserProfileMigrator.HISTORY: + type = "history"; + break; + case Ci.nsIBrowserProfileMigrator.FORMDATA: + type = "form data"; + break; + case Ci.nsIBrowserProfileMigrator.PASSWORDS: + type = "passwords"; + break; + case Ci.nsIBrowserProfileMigrator.BOOKMARKS: + type = "bookmarks"; + break; + case Ci.nsIBrowserProfileMigrator.OTHERDATA: + type = "misc. data"; + break; + } + Cc["@mozilla.org/consoleservice;1"] + .getService(Ci.nsIConsoleService) + .logStringMessage("some " + type + " did not successfully migrate."); + break; + } + }, + + onDonePageShow: function () + { + this._wiz.getButton("cancel").disabled = true; + this._wiz.canRewind = false; + this._listItems("doneItems"); + } +}; diff --git a/application/palemoon/components/migration/content/migration.xul b/application/palemoon/components/migration/content/migration.xul new file mode 100644 index 000000000..1f205fba7 --- /dev/null +++ b/application/palemoon/components/migration/content/migration.xul @@ -0,0 +1,86 @@ +<?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://browser/locale/migration/migration.dtd" > + +<wizard id="migrationWizard" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + windowtype="Browser:MigrationWizard" + title="&migrationWizard.title;" + onload="MigrationWizard.init()" + onunload="MigrationWizard.uninit()" + style="width: 40em;" + buttons="accept,cancel" + branded="true"> + + <script type="application/javascript" src="chrome://browser/content/migration/migration.js"/> + + <stringbundle id="brandBundle" src="chrome://branding/locale/brand.properties"/> + + <wizardpage id="importSource" pageid="importSource" next="selectProfile" + label="&importSource.title;" + onpageadvanced="return MigrationWizard.onImportSourcePageAdvanced();"> + <description id="importAll" control="importSourceGroup">&importFrom.label;</description> + <description id="importBookmarks" control="importSourceGroup" hidden="true">&importFromBookmarks.label;</description> + + <radiogroup id="importSourceGroup" align="start"> + <radio id="firefox" label="&importFromFirefox.label;" accesskey="&importFromFirefox.accesskey;"/> + <radio id="nothing" label="&importFromNothing.label;" accesskey="&importFromNothing.accesskey;" hidden="true"/> + </radiogroup> + <label id="noSources" hidden="true">&noMigrationSources.label;</label> + </wizardpage> + + <wizardpage id="selectProfile" pageid="selectProfile" label="&selectProfile.title;" + next="importItems" + onpageshow="return MigrationWizard.onSelectProfilePageShow();" + onpagerewound="return MigrationWizard.onSelectProfilePageRewound();" + onpageadvanced="return MigrationWizard.onSelectProfilePageAdvanced();"> + <description control="profiles">&selectProfile.label;</description> + + <radiogroup id="profiles" align="left"/> + </wizardpage> + + <wizardpage id="importItems" pageid="importItems" label="&importItems.title;" + next="homePageImport" + onpageshow="return MigrationWizard.onImportItemsPageShow();" + onpagerewound="return MigrationWizard.onImportItemsPageRewound();" + onpageadvanced="return MigrationWizard.onImportItemsPageAdvanced();" + oncommand="MigrationWizard.onImportItemCommand();"> + <description control="dataSources">&importItems.label;</description> + + <vbox id="dataSources" style="overflow: auto; -moz-appearance: listbox" align="left" flex="1" role="group"/> + </wizardpage> + + <wizardpage id="homePageImport" pageid="homePageImport" + next="migrating" + onpageshow="return MigrationWizard.onHomePageMigrationPageShow();" + onpageadvanced="return MigrationWizard.onHomePageMigrationPageAdvanced();"> + + <description id="homePageImportDesc" control="homePageRadioGroup"/> + <radiogroup id="homePageRadiogroup"> + <radio id="homePageSingleStart" selected="true" /> + <radio id="oldHomePage" hidden="true" /> + </radiogroup> + </wizardpage> + + <wizardpage id="migrating" pageid="migrating" label="&migrating.title;" + next="done" + onpageshow="MigrationWizard.onMigratingPageShow();"> + <description control="migratingItems">&migrating.label;</description> + + <vbox id="migratingItems" style="overflow: auto;" align="left" role="group"/> + </wizardpage> + + <wizardpage id="done" pageid="done" label="&done.title;" + onpageshow="MigrationWizard.onDonePageShow();"> + <description control="doneItems">&done.label;</description> + + <vbox id="doneItems" style="overflow: auto;" align="left" role="group"/> + </wizardpage> + +</wizard> + diff --git a/application/palemoon/components/migration/jar.mn b/application/palemoon/components/migration/jar.mn new file mode 100644 index 000000000..ab580b2bc --- /dev/null +++ b/application/palemoon/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/. + +browser.jar: + content/browser/migration/migration.xul (content/migration.xul) + content/browser/migration/migration.js (content/migration.js) diff --git a/application/palemoon/components/migration/moz.build b/application/palemoon/components/migration/moz.build new file mode 100644 index 000000000..ba85f865f --- /dev/null +++ b/application/palemoon/components/migration/moz.build @@ -0,0 +1,26 @@ +# -*- Mode: python; c-basic-offset: 4; 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/. + +JAR_MANIFESTS += ['jar.mn'] + +XPIDL_SOURCES += [ + 'nsIBrowserProfileMigrator.idl', +] + +XPIDL_MODULE = 'migration' + +EXTRA_COMPONENTS += [ + 'BrowserProfileMigrators.manifest', + 'FirefoxProfileMigrator.js', + 'ProfileMigrator.js', +] + +EXTRA_PP_JS_MODULES += [ + 'MigrationUtils.jsm', +] + +FINAL_LIBRARY = 'browsercomps' + diff --git a/application/palemoon/components/migration/nsIBrowserProfileMigrator.idl b/application/palemoon/components/migration/nsIBrowserProfileMigrator.idl new file mode 100644 index 000000000..ebff4628c --- /dev/null +++ b/application/palemoon/components/migration/nsIBrowserProfileMigrator.idl @@ -0,0 +1,63 @@ +/* -*- 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(30e5a7ec-f71e-4f41-9dbd-7429c02132ec)] +interface nsIBrowserProfileMigrator : nsISupports +{ + /** + * profile items to migrate. use with migrate(). + */ + const unsigned short ALL = 0x0000; + const unsigned short SETTINGS = 0x0001; + const unsigned short COOKIES = 0x0002; + const unsigned short HISTORY = 0x0004; + const unsigned short FORMDATA = 0x0008; + const unsigned short PASSWORDS = 0x0010; + const unsigned short BOOKMARKS = 0x0020; + const unsigned short OTHERDATA = 0x0040; + + /** + * Copy user profile information to the current active profile. + * @param aItems list of data items to migrate. see above for values. + * @param aStartup helper interface which is non-null if called during startup. + * @param aProfile profile to migrate from, if there is more than one. + */ + void migrate(in unsigned short aItems, in nsIProfileStartup aStartup, in jsval aProfile); + + /** + * A bit field containing profile items that this migrator + * offers for import. + * @param aProfile the profile that we are looking for available data + * to import + * @param aDoingStartup "true" if the profile is not currently being used. + * @return bit field containing profile items (see above) + * @note a return value of 0 represents no items rather than ALL. + */ + unsigned short getMigrateData(in jsval aProfile, in boolean aDoingStartup); + + /** + * 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; + + + /** + * An enumeration of available profiles. If the import source does + * not support profiles, this attribute is null. + */ + readonly attribute jsval sourceProfiles; + + /** + * The import source homepage. Returns null if not present/available + */ + readonly attribute AUTF8String sourceHomePageURL; +}; diff --git a/application/palemoon/components/nsBrowserContentHandler.js b/application/palemoon/components/nsBrowserContentHandler.js index 13ea9da12..6a75b40f2 100644 --- a/application/palemoon/components/nsBrowserContentHandler.js +++ b/application/palemoon/components/nsBrowserContentHandler.js @@ -518,16 +518,16 @@ nsBrowserContentHandler.prototype = { #endif }, - helpInfo : " -browser Open a browser window.\n" + - " -new-window <url> Open <url> in a new window.\n" + - " -new-tab <url> Open <url> in a new tab.\n" + - " -private-window <url> Open <url> in a new private window.\n" + + helpInfo : " --browser Open a browser window.\n" + + " --new-window <url> Open <url> in a new window.\n" + + " --new-tab <url> Open <url> in a new tab.\n" + + " --private-window <url> Open <url> in a new private window.\n" + #ifdef XP_WIN - " -preferences Open Options dialog.\n" + + " --preferences Open Options dialog.\n" + #else - " -preferences Open Preferences dialog.\n" + + " --preferences Open Preferences dialog.\n" + #endif - " -search <term> Search <term> with your default search engine.\n", + " --search <term> Search <term> with your default search engine.\n", /* nsIBrowserHandler */ diff --git a/application/palemoon/locales/en-US/chrome/browser/migration/migration.dtd b/application/palemoon/locales/en-US/chrome/browser/migration/migration.dtd new file mode 100644 index 000000000..e415b8f5a --- /dev/null +++ b/application/palemoon/locales/en-US/chrome/browser/migration/migration.dtd @@ -0,0 +1,30 @@ +<!-- 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/. --> + + +<!ENTITY migrationWizard.title "Import Wizard"> + +<!ENTITY importFrom.label "Import Preferences, Bookmarks, History, Passwords and other data from:"> +<!ENTITY importFromBookmarks.label "Import Bookmarks from:"> + +<!ENTITY importFromNothing.label "Don't import anything"> +<!ENTITY importFromNothing.accesskey "D"> +<!ENTITY importFromFirefox.label "Firefox"> +<!ENTITY importFromFirefox.accesskey "X"> + +<!ENTITY noMigrationSources.label "No programs that contain bookmarks, history or password data could be found."> + +<!ENTITY importSource.title "Import Settings and Data"> +<!ENTITY importItems.title "Items to Import"> +<!ENTITY importItems.label "Select which items to import:"> + +<!ENTITY migrating.title "Importing…"> +<!ENTITY migrating.label "The following items are currently being imported…"> + +<!ENTITY selectProfile.title "Select Profile"> +<!ENTITY selectProfile.label "The following profiles are available to import from:"> + +<!ENTITY done.title "Import Complete"> +<!ENTITY done.label "The following items were successfully imported:"> + diff --git a/application/palemoon/locales/en-US/chrome/browser/migration/migration.properties b/application/palemoon/locales/en-US/chrome/browser/migration/migration.properties new file mode 100644 index 000000000..fe49e66a5 --- /dev/null +++ b/application/palemoon/locales/en-US/chrome/browser/migration/migration.properties @@ -0,0 +1,23 @@ +# 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/. + +profileName_format=%S %S + +# Browser Specific +sourceNameFirefox=Mozilla Firefox + +importedBookmarksFolder=From %S + +# Import Sources +# Note: When adding an import source for profile reset, add the string name to +# resetProfile.js if it should be listed in the reset dialog. +2_firefox=Cookies + +4_firefox_history_and_bookmarks=Browsing History and Bookmarks + +8_firefox=Saved Form History + +16_firefox=Saved Passwords + +64_firefox_other=Other Data diff --git a/application/palemoon/locales/jar.mn b/application/palemoon/locales/jar.mn index f2b9ddeb2..6512c683e 100644 --- a/application/palemoon/locales/jar.mn +++ b/application/palemoon/locales/jar.mn @@ -55,6 +55,8 @@ locale/browser/places/moveBookmarks.dtd (%chrome/browser/places/moveBookmarks.dtd) locale/browser/feeds/subscribe.dtd (%chrome/browser/feeds/subscribe.dtd) locale/browser/feeds/subscribe.properties (%chrome/browser/feeds/subscribe.properties) + locale/browser/migration/migration.dtd (%chrome/browser/migration/migration.dtd) + locale/browser/migration/migration.properties (%chrome/browser/migration/migration.properties) locale/browser/preferences/aboutPermissions.dtd (%chrome/browser/preferences/aboutPermissions.dtd) locale/browser/preferences/aboutPermissions.properties (%chrome/browser/preferences/aboutPermissions.properties) locale/browser/preferences/advanced.dtd (%chrome/browser/preferences/advanced.dtd) diff --git a/toolkit/modules/Dict.jsm b/toolkit/modules/Dict.jsm new file mode 100644 index 000000000..8c41bb1c0 --- /dev/null +++ b/toolkit/modules/Dict.jsm @@ -0,0 +1,291 @@ +/* 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"; + +this.EXPORTED_SYMBOLS = ["Dict"]; + +/** + * Transforms a given key into a property name guaranteed not to collide with + * any built-ins. + */ +function convert(aKey) { + return ":" + aKey; +} + +/** + * Transforms a property into a key suitable for providing to the outside world. + */ +function unconvert(aProp) { + return aProp.substr(1); +} + +/** + * A dictionary of strings to arbitrary JS objects. This should be used whenever + * the keys are potentially arbitrary, to avoid collisions with built-in + * properties. + * + * @param aInitial An object containing the initial keys and values of this + * dictionary. Only the "own" enumerable properties of the + * object are considered. + * If |aInitial| is a string, it is assumed to be JSON and parsed into an object. + */ +this.Dict = function Dict(aInitial) { + if (aInitial === undefined) + aInitial = {}; + if (typeof aInitial == "string") + aInitial = JSON.parse(aInitial); + var items = {}, count = 0; + // That we don't look up the prototype chain is guaranteed by Iterator. + for (var [key, val] in Iterator(aInitial)) { + items[convert(key)] = val; + count++; + } + this._state = {count: count, items: items}; + return Object.freeze(this); +} + +Dict.prototype = Object.freeze({ + /** + * The number of items in the dictionary. + */ + get count() { + return this._state.count; + }, + + /** + * Gets the value for a key from the dictionary. If the key is not a string, + * it will be converted to a string before the lookup happens. + * + * @param aKey The key to look up + * @param [aDefault] An optional default value to return if the key is not + * present. Defaults to |undefined|. + * @returns The item, or aDefault if it isn't found. + */ + get: function Dict_get(aKey, aDefault) { + var prop = convert(aKey); + var items = this._state.items; + return items.hasOwnProperty(prop) ? items[prop] : aDefault; + }, + + /** + * Sets the value for a key in the dictionary. If the key is a not a string, + * it will be converted to a string before the set happens. + */ + set: function Dict_set(aKey, aValue) { + var prop = convert(aKey); + var items = this._state.items; + if (!items.hasOwnProperty(prop)) + this._state.count++; + items[prop] = aValue; + }, + + /** + * Sets a lazy getter function for a key's value. If the key is a not a string, + * it will be converted to a string before the set happens. + * @param aKey + * The key to set + * @param aThunk + * A getter function to be called the first time the value for aKey is + * retrieved. It is guaranteed that aThunk wouldn't be called more + * than once. Note that the key value may be retrieved either + * directly, by |get|, or indirectly, by |listvalues| or by iterating + * |values|. For the later, the value is only retrieved if and when + * the iterator gets to the value in question. Also note that calling + * |has| for a lazy-key does not invoke aThunk. + * + * @note No context is provided for aThunk when it's invoked. + * Use Function.bind if you wish to run it in a certain context. + */ + setAsLazyGetter: function Dict_setAsLazyGetter(aKey, aThunk) { + let prop = convert(aKey); + let items = this._state.items; + if (!items.hasOwnProperty(prop)) + this._state.count++; + + Object.defineProperty(items, prop, { + get: function() { + delete items[prop]; + return items[prop] = aThunk(); + }, + configurable: true, + enumerable: true + }); + }, + + /** + * Returns whether a key is set as a lazy getter. This returns + * true only if the getter function was not called already. + * @param aKey + * The key to look up. + * @returns whether aKey is set as a lazy getter. + */ + isLazyGetter: function Dict_isLazyGetter(aKey) { + let descriptor = Object.getOwnPropertyDescriptor(this._state.items, + convert(aKey)); + return (descriptor && descriptor.get != null); + }, + + /** + * Returns whether a key is in the dictionary. If the key is a not a string, + * it will be converted to a string before the lookup happens. + */ + has: function Dict_has(aKey) { + return (this._state.items.hasOwnProperty(convert(aKey))); + }, + + /** + * Deletes a key from the dictionary. If the key is a not a string, it will be + * converted to a string before the delete happens. + * + * @returns true if the key was found, false if it wasn't. + */ + del: function Dict_del(aKey) { + var prop = convert(aKey); + if (this._state.items.hasOwnProperty(prop)) { + delete this._state.items[prop]; + this._state.count--; + return true; + } + return false; + }, + + /** + * Returns a shallow copy of this dictionary. + */ + copy: function Dict_copy() { + var newItems = {}; + for (var [key, val] in this.items) + newItems[key] = val; + return new Dict(newItems); + }, + + /* + * List and iterator functions + * + * No guarantees whatsoever are made about the order of elements. + */ + + /** + * Returns a list of all the keys in the dictionary in an arbitrary order. + */ + listkeys: function Dict_listkeys() { + // Tycho: return [unconvert(k) for (k in this._state.items)]; + let list = []; + for (let k in this._state.items) { + list.push(unconvert(k)); + } + return list; + }, + + /** + * Returns a list of all the values in the dictionary in an arbitrary order. + */ + listvalues: function Dict_listvalues() { + let items = this._state.items; + // Tycho: return [items[k] for (k in items)]; + let list = []; + for (let k in items) { + list.push(items[k]); + } + return list; + }, + + /** + * Returns a list of all the items in the dictionary as key-value pairs + * in an arbitrary order. + */ + listitems: function Dict_listitems() { + let items = this._state.items; + // Tycho: return [[unconvert(k), items[k]] for (k in items)]; + let list = []; + let obj; + for (let k in items) { + obj = {}; + obj[unconvert(k)] = items[k]; + list.push(obj); + } + return list; + }, + + /** + * Returns an iterator over all the keys in the dictionary in an arbitrary + * order. No guarantees are made about what happens if the dictionary is + * mutated during iteration. + */ + get keys() { + // If we don't capture this._state.items here then the this-binding will be + // incorrect when the generator is executed + let items = this._state.items; + // Tycho: return (unconvert(k) for (k in items)); + let list = []; + for (let k in items) { + list.push(unconvert(k)); + } + return list; + }, + + /** + * Returns an iterator over all the values in the dictionary in an arbitrary + * order. No guarantees are made about what happens if the dictionary is + * mutated during iteration. + */ + get values() { + // If we don't capture this._state.items here then the this-binding will be + // incorrect when the generator is executed + let items = this._state.items; + // Tycho: return (items[k] for (k in items)); + let list = []; + for (let k in items) { + list.push(items[k]); + } + return list; + }, + + /** + * Returns an iterator over all the items in the dictionary as key-value pairs + * in an arbitrary order. No guarantees are made about what happens if the + * dictionary is mutated during iteration. + */ + get items() { + // If we don't capture this._state.items here then the this-binding will be + // incorrect when the generator is executed + let items = this._state.items; + // Tycho: return ([unconvert(k), items[k]] for (k in items)); + let list = []; + let obj; + for each (let k in items) { + obj = {}; + obj[unconvert(k)] = items[k]; + list.push(obj); + } + return list; + }, + + /** + * Returns a String representation of this dictionary. + */ + toString: function Dict_toString() { + /* Tycho: + return "{" + + [(key + ": " + val) for ([key, val] in this.items)].join(", ") + + "}"; + */ + let list = this.items.map(function (item) { + return item["key"] + ": " + item["val"]; + }); + return "{" + list.join(", ") + "}"; + }, + + /** + * Returns a JSON representation of this dictionary. + */ + toJSON: function Dict_toJSON() { + let obj = {}; + for (let [key, item] of Iterator(this._state.items)) { + obj[unconvert(key)] = item; + } + return JSON.stringify(obj); + }, +}); diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build index 60f3cc3da..d675f2f60 100644 --- a/toolkit/modules/moz.build +++ b/toolkit/modules/moz.build @@ -100,6 +100,12 @@ EXTRA_JS_MODULES += [ 'WindowDraggingUtils.jsm', 'ZipUtils.jsm', ] + +if CONFIG['MC_PALEMOON']: + EXTRA_JS_MODULES += [ + 'Dict.jsm', + ] + EXTRA_JS_MODULES.third_party.jsesc += ['third_party/jsesc/jsesc.js'] EXTRA_JS_MODULES.sessionstore += ['sessionstore/Utils.jsm'] |