mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-07 08:18:41 +09:00
[PALEMOON] Remove the migrator
This commit is contained in:
parent
5e8d7ac9ea
commit
6bb8c2d3ab
25 changed files with 3 additions and 3228 deletions
|
|
@ -18,7 +18,6 @@ LOCAL_INCLUDES += [
|
|||
'../about',
|
||||
'../dirprovider',
|
||||
'../feeds',
|
||||
'../migration',
|
||||
'../shell',
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -4,14 +4,6 @@
|
|||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef XP_WIN
|
||||
#define NS_WINIEHISTORYENUMERATOR_CID \
|
||||
{ 0x93480624, 0x806e, 0x4756, { 0xb7, 0xcb, 0x0f, 0xb7, 0xdd, 0x74, 0x6a, 0x8f } }
|
||||
|
||||
#define NS_IEHISTORYENUMERATOR_CONTRACTID \
|
||||
"@mozilla.org/profile/migrator/iehistoryenumerator;1"
|
||||
#endif
|
||||
|
||||
#define NS_SHELLSERVICE_CID \
|
||||
{ 0x63c7b9f4, 0xcc8, 0x43f8, { 0xb6, 0x66, 0xa, 0x66, 0x16, 0x55, 0xcb, 0x73 } }
|
||||
|
||||
|
|
|
|||
|
|
@ -16,10 +16,6 @@
|
|||
#include "nsGNOMEShellService.h"
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN)
|
||||
#include "nsIEHistoryEnumerator.h"
|
||||
#endif
|
||||
|
||||
#include "rdf.h"
|
||||
#include "nsFeedSniffer.h"
|
||||
#include "AboutRedirector.h"
|
||||
|
|
@ -40,10 +36,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacShellService)
|
|||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGNOMEShellService, Init)
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsIEHistoryEnumerator)
|
||||
#endif
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFeedSniffer)
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_BROWSERDIRECTORYPROVIDER_CID);
|
||||
|
|
@ -54,9 +46,7 @@ NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
|
|||
#endif
|
||||
NS_DEFINE_NAMED_CID(NS_FEEDSNIFFER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_BROWSER_ABOUT_REDIRECTOR_CID);
|
||||
#if defined(XP_WIN)
|
||||
NS_DEFINE_NAMED_CID(NS_WINIEHISTORYENUMERATOR_CID);
|
||||
#elif defined(XP_MACOSX)
|
||||
#ifdef XP_MACOSX
|
||||
NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
|
||||
#endif
|
||||
|
||||
|
|
@ -69,9 +59,7 @@ static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
|
|||
#endif
|
||||
{ &kNS_FEEDSNIFFER_CID, false, nullptr, nsFeedSnifferConstructor },
|
||||
{ &kNS_BROWSER_ABOUT_REDIRECTOR_CID, false, nullptr, AboutRedirector::Create },
|
||||
#if defined(XP_WIN)
|
||||
{ &kNS_WINIEHISTORYENUMERATOR_CID, false, nullptr, nsIEHistoryEnumeratorConstructor },
|
||||
#elif defined(XP_MACOSX)
|
||||
#ifdef XP_MACOSX
|
||||
{ &kNS_SHELLSERVICE_CID, false, nullptr, nsMacShellServiceConstructor },
|
||||
#endif
|
||||
{ nullptr }
|
||||
|
|
@ -101,9 +89,7 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
|
|||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "newtab", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "permissions", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "downloads", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
#if defined(XP_WIN)
|
||||
{ NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID },
|
||||
#elif defined(XP_MACOSX)
|
||||
#ifdef XP_MACOSX
|
||||
{ NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
|
||||
#endif
|
||||
{ nullptr }
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
component {6F8BB968-C14F-4D6F-9733-6C6737B35DCE} ProfileMigrator.js
|
||||
contract @mozilla.org/toolkit/profile-migrator;1 {6F8BB968-C14F-4D6F-9733-6C6737B35DCE}
|
||||
component {4cec1de4-1671-4fc3-a53e-6c539dc77a26} ChromeProfileMigrator.js
|
||||
contract @mozilla.org/profile/migrator;1?app=browser&type=chrome {4cec1de4-1671-4fc3-a53e-6c539dc77a26}
|
||||
component {91185366-ba97-4438-acba-48deaca63386} FirefoxProfileMigrator.js
|
||||
contract @mozilla.org/profile/migrator;1?app=browser&type=firefox {91185366-ba97-4438-acba-48deaca63386}
|
||||
#ifdef HAS_IE_MIGRATOR
|
||||
component {3d2532e3-4932-4774-b7ba-968f5899d3a4} IEProfileMigrator.js
|
||||
contract @mozilla.org/profile/migrator;1?app=browser&type=ie {3d2532e3-4932-4774-b7ba-968f5899d3a4}
|
||||
#endif
|
||||
#ifdef HAS_SAFARI_MIGRATOR
|
||||
component {4b609ecf-60b2-4655-9df4-dc149e474da1} SafariProfileMigrator.js
|
||||
contract @mozilla.org/profile/migrator;1?app=browser&type=safari {4b609ecf-60b2-4655-9df4-dc149e474da1}
|
||||
#endif
|
||||
|
|
@ -1,463 +0,0 @@
|
|||
/* -*- 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";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
const FILE_INPUT_STREAM_CID = "@mozilla.org/network/file-input-stream;1";
|
||||
|
||||
const S100NS_FROM1601TO1970 = 0x19DB1DED53E8000;
|
||||
const S100NS_PER_MS = 10;
|
||||
|
||||
const AUTH_TYPE = {
|
||||
SCHEME_HTML: 0,
|
||||
SCHEME_BASIC: 1,
|
||||
SCHEME_DIGEST: 2
|
||||
};
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
Cu.import("resource:///modules/MigrationUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OSCrypto",
|
||||
"resource://gre/modules/OSCrypto.jsm");
|
||||
|
||||
/**
|
||||
* Convert Chrome time format to Date object
|
||||
*
|
||||
* @param aTime
|
||||
* Chrome time
|
||||
* @return converted Date object
|
||||
* @note Google Chrome uses FILETIME / 10 as time.
|
||||
* FILETIME is based on same structure of Windows.
|
||||
*/
|
||||
function chromeTimeToDate(aTime)
|
||||
{
|
||||
return new Date((aTime * S100NS_PER_MS - S100NS_FROM1601TO1970 ) / 10000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert bookmark items into specific folder.
|
||||
*
|
||||
* @param aFolderId
|
||||
* id of folder where items will be inserted
|
||||
* @param aItems
|
||||
* bookmark items to be inserted
|
||||
*/
|
||||
function insertBookmarkItems(aFolderId, aItems)
|
||||
{
|
||||
for (let i = 0; i < aItems.length; i++) {
|
||||
let item = aItems[i];
|
||||
|
||||
try {
|
||||
if (item.type == "url") {
|
||||
PlacesUtils.bookmarks.insertBookmark(aFolderId,
|
||||
NetUtil.newURI(item.url),
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
item.name);
|
||||
} else if (item.type == "folder") {
|
||||
let newFolderId =
|
||||
PlacesUtils.bookmarks.createFolder(aFolderId,
|
||||
item.name,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX);
|
||||
|
||||
insertBookmarkItems(newFolderId, item.children);
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function ChromeProfileMigrator() {
|
||||
let chromeUserDataFolder = FileUtils.getDir(
|
||||
#ifdef XP_WIN
|
||||
"LocalAppData", ["Google", "Chrome", "User Data"]
|
||||
#elifdef XP_MACOSX
|
||||
"ULibDir", ["Application Support", "Google", "Chrome"]
|
||||
#else
|
||||
"Home", [".config", "google-chrome"]
|
||||
#endif
|
||||
, false);
|
||||
this._chromeUserDataFolder = chromeUserDataFolder.exists() ?
|
||||
chromeUserDataFolder : null;
|
||||
}
|
||||
|
||||
ChromeProfileMigrator.prototype = Object.create(MigratorPrototype);
|
||||
|
||||
ChromeProfileMigrator.prototype.getResources =
|
||||
function Chrome_getResources(aProfile) {
|
||||
if (this._chromeUserDataFolder) {
|
||||
let profileFolder = this._chromeUserDataFolder.clone();
|
||||
profileFolder.append(aProfile.id);
|
||||
if (profileFolder.exists()) {
|
||||
let possibleResources = [GetBookmarksResource(profileFolder),
|
||||
GetHistoryResource(profileFolder),
|
||||
GetCookiesResource(profileFolder),
|
||||
#ifdef XP_WIN
|
||||
GetWindowsPasswordsResource(profileFolder)
|
||||
#endif
|
||||
];
|
||||
return [r for each (r in possibleResources) if (r != null)];
|
||||
}
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
Object.defineProperty(ChromeProfileMigrator.prototype, "sourceProfiles", {
|
||||
get: function Chrome_sourceProfiles() {
|
||||
if ("__sourceProfiles" in this)
|
||||
return this.__sourceProfiles;
|
||||
|
||||
if (!this._chromeUserDataFolder)
|
||||
return [];
|
||||
|
||||
let profiles = [];
|
||||
try {
|
||||
// Local State is a JSON file that contains profile info.
|
||||
let localState = this._chromeUserDataFolder.clone();
|
||||
localState.append("Local State");
|
||||
if (!localState.exists())
|
||||
throw new Error("Chrome's 'Local State' file does not exist.");
|
||||
if (!localState.isReadable())
|
||||
throw new Error("Chrome's 'Local State' file could not be read.");
|
||||
|
||||
let fstream = Cc[FILE_INPUT_STREAM_CID].createInstance(Ci.nsIFileInputStream);
|
||||
fstream.init(localState, -1, 0, 0);
|
||||
let inputStream = NetUtil.readInputStreamToString(fstream, fstream.available(),
|
||||
{ charset: "UTF-8" });
|
||||
let info_cache = JSON.parse(inputStream).profile.info_cache;
|
||||
for (let profileFolderName in info_cache) {
|
||||
let profileFolder = this._chromeUserDataFolder.clone();
|
||||
profileFolder.append(profileFolderName);
|
||||
profiles.push({
|
||||
id: profileFolderName,
|
||||
name: info_cache[profileFolderName].name || profileFolderName,
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError("Error detecting Chrome profiles: " + e);
|
||||
// If we weren't able to detect any profiles above, fallback to the Default profile.
|
||||
let defaultProfileFolder = this._chromeUserDataFolder.clone();
|
||||
defaultProfileFolder.append("Default");
|
||||
if (defaultProfileFolder.exists()) {
|
||||
profiles = [{
|
||||
id: "Default",
|
||||
name: "Default",
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
// Only list profiles from which any data can be imported
|
||||
return this.__sourceProfiles = profiles.filter(function(profile) {
|
||||
let resources = this.getResources(profile);
|
||||
return resources && resources.length > 0;
|
||||
}, this);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(ChromeProfileMigrator.prototype, "sourceHomePageURL", {
|
||||
get: function Chrome_sourceHomePageURL() {
|
||||
let prefsFile = this._chromeUserDataFolder.clone();
|
||||
prefsFile.append("Preferences");
|
||||
if (prefsFile.exists()) {
|
||||
// XXX reading and parsing JSON is synchronous.
|
||||
let fstream = Cc[FILE_INPUT_STREAM_CID].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
fstream.init(file, -1, 0, 0);
|
||||
try {
|
||||
return JSON.parse(
|
||||
NetUtil.readInputStreamToString(fstream, fstream.available(),
|
||||
{ charset: "UTF-8" })
|
||||
).homepage;
|
||||
}
|
||||
catch(e) {
|
||||
Cu.reportError("Error parsing Chrome's preferences file: " + e);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
});
|
||||
|
||||
function GetBookmarksResource(aProfileFolder) {
|
||||
let bookmarksFile = aProfileFolder.clone();
|
||||
bookmarksFile.append("Bookmarks");
|
||||
if (!bookmarksFile.exists())
|
||||
return null;
|
||||
|
||||
return {
|
||||
type: MigrationUtils.resourceTypes.BOOKMARKS,
|
||||
|
||||
migrate: function(aCallback) {
|
||||
NetUtil.asyncFetch(bookmarksFile, MigrationUtils.wrapMigrateFunction(
|
||||
function(aInputStream, aResultCode) {
|
||||
if (!Components.isSuccessCode(aResultCode))
|
||||
throw new Error("Could not read Bookmarks file");
|
||||
|
||||
// Parse Chrome bookmark file that is JSON format
|
||||
let bookmarkJSON = NetUtil.readInputStreamToString(
|
||||
aInputStream, aInputStream.available(), { charset : "UTF-8" });
|
||||
let roots = JSON.parse(bookmarkJSON).roots;
|
||||
PlacesUtils.bookmarks.runInBatchMode({
|
||||
runBatched: function() {
|
||||
// Importing bookmark bar items
|
||||
if (roots.bookmark_bar.children &&
|
||||
roots.bookmark_bar.children.length > 0) {
|
||||
// Toolbar
|
||||
let parentId = PlacesUtils.toolbarFolderId;
|
||||
if (!MigrationUtils.isStartupMigration) {
|
||||
parentId = MigrationUtils.createImportedBookmarksFolder(
|
||||
"Chrome", parentId);
|
||||
}
|
||||
insertBookmarkItems(parentId, roots.bookmark_bar.children);
|
||||
}
|
||||
|
||||
// Importing bookmark menu items
|
||||
if (roots.other.children &&
|
||||
roots.other.children.length > 0) {
|
||||
// Bookmark menu
|
||||
let parentId = PlacesUtils.bookmarksMenuFolderId;
|
||||
if (!MigrationUtils.isStartupMigration) {
|
||||
parentId = MigrationUtils.createImportedBookmarksFolder(
|
||||
"Chrome", parentId);
|
||||
}
|
||||
insertBookmarkItems(parentId, roots.other.children);
|
||||
}
|
||||
}
|
||||
}, null);
|
||||
}, aCallback));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function GetHistoryResource(aProfileFolder) {
|
||||
let historyFile = aProfileFolder.clone();
|
||||
historyFile.append("History");
|
||||
if (!historyFile.exists())
|
||||
return null;
|
||||
|
||||
return {
|
||||
type: MigrationUtils.resourceTypes.HISTORY,
|
||||
|
||||
migrate: function(aCallback) {
|
||||
let dbConn = Services.storage.openUnsharedDatabase(historyFile);
|
||||
let stmt = dbConn.createAsyncStatement(
|
||||
"SELECT url, title, last_visit_time, typed_count FROM urls WHERE hidden = 0");
|
||||
|
||||
stmt.executeAsync({
|
||||
handleResult : function(aResults) {
|
||||
let places = [];
|
||||
for (let row = aResults.getNextRow(); row; row = aResults.getNextRow()) {
|
||||
try {
|
||||
// if having typed_count, we changes transition type to typed.
|
||||
let transType = PlacesUtils.history.TRANSITION_LINK;
|
||||
if (row.getResultByName("typed_count") > 0)
|
||||
transType = PlacesUtils.history.TRANSITION_TYPED;
|
||||
|
||||
places.push({
|
||||
uri: NetUtil.newURI(row.getResultByName("url")),
|
||||
title: row.getResultByName("title"),
|
||||
visits: [{
|
||||
transitionType: transType,
|
||||
visitDate: chromeTimeToDate(
|
||||
row.getResultByName(
|
||||
"last_visit_time")) * 1000,
|
||||
}],
|
||||
});
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
PlacesUtils.asyncHistory.updatePlaces(places);
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
},
|
||||
|
||||
handleError : function(aError) {
|
||||
Cu.reportError("Async statement execution returned with '" +
|
||||
aError.result + "', '" + aError.message + "'");
|
||||
},
|
||||
|
||||
handleCompletion : function(aReason) {
|
||||
dbConn.asyncClose();
|
||||
aCallback(aReason == Ci.mozIStorageStatementCallback.REASON_FINISHED);
|
||||
}
|
||||
});
|
||||
stmt.finalize();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function GetCookiesResource(aProfileFolder) {
|
||||
let cookiesFile = aProfileFolder.clone();
|
||||
cookiesFile.append("Cookies");
|
||||
if (!cookiesFile.exists())
|
||||
return null;
|
||||
|
||||
return {
|
||||
type: MigrationUtils.resourceTypes.COOKIES,
|
||||
|
||||
migrate: function(aCallback) {
|
||||
let dbConn = Services.storage.openUnsharedDatabase(cookiesFile);
|
||||
let stmt = dbConn.createAsyncStatement(
|
||||
"SELECT host_key, path, name, value, secure, httponly, expires_utc FROM cookies");
|
||||
|
||||
stmt.executeAsync({
|
||||
handleResult : function(aResults) {
|
||||
for (let row = aResults.getNextRow(); row; row = aResults.getNextRow()) {
|
||||
let host_key = row.getResultByName("host_key");
|
||||
if (host_key.match(/^\./)) {
|
||||
// 1st character of host_key may be ".", so we have to remove it
|
||||
host_key = host_key.substr(1);
|
||||
}
|
||||
|
||||
try {
|
||||
let expiresUtc =
|
||||
chromeTimeToDate(row.getResultByName("expires_utc")) / 1000;
|
||||
Services.cookies.add(host_key,
|
||||
row.getResultByName("path"),
|
||||
row.getResultByName("name"),
|
||||
row.getResultByName("value"),
|
||||
row.getResultByName("secure"),
|
||||
row.getResultByName("httponly"),
|
||||
false,
|
||||
parseInt(expiresUtc));
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
handleError : function(aError) {
|
||||
Cu.reportError("Async statement execution returned with '" +
|
||||
aError.result + "', '" + aError.message + "'");
|
||||
},
|
||||
|
||||
handleCompletion : function(aReason) {
|
||||
dbConn.asyncClose();
|
||||
aCallback(aReason == Ci.mozIStorageStatementCallback.REASON_FINISHED);
|
||||
},
|
||||
});
|
||||
stmt.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function GetWindowsPasswordsResource(aProfileFolder) {
|
||||
let loginFile = aProfileFolder.clone();
|
||||
loginFile.append("Login Data");
|
||||
if (!loginFile.exists())
|
||||
return null;
|
||||
|
||||
return {
|
||||
type: MigrationUtils.resourceTypes.PASSWORDS,
|
||||
|
||||
migrate(aCallback) {
|
||||
let dbConn = Services.storage.openUnsharedDatabase(loginFile);
|
||||
let stmt = dbConn.createAsyncStatement(`
|
||||
SELECT origin_url, action_url, username_element, username_value,
|
||||
password_element, password_value, signon_realm, scheme, date_created,
|
||||
times_used FROM logins WHERE blacklisted_by_user = 0`);
|
||||
let crypto = new OSCrypto();
|
||||
let utf8Converter = Cc["@mozilla.org/intl/utf8converterservice;1"].getService(Ci.nsIUTF8ConverterService);
|
||||
|
||||
stmt.executeAsync({
|
||||
_rowToLoginInfo(row) {
|
||||
let loginInfo = {
|
||||
username: utf8Converter.convertURISpecToUTF8(row.getResultByName("username_value"), "UTF-8"),
|
||||
password: utf8Converter.convertURISpecToUTF8(
|
||||
crypto.decryptData(crypto.arrayToString(row.getResultByName("password_value")), null),
|
||||
"UTF-8"),
|
||||
hostName: NetUtil.newURI(row.getResultByName("origin_url")).prePath,
|
||||
submitURL: null,
|
||||
httpRealm: null,
|
||||
usernameElement: row.getResultByName("username_element"),
|
||||
passwordElement: row.getResultByName("password_element"),
|
||||
timeCreated: chromeTimeToDate(row.getResultByName("date_created") + 0).getTime(),
|
||||
timesUsed: row.getResultByName("times_used") + 0,
|
||||
};
|
||||
|
||||
switch (row.getResultByName("scheme")) {
|
||||
case AUTH_TYPE.SCHEME_HTML:
|
||||
loginInfo.submitURL = NetUtil.newURI(row.getResultByName("action_url")).prePath;
|
||||
break;
|
||||
case AUTH_TYPE.SCHEME_BASIC:
|
||||
case AUTH_TYPE.SCHEME_DIGEST:
|
||||
// signon_realm format is URIrealm, so we need remove URI
|
||||
loginInfo.httpRealm = row.getResultByName("signon_realm")
|
||||
.substring(loginInfo.hostName.length + 1);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Login data scheme type not supported: " +
|
||||
row.getResultByName("scheme"));
|
||||
}
|
||||
|
||||
return loginInfo;
|
||||
},
|
||||
|
||||
handleResult(aResults) {
|
||||
for (let row = aResults.getNextRow(); row; row = aResults.getNextRow()) {
|
||||
try {
|
||||
let loginInfo = this._rowToLoginInfo(row);
|
||||
let login = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(Ci.nsILoginInfo);
|
||||
|
||||
login.init(loginInfo.hostName, loginInfo.submitURL, loginInfo.httpRealm,
|
||||
loginInfo.username, loginInfo.password, loginInfo.usernameElement,
|
||||
loginInfo.passwordElement);
|
||||
login.QueryInterface(Ci.nsILoginMetaInfo);
|
||||
login.timeCreated = loginInfo.timeCreated;
|
||||
login.timeLastUsed = loginInfo.timeCreated;
|
||||
login.timePasswordChanged = loginInfo.timeCreated;
|
||||
login.timesUsed = loginInfo.timesUsed;
|
||||
|
||||
// Add the login only if there's not an existing entry
|
||||
let logins = Services.logins.findLogins({}, login.hostname,
|
||||
login.formSubmitURL,
|
||||
login.httpRealm);
|
||||
|
||||
// Bug 1187190: Password changes should be propagated depending on timestamps.
|
||||
if (!logins.some(l => login.matches(l, true))) {
|
||||
Services.logins.addLogin(login);
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
handleError(aError) {
|
||||
Cu.reportError("Async statement execution returned with '" +
|
||||
aError.result + "', '" + aError.message + "'");
|
||||
},
|
||||
|
||||
handleCompletion(aReason) {
|
||||
dbConn.asyncClose();
|
||||
aCallback(aReason == Ci.mozIStorageStatementCallback.REASON_FINISHED);
|
||||
crypto.finalize();
|
||||
},
|
||||
});
|
||||
stmt.finalize();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ChromeProfileMigrator.prototype.classDescription = "Chrome Profile Migrator";
|
||||
ChromeProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=chrome";
|
||||
ChromeProfileMigrator.prototype.classID = Components.ID("{4cec1de4-1671-4fc3-a53e-6c539dc77a26}");
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ChromeProfileMigrator]);
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
/* -*- 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() {
|
||||
return [{id: x, name: x} for (x of this._getAllProfiles().keys())].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"]);
|
||||
|
||||
return [r for each (r in [places, cookies, passwords, formData,
|
||||
dictionary, bookmarksBackups]) if (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]);
|
||||
|
|
@ -1,521 +0,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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
const kMainKey = "Software\\Microsoft\\Internet Explorer\\Main";
|
||||
const kRegMultiSz = 7;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource:///modules/MigrationUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ctypes",
|
||||
"resource://gre/modules/ctypes.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "WindowsRegistry",
|
||||
"resource://gre/modules/WindowsRegistry.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["File"]);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Helpers.
|
||||
|
||||
let CtypesHelpers = {
|
||||
_structs: {},
|
||||
_functions: {},
|
||||
_libs: {},
|
||||
|
||||
/**
|
||||
* Must be invoked once before first use of any of the provided helpers.
|
||||
*/
|
||||
initialize: function CH_initialize() {
|
||||
const WORD = ctypes.uint16_t;
|
||||
const DWORD = ctypes.uint32_t;
|
||||
const BOOL = ctypes.int;
|
||||
|
||||
this._structs.SYSTEMTIME = new ctypes.StructType('SYSTEMTIME', [
|
||||
{wYear: WORD},
|
||||
{wMonth: WORD},
|
||||
{wDayOfWeek: WORD},
|
||||
{wDay: WORD},
|
||||
{wHour: WORD},
|
||||
{wMinute: WORD},
|
||||
{wSecond: WORD},
|
||||
{wMilliseconds: WORD}
|
||||
]);
|
||||
|
||||
this._structs.FILETIME = new ctypes.StructType('FILETIME', [
|
||||
{dwLowDateTime: DWORD},
|
||||
{dwHighDateTime: DWORD}
|
||||
]);
|
||||
|
||||
try {
|
||||
this._libs.kernel32 = ctypes.open("Kernel32");
|
||||
this._functions.FileTimeToSystemTime =
|
||||
this._libs.kernel32.declare("FileTimeToSystemTime",
|
||||
ctypes.default_abi,
|
||||
BOOL,
|
||||
this._structs.FILETIME.ptr,
|
||||
this._structs.SYSTEMTIME.ptr);
|
||||
} catch (ex) {
|
||||
this.finalize();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Must be invoked once after last use of any of the provided helpers.
|
||||
*/
|
||||
finalize: function CH_finalize() {
|
||||
this._structs = {};
|
||||
this._functions = {};
|
||||
for each (let lib in this._libs) {
|
||||
try {
|
||||
lib.close();
|
||||
} catch (ex) {}
|
||||
}
|
||||
this._libs = {};
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts a FILETIME struct (2 DWORDS), to a SYSTEMTIME struct.
|
||||
*
|
||||
* @param aTimeHi
|
||||
* Least significant DWORD.
|
||||
* @param aTimeLo
|
||||
* Most significant DWORD.
|
||||
* @return a Date object representing the converted datetime.
|
||||
*/
|
||||
fileTimeToDate: function CH_fileTimeToDate(aTimeHi, aTimeLo) {
|
||||
let fileTime = this._structs.FILETIME();
|
||||
fileTime.dwLowDateTime = aTimeLo;
|
||||
fileTime.dwHighDateTime = aTimeHi;
|
||||
let systemTime = this._structs.SYSTEMTIME();
|
||||
let result = this._functions.FileTimeToSystemTime(fileTime.address(),
|
||||
systemTime.address());
|
||||
if (result == 0)
|
||||
throw new Error(ctypes.winLastError);
|
||||
|
||||
return new Date(systemTime.wYear,
|
||||
systemTime.wMonth - 1,
|
||||
systemTime.wDay,
|
||||
systemTime.wHour,
|
||||
systemTime.wMinute,
|
||||
systemTime.wSecond,
|
||||
systemTime.wMilliseconds);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether an host is an IP (v4 or v6) address.
|
||||
*
|
||||
* @param aHost
|
||||
* The host to check.
|
||||
* @return whether aHost is an IP address.
|
||||
*/
|
||||
function hostIsIPAddress(aHost) {
|
||||
try {
|
||||
Services.eTLD.getBaseDomainFromHost(aHost);
|
||||
} catch (e if e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS) {
|
||||
return true;
|
||||
} catch (e) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Resources
|
||||
|
||||
function Bookmarks() {
|
||||
}
|
||||
|
||||
Bookmarks.prototype = {
|
||||
type: MigrationUtils.resourceTypes.BOOKMARKS,
|
||||
|
||||
get exists() !!this._favoritesFolder,
|
||||
|
||||
__favoritesFolder: null,
|
||||
get _favoritesFolder() {
|
||||
if (!this.__favoritesFolder) {
|
||||
let favoritesFolder = Services.dirsvc.get("Favs", Ci.nsIFile);
|
||||
if (favoritesFolder.exists() && favoritesFolder.isReadable())
|
||||
this.__favoritesFolder = favoritesFolder;
|
||||
}
|
||||
return this.__favoritesFolder;
|
||||
},
|
||||
|
||||
__toolbarFolderName: null,
|
||||
get _toolbarFolderName() {
|
||||
if (!this.__toolbarFolderName) {
|
||||
// Retrieve the name of IE's favorites subfolder that holds the bookmarks
|
||||
// in the toolbar. This was previously stored in the registry and changed
|
||||
// in IE7 to always be called "Links".
|
||||
let folderName = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
|
||||
"Software\\Microsoft\\Internet Explorer\\Toolbar",
|
||||
"LinksFolderName");
|
||||
this.__toolbarFolderName = folderName || "Links";
|
||||
}
|
||||
return this.__toolbarFolderName;
|
||||
},
|
||||
|
||||
migrate: function B_migrate(aCallback) {
|
||||
PlacesUtils.bookmarks.runInBatchMode({
|
||||
runBatched: (function migrateBatched() {
|
||||
// Import to the bookmarks menu.
|
||||
let destFolderId = PlacesUtils.bookmarksMenuFolderId;
|
||||
if (!MigrationUtils.isStartupMigration) {
|
||||
destFolderId =
|
||||
MigrationUtils.createImportedBookmarksFolder("IE", destFolderId);
|
||||
}
|
||||
|
||||
this._migrateFolder(this._favoritesFolder, destFolderId);
|
||||
|
||||
aCallback(true);
|
||||
}).bind(this)
|
||||
}, null);
|
||||
},
|
||||
|
||||
_migrateFolder: function B__migrateFolder(aSourceFolder, aDestFolderId) {
|
||||
// TODO (bug 741993): the favorites order is stored in the Registry, at
|
||||
// HCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MenuOrder\Favorites
|
||||
// Until we support it, bookmarks are imported in alphabetical order.
|
||||
let entries = aSourceFolder.directoryEntries;
|
||||
while (entries.hasMoreElements()) {
|
||||
let entry = entries.getNext().QueryInterface(Ci.nsIFile);
|
||||
|
||||
// Make sure that entry.path == entry.target to not follow .lnk folder
|
||||
// shortcuts which could lead to infinite cycles.
|
||||
if (entry.isDirectory() && entry.path == entry.target) {
|
||||
let destFolderId;
|
||||
if (entry.leafName == this._toolbarFolderName &&
|
||||
entry.parent.equals(this._favoritesFolder)) {
|
||||
// Import to the bookmarks toolbar.
|
||||
destFolderId = PlacesUtils.toolbarFolderId;
|
||||
if (!MigrationUtils.isStartupMigration) {
|
||||
destFolderId =
|
||||
MigrationUtils.createImportedBookmarksFolder("IE", destFolderId);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Import to a new folder.
|
||||
destFolderId =
|
||||
PlacesUtils.bookmarks.createFolder(aDestFolderId, entry.leafName,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX);
|
||||
}
|
||||
|
||||
if (entry.isReadable()) {
|
||||
// Recursively import the folder.
|
||||
this._migrateFolder(entry, destFolderId);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Strip the .url extension, to both check this is a valid link file,
|
||||
// and get the associated title.
|
||||
let matches = entry.leafName.match(/(.+)\.url$/i);
|
||||
if (matches) {
|
||||
let fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].
|
||||
getService(Ci.nsIFileProtocolHandler);
|
||||
let uri = fileHandler.readURLFile(entry);
|
||||
let title = matches[1];
|
||||
|
||||
PlacesUtils.bookmarks.insertBookmark(aDestFolderId,
|
||||
uri,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
title);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function History() {
|
||||
}
|
||||
|
||||
History.prototype = {
|
||||
type: MigrationUtils.resourceTypes.HISTORY,
|
||||
|
||||
get exists() true,
|
||||
|
||||
__typedURLs: null,
|
||||
get _typedURLs() {
|
||||
if (!this.__typedURLs) {
|
||||
// The list of typed URLs is a sort of annotation stored in the registry.
|
||||
// Currently, IE stores 25 entries and this value is not configurable,
|
||||
// but we just keep reading up to the first non-existing entry to support
|
||||
// possible future bumps of this limit.
|
||||
this.__typedURLs = {};
|
||||
let registry = Cc["@mozilla.org/windows-registry-key;1"].
|
||||
createInstance(Ci.nsIWindowsRegKey);
|
||||
try {
|
||||
registry.open(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
|
||||
"Software\\Microsoft\\Internet Explorer\\TypedURLs",
|
||||
Ci.nsIWindowsRegKey.ACCESS_READ);
|
||||
for (let entry = 1; registry.hasValue("url" + entry); entry++) {
|
||||
let url = registry.readStringValue("url" + entry);
|
||||
this.__typedURLs[url] = true;
|
||||
}
|
||||
} catch (ex) {
|
||||
} finally {
|
||||
registry.close();
|
||||
}
|
||||
}
|
||||
return this.__typedURLs;
|
||||
},
|
||||
|
||||
migrate: function H_migrate(aCallback) {
|
||||
let places = [];
|
||||
let historyEnumerator = Cc["@mozilla.org/profile/migrator/iehistoryenumerator;1"].
|
||||
createInstance(Ci.nsISimpleEnumerator);
|
||||
while (historyEnumerator.hasMoreElements()) {
|
||||
let entry = historyEnumerator.getNext().QueryInterface(Ci.nsIPropertyBag2);
|
||||
let uri = entry.get("uri").QueryInterface(Ci.nsIURI);
|
||||
// MSIE stores some types of URLs in its history that we don't handle,
|
||||
// like HTMLHelp and others. Since we don't properly map handling for
|
||||
// all of them we just avoid importing them.
|
||||
if (["http", "https", "ftp", "file"].indexOf(uri.scheme) == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let title = entry.get("title");
|
||||
// Embed visits have no title and don't need to be imported.
|
||||
if (title.length == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The typed urls are already fixed-up, so we can use them for comparison.
|
||||
let transitionType = this._typedURLs[uri.spec] ?
|
||||
Ci.nsINavHistoryService.TRANSITION_TYPED :
|
||||
Ci.nsINavHistoryService.TRANSITION_LINK;
|
||||
let lastVisitTime = entry.get("time");
|
||||
|
||||
places.push(
|
||||
{ uri: uri,
|
||||
title: title,
|
||||
visits: [{ transitionType: transitionType,
|
||||
visitDate: lastVisitTime }]
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Check whether there is any history to import.
|
||||
if (places.length == 0) {
|
||||
aCallback(true);
|
||||
return;
|
||||
}
|
||||
|
||||
PlacesUtils.asyncHistory.updatePlaces(places, {
|
||||
_success: false,
|
||||
handleResult: function() {
|
||||
// Importing any entry is considered a successful import.
|
||||
this._success = true;
|
||||
},
|
||||
handleError: function() {},
|
||||
handleCompletion: function() {
|
||||
aCallback(this._success);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function Cookies() {
|
||||
}
|
||||
|
||||
Cookies.prototype = {
|
||||
type: MigrationUtils.resourceTypes.COOKIES,
|
||||
|
||||
get exists() !!this._cookiesFolder,
|
||||
|
||||
__cookiesFolder: null,
|
||||
get _cookiesFolder() {
|
||||
// Cookies are stored in txt files, in a Cookies folder whose path varies
|
||||
// across the different OS versions. CookD takes care of most of these
|
||||
// cases, though, in Windows Vista/7, UAC makes a difference.
|
||||
// If UAC is enabled, the most common destination is CookD/Low. Though,
|
||||
// if the user runs the application in administrator mode or disables UAC,
|
||||
// cookies are stored in the original CookD destination. Cause running the
|
||||
// browser in administrator mode is unsafe and discouraged, we just care
|
||||
// about the UAC state.
|
||||
if (!this.__cookiesFolder) {
|
||||
let cookiesFolder = Services.dirsvc.get("CookD", Ci.nsIFile);
|
||||
if (cookiesFolder.exists() && cookiesFolder.isReadable()) {
|
||||
// Check if UAC is enabled.
|
||||
if (Services.appinfo.QueryInterface(Ci.nsIWinAppHelper).userCanElevate) {
|
||||
cookiesFolder.append("Low");
|
||||
}
|
||||
this.__cookiesFolder = cookiesFolder;
|
||||
}
|
||||
}
|
||||
return this.__cookiesFolder;
|
||||
},
|
||||
|
||||
migrate: function C_migrate(aCallback) {
|
||||
CtypesHelpers.initialize();
|
||||
|
||||
let cookiesGenerator = (function genCookie() {
|
||||
let success = false;
|
||||
let entries = this._cookiesFolder.directoryEntries;
|
||||
while (entries.hasMoreElements()) {
|
||||
let entry = entries.getNext().QueryInterface(Ci.nsIFile);
|
||||
// Skip eventual bogus entries.
|
||||
if (!entry.isFile() || !/\.txt$/.test(entry.leafName))
|
||||
continue;
|
||||
|
||||
this._readCookieFile(entry, function(aSuccess) {
|
||||
// Importing even a single cookie file is considered a success.
|
||||
if (aSuccess)
|
||||
success = true;
|
||||
try {
|
||||
cookiesGenerator.next();
|
||||
} catch (ex) {}
|
||||
});
|
||||
|
||||
yield;
|
||||
}
|
||||
|
||||
CtypesHelpers.finalize();
|
||||
|
||||
aCallback(success);
|
||||
}).apply(this);
|
||||
cookiesGenerator.next();
|
||||
},
|
||||
|
||||
_readCookieFile: function C__readCookieFile(aFile, aCallback) {
|
||||
let fileReader = Cc["@mozilla.org/files/filereader;1"].
|
||||
createInstance(Ci.nsIDOMFileReader);
|
||||
fileReader.addEventListener("loadend", (function onLoadEnd() {
|
||||
fileReader.removeEventListener("loadend", onLoadEnd, false);
|
||||
|
||||
if (fileReader.readyState != fileReader.DONE) {
|
||||
Cu.reportError("Could not read cookie contents: " + fileReader.error);
|
||||
aCallback(false);
|
||||
return;
|
||||
}
|
||||
|
||||
let success = true;
|
||||
try {
|
||||
this._parseCookieBuffer(fileReader.result);
|
||||
} catch (ex) {
|
||||
Components.utils.reportError("Unable to migrate cookie: " + ex);
|
||||
success = false;
|
||||
} finally {
|
||||
aCallback(success);
|
||||
}
|
||||
}).bind(this), false);
|
||||
fileReader.readAsText(new File(aFile));
|
||||
},
|
||||
|
||||
/**
|
||||
* Parses a cookie file buffer and returns an array of the contained cookies.
|
||||
*
|
||||
* The cookie file format is a newline-separated-values with a "*" used as
|
||||
* delimeter between multiple records.
|
||||
* Each cookie has the following fields:
|
||||
* - name
|
||||
* - value
|
||||
* - host/path
|
||||
* - flags
|
||||
* - Expiration time most significant integer
|
||||
* - Expiration time least significant integer
|
||||
* - Creation time most significant integer
|
||||
* - Creation time least significant integer
|
||||
* - Record delimiter "*"
|
||||
*
|
||||
* @note All the times are in FILETIME format.
|
||||
*/
|
||||
_parseCookieBuffer: function C__parseCookieBuffer(aTextBuffer) {
|
||||
// Note the last record is an empty string.
|
||||
let records = [r for each (r in aTextBuffer.split("*\n")) if (r)];
|
||||
for (let record of records) {
|
||||
let [name, value, hostpath, flags,
|
||||
expireTimeLo, expireTimeHi] = record.split("\n");
|
||||
|
||||
// IE stores deleted cookies with a zero-length value, skip them.
|
||||
if (value.length == 0)
|
||||
continue;
|
||||
|
||||
let hostLen = hostpath.indexOf("/");
|
||||
let host = hostpath.substr(0, hostLen);
|
||||
let path = hostpath.substr(hostLen);
|
||||
|
||||
// For a non-null domain, assume it's what Mozilla considers
|
||||
// a domain cookie. See bug 222343.
|
||||
if (host.length > 0) {
|
||||
// Fist delete any possible extant matching host cookie.
|
||||
Services.cookies.remove(host, name, path, false);
|
||||
// Now make it a domain cookie.
|
||||
if (host[0] != "." && !hostIsIPAddress(host))
|
||||
host = "." + host;
|
||||
}
|
||||
|
||||
let expireTime = CtypesHelpers.fileTimeToDate(Number(expireTimeHi),
|
||||
Number(expireTimeLo));
|
||||
Services.cookies.add(host,
|
||||
path,
|
||||
name,
|
||||
value,
|
||||
Number(flags) & 0x1, // secure
|
||||
false, // httpOnly
|
||||
false, // session
|
||||
expireTime);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Migrator
|
||||
|
||||
function IEProfileMigrator()
|
||||
{
|
||||
}
|
||||
|
||||
IEProfileMigrator.prototype = Object.create(MigratorPrototype);
|
||||
|
||||
IEProfileMigrator.prototype.getResources = function IE_getResources() {
|
||||
let resources = [
|
||||
new Bookmarks()
|
||||
, new History()
|
||||
, new Cookies()
|
||||
];
|
||||
return [r for each (r in resources) if (r.exists)];
|
||||
};
|
||||
|
||||
Object.defineProperty(IEProfileMigrator.prototype, "sourceHomePageURL", {
|
||||
get: function IE_get_sourceHomePageURL() {
|
||||
let defaultStartPage = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
|
||||
kMainKey, "Default_Page_URL");
|
||||
let startPage = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
|
||||
kMainKey, "Start Page");
|
||||
// If the user didn't customize the Start Page, he is still on the default
|
||||
// page, that may be considered the equivalent of our about:home. There's
|
||||
// no reason to retain it, since it is heavily targeted to IE.
|
||||
let homepage = startPage != defaultStartPage ? startPage : "";
|
||||
|
||||
// IE7+ supports secondary home pages located in a REG_MULTI_SZ key. These
|
||||
// are in addition to the Start Page, and no empty entries are possible,
|
||||
// thus a Start Page is always defined if any of these exists, though it
|
||||
// may be the default one.
|
||||
let secondaryPages = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
|
||||
kMainKey, "Secondary Start Pages");
|
||||
if (secondaryPages) {
|
||||
if (homepage)
|
||||
secondaryPages.unshift(homepage);
|
||||
homepage = secondaryPages.join("|");
|
||||
}
|
||||
|
||||
return homepage;
|
||||
}
|
||||
});
|
||||
|
||||
IEProfileMigrator.prototype.classDescription = "IE Profile Migrator";
|
||||
IEProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=ie";
|
||||
IEProfileMigrator.prototype.classID = Components.ID("{3d2532e3-4932-4774-b7ba-968f5899d3a4}");
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([IEProfileMigrator]);
|
||||
|
|
@ -1,657 +0,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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["MigrationUtils", "MigratorPrototype"];
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
|
||||
const TOPIC_WILL_IMPORT_BOOKMARKS = "initial-migration-will-import-default-bookmarks";
|
||||
const TOPIC_DID_IMPORT_BOOKMARKS = "initial-migration-did-import-default-bookmarks";
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Dict",
|
||||
"resource://gre/modules/Dict.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "BookmarkHTMLUtils",
|
||||
"resource://gre/modules/BookmarkHTMLUtils.jsm");
|
||||
|
||||
let gMigrators = null;
|
||||
let gProfileStartup = null;
|
||||
let gMigrationBundle = null;
|
||||
|
||||
function getMigrationBundle() {
|
||||
if (!gMigrationBundle) {
|
||||
gMigrationBundle = Services.strings.createBundle(
|
||||
"chrome://browser/locale/migration/migration.properties");
|
||||
}
|
||||
return gMigrationBundle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Figure out what is the default browser, and if there is a migrator
|
||||
* for it, return that migrator's internal name.
|
||||
* For the time being, the "internal name" of a migraotr is its contract-id
|
||||
* trailer (e.g. ie for @mozilla.org/profile/migrator;1?app=browser&type=ie),
|
||||
* but it will soon be exposed properly.
|
||||
*/
|
||||
function getMigratorKeyForDefaultBrowser() {
|
||||
const APP_DESC_TO_KEY = {
|
||||
"Internet Explorer": "ie",
|
||||
"Safari": "safari",
|
||||
"Pale Moon web browser": "firefox",
|
||||
"Google Chrome": "chrome", // Windows, Linux
|
||||
"Chrome": "chrome", // OS X
|
||||
};
|
||||
|
||||
let browserDesc = "";
|
||||
try {
|
||||
let browserDesc =
|
||||
Cc["@mozilla.org/uriloader/external-protocol-service;1"].
|
||||
getService(Ci.nsIExternalProtocolService).
|
||||
getApplicationDescription("http");
|
||||
return APP_DESC_TO_KEY[browserDesc] || "";
|
||||
}
|
||||
catch(ex) {
|
||||
Cu.reportError("Could not detect default browser: " + ex);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared prototype for migrators, implementing nsIBrowserProfileMigrator.
|
||||
*
|
||||
* To implement a migrator:
|
||||
* 1. Import this module.
|
||||
* 2. Create the prototype for the migrator, extending MigratorPrototype.
|
||||
* Namely: MosaicMigrator.prototype = Object.create(MigratorPrototype);
|
||||
* 3. Set classDescription, contractID and classID for your migrator, and set
|
||||
* NSGetFactory appropriately.
|
||||
* 4. If the migrator supports multiple profiles, override the sourceProfiles
|
||||
* Here we default for single-profile migrator.
|
||||
* 5. Implement getResources(aProfile) (see below).
|
||||
* 6. If the migrator supports reading the home page of the source browser,
|
||||
* override |sourceHomePageURL| getter.
|
||||
* 7. For startup-only migrators, override |startupOnlyMigrator|.
|
||||
*/
|
||||
this.MigratorPrototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserProfileMigrator]),
|
||||
|
||||
/**
|
||||
* OVERRIDE IF AND ONLY IF the source supports multiple profiles.
|
||||
*
|
||||
* Returns array of profile objects from which data may be imported. The object
|
||||
* should have the following keys:
|
||||
* id - a unique string identifier for the profile
|
||||
* name - a pretty name to display to the user in the UI
|
||||
*
|
||||
* Only profiles from which data can be imported should be listed. Otherwise
|
||||
* the behavior of the migration wizard isn't well-defined.
|
||||
*
|
||||
* For a single-profile source (e.g. safari, ie), this returns null,
|
||||
* and not an empty array. That is the default implementation.
|
||||
*/
|
||||
get sourceProfiles() null,
|
||||
|
||||
/**
|
||||
* MUST BE OVERRIDDEN.
|
||||
*
|
||||
* Returns an array of "migration resources" objects for the given profile,
|
||||
* or for the "default" profile, if the migrator does not support multiple
|
||||
* profiles.
|
||||
*
|
||||
* Each migration resource should provide:
|
||||
* - a |type| getter, retunring any of the migration types (see
|
||||
* nsIBrowserProfileMigrator).
|
||||
*
|
||||
* - a |migrate| method, taking a single argument, aCallback(bool success),
|
||||
* for migrating the data for this resource. It may do its job
|
||||
* synchronously or asynchronously. Either way, it must call
|
||||
* aCallback(bool aSuccess) when it's done. In the case of an exception
|
||||
* thrown from |migrate|, it's taken as if aCallback(false) is called.
|
||||
*
|
||||
* Note: In the case of a simple asynchronous implementation, you may find
|
||||
* MigrationUtils.wrapMigrateFunction handy for handling aCallback easily.
|
||||
*
|
||||
* For each migration type listed in nsIBrowserProfileMigrator, multiple
|
||||
* migration resources may be provided. This practice is useful when the
|
||||
* data for a certain migration type is independently stored in few
|
||||
* locations. For example, the mac version of Safari stores its "reading list"
|
||||
* bookmarks in a separate property list.
|
||||
*
|
||||
* Note that the importation of a particular migration type is reported as
|
||||
* successful if _any_ of its resources succeeded to import (that is, called,
|
||||
* |aCallback(true)|). However, completion-status for a particular migration
|
||||
* type is reported to the UI only once all of its migrators have called
|
||||
* aCallback.
|
||||
*
|
||||
* @note The returned array should only include resources from which data
|
||||
* can be imported. So, for example, before adding a resource for the
|
||||
* BOOKMARKS migration type, you should check if you should check that the
|
||||
* bookmarks file exists.
|
||||
*
|
||||
* @param aProfile
|
||||
* The profile from which data may be imported, or an empty string
|
||||
* in the case of a single-profile migrator.
|
||||
* In the case of multiple-profiles migrator, it is guaranteed that
|
||||
* aProfile is a value returned by the sourceProfiles getter (see
|
||||
* above).
|
||||
*/
|
||||
getResources: function MP_getResources(aProfile) {
|
||||
throw new Error("getResources must be overridden");
|
||||
},
|
||||
|
||||
/**
|
||||
* OVERRIDE IF AND ONLY IF the migrator is a startup-only migrator (For now,
|
||||
* that is just the Firefox migrator, see bug 737381). Default: false.
|
||||
*
|
||||
* Startup-only migrators are different in two ways:
|
||||
* - they may only be used during startup.
|
||||
* - the user-profile is half baked during migration. The folder exists,
|
||||
* but it's only accessible through MigrationUtils.profileStartup.
|
||||
* The migrator can call MigrationUtils.profileStartup.doStartup
|
||||
* at any point in order to initialize the profile.
|
||||
*/
|
||||
get startupOnlyMigrator() false,
|
||||
|
||||
/**
|
||||
* OVERRIDE IF AND ONLY IF your migrator supports importing the homepage.
|
||||
* @see nsIBrowserProfileMigrator
|
||||
*/
|
||||
get sourceHomePageURL() "",
|
||||
|
||||
/**
|
||||
* DO NOT OVERRIDE - After deCOMing migration, the UI will just call
|
||||
* getResources.
|
||||
*
|
||||
* @see nsIBrowserProfileMigrator
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
return types.reduce(function(a, b) a |= b, 0);
|
||||
},
|
||||
|
||||
/**
|
||||
* DO NOT OVERRIDE - After deCOMing migration, the UI will just call
|
||||
* migrate for each resource.
|
||||
*
|
||||
* @see nsIBrowserProfileMigrator
|
||||
*/
|
||||
migrate: function MP_migrate(aItems, aStartup, aProfile) {
|
||||
let resources = this._getMaybeCachedResources(aProfile);
|
||||
if (resources.length == 0)
|
||||
throw new Error("migrate called for a non-existent source");
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Called either directly or through the bookmarks import callback.
|
||||
function doMigrate() {
|
||||
// TODO: use Map (for the items) and Set (for the resources)
|
||||
// once they are iterable.
|
||||
let resourcesGroupedByItems = new Dict();
|
||||
resources.forEach(function(resource) {
|
||||
if (resourcesGroupedByItems.has(resource.type))
|
||||
resourcesGroupedByItems.get(resource.type).push(resource);
|
||||
else
|
||||
resourcesGroupedByItems.set(resource.type, [resource]);
|
||||
});
|
||||
|
||||
if (resourcesGroupedByItems.count == 0)
|
||||
throw new Error("No items to import");
|
||||
|
||||
let notify = function(aMsg, aItemType) {
|
||||
Services.obs.notifyObservers(null, aMsg, aItemType);
|
||||
}
|
||||
|
||||
notify("Migration:Started");
|
||||
resourcesGroupedByItems.listkeys().forEach(function(migrationType) {
|
||||
let migrationTypeA = migrationType;
|
||||
let itemResources = resourcesGroupedByItems.get(migrationType);
|
||||
notify("Migration:ItemBeforeMigrate", migrationType);
|
||||
|
||||
let itemSuccess = false;
|
||||
itemResources.forEach(function(resource) {
|
||||
let resourceDone = function(aSuccess) {
|
||||
let resourceIndex = itemResources.indexOf(resource);
|
||||
if (resourceIndex != -1) {
|
||||
itemResources.splice(resourceIndex, 1);
|
||||
itemSuccess |= aSuccess;
|
||||
if (itemResources.length == 0) {
|
||||
resourcesGroupedByItems.del(migrationType);
|
||||
notify(itemSuccess ?
|
||||
"Migration:ItemAfterMigrate" : "Migration:ItemError",
|
||||
migrationType);
|
||||
if (resourcesGroupedByItems.count == 0)
|
||||
notify("Migration:Ended");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Services.tm.mainThread.dispatch(function() {
|
||||
// If migrate throws, an error occurred, and the callback
|
||||
// (itemMayBeDone) might haven't been called.
|
||||
try {
|
||||
resource.migrate(resourceDone);
|
||||
}
|
||||
catch(ex) {
|
||||
Cu.reportError(ex);
|
||||
resourceDone(false);
|
||||
}
|
||||
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (MigrationUtils.isStartupMigration && !this.startupOnlyMigrator) {
|
||||
MigrationUtils.profileStartup.doStartup();
|
||||
|
||||
// If we're about to migrate bookmarks, first import the default bookmarks.
|
||||
// Note We do not need to do so for the Firefox migrator
|
||||
// (=startupOnlyMigrator), as it just copies over the places database
|
||||
// from another profile.
|
||||
const BOOKMARKS = MigrationUtils.resourceTypes.BOOKMARKS;
|
||||
let migratingBookmarks = resources.some(function(r) r.type == BOOKMARKS);
|
||||
if (migratingBookmarks) {
|
||||
let browserGlue = Cc["@mozilla.org/browser/browserglue;1"].
|
||||
getService(Ci.nsIObserver);
|
||||
browserGlue.observe(null, TOPIC_WILL_IMPORT_BOOKMARKS, "");
|
||||
|
||||
// Note doMigrate doesn't care about the success of the import.
|
||||
let onImportComplete = function() {
|
||||
browserGlue.observe(null, TOPIC_DID_IMPORT_BOOKMARKS, "");
|
||||
doMigrate();
|
||||
};
|
||||
BookmarkHTMLUtils.importFromURL(
|
||||
"resource:///defaults/profile/bookmarks.html", true).then(
|
||||
onImportComplete, onImportComplete);
|
||||
return;
|
||||
}
|
||||
}
|
||||
doMigrate();
|
||||
},
|
||||
|
||||
/**
|
||||
* DO NOT OVERRIDE - After deCOMing migration, this code
|
||||
* won't be part of the migrator itself.
|
||||
*
|
||||
* @see nsIBrowserProfileMigrator
|
||||
*/
|
||||
get sourceExists() {
|
||||
if (this.startupOnlyMigrator && !MigrationUtils.isStartupMigration)
|
||||
return false;
|
||||
|
||||
// For a single-profile source, check if any data is available.
|
||||
// For multiple-profiles source, make sure that at least one
|
||||
// profile is available.
|
||||
let exists = false;
|
||||
try {
|
||||
let profiles = this.sourceProfiles;
|
||||
if (!profiles) {
|
||||
let resources = this._getMaybeCachedResources("");
|
||||
if (resources && resources.length > 0)
|
||||
exists = true;
|
||||
}
|
||||
else {
|
||||
exists = profiles.length > 0;
|
||||
}
|
||||
}
|
||||
catch(ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
return exists;
|
||||
},
|
||||
|
||||
/*** PRIVATE STUFF - DO NOT OVERRIDE ***/
|
||||
_getMaybeCachedResources: function PMB__getMaybeCachedResources(aProfile) {
|
||||
let profileKey = aProfile ? aProfile.id : "";
|
||||
if (this._resourcesByProfile) {
|
||||
if (profileKey in this._resourcesByProfile)
|
||||
return this._resourcesByProfile[profileKey];
|
||||
}
|
||||
else {
|
||||
this._resourcesByProfile = { };
|
||||
}
|
||||
return this._resourcesByProfile[profileKey] = this.getResources(aProfile);
|
||||
}
|
||||
};
|
||||
|
||||
this.MigrationUtils = Object.freeze({
|
||||
resourceTypes: {
|
||||
SETTINGS: Ci.nsIBrowserProfileMigrator.SETTINGS,
|
||||
COOKIES: Ci.nsIBrowserProfileMigrator.COOKIES,
|
||||
HISTORY: Ci.nsIBrowserProfileMigrator.HISTORY,
|
||||
FORMDATA: Ci.nsIBrowserProfileMigrator.FORMDATA,
|
||||
PASSWORDS: Ci.nsIBrowserProfileMigrator.PASSWORDS,
|
||||
BOOKMARKS: Ci.nsIBrowserProfileMigrator.BOOKMARKS,
|
||||
OTHERDATA: Ci.nsIBrowserProfileMigrator.OTHERDATA
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper for implementing simple asynchronous cases of migration resources'
|
||||
* |migrate(aCallback)| (see MigratorPrototype). If your |migrate| method
|
||||
* just waits for some file to be read, for example, and then migrates
|
||||
* everything right away, you can wrap the async-function with this helper
|
||||
* and not worry about notifying the callback.
|
||||
*
|
||||
* For example, instead of writing:
|
||||
* setTimeout(function() {
|
||||
* try {
|
||||
* ....
|
||||
* aCallback(true);
|
||||
* }
|
||||
* catch() {
|
||||
* aCallback(false);
|
||||
* }
|
||||
* }, 0);
|
||||
*
|
||||
* You may write:
|
||||
* setTimeout(MigrationUtils.wrapMigrateFunction(function() {
|
||||
* if (importingFromMosaic)
|
||||
* throw Cr.NS_ERROR_UNEXPECTED;
|
||||
* }, aCallback), 0);
|
||||
*
|
||||
* ... and aCallback will be called with aSuccess=false when importing
|
||||
* from Mosaic, or with aSuccess=true otherwise.
|
||||
*
|
||||
* @param aFunction
|
||||
* the function that will be called sometime later. If aFunction
|
||||
* throws when it's called, aCallback(false) is called, otherwise
|
||||
* aCallback(true) is called.
|
||||
* @param aCallback
|
||||
* the callback function passed to |migrate|.
|
||||
* @return the wrapped function.
|
||||
*/
|
||||
wrapMigrateFunction: function MU_wrapMigrateFunction(aFunction, aCallback) {
|
||||
return function() {
|
||||
let success = false;
|
||||
try {
|
||||
aFunction.apply(null, arguments);
|
||||
success = true;
|
||||
}
|
||||
catch(ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
// Do not change this to call aCallback directly in try try & catch
|
||||
// blocks, because if aCallback throws, we may end up calling aCallback
|
||||
// twice.
|
||||
aCallback(success);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a string from the migration bundle. Shorthand for
|
||||
* nsIStringBundle.GetStringFromName, if aReplacements isn't passed, or for
|
||||
* nsIStringBundle.formatStringFromName if it is.
|
||||
*
|
||||
* This method also takes care of "bumped" keys (See bug 737381 comment 8 for
|
||||
* details).
|
||||
*
|
||||
* @param aKey
|
||||
* The key of the string to retrieve.
|
||||
* @param aReplacemts
|
||||
* [optioanl] Array of replacements to run on the retrieved string.
|
||||
* @return the retrieved string.
|
||||
*
|
||||
* @see nsIStringBundle
|
||||
*/
|
||||
getLocalizedString: function MU_getLocalizedString(aKey, aReplacements) {
|
||||
const OVERRIDES = {
|
||||
"4_firefox": "4_firefox_history_and_bookmarks",
|
||||
"64_firefox": "64_firefox_other"
|
||||
};
|
||||
aKey = OVERRIDES[aKey] || aKey;
|
||||
|
||||
if (aReplacements === undefined)
|
||||
return getMigrationBundle().GetStringFromName(aKey);
|
||||
return getMigrationBundle().formatStringFromName(
|
||||
aKey, aReplacements, aReplacements.length);
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper for creating a folder for imported bookmarks from a particular
|
||||
* migration source. The folder is created at the end of the given folder.
|
||||
*
|
||||
* @param aSourceNameStr
|
||||
* the source name (first letter capitalized). This is used
|
||||
* for reading the localized source name from the migration
|
||||
* bundle (e.g. if aSourceNameStr is Mosaic, this will try to read
|
||||
* sourceNameMosaic from the migration bundle).
|
||||
* @param aParentId
|
||||
* the item-id of the folder in which the new folder should be
|
||||
* created.
|
||||
* @return the item-id of the new folder.
|
||||
*/
|
||||
createImportedBookmarksFolder:
|
||||
function MU_createImportedBookmarksFolder(aSourceNameStr, aParentId) {
|
||||
let source = this.getLocalizedString("sourceName" + aSourceNameStr);
|
||||
let label = this.getLocalizedString("importedBookmarksFolder", [source]);
|
||||
return PlacesUtils.bookmarks.createFolder(
|
||||
aParentId, label, PlacesUtils.bookmarks.DEFAULT_INDEX);
|
||||
},
|
||||
|
||||
get _migrators() gMigrators ? gMigrators : gMigrators = new Dict(),
|
||||
|
||||
/*
|
||||
* Returns the migrator for the given source, if any data is available
|
||||
* for this source, or null otherwise.
|
||||
*
|
||||
* @param aKey internal name of the migration source.
|
||||
* Supported values: ie (windows),
|
||||
* safari (mac/windows),
|
||||
* chrome (mac/windows/linux),
|
||||
* firefox.
|
||||
*
|
||||
* If null is returned, either no data can be imported
|
||||
* for the given migrator, or aMigratorKey is invalid (e.g. ie on mac,
|
||||
* or mosaic everywhere). This method should be used rather than direct
|
||||
* getService for future compatibility (see bug 718280).
|
||||
*
|
||||
* @return profile migrator implementing nsIBrowserProfileMigrator, if it can
|
||||
* import any data, null otherwise.
|
||||
*/
|
||||
getMigrator: function MU_getMigrator(aKey) {
|
||||
let migrator = null;
|
||||
if (this._migrators.has(aKey)) {
|
||||
migrator = this._migrators.get(aKey);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
migrator = Cc["@mozilla.org/profile/migrator;1?app=browser&type=" +
|
||||
aKey].createInstance(Ci.nsIBrowserProfileMigrator);
|
||||
}
|
||||
catch(ex) { }
|
||||
this._migrators.set(aKey, migrator);
|
||||
}
|
||||
|
||||
return migrator && migrator.sourceExists ? migrator : null;
|
||||
},
|
||||
|
||||
// Iterates the available migrators, in the most suitable
|
||||
// order for the running platform.
|
||||
migrators: function* MU_migrators() {
|
||||
let migratorKeysOrdered = [
|
||||
#ifdef XP_WIN
|
||||
"firefox", "ie", "chrome", "safari"
|
||||
#elifdef XP_MACOSX
|
||||
"firefox", "safari", "chrome"
|
||||
#elifdef XP_UNIX
|
||||
"firefox", "chrome"
|
||||
#endif
|
||||
];
|
||||
|
||||
// If a supported default browser is found check it first
|
||||
// so that the wizard defaults to import from that browser.
|
||||
let defaultBrowserKey = getMigratorKeyForDefaultBrowser();
|
||||
if (defaultBrowserKey)
|
||||
migratorKeysOrdered.sort(function (a, b) b == defaultBrowserKey ? 1 : 0);
|
||||
|
||||
for (let migratorKey of migratorKeysOrdered) {
|
||||
let migrator = this.getMigrator(migratorKey);
|
||||
if (migrator)
|
||||
yield migrator;
|
||||
}
|
||||
},
|
||||
|
||||
// Whether or not we're in the process of startup migration
|
||||
get isStartupMigration() gProfileStartup != null,
|
||||
|
||||
/**
|
||||
* In the case of startup migration, this is set to the nsIProfileStartup
|
||||
* instance passed to ProfileMigrator's migrate.
|
||||
*
|
||||
* @see showMigrationWizard
|
||||
*/
|
||||
get profileStartup() gProfileStartup,
|
||||
|
||||
/**
|
||||
* Show the migration wizard. On mac, this may just focus the wizard if it's
|
||||
* already running, in which case aOpener and aParams are ignored.
|
||||
*
|
||||
* @param [optional] aOpener
|
||||
* the window that asks to open the wizard.
|
||||
* @param [optional] aParams
|
||||
* arguments for the migration wizard, in the form of an nsIArray.
|
||||
* This is passed as-is for the params argument of
|
||||
* nsIWindowWatcher.openWindow.
|
||||
*/
|
||||
showMigrationWizard:
|
||||
function MU_showMigrationWizard(aOpener, aParams) {
|
||||
let features = "chrome,dialog,modal,centerscreen,titlebar,resizable=no";
|
||||
#ifdef XP_MACOSX
|
||||
if (!this.isStartupMigration) {
|
||||
let win = Services.wm.getMostRecentWindow("Browser:MigrationWizard");
|
||||
if (win) {
|
||||
win.focus();
|
||||
return;
|
||||
}
|
||||
// On mac, the migration wiazrd should only be modal in the case of
|
||||
// startup-migration.
|
||||
features = "centerscreen,chrome,resizable=no";
|
||||
}
|
||||
#endif
|
||||
|
||||
Services.ww.openWindow(aOpener,
|
||||
"chrome://browser/content/migration/migration.xul",
|
||||
"_blank",
|
||||
features,
|
||||
aParams);
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the migration wizard for startup-migration. This should only be
|
||||
* called by ProfileMigrator (see ProfileMigrator.js), which implements
|
||||
* nsIProfileMigrator.
|
||||
*
|
||||
* @param aProfileStartup
|
||||
* the nsIProfileStartup instance provided to ProfileMigrator.migrate.
|
||||
* @param [optional] aMigratorKey
|
||||
* If set, the migration wizard will import from the corresponding
|
||||
* migrator, bypassing the source-selection page. Otherwise, the
|
||||
* source-selection page will be displayed, either with the default
|
||||
* browser selected, if it could be detected and if there is a
|
||||
* migrator for it, or with the first option selected as a fallback
|
||||
* (The first option is hardcoded to be the most common browser for
|
||||
* the OS we run on. See migration.xul).
|
||||
* @param [optional] aProfileToMigrate
|
||||
* If set, the migration wizard will import from the profile indicated.
|
||||
*
|
||||
* @throws if aMigratorKey is invalid or if it points to a non-existent
|
||||
* source.
|
||||
*/
|
||||
startupMigration:
|
||||
function MU_startupMigrator(aProfileStartup, aMigratorKey, aProfileToMigrate) {
|
||||
if (!aProfileStartup) {
|
||||
throw new Error("a profile-startup instance is required for startup-migration");
|
||||
}
|
||||
gProfileStartup = aProfileStartup;
|
||||
|
||||
let skipSourcePage = false, migrator = null, migratorKey = "";
|
||||
if (aMigratorKey) {
|
||||
migrator = this.getMigrator(aMigratorKey);
|
||||
if (!migrator) {
|
||||
// aMigratorKey must point to a valid source, so, if it doesn't
|
||||
// cleanup and throw.
|
||||
this.finishMigration();
|
||||
throw new Error("startMigration was asked to open auto-migrate from " +
|
||||
"a non-existent source: " + aMigratorKey);
|
||||
}
|
||||
migratorKey = aMigratorKey;
|
||||
skipSourcePage = true;
|
||||
}
|
||||
else {
|
||||
let defaultBrowserKey = getMigratorKeyForDefaultBrowser();
|
||||
if (defaultBrowserKey) {
|
||||
migrator = this.getMigrator(defaultBrowserKey);
|
||||
if (migrator)
|
||||
migratorKey = defaultBrowserKey;
|
||||
}
|
||||
}
|
||||
|
||||
if (!migrator) {
|
||||
// If there's no migrator set so far, ensure that there is at least one
|
||||
// migrator available before opening the wizard.
|
||||
try {
|
||||
this.migrators.next();
|
||||
}
|
||||
catch(ex) {
|
||||
this.finishMigration();
|
||||
if (!(ex instanceof StopIteration))
|
||||
throw ex;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let params = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
||||
let keyCSTR = Cc["@mozilla.org/supports-cstring;1"].
|
||||
createInstance(Ci.nsISupportsCString);
|
||||
keyCSTR.data = migratorKey;
|
||||
let skipImportSourcePageBool = Cc["@mozilla.org/supports-PRBool;1"].
|
||||
createInstance(Ci.nsISupportsPRBool);
|
||||
skipImportSourcePageBool.data = skipSourcePage;
|
||||
let profileToMigrate = null;
|
||||
if (aProfileToMigrate) {
|
||||
profileToMigrate = Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
profileToMigrate.data = aProfileToMigrate;
|
||||
}
|
||||
params.appendElement(keyCSTR, false);
|
||||
params.appendElement(migrator, false);
|
||||
params.appendElement(aProfileStartup, false);
|
||||
params.appendElement(skipImportSourcePageBool, false);
|
||||
params.appendElement(profileToMigrate, false);
|
||||
|
||||
this.showMigrationWizard(null, params);
|
||||
},
|
||||
|
||||
/**
|
||||
* Cleans up references to migrators and nsIProfileInstance instances.
|
||||
*/
|
||||
finishMigration: function MU_finishMigration() {
|
||||
gMigrators = null;
|
||||
gProfileStartup = null;
|
||||
gMigrationBundle = null;
|
||||
}
|
||||
});
|
||||
|
|
@ -1,21 +0,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/. */
|
||||
|
||||
"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]);
|
||||
|
|
@ -1,416 +0,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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource:///modules/MigrationUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PropertyListUtils",
|
||||
"resource://gre/modules/PropertyListUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
|
||||
"resource://gre/modules/FormHistory.jsm");
|
||||
|
||||
function Bookmarks(aBookmarksFile) {
|
||||
this._file = aBookmarksFile;
|
||||
}
|
||||
Bookmarks.prototype = {
|
||||
type: MigrationUtils.resourceTypes.BOOKMARKS,
|
||||
|
||||
migrate: function B_migrate(aCallback) {
|
||||
PropertyListUtils.read(this._file,
|
||||
MigrationUtils.wrapMigrateFunction(function migrateBookmarks(aDict) {
|
||||
if (!aDict)
|
||||
throw new Error("Could not read Bookmarks.plist");
|
||||
|
||||
let children = aDict.get("Children");;
|
||||
if (!children)
|
||||
throw new Error("Invalid Bookmarks.plist format");
|
||||
|
||||
PlacesUtils.bookmarks.runInBatchMode({
|
||||
runBatched: function() {
|
||||
let collection = aDict.get("Title") == "com.apple.ReadingList" ?
|
||||
this.READING_LIST_COLLECTION : this.ROOT_COLLECTION;
|
||||
this._migrateCollection(children, collection);
|
||||
}.bind(this)
|
||||
}, null);
|
||||
}.bind(this), aCallback));
|
||||
},
|
||||
|
||||
// Bookmarks collections in Safari. Constants for migrateCollection.
|
||||
ROOT_COLLECTION: 0,
|
||||
MENU_COLLECTION: 1,
|
||||
TOOLBAR_COLLECTION: 2,
|
||||
READING_LIST_COLLECTION: 3,
|
||||
|
||||
/**
|
||||
* Recursively migrate a Safari collection of bookmarks.
|
||||
*
|
||||
* @param aEntries
|
||||
* the collection's children
|
||||
* @param aCollection
|
||||
* one of the values above.
|
||||
*/
|
||||
_migrateCollection: function B__migrateCollection(aEntries, aCollection) {
|
||||
// A collection of bookmarks in Safari resembles places roots. In the
|
||||
// property list files (Bookmarks.plist, ReadingList.plist) they are
|
||||
// stored as regular bookmarks folders, and thus can only be distinguished
|
||||
// from by their names and places in the hierarchy.
|
||||
|
||||
let entriesFiltered = [];
|
||||
if (aCollection == this.ROOT_COLLECTION) {
|
||||
for (let entry of aEntries) {
|
||||
let type = entry.get("WebBookmarkType");
|
||||
if (type == "WebBookmarkTypeList" && entry.has("Children")) {
|
||||
let title = entry.get("Title");
|
||||
let children = entry.get("Children");
|
||||
if (title == "BookmarksBar")
|
||||
this._migrateCollection(children, this.TOOLBAR_COLLECTION);
|
||||
else if (title == "BookmarksMenu")
|
||||
this._migrateCollection(children, this.MENU_COLLECTION);
|
||||
else if (title == "com.apple.ReadingList")
|
||||
this._migrateCollection(children, this.READING_LIST_COLLECTION);
|
||||
else if (entry.get("ShouldOmitFromUI") !== true)
|
||||
entriesFiltered.push(entry);
|
||||
}
|
||||
else if (type == "WebBookmarkTypeLeaf") {
|
||||
entriesFiltered.push(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
entriesFiltered = aEntries;
|
||||
}
|
||||
|
||||
if (entriesFiltered.length == 0)
|
||||
return;
|
||||
|
||||
let folder = -1;
|
||||
switch (aCollection) {
|
||||
case this.ROOT_COLLECTION: {
|
||||
// In Safari, it is possible (though quite cumbersome) to move
|
||||
// bookmarks to the bookmarks root, which is the parent folder of
|
||||
// all bookmarks "collections". That is somewhat in parallel with
|
||||
// both the places root and the unfiled-bookmarks root.
|
||||
// Because the former is only an implementation detail in our UI,
|
||||
// the unfiled root seems to be the best choice.
|
||||
folder = PlacesUtils.unfiledBookmarksFolderId;
|
||||
break;
|
||||
}
|
||||
case this.MENU_COLLECTION: {
|
||||
folder = PlacesUtils.bookmarksMenuFolderId;
|
||||
if (!MigrationUtils.isStartupMigration) {
|
||||
folder = MigrationUtils.createImportedBookmarksFolder("Safari",
|
||||
folder);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case this.TOOLBAR_COLLECTION: {
|
||||
folder = PlacesUtils.toolbarFolderId;
|
||||
if (!MigrationUtils.isStartupMigration) {
|
||||
folder = MigrationUtils.createImportedBookmarksFolder("Safari",
|
||||
folder);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case this.READING_LIST_COLLECTION: {
|
||||
// Reading list items are imported as regular bookmarks.
|
||||
// They are imported under their own folder, created either under the
|
||||
// bookmarks menu (in the case of startup migration).
|
||||
folder = PlacesUtils.bookmarks.createFolder(
|
||||
PlacesUtils.bookmarksMenuFolderId,
|
||||
MigrationUtils.getLocalizedString("importedSafariReadingList"),
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error("Unexpected value for aCollection!");
|
||||
}
|
||||
|
||||
this._migrateEntries(entriesFiltered, folder);
|
||||
},
|
||||
|
||||
// migrate the given array of safari bookmarks to the given places
|
||||
// folder.
|
||||
_migrateEntries: function B__migrateEntries(aEntries, aFolderId) {
|
||||
for (let entry of aEntries) {
|
||||
let type = entry.get("WebBookmarkType");
|
||||
if (type == "WebBookmarkTypeList" && entry.has("Children")) {
|
||||
let title = entry.get("Title");
|
||||
let folderId = PlacesUtils.bookmarks.createFolder(
|
||||
aFolderId, title, PlacesUtils.bookmarks.DEFAULT_INDEX);
|
||||
|
||||
// Empty folders may not have a children array.
|
||||
if (entry.has("Children"))
|
||||
this._migrateEntries(entry.get("Children"), folderId, false);
|
||||
}
|
||||
else if (type == "WebBookmarkTypeLeaf" && entry.has("URLString")) {
|
||||
let title, uri;
|
||||
if (entry.has("URIDictionary"))
|
||||
title = entry.get("URIDictionary").get("title");
|
||||
|
||||
try {
|
||||
uri = NetUtil.newURI(entry.get("URLString"));
|
||||
}
|
||||
catch(ex) {
|
||||
Cu.reportError("Invalid uri set for Safari bookmark: " + entry.get("URLString"));
|
||||
}
|
||||
if (uri) {
|
||||
PlacesUtils.bookmarks.insertBookmark(aFolderId, uri,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX, title);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function History(aHistoryFile) {
|
||||
this._file = aHistoryFile;
|
||||
}
|
||||
History.prototype = {
|
||||
type: MigrationUtils.resourceTypes.HISTORY,
|
||||
|
||||
// Helper method for converting the visit date property to a PRTime value.
|
||||
// The visit date is stored as a string, so it's not read as a Date
|
||||
// object by PropertyListUtils.
|
||||
_parseCocoaDate: function H___parseCocoaDate(aCocoaDateStr) {
|
||||
let asDouble = parseFloat(aCocoaDateStr);
|
||||
if (!isNaN(asDouble)) {
|
||||
// reference date of NSDate.
|
||||
let date = new Date("1 January 2001, GMT");
|
||||
date.setMilliseconds(asDouble * 1000);
|
||||
return date * 1000;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
|
||||
migrate: function H_migrate(aCallback) {
|
||||
PropertyListUtils.read(this._file, function migrateHistory(aDict) {
|
||||
try {
|
||||
if (!aDict)
|
||||
throw new Error("Could not read history property list");
|
||||
if (!aDict.has("WebHistoryDates"))
|
||||
throw new Error("Unexpected history-property list format");
|
||||
|
||||
// Safari's History file contains only top-level urls. It does not
|
||||
// distinguish between typed urls and linked urls.
|
||||
let transType = PlacesUtils.history.TRANSITION_LINK;
|
||||
|
||||
let places = [];
|
||||
let entries = aDict.get("WebHistoryDates");
|
||||
for (let entry of entries) {
|
||||
if (entry.has("lastVisitedDate")) {
|
||||
let visitDate = this._parseCocoaDate(entry.get("lastVisitedDate"));
|
||||
places.push({ uri: NetUtil.newURI(entry.get("")),
|
||||
title: entry.get("title"),
|
||||
visits: [{ transitionType: transType,
|
||||
visitDate: visitDate }] });
|
||||
}
|
||||
}
|
||||
if (places.length > 0) {
|
||||
PlacesUtils.asyncHistory.updatePlaces(places, {
|
||||
_success: false,
|
||||
handleResult: function() {
|
||||
// Importing any entry is considered a successful import.
|
||||
this._success = true;
|
||||
},
|
||||
handleError: function() {},
|
||||
handleCompletion: function() {
|
||||
aCallback(this._success);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
aCallback(false);
|
||||
}
|
||||
}
|
||||
catch(ex) {
|
||||
Cu.reportError(ex);
|
||||
aCallback(false);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Safari's preferences property list is independently used for three purposes:
|
||||
* (a) importation of preferences
|
||||
* (b) importation of search strings
|
||||
* (c) retrieving the home page.
|
||||
*
|
||||
* So, rather than reading it three times, it's cached and managed here.
|
||||
*/
|
||||
function MainPreferencesPropertyList(aPreferencesFile) {
|
||||
this._file = aPreferencesFile;
|
||||
this._callbacks = [];
|
||||
}
|
||||
MainPreferencesPropertyList.prototype = {
|
||||
/**
|
||||
* @see PropertyListUtils.read
|
||||
*/
|
||||
read: function MPPL_read(aCallback) {
|
||||
if ("_dict" in this) {
|
||||
aCallback(this._dict);
|
||||
return;
|
||||
}
|
||||
|
||||
let alreadyReading = this._callbacks.length > 0;
|
||||
this._callbacks.push(aCallback);
|
||||
if (!alreadyReading) {
|
||||
PropertyListUtils.read(this._file, function readPrefs(aDict) {
|
||||
this._dict = aDict;
|
||||
for (let callback of this._callbacks) {
|
||||
try {
|
||||
callback(aDict);
|
||||
}
|
||||
catch(ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}
|
||||
this._callbacks.splice(0);
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
// Workaround for nsIBrowserProfileMigrator.sourceHomePageURL until
|
||||
// it's replaced with an async method.
|
||||
_readSync: function MPPL__readSync() {
|
||||
if ("_dict" in this)
|
||||
return this._dict;
|
||||
|
||||
let inputStream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
inputStream.init(this._file, -1, -1, 0);
|
||||
let binaryStream = Cc["@mozilla.org/binaryinputstream;1"].
|
||||
createInstance(Ci.nsIBinaryInputStream);
|
||||
binaryStream.setInputStream(inputStream);
|
||||
let bytes = binaryStream.readByteArray(inputStream.available());
|
||||
this._dict = PropertyListUtils._readFromArrayBufferSync(
|
||||
Uint8Array(bytes).buffer);
|
||||
return this._dict;
|
||||
}
|
||||
};
|
||||
|
||||
function SearchStrings(aMainPreferencesPropertyListInstance) {
|
||||
this._mainPreferencesPropertyList = aMainPreferencesPropertyListInstance;
|
||||
}
|
||||
SearchStrings.prototype = {
|
||||
type: MigrationUtils.resourceTypes.OTHERDATA,
|
||||
|
||||
migrate: function SS_migrate(aCallback) {
|
||||
this._mainPreferencesPropertyList.read(MigrationUtils.wrapMigrateFunction(
|
||||
function migrateSearchStrings(aDict) {
|
||||
if (!aDict)
|
||||
throw new Error("Could not get preferences dictionary");
|
||||
|
||||
if (aDict.has("RecentSearchStrings")) {
|
||||
let recentSearchStrings = aDict.get("RecentSearchStrings");
|
||||
if (recentSearchStrings && recentSearchStrings.length > 0) {
|
||||
let changes = [{op: "add",
|
||||
fieldname: "searchbar-history",
|
||||
value: searchString}
|
||||
for (searchString of recentSearchStrings)];
|
||||
FormHistory.update(changes);
|
||||
}
|
||||
}
|
||||
}.bind(this), aCallback));
|
||||
}
|
||||
};
|
||||
|
||||
function SafariProfileMigrator() {
|
||||
}
|
||||
|
||||
SafariProfileMigrator.prototype = Object.create(MigratorPrototype);
|
||||
|
||||
SafariProfileMigrator.prototype.getResources = function SM_getResources() {
|
||||
let profileDir =
|
||||
#ifdef XP_MACOSX
|
||||
FileUtils.getDir("ULibDir", ["Safari"], false);
|
||||
#else
|
||||
FileUtils.getDir("AppData", ["Apple Computer", "Safari"], false);
|
||||
#endif
|
||||
if (!profileDir.exists())
|
||||
return null;
|
||||
|
||||
let resources = [];
|
||||
let pushProfileFileResource = function(aFileName, aConstructor) {
|
||||
let file = profileDir.clone();
|
||||
file.append(aFileName);
|
||||
if (file.exists())
|
||||
resources.push(new aConstructor(file));
|
||||
};
|
||||
|
||||
pushProfileFileResource("History.plist", History);
|
||||
pushProfileFileResource("Bookmarks.plist", Bookmarks);
|
||||
|
||||
// The Reading List feature was introduced at the same time in Windows and
|
||||
// Mac versions of Safari. Not surprisingly, they are stored in the same
|
||||
// format in both versions. Surpsingly, only on Windows there is a
|
||||
// separate property list for it. This isn't #ifdefed out on mac, because
|
||||
// Apple may fix this at some point.
|
||||
pushProfileFileResource("ReadingList.plist", Bookmarks);
|
||||
|
||||
let prefsDir =
|
||||
#ifdef XP_MACOSX
|
||||
FileUtils.getDir("UsrPrfs", [], false);
|
||||
#else
|
||||
FileUtils.getDir("AppData", ["Apple Computer", "Preferences"], false);
|
||||
#endif
|
||||
|
||||
let prefs = this.mainPreferencesPropertyList;
|
||||
if (prefs) {
|
||||
resources.push(new SearchStrings(prefs));
|
||||
}
|
||||
|
||||
return resources;
|
||||
};
|
||||
|
||||
Object.defineProperty(SafariProfileMigrator.prototype, "mainPreferencesPropertyList", {
|
||||
get: function get_mainPreferencesPropertyList() {
|
||||
if (this._mainPreferencesPropertyList === undefined) {
|
||||
let file =
|
||||
#ifdef XP_MACOSX
|
||||
FileUtils.getDir("UsrPrfs", [], false);
|
||||
#else
|
||||
FileUtils.getDir("AppData", ["Apple Computer", "Preferences"], false);
|
||||
#endif
|
||||
if (file.exists()) {
|
||||
file.append("com.apple.Safari.plist");
|
||||
if (file.exists()) {
|
||||
return this._mainPreferencesPropertyList =
|
||||
new MainPreferencesPropertyList(file);
|
||||
}
|
||||
}
|
||||
return this._mainPreferencesPropertyList = null;
|
||||
}
|
||||
return this._mainPreferencesPropertyList;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(SafariProfileMigrator.prototype, "sourceHomePageURL", {
|
||||
get: function get_sourceHomePageURL() {
|
||||
if (this.mainPreferencesPropertyList) {
|
||||
let dict = this.mainPreferencesPropertyList._readSync();
|
||||
if (dict.has("HomePage"))
|
||||
return dict.get("HomePage");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
});
|
||||
|
||||
SafariProfileMigrator.prototype.classDescription = "Safari Profile Migrator";
|
||||
SafariProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=safari";
|
||||
SafariProfileMigrator.prototype.classID = Components.ID("{4b609ecf-60b2-4655-9df4-dc149e474da1}");
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SafariProfileMigrator]);
|
||||
|
|
@ -1,474 +0,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/. */
|
||||
|
||||
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 "ie":
|
||||
source = "sourceNameIE";
|
||||
break;
|
||||
case "safari":
|
||||
source = "sourceNameSafari";
|
||||
break;
|
||||
case "chrome":
|
||||
source = "sourceNameChrome";
|
||||
break;
|
||||
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");
|
||||
}
|
||||
};
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
<?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;"/>
|
||||
#ifdef XP_WIN
|
||||
<radio id="ie" label="&importFromIE.label;" accesskey="&importFromIE.accesskey;"/>
|
||||
<radio id="chrome" label="&importFromChrome.label;" accesskey="&importFromChrome.accesskey;"/>
|
||||
<radio id="safari" label="&importFromSafari.label;" accesskey="&importFromSafari.accesskey;"/>
|
||||
#elifdef XP_MACOSX
|
||||
<radio id="safari" label="&importFromSafari.label;" accesskey="&importFromSafari.accesskey;"/>
|
||||
<radio id="chrome" label="&importFromChrome.label;" accesskey="&importFromChrome.accesskey;"/>
|
||||
#elifdef XP_UNIX
|
||||
<radio id="chrome" label="&importFromChrome.label;" accesskey="&importFromChrome.accesskey;"/>
|
||||
#endif
|
||||
<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>
|
||||
|
||||
|
|
@ -1,7 +0,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/.
|
||||
|
||||
browser.jar:
|
||||
* content/browser/migration/migration.xul (content/migration.xul)
|
||||
content/browser/migration/migration.js (content/migration.js)
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
# -*- 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'
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
SOURCES += [
|
||||
'nsIEHistoryEnumerator.cpp',
|
||||
]
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'FirefoxProfileMigrator.js',
|
||||
'ProfileMigrator.js',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
EXTRA_COMPONENTS += [
|
||||
'IEProfileMigrator.js',
|
||||
]
|
||||
DEFINES['HAS_IE_MIGRATOR'] = True
|
||||
|
||||
EXTRA_PP_COMPONENTS += [
|
||||
'BrowserProfileMigrators.manifest',
|
||||
'ChromeProfileMigrator.js',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
EXTRA_PP_COMPONENTS += [
|
||||
'SafariProfileMigrator.js',
|
||||
]
|
||||
DEFINES['HAS_SAFARI_MIGRATOR'] = True
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
EXTRA_PP_COMPONENTS += [
|
||||
'SafariProfileMigrator.js',
|
||||
]
|
||||
DEFINES['HAS_SAFARI_MIGRATOR'] = True
|
||||
|
||||
EXTRA_PP_JS_MODULES += [
|
||||
'MigrationUtils.jsm',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'browsercomps'
|
||||
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
/* -*- 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;
|
||||
};
|
||||
|
|
@ -1,119 +0,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/. */
|
||||
|
||||
#include "nsIEHistoryEnumerator.h"
|
||||
|
||||
#include <urlhist.h>
|
||||
#include <shlguid.h>
|
||||
|
||||
#include "nsArrayEnumerator.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsIVariant.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsStringAPI.h"
|
||||
#include "nsWindowsMigrationUtils.h"
|
||||
#include "prtime.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// nsIEHistoryEnumerator
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsIEHistoryEnumerator, nsISimpleEnumerator)
|
||||
|
||||
nsIEHistoryEnumerator::nsIEHistoryEnumerator()
|
||||
{
|
||||
::CoInitialize(nullptr);
|
||||
}
|
||||
|
||||
nsIEHistoryEnumerator::~nsIEHistoryEnumerator()
|
||||
{
|
||||
::CoUninitialize();
|
||||
}
|
||||
|
||||
void
|
||||
nsIEHistoryEnumerator::EnsureInitialized()
|
||||
{
|
||||
if (mURLEnumerator)
|
||||
return;
|
||||
|
||||
HRESULT hr = ::CoCreateInstance(CLSID_CUrlHistory,
|
||||
nullptr,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
IID_IUrlHistoryStg2,
|
||||
getter_AddRefs(mIEHistory));
|
||||
if (FAILED(hr))
|
||||
return;
|
||||
|
||||
hr = mIEHistory->EnumUrls(getter_AddRefs(mURLEnumerator));
|
||||
if (FAILED(hr))
|
||||
return;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIEHistoryEnumerator::HasMoreElements(bool* _retval)
|
||||
{
|
||||
*_retval = false;
|
||||
|
||||
EnsureInitialized();
|
||||
MOZ_ASSERT(mURLEnumerator, "Should have instanced an IE History URLEnumerator");
|
||||
if (!mURLEnumerator)
|
||||
return NS_OK;
|
||||
|
||||
STATURL statURL;
|
||||
ULONG fetched;
|
||||
|
||||
// First argument is not implemented, so doesn't matter what we pass.
|
||||
HRESULT hr = mURLEnumerator->Next(1, &statURL, &fetched);
|
||||
if (FAILED(hr) || fetched != 1UL) {
|
||||
// Reached the last entry.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
if (statURL.pwcsUrl) {
|
||||
nsDependentString url(statURL.pwcsUrl);
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
|
||||
::CoTaskMemFree(statURL.pwcsUrl);
|
||||
if (NS_FAILED(rv)) {
|
||||
// Got a corrupt or invalid URI, continue to the next entry.
|
||||
return HasMoreElements(_retval);
|
||||
}
|
||||
}
|
||||
|
||||
nsDependentString title(statURL.pwcsTitle ? statURL.pwcsTitle : L"");
|
||||
|
||||
bool lastVisitTimeIsValid;
|
||||
PRTime lastVisited = WinMigrationFileTimeToPRTime(&(statURL.ftLastVisited), &lastVisitTimeIsValid);
|
||||
|
||||
mCachedNextEntry = do_CreateInstance("@mozilla.org/hash-property-bag;1");
|
||||
MOZ_ASSERT(mCachedNextEntry, "Should have instanced a new property bag");
|
||||
if (mCachedNextEntry) {
|
||||
mCachedNextEntry->SetPropertyAsInterface(NS_LITERAL_STRING("uri"), uri);
|
||||
mCachedNextEntry->SetPropertyAsAString(NS_LITERAL_STRING("title"), title);
|
||||
if (lastVisitTimeIsValid) {
|
||||
mCachedNextEntry->SetPropertyAsInt64(NS_LITERAL_STRING("time"), lastVisited);
|
||||
}
|
||||
|
||||
*_retval = true;
|
||||
}
|
||||
|
||||
if (statURL.pwcsTitle)
|
||||
::CoTaskMemFree(statURL.pwcsTitle);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIEHistoryEnumerator::GetNext(nsISupports** _retval)
|
||||
{
|
||||
*_retval = nullptr;
|
||||
|
||||
if (!mCachedNextEntry)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
NS_ADDREF(*_retval = mCachedNextEntry);
|
||||
// Release the cached entry, so it can't be returned twice.
|
||||
mCachedNextEntry = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
@ -1,37 +0,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/. */
|
||||
|
||||
#ifndef iehistoryenumerator___h___
|
||||
#define iehistoryenumerator___h___
|
||||
|
||||
#include <urlhist.h>
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsIWritablePropertyBag2.h"
|
||||
|
||||
class nsIEHistoryEnumerator final : public nsISimpleEnumerator
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISIMPLEENUMERATOR
|
||||
|
||||
nsIEHistoryEnumerator();
|
||||
|
||||
private:
|
||||
~nsIEHistoryEnumerator();
|
||||
|
||||
/**
|
||||
* Initializes the history reader, if needed.
|
||||
*/
|
||||
void EnsureInitialized();
|
||||
|
||||
RefPtr<IUrlHistoryStg2> mIEHistory;
|
||||
RefPtr<IEnumSTATURL> mURLEnumerator;
|
||||
|
||||
nsCOMPtr<nsIWritablePropertyBag2> mCachedNextEntry;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,36 +0,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/. */
|
||||
|
||||
#ifndef windowsmigrationutils__h__
|
||||
#define windowsmigrationutils__h__
|
||||
|
||||
#include "prtime.h"
|
||||
|
||||
static
|
||||
PRTime WinMigrationFileTimeToPRTime(FILETIME* filetime, bool* isValid)
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
*isValid = ::FileTimeToSystemTime(filetime, &st);
|
||||
if (!*isValid) {
|
||||
return 0;
|
||||
}
|
||||
PRExplodedTime prt;
|
||||
prt.tm_year = st.wYear;
|
||||
// SYSTEMTIME's day-of-month parameter is 1-based,
|
||||
// PRExplodedTime's is 0-based.
|
||||
prt.tm_month = st.wMonth - 1;
|
||||
prt.tm_mday = st.wDay;
|
||||
prt.tm_hour = st.wHour;
|
||||
prt.tm_min = st.wMinute;
|
||||
prt.tm_sec = st.wSecond;
|
||||
prt.tm_usec = st.wMilliseconds * 1000;
|
||||
prt.tm_wday = 0;
|
||||
prt.tm_yday = 0;
|
||||
prt.tm_params.tp_gmt_offset = 0;
|
||||
prt.tm_params.tp_dst_offset = 0;
|
||||
return PR_ImplodeTime(&prt);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -17,7 +17,6 @@ DIRS += [
|
|||
'search',
|
||||
'sessionstore',
|
||||
'shell',
|
||||
'migration',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_BROWSER_STATUSBAR']:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource:///modules/MigrationUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "BookmarkJSONUtils",
|
||||
|
|
@ -334,14 +333,6 @@ var PlacesOrganizer = {
|
|||
return PlacesUtils.asQuery(ContentArea.currentView.result.root).getQueries();
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the migration wizard for importing passwords,
|
||||
* cookies, history, preferences, and bookmarks.
|
||||
*/
|
||||
importFromBrowser: function PO_importFromBrowser() {
|
||||
MigrationUtils.showMigrationWizard(window);
|
||||
},
|
||||
|
||||
/**
|
||||
* Open a file-picker and import the selected file into the bookmarks store
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -68,8 +68,6 @@
|
|||
oncommand="PlacesOrganizer.exportBookmarks();"/>
|
||||
<command id="OrganizerCommand_import"
|
||||
oncommand="PlacesOrganizer.importFromFile();"/>
|
||||
<command id="OrganizerCommand_browserImport"
|
||||
oncommand="PlacesOrganizer.importFromBrowser();"/>
|
||||
<command id="OrganizerCommand_backup"
|
||||
oncommand="PlacesOrganizer.backupBookmarks();"/>
|
||||
<command id="OrganizerCommand_restoreFromFile"
|
||||
|
|
@ -312,11 +310,6 @@
|
|||
command="OrganizerCommand_export"
|
||||
label="&exportBookmarksToHTML.label;"
|
||||
accesskey="&exportBookmarksToHTML.accesskey;"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="browserImport"
|
||||
command="OrganizerCommand_browserImport"
|
||||
label="&importOtherBrowser.label;"
|
||||
accesskey="&importOtherBrowser.accesskey;"/>
|
||||
</menupopup>
|
||||
#ifdef XP_MACOSX
|
||||
</toolbarbutton>
|
||||
|
|
|
|||
|
|
@ -1,36 +0,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/. -->
|
||||
|
||||
|
||||
<!ENTITY migrationWizard.title "Import Wizard">
|
||||
|
||||
<!ENTITY importFrom.label "Import Preferences, Bookmarks, History, Passwords and other data from:">
|
||||
<!ENTITY importFromBookmarks.label "Import Bookmarks from:">
|
||||
|
||||
<!ENTITY importFromIE.label "Microsoft Internet Explorer">
|
||||
<!ENTITY importFromIE.accesskey "M">
|
||||
<!ENTITY importFromNothing.label "Don't import anything">
|
||||
<!ENTITY importFromNothing.accesskey "D">
|
||||
<!ENTITY importFromSafari.label "Safari">
|
||||
<!ENTITY importFromSafari.accesskey "S">
|
||||
<!ENTITY importFromChrome.label "Chrome">
|
||||
<!ENTITY importFromChrome.accesskey "C">
|
||||
<!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:">
|
||||
|
||||
|
|
@ -1,51 +0,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/.
|
||||
|
||||
profileName_format=%S %S
|
||||
|
||||
# Browser Specific
|
||||
sourceNameIE=Internet Explorer
|
||||
sourceNameSafari=Safari
|
||||
sourceNameChrome=Google Chrome
|
||||
sourceNameFirefox=Mozilla Firefox
|
||||
|
||||
importedBookmarksFolder=From %S
|
||||
|
||||
importedSafariReadingList=Reading List (From Safari)
|
||||
|
||||
# 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.
|
||||
1_ie=Internet Options
|
||||
1_safari=Preferences
|
||||
1_chrome=Preferences
|
||||
|
||||
2_ie=Cookies
|
||||
2_safari=Cookies
|
||||
2_chrome=Cookies
|
||||
2_firefox=Cookies
|
||||
|
||||
4_ie=Browsing History
|
||||
4_safari=Browsing History
|
||||
4_chrome=Browsing History
|
||||
4_firefox_history_and_bookmarks=Browsing History and Bookmarks
|
||||
|
||||
8_ie=Saved Form History
|
||||
8_safari=Saved Form History
|
||||
8_chrome=Saved Form History
|
||||
8_firefox=Saved Form History
|
||||
|
||||
16_ie=Saved Passwords
|
||||
16_safari=Saved Passwords
|
||||
16_chrome=Saved Passwords
|
||||
16_firefox=Saved Passwords
|
||||
|
||||
32_ie=Favorites
|
||||
32_safari=Bookmarks
|
||||
32_chrome=Bookmarks
|
||||
|
||||
64_ie=Other Data
|
||||
64_safari=Other Data
|
||||
64_chrome=Other Data
|
||||
64_firefox_other=Other Data
|
||||
|
|
@ -31,8 +31,6 @@
|
|||
<!ENTITY importBookmarksFromHTML.accesskey "I">
|
||||
<!ENTITY exportBookmarksToHTML.label "Export Bookmarks to HTML…">
|
||||
<!ENTITY exportBookmarksToHTML.accesskey "E">
|
||||
<!ENTITY importOtherBrowser.label "Import Data from Another Browser…">
|
||||
<!ENTITY importOtherBrowser.accesskey "A">
|
||||
|
||||
<!ENTITY cmd.backup.label "Backup…">
|
||||
<!ENTITY cmd.backup.accesskey "B">
|
||||
|
|
|
|||
|
|
@ -55,8 +55,6 @@
|
|||
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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue