michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: const Cc = Components.classes; michael@0: const Ci = Components.interfaces; michael@0: const Cu = Components.utils; michael@0: const Cr = Components.results; michael@0: michael@0: const kMainKey = "Software\\Microsoft\\Internet Explorer\\Main"; michael@0: michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: Cu.import("resource://gre/modules/NetUtil.jsm"); michael@0: Cu.import("resource:///modules/MigrationUtils.jsm"); michael@0: michael@0: XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", michael@0: "resource://gre/modules/PlacesUtils.jsm"); michael@0: XPCOMUtils.defineLazyModuleGetter(this, "ctypes", michael@0: "resource://gre/modules/ctypes.jsm"); michael@0: XPCOMUtils.defineLazyModuleGetter(this, "WindowsRegistry", michael@0: "resource://gre/modules/WindowsRegistry.jsm"); michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: //// Helpers. michael@0: michael@0: let CtypesHelpers = { michael@0: _structs: {}, michael@0: _functions: {}, michael@0: _libs: {}, michael@0: michael@0: /** michael@0: * Must be invoked once before first use of any of the provided helpers. michael@0: */ michael@0: initialize: function CH_initialize() { michael@0: const WORD = ctypes.uint16_t; michael@0: const DWORD = ctypes.uint32_t; michael@0: const BOOL = ctypes.int; michael@0: michael@0: this._structs.SYSTEMTIME = new ctypes.StructType('SYSTEMTIME', [ michael@0: {wYear: WORD}, michael@0: {wMonth: WORD}, michael@0: {wDayOfWeek: WORD}, michael@0: {wDay: WORD}, michael@0: {wHour: WORD}, michael@0: {wMinute: WORD}, michael@0: {wSecond: WORD}, michael@0: {wMilliseconds: WORD} michael@0: ]); michael@0: michael@0: this._structs.FILETIME = new ctypes.StructType('FILETIME', [ michael@0: {dwLowDateTime: DWORD}, michael@0: {dwHighDateTime: DWORD} michael@0: ]); michael@0: michael@0: try { michael@0: this._libs.kernel32 = ctypes.open("Kernel32"); michael@0: this._functions.FileTimeToSystemTime = michael@0: this._libs.kernel32.declare("FileTimeToSystemTime", michael@0: ctypes.default_abi, michael@0: BOOL, michael@0: this._structs.FILETIME.ptr, michael@0: this._structs.SYSTEMTIME.ptr); michael@0: } catch (ex) { michael@0: this.finalize(); michael@0: } michael@0: }, michael@0: michael@0: /** michael@0: * Must be invoked once after last use of any of the provided helpers. michael@0: */ michael@0: finalize: function CH_finalize() { michael@0: this._structs = {}; michael@0: this._functions = {}; michael@0: for each (let lib in this._libs) { michael@0: try { michael@0: lib.close(); michael@0: } catch (ex) {} michael@0: } michael@0: this._libs = {}; michael@0: }, michael@0: michael@0: /** michael@0: * Converts a FILETIME struct (2 DWORDS), to a SYSTEMTIME struct. michael@0: * michael@0: * @param aTimeHi michael@0: * Least significant DWORD. michael@0: * @param aTimeLo michael@0: * Most significant DWORD. michael@0: * @return a Date object representing the converted datetime. michael@0: */ michael@0: fileTimeToDate: function CH_fileTimeToDate(aTimeHi, aTimeLo) { michael@0: let fileTime = this._structs.FILETIME(); michael@0: fileTime.dwLowDateTime = aTimeLo; michael@0: fileTime.dwHighDateTime = aTimeHi; michael@0: let systemTime = this._structs.SYSTEMTIME(); michael@0: let result = this._functions.FileTimeToSystemTime(fileTime.address(), michael@0: systemTime.address()); michael@0: if (result == 0) michael@0: throw new Error(ctypes.winLastError); michael@0: michael@0: return new Date(systemTime.wYear, michael@0: systemTime.wMonth - 1, michael@0: systemTime.wDay, michael@0: systemTime.wHour, michael@0: systemTime.wMinute, michael@0: systemTime.wSecond, michael@0: systemTime.wMilliseconds); michael@0: } michael@0: }; michael@0: michael@0: /** michael@0: * Checks whether an host is an IP (v4 or v6) address. michael@0: * michael@0: * @param aHost michael@0: * The host to check. michael@0: * @return whether aHost is an IP address. michael@0: */ michael@0: function hostIsIPAddress(aHost) { michael@0: try { michael@0: Services.eTLD.getBaseDomainFromHost(aHost); michael@0: } catch (e if e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS) { michael@0: return true; michael@0: } catch (e) {} michael@0: return false; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: //// Resources michael@0: michael@0: function Bookmarks() { michael@0: } michael@0: michael@0: Bookmarks.prototype = { michael@0: type: MigrationUtils.resourceTypes.BOOKMARKS, michael@0: michael@0: get exists() !!this._favoritesFolder, michael@0: michael@0: __favoritesFolder: null, michael@0: get _favoritesFolder() { michael@0: if (!this.__favoritesFolder) { michael@0: let favoritesFolder = Services.dirsvc.get("Favs", Ci.nsIFile); michael@0: if (favoritesFolder.exists() && favoritesFolder.isReadable()) michael@0: this.__favoritesFolder = favoritesFolder; michael@0: } michael@0: return this.__favoritesFolder; michael@0: }, michael@0: michael@0: __toolbarFolderName: null, michael@0: get _toolbarFolderName() { michael@0: if (!this.__toolbarFolderName) { michael@0: // Retrieve the name of IE's favorites subfolder that holds the bookmarks michael@0: // in the toolbar. This was previously stored in the registry and changed michael@0: // in IE7 to always be called "Links". michael@0: let folderName = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, michael@0: "Software\\Microsoft\\Internet Explorer\\Toolbar", michael@0: "LinksFolderName"); michael@0: this.__toolbarFolderName = folderName || "Links"; michael@0: } michael@0: return this.__toolbarFolderName; michael@0: }, michael@0: michael@0: migrate: function B_migrate(aCallback) { michael@0: PlacesUtils.bookmarks.runInBatchMode({ michael@0: runBatched: (function migrateBatched() { michael@0: // Import to the bookmarks menu. michael@0: let destFolderId = PlacesUtils.bookmarksMenuFolderId; michael@0: if (!MigrationUtils.isStartupMigration) { michael@0: destFolderId = michael@0: MigrationUtils.createImportedBookmarksFolder("IE", destFolderId); michael@0: } michael@0: michael@0: this._migrateFolder(this._favoritesFolder, destFolderId); michael@0: michael@0: aCallback(true); michael@0: }).bind(this) michael@0: }, null); michael@0: }, michael@0: michael@0: _migrateFolder: function B__migrateFolder(aSourceFolder, aDestFolderId) { michael@0: // TODO (bug 741993): the favorites order is stored in the Registry, at michael@0: // HCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MenuOrder\Favorites michael@0: // Until we support it, bookmarks are imported in alphabetical order. michael@0: let entries = aSourceFolder.directoryEntries; michael@0: while (entries.hasMoreElements()) { michael@0: let entry = entries.getNext().QueryInterface(Ci.nsIFile); michael@0: try { michael@0: // Make sure that entry.path == entry.target to not follow .lnk folder michael@0: // shortcuts which could lead to infinite cycles. michael@0: // Don't use isSymlink(), since it would throw for invalid michael@0: // lnk files pointing to URLs or to unresolvable paths. michael@0: if (entry.path == entry.target && entry.isDirectory()) { michael@0: let destFolderId; michael@0: if (entry.leafName == this._toolbarFolderName && michael@0: entry.parent.equals(this._favoritesFolder)) { michael@0: // Import to the bookmarks toolbar. michael@0: destFolderId = PlacesUtils.toolbarFolderId; michael@0: if (!MigrationUtils.isStartupMigration) { michael@0: destFolderId = michael@0: MigrationUtils.createImportedBookmarksFolder("IE", destFolderId); michael@0: } michael@0: } michael@0: else { michael@0: // Import to a new folder. michael@0: destFolderId = michael@0: PlacesUtils.bookmarks.createFolder(aDestFolderId, entry.leafName, michael@0: PlacesUtils.bookmarks.DEFAULT_INDEX); michael@0: } michael@0: michael@0: if (entry.isReadable()) { michael@0: // Recursively import the folder. michael@0: this._migrateFolder(entry, destFolderId); michael@0: } michael@0: } michael@0: else { michael@0: // Strip the .url extension, to both check this is a valid link file, michael@0: // and get the associated title. michael@0: let matches = entry.leafName.match(/(.+)\.url$/i); michael@0: if (matches) { michael@0: let fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"]. michael@0: getService(Ci.nsIFileProtocolHandler); michael@0: let uri = fileHandler.readURLFile(entry); michael@0: let title = matches[1]; michael@0: michael@0: PlacesUtils.bookmarks.insertBookmark(aDestFolderId, michael@0: uri, michael@0: PlacesUtils.bookmarks.DEFAULT_INDEX, michael@0: title); michael@0: } michael@0: } michael@0: } catch (ex) { michael@0: Components.utils.reportError("Unable to import IE favorite (" + entry.leafName + "): " + ex); michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: michael@0: function History() { michael@0: } michael@0: michael@0: History.prototype = { michael@0: type: MigrationUtils.resourceTypes.HISTORY, michael@0: michael@0: get exists() true, michael@0: michael@0: __typedURLs: null, michael@0: get _typedURLs() { michael@0: if (!this.__typedURLs) { michael@0: // The list of typed URLs is a sort of annotation stored in the registry. michael@0: // Currently, IE stores 25 entries and this value is not configurable, michael@0: // but we just keep reading up to the first non-existing entry to support michael@0: // possible future bumps of this limit. michael@0: this.__typedURLs = {}; michael@0: let registry = Cc["@mozilla.org/windows-registry-key;1"]. michael@0: createInstance(Ci.nsIWindowsRegKey); michael@0: try { michael@0: registry.open(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, michael@0: "Software\\Microsoft\\Internet Explorer\\TypedURLs", michael@0: Ci.nsIWindowsRegKey.ACCESS_READ); michael@0: for (let entry = 1; registry.hasValue("url" + entry); entry++) { michael@0: let url = registry.readStringValue("url" + entry); michael@0: this.__typedURLs[url] = true; michael@0: } michael@0: } catch (ex) { michael@0: } finally { michael@0: registry.close(); michael@0: } michael@0: } michael@0: return this.__typedURLs; michael@0: }, michael@0: michael@0: migrate: function H_migrate(aCallback) { michael@0: let places = []; michael@0: let historyEnumerator = Cc["@mozilla.org/profile/migrator/iehistoryenumerator;1"]. michael@0: createInstance(Ci.nsISimpleEnumerator); michael@0: while (historyEnumerator.hasMoreElements()) { michael@0: let entry = historyEnumerator.getNext().QueryInterface(Ci.nsIPropertyBag2); michael@0: let uri = entry.get("uri").QueryInterface(Ci.nsIURI); michael@0: // MSIE stores some types of URLs in its history that we don't handle, michael@0: // like HTMLHelp and others. Since we don't properly map handling for michael@0: // all of them we just avoid importing them. michael@0: if (["http", "https", "ftp", "file"].indexOf(uri.scheme) == -1) { michael@0: continue; michael@0: } michael@0: michael@0: let title = entry.get("title"); michael@0: // Embed visits have no title and don't need to be imported. michael@0: if (title.length == 0) { michael@0: continue; michael@0: } michael@0: michael@0: // The typed urls are already fixed-up, so we can use them for comparison. michael@0: let transitionType = this._typedURLs[uri.spec] ? michael@0: Ci.nsINavHistoryService.TRANSITION_TYPED : michael@0: Ci.nsINavHistoryService.TRANSITION_LINK; michael@0: let lastVisitTime = entry.get("time"); michael@0: michael@0: places.push( michael@0: { uri: uri, michael@0: title: title, michael@0: visits: [{ transitionType: transitionType, michael@0: visitDate: lastVisitTime }] michael@0: } michael@0: ); michael@0: } michael@0: michael@0: // Check whether there is any history to import. michael@0: if (places.length == 0) { michael@0: aCallback(true); michael@0: return; michael@0: } michael@0: michael@0: PlacesUtils.asyncHistory.updatePlaces(places, { michael@0: _success: false, michael@0: handleResult: function() { michael@0: // Importing any entry is considered a successful import. michael@0: this._success = true; michael@0: }, michael@0: handleError: function() {}, michael@0: handleCompletion: function() { michael@0: aCallback(this._success); michael@0: } michael@0: }); michael@0: } michael@0: }; michael@0: michael@0: function Cookies() { michael@0: } michael@0: michael@0: Cookies.prototype = { michael@0: type: MigrationUtils.resourceTypes.COOKIES, michael@0: michael@0: get exists() !!this._cookiesFolder, michael@0: michael@0: __cookiesFolder: null, michael@0: get _cookiesFolder() { michael@0: // Cookies are stored in txt files, in a Cookies folder whose path varies michael@0: // across the different OS versions. CookD takes care of most of these michael@0: // cases, though, in Windows Vista/7, UAC makes a difference. michael@0: // If UAC is enabled, the most common destination is CookD/Low. Though, michael@0: // if the user runs the application in administrator mode or disables UAC, michael@0: // cookies are stored in the original CookD destination. Cause running the michael@0: // browser in administrator mode is unsafe and discouraged, we just care michael@0: // about the UAC state. michael@0: if (!this.__cookiesFolder) { michael@0: let cookiesFolder = Services.dirsvc.get("CookD", Ci.nsIFile); michael@0: if (cookiesFolder.exists() && cookiesFolder.isReadable()) { michael@0: // Check if UAC is enabled. michael@0: if (Services.appinfo.QueryInterface(Ci.nsIWinAppHelper).userCanElevate) { michael@0: cookiesFolder.append("Low"); michael@0: } michael@0: this.__cookiesFolder = cookiesFolder; michael@0: } michael@0: } michael@0: return this.__cookiesFolder; michael@0: }, michael@0: michael@0: migrate: function C_migrate(aCallback) { michael@0: CtypesHelpers.initialize(); michael@0: michael@0: let cookiesGenerator = (function genCookie() { michael@0: let success = false; michael@0: let entries = this._cookiesFolder.directoryEntries; michael@0: while (entries.hasMoreElements()) { michael@0: let entry = entries.getNext().QueryInterface(Ci.nsIFile); michael@0: // Skip eventual bogus entries. michael@0: if (!entry.isFile() || !/\.txt$/.test(entry.leafName)) michael@0: continue; michael@0: michael@0: this._readCookieFile(entry, function(aSuccess) { michael@0: // Importing even a single cookie file is considered a success. michael@0: if (aSuccess) michael@0: success = true; michael@0: try { michael@0: cookiesGenerator.next(); michael@0: } catch (ex) {} michael@0: }); michael@0: michael@0: yield undefined; michael@0: } michael@0: michael@0: CtypesHelpers.finalize(); michael@0: michael@0: aCallback(success); michael@0: }).apply(this); michael@0: cookiesGenerator.next(); michael@0: }, michael@0: michael@0: _readCookieFile: function C__readCookieFile(aFile, aCallback) { michael@0: let fileReader = Cc["@mozilla.org/files/filereader;1"]. michael@0: createInstance(Ci.nsIDOMFileReader); michael@0: fileReader.addEventListener("loadend", (function onLoadEnd() { michael@0: fileReader.removeEventListener("loadend", onLoadEnd, false); michael@0: michael@0: if (fileReader.readyState != fileReader.DONE) { michael@0: Cu.reportError("Could not read cookie contents: " + fileReader.error); michael@0: aCallback(false); michael@0: return; michael@0: } michael@0: michael@0: let success = true; michael@0: try { michael@0: this._parseCookieBuffer(fileReader.result); michael@0: } catch (ex) { michael@0: Components.utils.reportError("Unable to migrate cookie: " + ex); michael@0: success = false; michael@0: } finally { michael@0: aCallback(success); michael@0: } michael@0: }).bind(this), false); michael@0: fileReader.readAsText(File(aFile)); michael@0: }, michael@0: michael@0: /** michael@0: * Parses a cookie file buffer and returns an array of the contained cookies. michael@0: * michael@0: * The cookie file format is a newline-separated-values with a "*" used as michael@0: * delimeter between multiple records. michael@0: * Each cookie has the following fields: michael@0: * - name michael@0: * - value michael@0: * - host/path michael@0: * - flags michael@0: * - Expiration time most significant integer michael@0: * - Expiration time least significant integer michael@0: * - Creation time most significant integer michael@0: * - Creation time least significant integer michael@0: * - Record delimiter "*" michael@0: * michael@0: * @note All the times are in FILETIME format. michael@0: */ michael@0: _parseCookieBuffer: function C__parseCookieBuffer(aTextBuffer) { michael@0: // Note the last record is an empty string. michael@0: let records = [r for each (r in aTextBuffer.split("*\n")) if (r)]; michael@0: for (let record of records) { michael@0: let [name, value, hostpath, flags, michael@0: expireTimeLo, expireTimeHi] = record.split("\n"); michael@0: michael@0: // IE stores deleted cookies with a zero-length value, skip them. michael@0: if (value.length == 0) michael@0: continue; michael@0: michael@0: let hostLen = hostpath.indexOf("/"); michael@0: let host = hostpath.substr(0, hostLen); michael@0: michael@0: // For a non-null domain, assume it's what Mozilla considers michael@0: // a domain cookie. See bug 222343. michael@0: if (host.length > 0) { michael@0: // Fist delete any possible extant matching host cookie. michael@0: Services.cookies.remove(host, name, path, false); michael@0: // Now make it a domain cookie. michael@0: if (host[0] != "." && !hostIsIPAddress(host)) michael@0: host = "." + host; michael@0: } michael@0: michael@0: let path = hostpath.substr(hostLen); michael@0: let expireTime = CtypesHelpers.fileTimeToDate(Number(expireTimeHi), michael@0: Number(expireTimeLo)); michael@0: Services.cookies.add(host, michael@0: path, michael@0: name, michael@0: value, michael@0: Number(flags) & 0x1, // secure michael@0: false, // httpOnly michael@0: false, // session michael@0: expireTime); michael@0: } michael@0: } michael@0: }; michael@0: michael@0: function Settings() { michael@0: } michael@0: michael@0: Settings.prototype = { michael@0: type: MigrationUtils.resourceTypes.SETTINGS, michael@0: michael@0: get exists() true, michael@0: michael@0: migrate: function S_migrate(aCallback) { michael@0: // Converts from yes/no to a boolean. michael@0: function yesNoToBoolean(v) v == "yes"; michael@0: michael@0: // Converts source format like "en-us,ar-kw;q=0.7,ar-om;q=0.3" into michael@0: // destination format like "en-us, ar-kw, ar-om". michael@0: // Final string is sorted by quality (q=) param. michael@0: function parseAcceptLanguageList(v) { michael@0: return v.match(/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/gi) michael@0: .sort(function (a , b) { michael@0: let qA = parseFloat(a.split(";q=")[1]) || 1.0; michael@0: let qB = parseFloat(b.split(";q=")[1]) || 1.0; michael@0: return qA < qB ? 1 : qA == qB ? 0 : -1; michael@0: }) michael@0: .map(function(a) a.split(";")[0]); michael@0: } michael@0: michael@0: // For reference on some of the available IE Registry settings: michael@0: // * http://msdn.microsoft.com/en-us/library/cc980058%28v=prot.13%29.aspx michael@0: // * http://msdn.microsoft.com/en-us/library/cc980059%28v=prot.13%29.aspx michael@0: michael@0: // Note that only settings exposed in our UI should be migrated. michael@0: michael@0: this._set("Software\\Microsoft\\Internet Explorer\\International", michael@0: "AcceptLanguage", michael@0: "intl.accept_languages", michael@0: parseAcceptLanguageList); michael@0: // TODO (bug 745853): For now, only x-western font is translated. michael@0: this._set("Software\\Microsoft\\Internet Explorer\\International\\Scripts\\3", michael@0: "IEFixedFontName", michael@0: "font.name.monospace.x-western"); michael@0: this._set(kMainKey, michael@0: "Use FormSuggest", michael@0: "browser.formfill.enable", michael@0: yesNoToBoolean); michael@0: this._set(kMainKey, michael@0: "FormSuggest Passwords", michael@0: "signon.rememberSignons", michael@0: yesNoToBoolean); michael@0: this._set(kMainKey, michael@0: "Anchor Underline", michael@0: "browser.underline_anchors", michael@0: yesNoToBoolean); michael@0: this._set(kMainKey, michael@0: "Display Inline Images", michael@0: "permissions.default.image", michael@0: function (v) yesNoToBoolean(v) ? 1 : 2); michael@0: this._set(kMainKey, michael@0: "Move System Caret", michael@0: "accessibility.browsewithcaret", michael@0: yesNoToBoolean); michael@0: this._set("Software\\Microsoft\\Internet Explorer\\Settings", michael@0: "Always Use My Colors", michael@0: "browser.display.use_document_colors", michael@0: function (v) !Boolean(v)); michael@0: this._set("Software\\Microsoft\\Internet Explorer\\Settings", michael@0: "Always Use My Font Face", michael@0: "browser.display.use_document_fonts", michael@0: function (v) !Boolean(v)); michael@0: this._set(kMainKey, michael@0: "SmoothScroll", michael@0: "general.smoothScroll", michael@0: Boolean); michael@0: this._set("Software\\Microsoft\\Internet Explorer\\TabbedBrowsing\\", michael@0: "WarnOnClose", michael@0: "browser.tabs.warnOnClose", michael@0: Boolean); michael@0: this._set("Software\\Microsoft\\Internet Explorer\\TabbedBrowsing\\", michael@0: "OpenInForeground", michael@0: "browser.tabs.loadInBackground", michael@0: function (v) !Boolean(v)); michael@0: michael@0: aCallback(true); michael@0: }, michael@0: michael@0: /** michael@0: * Reads a setting from the Registry and stores the converted result into michael@0: * the appropriate Firefox preference. michael@0: * michael@0: * @param aPath michael@0: * Registry path under HKCU. michael@0: * @param aKey michael@0: * Name of the key. michael@0: * @param aPref michael@0: * Firefox preference. michael@0: * @param [optional] aTransformFn michael@0: * Conversion function from the Registry format to the pref format. michael@0: */ michael@0: _set: function S__set(aPath, aKey, aPref, aTransformFn) { michael@0: let value = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, michael@0: aPath, aKey); michael@0: // Don't import settings that have never been flipped. michael@0: if (value === undefined) michael@0: return; michael@0: michael@0: if (aTransformFn) michael@0: value = aTransformFn(value); michael@0: michael@0: switch (typeof(value)) { michael@0: case "string": michael@0: Services.prefs.setCharPref(aPref, value); michael@0: break; michael@0: case "number": michael@0: Services.prefs.setIntPref(aPref, value); michael@0: break; michael@0: case "boolean": michael@0: Services.prefs.setBoolPref(aPref, value); michael@0: break; michael@0: default: michael@0: throw new Error("Unexpected value type: " + typeof(value)); michael@0: } michael@0: } michael@0: }; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: //// Migrator michael@0: michael@0: function IEProfileMigrator() michael@0: { michael@0: } michael@0: michael@0: IEProfileMigrator.prototype = Object.create(MigratorPrototype); michael@0: michael@0: IEProfileMigrator.prototype.getResources = function IE_getResources() { michael@0: let resources = [ michael@0: new Bookmarks() michael@0: , new History() michael@0: , new Cookies() michael@0: , new Settings() michael@0: ]; michael@0: return [r for each (r in resources) if (r.exists)]; michael@0: }; michael@0: michael@0: Object.defineProperty(IEProfileMigrator.prototype, "sourceHomePageURL", { michael@0: get: function IE_get_sourceHomePageURL() { michael@0: let defaultStartPage = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, michael@0: kMainKey, "Default_Page_URL"); michael@0: let startPage = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, michael@0: kMainKey, "Start Page"); michael@0: // If the user didn't customize the Start Page, he is still on the default michael@0: // page, that may be considered the equivalent of our about:home. There's michael@0: // no reason to retain it, since it is heavily targeted to IE. michael@0: let homepage = startPage != defaultStartPage ? startPage : ""; michael@0: michael@0: // IE7+ supports secondary home pages located in a REG_MULTI_SZ key. These michael@0: // are in addition to the Start Page, and no empty entries are possible, michael@0: // thus a Start Page is always defined if any of these exists, though it michael@0: // may be the default one. michael@0: let secondaryPages = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, michael@0: kMainKey, "Secondary Start Pages"); michael@0: if (secondaryPages) { michael@0: if (homepage) michael@0: secondaryPages.unshift(homepage); michael@0: homepage = secondaryPages.join("|"); michael@0: } michael@0: michael@0: return homepage; michael@0: } michael@0: }); michael@0: michael@0: IEProfileMigrator.prototype.classDescription = "IE Profile Migrator"; michael@0: IEProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=ie"; michael@0: IEProfileMigrator.prototype.classID = Components.ID("{3d2532e3-4932-4774-b7ba-968f5899d3a4}"); michael@0: michael@0: this.NSGetFactory = XPCOMUtils.generateNSGetFactory([IEProfileMigrator]);