forked from mirrors/gecko-dev
This patch was autogenerated by my decomponents.py
It covers almost every file with the extension js, jsm, html, py,
xhtml, or xul.
It removes blank lines after removed lines, when the removed lines are
preceded by either blank lines or the start of a new block. The "start
of a new block" is defined fairly hackily: either the line starts with
//, ends with */, ends with {, <![CDATA[, """ or '''. The first two
cover comments, the third one covers JS, the fourth covers JS embedded
in XUL, and the final two cover JS embedded in Python. This also
applies if the removed line was the first line of the file.
It covers the pattern matching cases like "var {classes: Cc,
interfaces: Ci, utils: Cu, results: Cr} = Components;". It'll remove
the entire thing if they are all either Ci, Cr, Cc or Cu, or it will
remove the appropriate ones and leave the residue behind. If there's
only one behind, then it will turn it into a normal, non-pattern
matching variable definition. (For instance, "const { classes: Cc,
Constructor: CC, interfaces: Ci, utils: Cu } = Components" becomes
"const CC = Components.Constructor".)
MozReview-Commit-ID: DeSHcClQ7cG
--HG--
extra : rebase_source : d9c41878036c1ef7766ef5e91a7005025bc1d72b
329 lines
10 KiB
JavaScript
329 lines
10 KiB
JavaScript
/* 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";
|
|
|
|
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|
ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
|
ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
|
|
ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
|
ChromeUtils.import("resource:///modules/MigrationUtils.jsm");
|
|
|
|
ChromeUtils.defineModuleGetter(this, "PlacesUtils",
|
|
"resource://gre/modules/PlacesUtils.jsm");
|
|
ChromeUtils.defineModuleGetter(this, "Sqlite",
|
|
"resource://gre/modules/Sqlite.jsm");
|
|
|
|
Cu.importGlobalProperties(["URL"]);
|
|
|
|
const kBookmarksFileName = "360sefav.db";
|
|
|
|
function copyToTempUTF8File(file, charset) {
|
|
let inputStream = Cc["@mozilla.org/network/file-input-stream;1"]
|
|
.createInstance(Ci.nsIFileInputStream);
|
|
inputStream.init(file, -1, -1, 0);
|
|
let inputStr = NetUtil.readInputStreamToString(
|
|
inputStream, inputStream.available(), { charset });
|
|
|
|
// Use random to reduce the likelihood of a name collision in createUnique.
|
|
let rand = Math.floor(Math.random() * Math.pow(2, 15));
|
|
let leafName = "mozilla-temp-" + rand;
|
|
let tempUTF8File = FileUtils.getFile(
|
|
"TmpD", ["mozilla-temp-files", leafName], true);
|
|
tempUTF8File.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
|
|
|
|
let out = FileUtils.openAtomicFileOutputStream(tempUTF8File);
|
|
try {
|
|
let bufferedOut = Cc["@mozilla.org/network/buffered-output-stream;1"]
|
|
.createInstance(Ci.nsIBufferedOutputStream);
|
|
bufferedOut.init(out, 4096);
|
|
try {
|
|
let converterOut = Cc["@mozilla.org/intl/converter-output-stream;1"]
|
|
.createInstance(Ci.nsIConverterOutputStream);
|
|
converterOut.init(bufferedOut, "utf-8");
|
|
try {
|
|
converterOut.writeString(inputStr || "");
|
|
bufferedOut.QueryInterface(Ci.nsISafeOutputStream).finish();
|
|
} finally {
|
|
converterOut.close();
|
|
}
|
|
} finally {
|
|
bufferedOut.close();
|
|
}
|
|
} finally {
|
|
out.close();
|
|
}
|
|
|
|
return tempUTF8File;
|
|
}
|
|
|
|
function parseINIStrings(file) {
|
|
let factory = Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
|
|
getService(Ci.nsIINIParserFactory);
|
|
let parser = factory.createINIParser(file);
|
|
let obj = {};
|
|
let sections = parser.getSections();
|
|
while (sections.hasMore()) {
|
|
let section = sections.getNext();
|
|
obj[section] = {};
|
|
|
|
let keys = parser.getKeys(section);
|
|
while (keys.hasMore()) {
|
|
let key = keys.getNext();
|
|
obj[section][key] = parser.getString(section, key);
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
function getHash(aStr) {
|
|
// return the two-digit hexadecimal code for a byte
|
|
let toHexString = charCode => ("0" + charCode.toString(16)).slice(-2);
|
|
|
|
let hasher = Cc["@mozilla.org/security/hash;1"].
|
|
createInstance(Ci.nsICryptoHash);
|
|
hasher.init(Ci.nsICryptoHash.MD5);
|
|
let stringStream = Cc["@mozilla.org/io/string-input-stream;1"].
|
|
createInstance(Ci.nsIStringInputStream);
|
|
stringStream.data = aStr;
|
|
hasher.updateFromStream(stringStream, -1);
|
|
|
|
// convert the binary hash data to a hex string.
|
|
let binary = hasher.finish(false);
|
|
return Array.from(binary, (c, i) => toHexString(binary.charCodeAt(i))).join("").toLowerCase();
|
|
}
|
|
|
|
function Bookmarks(aProfileFolder) {
|
|
let file = aProfileFolder.clone();
|
|
file.append(kBookmarksFileName);
|
|
|
|
this._file = file;
|
|
}
|
|
Bookmarks.prototype = {
|
|
type: MigrationUtils.resourceTypes.BOOKMARKS,
|
|
|
|
get exists() {
|
|
return this._file.exists() && this._file.isReadable();
|
|
},
|
|
|
|
migrate(aCallback) {
|
|
return (async () => {
|
|
let folderMap = new Map();
|
|
let toolbarBMs = [];
|
|
|
|
let connection = await Sqlite.openConnection({
|
|
path: this._file.path,
|
|
});
|
|
|
|
try {
|
|
let rows = await connection.execute(
|
|
`WITH RECURSIVE
|
|
bookmark(id, parent_id, is_folder, title, url, pos) AS (
|
|
VALUES(0, -1, 1, '', '', 0)
|
|
UNION
|
|
SELECT f.id, f.parent_id, f.is_folder, f.title, f.url, f.pos
|
|
FROM tb_fav AS f
|
|
JOIN bookmark AS b ON f.parent_id = b.id
|
|
ORDER BY f.pos ASC
|
|
)
|
|
SELECT id, parent_id, is_folder, title, url FROM bookmark WHERE id`);
|
|
|
|
for (let row of rows) {
|
|
let id = parseInt(row.getResultByName("id"), 10);
|
|
let parent_id = parseInt(row.getResultByName("parent_id"), 10);
|
|
let is_folder = parseInt(row.getResultByName("is_folder"), 10);
|
|
let title = row.getResultByName("title");
|
|
let url = row.getResultByName("url");
|
|
|
|
let bmToInsert;
|
|
|
|
if (is_folder) {
|
|
bmToInsert = {
|
|
children: [],
|
|
title,
|
|
type: PlacesUtils.bookmarks.TYPE_FOLDER,
|
|
};
|
|
folderMap.set(id, bmToInsert);
|
|
} else {
|
|
try {
|
|
new URL(url);
|
|
} catch (ex) {
|
|
Cu.reportError(`Ignoring ${url} when importing from 360se because of exception: ${ex}`);
|
|
continue;
|
|
}
|
|
|
|
bmToInsert = {
|
|
title,
|
|
url,
|
|
};
|
|
}
|
|
|
|
if (folderMap.has(parent_id)) {
|
|
folderMap.get(parent_id).children.push(bmToInsert);
|
|
} else if (parent_id === 0) {
|
|
toolbarBMs.push(bmToInsert);
|
|
}
|
|
}
|
|
} finally {
|
|
await connection.close();
|
|
}
|
|
|
|
if (toolbarBMs.length) {
|
|
let parentGuid = PlacesUtils.bookmarks.toolbarGuid;
|
|
if (!MigrationUtils.isStartupMigration) {
|
|
parentGuid =
|
|
await MigrationUtils.createImportedBookmarksFolder("360se", parentGuid);
|
|
}
|
|
await MigrationUtils.insertManyBookmarksWrapper(toolbarBMs, parentGuid);
|
|
}
|
|
})().then(() => aCallback(true),
|
|
e => { Cu.reportError(e); aCallback(false); });
|
|
},
|
|
};
|
|
|
|
function Qihoo360seProfileMigrator() {
|
|
let paths = [
|
|
// for v6 and above
|
|
{
|
|
users: ["360se6", "apps", "data", "users"],
|
|
defaultUser: "default",
|
|
},
|
|
// for earlier versions
|
|
{
|
|
users: ["360se"],
|
|
defaultUser: "data",
|
|
},
|
|
];
|
|
this._usersDir = null;
|
|
this._defaultUserPath = null;
|
|
for (let path of paths) {
|
|
let usersDir = FileUtils.getDir("AppData", path.users, false);
|
|
if (usersDir.exists()) {
|
|
this._usersDir = usersDir;
|
|
this._defaultUserPath = path.defaultUser;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Qihoo360seProfileMigrator.prototype = Object.create(MigratorPrototype);
|
|
|
|
Qihoo360seProfileMigrator.prototype.getSourceProfiles = function() {
|
|
if ("__sourceProfiles" in this)
|
|
return this.__sourceProfiles;
|
|
|
|
if (!this._usersDir) {
|
|
this.__sourceProfiles = [];
|
|
return this.__sourceProfiles;
|
|
}
|
|
|
|
let profiles = [];
|
|
let noLoggedInUser = true;
|
|
try {
|
|
let loginIni = this._usersDir.clone();
|
|
loginIni.append("login.ini");
|
|
if (!loginIni.exists()) {
|
|
throw new Error("360 Secure Browser's 'login.ini' does not exist.");
|
|
}
|
|
if (!loginIni.isReadable()) {
|
|
throw new Error("360 Secure Browser's 'login.ini' file could not be read.");
|
|
}
|
|
|
|
let loginIniInUtf8 = copyToTempUTF8File(loginIni, "GBK");
|
|
let loginIniObj = parseINIStrings(loginIniInUtf8);
|
|
try {
|
|
loginIniInUtf8.remove(false);
|
|
} catch (ex) {}
|
|
|
|
let nowLoginEmail = loginIniObj.NowLogin && loginIniObj.NowLogin.email;
|
|
|
|
/*
|
|
* NowLogin section may:
|
|
* 1. be missing or without email, before any user logs in.
|
|
* 2. represents the current logged in user
|
|
* 3. represents the most recent logged in user
|
|
*
|
|
* In the second case, user represented by NowLogin should be the first
|
|
* profile; otherwise the default user should be selected by default.
|
|
*/
|
|
if (nowLoginEmail) {
|
|
if (loginIniObj.NowLogin.IsLogined === "1") {
|
|
noLoggedInUser = false;
|
|
}
|
|
|
|
profiles.push({
|
|
id: this._getIdFromConfig(loginIniObj.NowLogin),
|
|
name: nowLoginEmail,
|
|
});
|
|
}
|
|
|
|
for (let section in loginIniObj) {
|
|
if (!loginIniObj[section].email ||
|
|
(nowLoginEmail && loginIniObj[section].email == nowLoginEmail)) {
|
|
continue;
|
|
}
|
|
|
|
profiles.push({
|
|
id: this._getIdFromConfig(loginIniObj[section]),
|
|
name: loginIniObj[section].email,
|
|
});
|
|
}
|
|
} catch (e) {
|
|
Cu.reportError("Error detecting 360 Secure Browser profiles: " + e);
|
|
} finally {
|
|
profiles[noLoggedInUser ? "unshift" : "push"]({
|
|
id: this._defaultUserPath,
|
|
name: "Default",
|
|
});
|
|
}
|
|
|
|
this.__sourceProfiles = profiles.filter(profile => {
|
|
let resources = this.getResources(profile);
|
|
return resources && resources.length > 0;
|
|
});
|
|
return this.__sourceProfiles;
|
|
};
|
|
|
|
Qihoo360seProfileMigrator.prototype._getIdFromConfig = function(aConfig) {
|
|
return aConfig.UserMd5 || getHash(aConfig.email);
|
|
};
|
|
|
|
Qihoo360seProfileMigrator.prototype.getResources = function(aProfile) {
|
|
let profileFolder = this._usersDir.clone();
|
|
profileFolder.append(aProfile.id);
|
|
|
|
if (!profileFolder.exists()) {
|
|
return [];
|
|
}
|
|
|
|
let resources = [
|
|
new Bookmarks(profileFolder),
|
|
];
|
|
return resources.filter(r => r.exists);
|
|
};
|
|
|
|
Qihoo360seProfileMigrator.prototype.getLastUsedDate = async function() {
|
|
let sourceProfiles = await this.getSourceProfiles();
|
|
let bookmarksPaths = sourceProfiles.map(({id}) => {
|
|
return OS.Path.join(this._usersDir.path, id, kBookmarksFileName);
|
|
});
|
|
if (!bookmarksPaths.length) {
|
|
return new Date(0);
|
|
}
|
|
let datePromises = bookmarksPaths.map(path => {
|
|
return OS.File.stat(path).catch(() => null).then(info => {
|
|
return info ? info.lastModificationDate : 0;
|
|
});
|
|
});
|
|
return Promise.all(datePromises).then(dates => {
|
|
return new Date(Math.max.apply(Math, dates));
|
|
});
|
|
};
|
|
|
|
Qihoo360seProfileMigrator.prototype.classDescription = "360 Secure Browser Profile Migrator";
|
|
Qihoo360seProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=360se";
|
|
Qihoo360seProfileMigrator.prototype.classID = Components.ID("{d0037b95-296a-4a4e-94b2-c3d075d20ab1}");
|
|
|
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Qihoo360seProfileMigrator]);
|