browser/components/migration/src/IEProfileMigrator.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 "use strict";
michael@0 6
michael@0 7 const Cc = Components.classes;
michael@0 8 const Ci = Components.interfaces;
michael@0 9 const Cu = Components.utils;
michael@0 10 const Cr = Components.results;
michael@0 11
michael@0 12 const kMainKey = "Software\\Microsoft\\Internet Explorer\\Main";
michael@0 13
michael@0 14 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
michael@0 15 Cu.import("resource://gre/modules/Services.jsm");
michael@0 16 Cu.import("resource://gre/modules/NetUtil.jsm");
michael@0 17 Cu.import("resource:///modules/MigrationUtils.jsm");
michael@0 18
michael@0 19 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
michael@0 20 "resource://gre/modules/PlacesUtils.jsm");
michael@0 21 XPCOMUtils.defineLazyModuleGetter(this, "ctypes",
michael@0 22 "resource://gre/modules/ctypes.jsm");
michael@0 23 XPCOMUtils.defineLazyModuleGetter(this, "WindowsRegistry",
michael@0 24 "resource://gre/modules/WindowsRegistry.jsm");
michael@0 25
michael@0 26 ////////////////////////////////////////////////////////////////////////////////
michael@0 27 //// Helpers.
michael@0 28
michael@0 29 let CtypesHelpers = {
michael@0 30 _structs: {},
michael@0 31 _functions: {},
michael@0 32 _libs: {},
michael@0 33
michael@0 34 /**
michael@0 35 * Must be invoked once before first use of any of the provided helpers.
michael@0 36 */
michael@0 37 initialize: function CH_initialize() {
michael@0 38 const WORD = ctypes.uint16_t;
michael@0 39 const DWORD = ctypes.uint32_t;
michael@0 40 const BOOL = ctypes.int;
michael@0 41
michael@0 42 this._structs.SYSTEMTIME = new ctypes.StructType('SYSTEMTIME', [
michael@0 43 {wYear: WORD},
michael@0 44 {wMonth: WORD},
michael@0 45 {wDayOfWeek: WORD},
michael@0 46 {wDay: WORD},
michael@0 47 {wHour: WORD},
michael@0 48 {wMinute: WORD},
michael@0 49 {wSecond: WORD},
michael@0 50 {wMilliseconds: WORD}
michael@0 51 ]);
michael@0 52
michael@0 53 this._structs.FILETIME = new ctypes.StructType('FILETIME', [
michael@0 54 {dwLowDateTime: DWORD},
michael@0 55 {dwHighDateTime: DWORD}
michael@0 56 ]);
michael@0 57
michael@0 58 try {
michael@0 59 this._libs.kernel32 = ctypes.open("Kernel32");
michael@0 60 this._functions.FileTimeToSystemTime =
michael@0 61 this._libs.kernel32.declare("FileTimeToSystemTime",
michael@0 62 ctypes.default_abi,
michael@0 63 BOOL,
michael@0 64 this._structs.FILETIME.ptr,
michael@0 65 this._structs.SYSTEMTIME.ptr);
michael@0 66 } catch (ex) {
michael@0 67 this.finalize();
michael@0 68 }
michael@0 69 },
michael@0 70
michael@0 71 /**
michael@0 72 * Must be invoked once after last use of any of the provided helpers.
michael@0 73 */
michael@0 74 finalize: function CH_finalize() {
michael@0 75 this._structs = {};
michael@0 76 this._functions = {};
michael@0 77 for each (let lib in this._libs) {
michael@0 78 try {
michael@0 79 lib.close();
michael@0 80 } catch (ex) {}
michael@0 81 }
michael@0 82 this._libs = {};
michael@0 83 },
michael@0 84
michael@0 85 /**
michael@0 86 * Converts a FILETIME struct (2 DWORDS), to a SYSTEMTIME struct.
michael@0 87 *
michael@0 88 * @param aTimeHi
michael@0 89 * Least significant DWORD.
michael@0 90 * @param aTimeLo
michael@0 91 * Most significant DWORD.
michael@0 92 * @return a Date object representing the converted datetime.
michael@0 93 */
michael@0 94 fileTimeToDate: function CH_fileTimeToDate(aTimeHi, aTimeLo) {
michael@0 95 let fileTime = this._structs.FILETIME();
michael@0 96 fileTime.dwLowDateTime = aTimeLo;
michael@0 97 fileTime.dwHighDateTime = aTimeHi;
michael@0 98 let systemTime = this._structs.SYSTEMTIME();
michael@0 99 let result = this._functions.FileTimeToSystemTime(fileTime.address(),
michael@0 100 systemTime.address());
michael@0 101 if (result == 0)
michael@0 102 throw new Error(ctypes.winLastError);
michael@0 103
michael@0 104 return new Date(systemTime.wYear,
michael@0 105 systemTime.wMonth - 1,
michael@0 106 systemTime.wDay,
michael@0 107 systemTime.wHour,
michael@0 108 systemTime.wMinute,
michael@0 109 systemTime.wSecond,
michael@0 110 systemTime.wMilliseconds);
michael@0 111 }
michael@0 112 };
michael@0 113
michael@0 114 /**
michael@0 115 * Checks whether an host is an IP (v4 or v6) address.
michael@0 116 *
michael@0 117 * @param aHost
michael@0 118 * The host to check.
michael@0 119 * @return whether aHost is an IP address.
michael@0 120 */
michael@0 121 function hostIsIPAddress(aHost) {
michael@0 122 try {
michael@0 123 Services.eTLD.getBaseDomainFromHost(aHost);
michael@0 124 } catch (e if e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS) {
michael@0 125 return true;
michael@0 126 } catch (e) {}
michael@0 127 return false;
michael@0 128 }
michael@0 129
michael@0 130 ////////////////////////////////////////////////////////////////////////////////
michael@0 131 //// Resources
michael@0 132
michael@0 133 function Bookmarks() {
michael@0 134 }
michael@0 135
michael@0 136 Bookmarks.prototype = {
michael@0 137 type: MigrationUtils.resourceTypes.BOOKMARKS,
michael@0 138
michael@0 139 get exists() !!this._favoritesFolder,
michael@0 140
michael@0 141 __favoritesFolder: null,
michael@0 142 get _favoritesFolder() {
michael@0 143 if (!this.__favoritesFolder) {
michael@0 144 let favoritesFolder = Services.dirsvc.get("Favs", Ci.nsIFile);
michael@0 145 if (favoritesFolder.exists() && favoritesFolder.isReadable())
michael@0 146 this.__favoritesFolder = favoritesFolder;
michael@0 147 }
michael@0 148 return this.__favoritesFolder;
michael@0 149 },
michael@0 150
michael@0 151 __toolbarFolderName: null,
michael@0 152 get _toolbarFolderName() {
michael@0 153 if (!this.__toolbarFolderName) {
michael@0 154 // Retrieve the name of IE's favorites subfolder that holds the bookmarks
michael@0 155 // in the toolbar. This was previously stored in the registry and changed
michael@0 156 // in IE7 to always be called "Links".
michael@0 157 let folderName = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
michael@0 158 "Software\\Microsoft\\Internet Explorer\\Toolbar",
michael@0 159 "LinksFolderName");
michael@0 160 this.__toolbarFolderName = folderName || "Links";
michael@0 161 }
michael@0 162 return this.__toolbarFolderName;
michael@0 163 },
michael@0 164
michael@0 165 migrate: function B_migrate(aCallback) {
michael@0 166 PlacesUtils.bookmarks.runInBatchMode({
michael@0 167 runBatched: (function migrateBatched() {
michael@0 168 // Import to the bookmarks menu.
michael@0 169 let destFolderId = PlacesUtils.bookmarksMenuFolderId;
michael@0 170 if (!MigrationUtils.isStartupMigration) {
michael@0 171 destFolderId =
michael@0 172 MigrationUtils.createImportedBookmarksFolder("IE", destFolderId);
michael@0 173 }
michael@0 174
michael@0 175 this._migrateFolder(this._favoritesFolder, destFolderId);
michael@0 176
michael@0 177 aCallback(true);
michael@0 178 }).bind(this)
michael@0 179 }, null);
michael@0 180 },
michael@0 181
michael@0 182 _migrateFolder: function B__migrateFolder(aSourceFolder, aDestFolderId) {
michael@0 183 // TODO (bug 741993): the favorites order is stored in the Registry, at
michael@0 184 // HCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MenuOrder\Favorites
michael@0 185 // Until we support it, bookmarks are imported in alphabetical order.
michael@0 186 let entries = aSourceFolder.directoryEntries;
michael@0 187 while (entries.hasMoreElements()) {
michael@0 188 let entry = entries.getNext().QueryInterface(Ci.nsIFile);
michael@0 189 try {
michael@0 190 // Make sure that entry.path == entry.target to not follow .lnk folder
michael@0 191 // shortcuts which could lead to infinite cycles.
michael@0 192 // Don't use isSymlink(), since it would throw for invalid
michael@0 193 // lnk files pointing to URLs or to unresolvable paths.
michael@0 194 if (entry.path == entry.target && entry.isDirectory()) {
michael@0 195 let destFolderId;
michael@0 196 if (entry.leafName == this._toolbarFolderName &&
michael@0 197 entry.parent.equals(this._favoritesFolder)) {
michael@0 198 // Import to the bookmarks toolbar.
michael@0 199 destFolderId = PlacesUtils.toolbarFolderId;
michael@0 200 if (!MigrationUtils.isStartupMigration) {
michael@0 201 destFolderId =
michael@0 202 MigrationUtils.createImportedBookmarksFolder("IE", destFolderId);
michael@0 203 }
michael@0 204 }
michael@0 205 else {
michael@0 206 // Import to a new folder.
michael@0 207 destFolderId =
michael@0 208 PlacesUtils.bookmarks.createFolder(aDestFolderId, entry.leafName,
michael@0 209 PlacesUtils.bookmarks.DEFAULT_INDEX);
michael@0 210 }
michael@0 211
michael@0 212 if (entry.isReadable()) {
michael@0 213 // Recursively import the folder.
michael@0 214 this._migrateFolder(entry, destFolderId);
michael@0 215 }
michael@0 216 }
michael@0 217 else {
michael@0 218 // Strip the .url extension, to both check this is a valid link file,
michael@0 219 // and get the associated title.
michael@0 220 let matches = entry.leafName.match(/(.+)\.url$/i);
michael@0 221 if (matches) {
michael@0 222 let fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].
michael@0 223 getService(Ci.nsIFileProtocolHandler);
michael@0 224 let uri = fileHandler.readURLFile(entry);
michael@0 225 let title = matches[1];
michael@0 226
michael@0 227 PlacesUtils.bookmarks.insertBookmark(aDestFolderId,
michael@0 228 uri,
michael@0 229 PlacesUtils.bookmarks.DEFAULT_INDEX,
michael@0 230 title);
michael@0 231 }
michael@0 232 }
michael@0 233 } catch (ex) {
michael@0 234 Components.utils.reportError("Unable to import IE favorite (" + entry.leafName + "): " + ex);
michael@0 235 }
michael@0 236 }
michael@0 237 }
michael@0 238 };
michael@0 239
michael@0 240 function History() {
michael@0 241 }
michael@0 242
michael@0 243 History.prototype = {
michael@0 244 type: MigrationUtils.resourceTypes.HISTORY,
michael@0 245
michael@0 246 get exists() true,
michael@0 247
michael@0 248 __typedURLs: null,
michael@0 249 get _typedURLs() {
michael@0 250 if (!this.__typedURLs) {
michael@0 251 // The list of typed URLs is a sort of annotation stored in the registry.
michael@0 252 // Currently, IE stores 25 entries and this value is not configurable,
michael@0 253 // but we just keep reading up to the first non-existing entry to support
michael@0 254 // possible future bumps of this limit.
michael@0 255 this.__typedURLs = {};
michael@0 256 let registry = Cc["@mozilla.org/windows-registry-key;1"].
michael@0 257 createInstance(Ci.nsIWindowsRegKey);
michael@0 258 try {
michael@0 259 registry.open(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
michael@0 260 "Software\\Microsoft\\Internet Explorer\\TypedURLs",
michael@0 261 Ci.nsIWindowsRegKey.ACCESS_READ);
michael@0 262 for (let entry = 1; registry.hasValue("url" + entry); entry++) {
michael@0 263 let url = registry.readStringValue("url" + entry);
michael@0 264 this.__typedURLs[url] = true;
michael@0 265 }
michael@0 266 } catch (ex) {
michael@0 267 } finally {
michael@0 268 registry.close();
michael@0 269 }
michael@0 270 }
michael@0 271 return this.__typedURLs;
michael@0 272 },
michael@0 273
michael@0 274 migrate: function H_migrate(aCallback) {
michael@0 275 let places = [];
michael@0 276 let historyEnumerator = Cc["@mozilla.org/profile/migrator/iehistoryenumerator;1"].
michael@0 277 createInstance(Ci.nsISimpleEnumerator);
michael@0 278 while (historyEnumerator.hasMoreElements()) {
michael@0 279 let entry = historyEnumerator.getNext().QueryInterface(Ci.nsIPropertyBag2);
michael@0 280 let uri = entry.get("uri").QueryInterface(Ci.nsIURI);
michael@0 281 // MSIE stores some types of URLs in its history that we don't handle,
michael@0 282 // like HTMLHelp and others. Since we don't properly map handling for
michael@0 283 // all of them we just avoid importing them.
michael@0 284 if (["http", "https", "ftp", "file"].indexOf(uri.scheme) == -1) {
michael@0 285 continue;
michael@0 286 }
michael@0 287
michael@0 288 let title = entry.get("title");
michael@0 289 // Embed visits have no title and don't need to be imported.
michael@0 290 if (title.length == 0) {
michael@0 291 continue;
michael@0 292 }
michael@0 293
michael@0 294 // The typed urls are already fixed-up, so we can use them for comparison.
michael@0 295 let transitionType = this._typedURLs[uri.spec] ?
michael@0 296 Ci.nsINavHistoryService.TRANSITION_TYPED :
michael@0 297 Ci.nsINavHistoryService.TRANSITION_LINK;
michael@0 298 let lastVisitTime = entry.get("time");
michael@0 299
michael@0 300 places.push(
michael@0 301 { uri: uri,
michael@0 302 title: title,
michael@0 303 visits: [{ transitionType: transitionType,
michael@0 304 visitDate: lastVisitTime }]
michael@0 305 }
michael@0 306 );
michael@0 307 }
michael@0 308
michael@0 309 // Check whether there is any history to import.
michael@0 310 if (places.length == 0) {
michael@0 311 aCallback(true);
michael@0 312 return;
michael@0 313 }
michael@0 314
michael@0 315 PlacesUtils.asyncHistory.updatePlaces(places, {
michael@0 316 _success: false,
michael@0 317 handleResult: function() {
michael@0 318 // Importing any entry is considered a successful import.
michael@0 319 this._success = true;
michael@0 320 },
michael@0 321 handleError: function() {},
michael@0 322 handleCompletion: function() {
michael@0 323 aCallback(this._success);
michael@0 324 }
michael@0 325 });
michael@0 326 }
michael@0 327 };
michael@0 328
michael@0 329 function Cookies() {
michael@0 330 }
michael@0 331
michael@0 332 Cookies.prototype = {
michael@0 333 type: MigrationUtils.resourceTypes.COOKIES,
michael@0 334
michael@0 335 get exists() !!this._cookiesFolder,
michael@0 336
michael@0 337 __cookiesFolder: null,
michael@0 338 get _cookiesFolder() {
michael@0 339 // Cookies are stored in txt files, in a Cookies folder whose path varies
michael@0 340 // across the different OS versions. CookD takes care of most of these
michael@0 341 // cases, though, in Windows Vista/7, UAC makes a difference.
michael@0 342 // If UAC is enabled, the most common destination is CookD/Low. Though,
michael@0 343 // if the user runs the application in administrator mode or disables UAC,
michael@0 344 // cookies are stored in the original CookD destination. Cause running the
michael@0 345 // browser in administrator mode is unsafe and discouraged, we just care
michael@0 346 // about the UAC state.
michael@0 347 if (!this.__cookiesFolder) {
michael@0 348 let cookiesFolder = Services.dirsvc.get("CookD", Ci.nsIFile);
michael@0 349 if (cookiesFolder.exists() && cookiesFolder.isReadable()) {
michael@0 350 // Check if UAC is enabled.
michael@0 351 if (Services.appinfo.QueryInterface(Ci.nsIWinAppHelper).userCanElevate) {
michael@0 352 cookiesFolder.append("Low");
michael@0 353 }
michael@0 354 this.__cookiesFolder = cookiesFolder;
michael@0 355 }
michael@0 356 }
michael@0 357 return this.__cookiesFolder;
michael@0 358 },
michael@0 359
michael@0 360 migrate: function C_migrate(aCallback) {
michael@0 361 CtypesHelpers.initialize();
michael@0 362
michael@0 363 let cookiesGenerator = (function genCookie() {
michael@0 364 let success = false;
michael@0 365 let entries = this._cookiesFolder.directoryEntries;
michael@0 366 while (entries.hasMoreElements()) {
michael@0 367 let entry = entries.getNext().QueryInterface(Ci.nsIFile);
michael@0 368 // Skip eventual bogus entries.
michael@0 369 if (!entry.isFile() || !/\.txt$/.test(entry.leafName))
michael@0 370 continue;
michael@0 371
michael@0 372 this._readCookieFile(entry, function(aSuccess) {
michael@0 373 // Importing even a single cookie file is considered a success.
michael@0 374 if (aSuccess)
michael@0 375 success = true;
michael@0 376 try {
michael@0 377 cookiesGenerator.next();
michael@0 378 } catch (ex) {}
michael@0 379 });
michael@0 380
michael@0 381 yield undefined;
michael@0 382 }
michael@0 383
michael@0 384 CtypesHelpers.finalize();
michael@0 385
michael@0 386 aCallback(success);
michael@0 387 }).apply(this);
michael@0 388 cookiesGenerator.next();
michael@0 389 },
michael@0 390
michael@0 391 _readCookieFile: function C__readCookieFile(aFile, aCallback) {
michael@0 392 let fileReader = Cc["@mozilla.org/files/filereader;1"].
michael@0 393 createInstance(Ci.nsIDOMFileReader);
michael@0 394 fileReader.addEventListener("loadend", (function onLoadEnd() {
michael@0 395 fileReader.removeEventListener("loadend", onLoadEnd, false);
michael@0 396
michael@0 397 if (fileReader.readyState != fileReader.DONE) {
michael@0 398 Cu.reportError("Could not read cookie contents: " + fileReader.error);
michael@0 399 aCallback(false);
michael@0 400 return;
michael@0 401 }
michael@0 402
michael@0 403 let success = true;
michael@0 404 try {
michael@0 405 this._parseCookieBuffer(fileReader.result);
michael@0 406 } catch (ex) {
michael@0 407 Components.utils.reportError("Unable to migrate cookie: " + ex);
michael@0 408 success = false;
michael@0 409 } finally {
michael@0 410 aCallback(success);
michael@0 411 }
michael@0 412 }).bind(this), false);
michael@0 413 fileReader.readAsText(File(aFile));
michael@0 414 },
michael@0 415
michael@0 416 /**
michael@0 417 * Parses a cookie file buffer and returns an array of the contained cookies.
michael@0 418 *
michael@0 419 * The cookie file format is a newline-separated-values with a "*" used as
michael@0 420 * delimeter between multiple records.
michael@0 421 * Each cookie has the following fields:
michael@0 422 * - name
michael@0 423 * - value
michael@0 424 * - host/path
michael@0 425 * - flags
michael@0 426 * - Expiration time most significant integer
michael@0 427 * - Expiration time least significant integer
michael@0 428 * - Creation time most significant integer
michael@0 429 * - Creation time least significant integer
michael@0 430 * - Record delimiter "*"
michael@0 431 *
michael@0 432 * @note All the times are in FILETIME format.
michael@0 433 */
michael@0 434 _parseCookieBuffer: function C__parseCookieBuffer(aTextBuffer) {
michael@0 435 // Note the last record is an empty string.
michael@0 436 let records = [r for each (r in aTextBuffer.split("*\n")) if (r)];
michael@0 437 for (let record of records) {
michael@0 438 let [name, value, hostpath, flags,
michael@0 439 expireTimeLo, expireTimeHi] = record.split("\n");
michael@0 440
michael@0 441 // IE stores deleted cookies with a zero-length value, skip them.
michael@0 442 if (value.length == 0)
michael@0 443 continue;
michael@0 444
michael@0 445 let hostLen = hostpath.indexOf("/");
michael@0 446 let host = hostpath.substr(0, hostLen);
michael@0 447
michael@0 448 // For a non-null domain, assume it's what Mozilla considers
michael@0 449 // a domain cookie. See bug 222343.
michael@0 450 if (host.length > 0) {
michael@0 451 // Fist delete any possible extant matching host cookie.
michael@0 452 Services.cookies.remove(host, name, path, false);
michael@0 453 // Now make it a domain cookie.
michael@0 454 if (host[0] != "." && !hostIsIPAddress(host))
michael@0 455 host = "." + host;
michael@0 456 }
michael@0 457
michael@0 458 let path = hostpath.substr(hostLen);
michael@0 459 let expireTime = CtypesHelpers.fileTimeToDate(Number(expireTimeHi),
michael@0 460 Number(expireTimeLo));
michael@0 461 Services.cookies.add(host,
michael@0 462 path,
michael@0 463 name,
michael@0 464 value,
michael@0 465 Number(flags) & 0x1, // secure
michael@0 466 false, // httpOnly
michael@0 467 false, // session
michael@0 468 expireTime);
michael@0 469 }
michael@0 470 }
michael@0 471 };
michael@0 472
michael@0 473 function Settings() {
michael@0 474 }
michael@0 475
michael@0 476 Settings.prototype = {
michael@0 477 type: MigrationUtils.resourceTypes.SETTINGS,
michael@0 478
michael@0 479 get exists() true,
michael@0 480
michael@0 481 migrate: function S_migrate(aCallback) {
michael@0 482 // Converts from yes/no to a boolean.
michael@0 483 function yesNoToBoolean(v) v == "yes";
michael@0 484
michael@0 485 // Converts source format like "en-us,ar-kw;q=0.7,ar-om;q=0.3" into
michael@0 486 // destination format like "en-us, ar-kw, ar-om".
michael@0 487 // Final string is sorted by quality (q=) param.
michael@0 488 function parseAcceptLanguageList(v) {
michael@0 489 return v.match(/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/gi)
michael@0 490 .sort(function (a , b) {
michael@0 491 let qA = parseFloat(a.split(";q=")[1]) || 1.0;
michael@0 492 let qB = parseFloat(b.split(";q=")[1]) || 1.0;
michael@0 493 return qA < qB ? 1 : qA == qB ? 0 : -1;
michael@0 494 })
michael@0 495 .map(function(a) a.split(";")[0]);
michael@0 496 }
michael@0 497
michael@0 498 // For reference on some of the available IE Registry settings:
michael@0 499 // * http://msdn.microsoft.com/en-us/library/cc980058%28v=prot.13%29.aspx
michael@0 500 // * http://msdn.microsoft.com/en-us/library/cc980059%28v=prot.13%29.aspx
michael@0 501
michael@0 502 // Note that only settings exposed in our UI should be migrated.
michael@0 503
michael@0 504 this._set("Software\\Microsoft\\Internet Explorer\\International",
michael@0 505 "AcceptLanguage",
michael@0 506 "intl.accept_languages",
michael@0 507 parseAcceptLanguageList);
michael@0 508 // TODO (bug 745853): For now, only x-western font is translated.
michael@0 509 this._set("Software\\Microsoft\\Internet Explorer\\International\\Scripts\\3",
michael@0 510 "IEFixedFontName",
michael@0 511 "font.name.monospace.x-western");
michael@0 512 this._set(kMainKey,
michael@0 513 "Use FormSuggest",
michael@0 514 "browser.formfill.enable",
michael@0 515 yesNoToBoolean);
michael@0 516 this._set(kMainKey,
michael@0 517 "FormSuggest Passwords",
michael@0 518 "signon.rememberSignons",
michael@0 519 yesNoToBoolean);
michael@0 520 this._set(kMainKey,
michael@0 521 "Anchor Underline",
michael@0 522 "browser.underline_anchors",
michael@0 523 yesNoToBoolean);
michael@0 524 this._set(kMainKey,
michael@0 525 "Display Inline Images",
michael@0 526 "permissions.default.image",
michael@0 527 function (v) yesNoToBoolean(v) ? 1 : 2);
michael@0 528 this._set(kMainKey,
michael@0 529 "Move System Caret",
michael@0 530 "accessibility.browsewithcaret",
michael@0 531 yesNoToBoolean);
michael@0 532 this._set("Software\\Microsoft\\Internet Explorer\\Settings",
michael@0 533 "Always Use My Colors",
michael@0 534 "browser.display.use_document_colors",
michael@0 535 function (v) !Boolean(v));
michael@0 536 this._set("Software\\Microsoft\\Internet Explorer\\Settings",
michael@0 537 "Always Use My Font Face",
michael@0 538 "browser.display.use_document_fonts",
michael@0 539 function (v) !Boolean(v));
michael@0 540 this._set(kMainKey,
michael@0 541 "SmoothScroll",
michael@0 542 "general.smoothScroll",
michael@0 543 Boolean);
michael@0 544 this._set("Software\\Microsoft\\Internet Explorer\\TabbedBrowsing\\",
michael@0 545 "WarnOnClose",
michael@0 546 "browser.tabs.warnOnClose",
michael@0 547 Boolean);
michael@0 548 this._set("Software\\Microsoft\\Internet Explorer\\TabbedBrowsing\\",
michael@0 549 "OpenInForeground",
michael@0 550 "browser.tabs.loadInBackground",
michael@0 551 function (v) !Boolean(v));
michael@0 552
michael@0 553 aCallback(true);
michael@0 554 },
michael@0 555
michael@0 556 /**
michael@0 557 * Reads a setting from the Registry and stores the converted result into
michael@0 558 * the appropriate Firefox preference.
michael@0 559 *
michael@0 560 * @param aPath
michael@0 561 * Registry path under HKCU.
michael@0 562 * @param aKey
michael@0 563 * Name of the key.
michael@0 564 * @param aPref
michael@0 565 * Firefox preference.
michael@0 566 * @param [optional] aTransformFn
michael@0 567 * Conversion function from the Registry format to the pref format.
michael@0 568 */
michael@0 569 _set: function S__set(aPath, aKey, aPref, aTransformFn) {
michael@0 570 let value = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
michael@0 571 aPath, aKey);
michael@0 572 // Don't import settings that have never been flipped.
michael@0 573 if (value === undefined)
michael@0 574 return;
michael@0 575
michael@0 576 if (aTransformFn)
michael@0 577 value = aTransformFn(value);
michael@0 578
michael@0 579 switch (typeof(value)) {
michael@0 580 case "string":
michael@0 581 Services.prefs.setCharPref(aPref, value);
michael@0 582 break;
michael@0 583 case "number":
michael@0 584 Services.prefs.setIntPref(aPref, value);
michael@0 585 break;
michael@0 586 case "boolean":
michael@0 587 Services.prefs.setBoolPref(aPref, value);
michael@0 588 break;
michael@0 589 default:
michael@0 590 throw new Error("Unexpected value type: " + typeof(value));
michael@0 591 }
michael@0 592 }
michael@0 593 };
michael@0 594
michael@0 595 ////////////////////////////////////////////////////////////////////////////////
michael@0 596 //// Migrator
michael@0 597
michael@0 598 function IEProfileMigrator()
michael@0 599 {
michael@0 600 }
michael@0 601
michael@0 602 IEProfileMigrator.prototype = Object.create(MigratorPrototype);
michael@0 603
michael@0 604 IEProfileMigrator.prototype.getResources = function IE_getResources() {
michael@0 605 let resources = [
michael@0 606 new Bookmarks()
michael@0 607 , new History()
michael@0 608 , new Cookies()
michael@0 609 , new Settings()
michael@0 610 ];
michael@0 611 return [r for each (r in resources) if (r.exists)];
michael@0 612 };
michael@0 613
michael@0 614 Object.defineProperty(IEProfileMigrator.prototype, "sourceHomePageURL", {
michael@0 615 get: function IE_get_sourceHomePageURL() {
michael@0 616 let defaultStartPage = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
michael@0 617 kMainKey, "Default_Page_URL");
michael@0 618 let startPage = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
michael@0 619 kMainKey, "Start Page");
michael@0 620 // If the user didn't customize the Start Page, he is still on the default
michael@0 621 // page, that may be considered the equivalent of our about:home. There's
michael@0 622 // no reason to retain it, since it is heavily targeted to IE.
michael@0 623 let homepage = startPage != defaultStartPage ? startPage : "";
michael@0 624
michael@0 625 // IE7+ supports secondary home pages located in a REG_MULTI_SZ key. These
michael@0 626 // are in addition to the Start Page, and no empty entries are possible,
michael@0 627 // thus a Start Page is always defined if any of these exists, though it
michael@0 628 // may be the default one.
michael@0 629 let secondaryPages = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
michael@0 630 kMainKey, "Secondary Start Pages");
michael@0 631 if (secondaryPages) {
michael@0 632 if (homepage)
michael@0 633 secondaryPages.unshift(homepage);
michael@0 634 homepage = secondaryPages.join("|");
michael@0 635 }
michael@0 636
michael@0 637 return homepage;
michael@0 638 }
michael@0 639 });
michael@0 640
michael@0 641 IEProfileMigrator.prototype.classDescription = "IE Profile Migrator";
michael@0 642 IEProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=ie";
michael@0 643 IEProfileMigrator.prototype.classID = Components.ID("{3d2532e3-4932-4774-b7ba-968f5899d3a4}");
michael@0 644
michael@0 645 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([IEProfileMigrator]);

mercurial