browser/components/migration/src/SafariProfileMigrator.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
michael@0 3 * file, 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 let Cc = Components.classes;
michael@0 8 let Ci = Components.interfaces;
michael@0 9 let Cu = Components.utils;
michael@0 10
michael@0 11 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
michael@0 12 Cu.import("resource://gre/modules/FileUtils.jsm");
michael@0 13 Cu.import("resource://gre/modules/Services.jsm");
michael@0 14 Cu.import("resource:///modules/MigrationUtils.jsm");
michael@0 15
michael@0 16 XPCOMUtils.defineLazyModuleGetter(this, "PropertyListUtils",
michael@0 17 "resource://gre/modules/PropertyListUtils.jsm");
michael@0 18 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
michael@0 19 "resource://gre/modules/PlacesUtils.jsm");
michael@0 20 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
michael@0 21 "resource://gre/modules/NetUtil.jsm");
michael@0 22 XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
michael@0 23 "resource://gre/modules/FormHistory.jsm");
michael@0 24
michael@0 25 function Bookmarks(aBookmarksFile) {
michael@0 26 this._file = aBookmarksFile;
michael@0 27 }
michael@0 28 Bookmarks.prototype = {
michael@0 29 type: MigrationUtils.resourceTypes.BOOKMARKS,
michael@0 30
michael@0 31 migrate: function B_migrate(aCallback) {
michael@0 32 PropertyListUtils.read(this._file,
michael@0 33 MigrationUtils.wrapMigrateFunction(function migrateBookmarks(aDict) {
michael@0 34 if (!aDict)
michael@0 35 throw new Error("Could not read Bookmarks.plist");
michael@0 36
michael@0 37 let children = aDict.get("Children");;
michael@0 38 if (!children)
michael@0 39 throw new Error("Invalid Bookmarks.plist format");
michael@0 40
michael@0 41 PlacesUtils.bookmarks.runInBatchMode({
michael@0 42 runBatched: function() {
michael@0 43 let collection = aDict.get("Title") == "com.apple.ReadingList" ?
michael@0 44 this.READING_LIST_COLLECTION : this.ROOT_COLLECTION;
michael@0 45 this._migrateCollection(children, collection);
michael@0 46 }.bind(this)
michael@0 47 }, null);
michael@0 48 }.bind(this), aCallback));
michael@0 49 },
michael@0 50
michael@0 51 // Bookmarks collections in Safari. Constants for migrateCollection.
michael@0 52 ROOT_COLLECTION: 0,
michael@0 53 MENU_COLLECTION: 1,
michael@0 54 TOOLBAR_COLLECTION: 2,
michael@0 55 READING_LIST_COLLECTION: 3,
michael@0 56
michael@0 57 /**
michael@0 58 * Recursively migrate a Safari collection of bookmarks.
michael@0 59 *
michael@0 60 * @param aEntries
michael@0 61 * the collection's children
michael@0 62 * @param aCollection
michael@0 63 * one of the values above.
michael@0 64 */
michael@0 65 _migrateCollection: function B__migrateCollection(aEntries, aCollection) {
michael@0 66 // A collection of bookmarks in Safari resembles places roots. In the
michael@0 67 // property list files (Bookmarks.plist, ReadingList.plist) they are
michael@0 68 // stored as regular bookmarks folders, and thus can only be distinguished
michael@0 69 // from by their names and places in the hierarchy.
michael@0 70
michael@0 71 let entriesFiltered = [];
michael@0 72 if (aCollection == this.ROOT_COLLECTION) {
michael@0 73 for (let entry of aEntries) {
michael@0 74 let type = entry.get("WebBookmarkType");
michael@0 75 if (type == "WebBookmarkTypeList" && entry.has("Children")) {
michael@0 76 let title = entry.get("Title");
michael@0 77 let children = entry.get("Children");
michael@0 78 if (title == "BookmarksBar")
michael@0 79 this._migrateCollection(children, this.TOOLBAR_COLLECTION);
michael@0 80 else if (title == "BookmarksMenu")
michael@0 81 this._migrateCollection(children, this.MENU_COLLECTION);
michael@0 82 else if (title == "com.apple.ReadingList")
michael@0 83 this._migrateCollection(children, this.READING_LIST_COLLECTION);
michael@0 84 else if (entry.get("ShouldOmitFromUI") !== true)
michael@0 85 entriesFiltered.push(entry);
michael@0 86 }
michael@0 87 else if (type == "WebBookmarkTypeLeaf") {
michael@0 88 entriesFiltered.push(entry);
michael@0 89 }
michael@0 90 }
michael@0 91 }
michael@0 92 else {
michael@0 93 entriesFiltered = aEntries;
michael@0 94 }
michael@0 95
michael@0 96 if (entriesFiltered.length == 0)
michael@0 97 return;
michael@0 98
michael@0 99 let folder = -1;
michael@0 100 switch (aCollection) {
michael@0 101 case this.ROOT_COLLECTION: {
michael@0 102 // In Safari, it is possible (though quite cumbersome) to move
michael@0 103 // bookmarks to the bookmarks root, which is the parent folder of
michael@0 104 // all bookmarks "collections". That is somewhat in parallel with
michael@0 105 // both the places root and the unfiled-bookmarks root.
michael@0 106 // Because the former is only an implementation detail in our UI,
michael@0 107 // the unfiled root seems to be the best choice.
michael@0 108 folder = PlacesUtils.unfiledBookmarksFolderId;
michael@0 109 break;
michael@0 110 }
michael@0 111 case this.MENU_COLLECTION: {
michael@0 112 folder = PlacesUtils.bookmarksMenuFolderId;
michael@0 113 if (!MigrationUtils.isStartupMigration) {
michael@0 114 folder = MigrationUtils.createImportedBookmarksFolder("Safari",
michael@0 115 folder);
michael@0 116 }
michael@0 117 break;
michael@0 118 }
michael@0 119 case this.TOOLBAR_COLLECTION: {
michael@0 120 folder = PlacesUtils.toolbarFolderId;
michael@0 121 if (!MigrationUtils.isStartupMigration) {
michael@0 122 folder = MigrationUtils.createImportedBookmarksFolder("Safari",
michael@0 123 folder);
michael@0 124 }
michael@0 125 break;
michael@0 126 }
michael@0 127 case this.READING_LIST_COLLECTION: {
michael@0 128 // Reading list items are imported as regular bookmarks.
michael@0 129 // They are imported under their own folder, created either under the
michael@0 130 // bookmarks menu (in the case of startup migration).
michael@0 131 folder = PlacesUtils.bookmarks.createFolder(
michael@0 132 PlacesUtils.bookmarksMenuFolderId,
michael@0 133 MigrationUtils.getLocalizedString("importedSafariReadingList"),
michael@0 134 PlacesUtils.bookmarks.DEFAULT_INDEX);
michael@0 135 break;
michael@0 136 }
michael@0 137 default:
michael@0 138 throw new Error("Unexpected value for aCollection!");
michael@0 139 }
michael@0 140
michael@0 141 this._migrateEntries(entriesFiltered, folder);
michael@0 142 },
michael@0 143
michael@0 144 // migrate the given array of safari bookmarks to the given places
michael@0 145 // folder.
michael@0 146 _migrateEntries: function B__migrateEntries(aEntries, aFolderId) {
michael@0 147 for (let entry of aEntries) {
michael@0 148 let type = entry.get("WebBookmarkType");
michael@0 149 if (type == "WebBookmarkTypeList" && entry.has("Children")) {
michael@0 150 let title = entry.get("Title");
michael@0 151 let folderId = PlacesUtils.bookmarks.createFolder(
michael@0 152 aFolderId, title, PlacesUtils.bookmarks.DEFAULT_INDEX);
michael@0 153
michael@0 154 // Empty folders may not have a children array.
michael@0 155 if (entry.has("Children"))
michael@0 156 this._migrateEntries(entry.get("Children"), folderId, false);
michael@0 157 }
michael@0 158 else if (type == "WebBookmarkTypeLeaf" && entry.has("URLString")) {
michael@0 159 let title, uri;
michael@0 160 if (entry.has("URIDictionary"))
michael@0 161 title = entry.get("URIDictionary").get("title");
michael@0 162
michael@0 163 try {
michael@0 164 uri = NetUtil.newURI(entry.get("URLString"));
michael@0 165 }
michael@0 166 catch(ex) {
michael@0 167 Cu.reportError("Invalid uri set for Safari bookmark: " + entry.get("URLString"));
michael@0 168 }
michael@0 169 if (uri) {
michael@0 170 PlacesUtils.bookmarks.insertBookmark(aFolderId, uri,
michael@0 171 PlacesUtils.bookmarks.DEFAULT_INDEX, title);
michael@0 172 }
michael@0 173 }
michael@0 174 }
michael@0 175 }
michael@0 176 };
michael@0 177
michael@0 178 function History(aHistoryFile) {
michael@0 179 this._file = aHistoryFile;
michael@0 180 }
michael@0 181 History.prototype = {
michael@0 182 type: MigrationUtils.resourceTypes.HISTORY,
michael@0 183
michael@0 184 // Helper method for converting the visit date property to a PRTime value.
michael@0 185 // The visit date is stored as a string, so it's not read as a Date
michael@0 186 // object by PropertyListUtils.
michael@0 187 _parseCocoaDate: function H___parseCocoaDate(aCocoaDateStr) {
michael@0 188 let asDouble = parseFloat(aCocoaDateStr);
michael@0 189 if (!isNaN(asDouble)) {
michael@0 190 // reference date of NSDate.
michael@0 191 let date = new Date("1 January 2001, GMT");
michael@0 192 date.setMilliseconds(asDouble * 1000);
michael@0 193 return date * 1000;
michael@0 194 }
michael@0 195 return 0;
michael@0 196 },
michael@0 197
michael@0 198 migrate: function H_migrate(aCallback) {
michael@0 199 PropertyListUtils.read(this._file, function migrateHistory(aDict) {
michael@0 200 try {
michael@0 201 if (!aDict)
michael@0 202 throw new Error("Could not read history property list");
michael@0 203 if (!aDict.has("WebHistoryDates"))
michael@0 204 throw new Error("Unexpected history-property list format");
michael@0 205
michael@0 206 // Safari's History file contains only top-level urls. It does not
michael@0 207 // distinguish between typed urls and linked urls.
michael@0 208 let transType = PlacesUtils.history.TRANSITION_LINK;
michael@0 209
michael@0 210 let places = [];
michael@0 211 let entries = aDict.get("WebHistoryDates");
michael@0 212 for (let entry of entries) {
michael@0 213 if (entry.has("lastVisitedDate")) {
michael@0 214 let visitDate = this._parseCocoaDate(entry.get("lastVisitedDate"));
michael@0 215 try {
michael@0 216 places.push({ uri: NetUtil.newURI(entry.get("")),
michael@0 217 title: entry.get("title"),
michael@0 218 visits: [{ transitionType: transType,
michael@0 219 visitDate: visitDate }] });
michael@0 220 }
michael@0 221 catch(ex) {
michael@0 222 // Safari's History file may contain malformed URIs which
michael@0 223 // will be ignored.
michael@0 224 Cu.reportError(ex)
michael@0 225 }
michael@0 226 }
michael@0 227 }
michael@0 228 if (places.length > 0) {
michael@0 229 PlacesUtils.asyncHistory.updatePlaces(places, {
michael@0 230 _success: false,
michael@0 231 handleResult: function() {
michael@0 232 // Importing any entry is considered a successful import.
michael@0 233 this._success = true;
michael@0 234 },
michael@0 235 handleError: function() {},
michael@0 236 handleCompletion: function() {
michael@0 237 aCallback(this._success);
michael@0 238 }
michael@0 239 });
michael@0 240 }
michael@0 241 else {
michael@0 242 aCallback(false);
michael@0 243 }
michael@0 244 }
michael@0 245 catch(ex) {
michael@0 246 Cu.reportError(ex);
michael@0 247 aCallback(false);
michael@0 248 }
michael@0 249 }.bind(this));
michael@0 250 }
michael@0 251 };
michael@0 252
michael@0 253 /**
michael@0 254 * Safari's preferences property list is independently used for three purposes:
michael@0 255 * (a) importation of preferences
michael@0 256 * (b) importation of search strings
michael@0 257 * (c) retrieving the home page.
michael@0 258 *
michael@0 259 * So, rather than reading it three times, it's cached and managed here.
michael@0 260 */
michael@0 261 function MainPreferencesPropertyList(aPreferencesFile) {
michael@0 262 this._file = aPreferencesFile;
michael@0 263 this._callbacks = [];
michael@0 264 }
michael@0 265 MainPreferencesPropertyList.prototype = {
michael@0 266 /**
michael@0 267 * @see PropertyListUtils.read
michael@0 268 */
michael@0 269 read: function MPPL_read(aCallback) {
michael@0 270 if ("_dict" in this) {
michael@0 271 aCallback(this._dict);
michael@0 272 return;
michael@0 273 }
michael@0 274
michael@0 275 let alreadyReading = this._callbacks.length > 0;
michael@0 276 this._callbacks.push(aCallback);
michael@0 277 if (!alreadyReading) {
michael@0 278 PropertyListUtils.read(this._file, function readPrefs(aDict) {
michael@0 279 this._dict = aDict;
michael@0 280 for (let callback of this._callbacks) {
michael@0 281 try {
michael@0 282 callback(aDict);
michael@0 283 }
michael@0 284 catch(ex) {
michael@0 285 Cu.reportError(ex);
michael@0 286 }
michael@0 287 }
michael@0 288 this._callbacks.splice(0);
michael@0 289 }.bind(this));
michael@0 290 }
michael@0 291 },
michael@0 292
michael@0 293 // Workaround for nsIBrowserProfileMigrator.sourceHomePageURL until
michael@0 294 // it's replaced with an async method.
michael@0 295 _readSync: function MPPL__readSync() {
michael@0 296 if ("_dict" in this)
michael@0 297 return this._dict;
michael@0 298
michael@0 299 let inputStream = Cc["@mozilla.org/network/file-input-stream;1"].
michael@0 300 createInstance(Ci.nsIFileInputStream);
michael@0 301 inputStream.init(this._file, -1, -1, 0);
michael@0 302 let binaryStream = Cc["@mozilla.org/binaryinputstream;1"].
michael@0 303 createInstance(Ci.nsIBinaryInputStream);
michael@0 304 binaryStream.setInputStream(inputStream);
michael@0 305 let bytes = binaryStream.readByteArray(inputStream.available());
michael@0 306 this._dict = PropertyListUtils._readFromArrayBufferSync(
michael@0 307 new Uint8Array(bytes).buffer);
michael@0 308 return this._dict;
michael@0 309 }
michael@0 310 };
michael@0 311
michael@0 312 function Preferences(aMainPreferencesPropertyListInstance) {
michael@0 313 this._mainPreferencesPropertyList = aMainPreferencesPropertyListInstance;
michael@0 314 }
michael@0 315 Preferences.prototype = {
michael@0 316 type: MigrationUtils.resourceTypes.SETTINGS,
michael@0 317
michael@0 318 migrate: function MPR_migrate(aCallback) {
michael@0 319 this._mainPreferencesPropertyList.read(
michael@0 320 MigrationUtils.wrapMigrateFunction(function migratePrefs(aDict) {
michael@0 321 if (!aDict)
michael@0 322 throw new Error("Could not read preferences file");
michael@0 323
michael@0 324 this._dict = aDict;
michael@0 325
michael@0 326 let invert = function(webkitVal) !webkitVal;
michael@0 327 this._set("AutoFillPasswords", "signon.rememberSignons");
michael@0 328 this._set("OpenNewTabsInFront", "browser.tabs.loadInBackground", invert);
michael@0 329 this._set("WebKitJavaScriptCanOpenWindowsAutomatically",
michael@0 330 "dom.disable_open_during_load", invert);
michael@0 331
michael@0 332 // layout.spellcheckDefault is a boolean stored as a number.
michael@0 333 this._set("WebContinuousSpellCheckingEnabled",
michael@0 334 "layout.spellcheckDefault", Number);
michael@0 335
michael@0 336 // Auto-load images
michael@0 337 // Firefox has an elaborate set of Image preferences. The correlation is:
michael@0 338 // Mode: Safari Firefox
michael@0 339 // Blocked FALSE 2
michael@0 340 // Allowed TRUE 1
michael@0 341 // Allowed, originating site only -- 3
michael@0 342 this._set("WebKitDisplayImagesKey", "permissions.default.image",
michael@0 343 function(webkitVal) webkitVal ? 1 : 2);
michael@0 344
michael@0 345 #ifdef XP_WIN
michael@0 346 // Cookie-accept policy.
michael@0 347 // For the OS X version, see WebFoundationCookieBehavior.
michael@0 348 // Setting Safari Firefox
michael@0 349 // Always Accept 0 0
michael@0 350 // Accept from Originating 2 1
michael@0 351 // Never Accept 1 2
michael@0 352 this._set("WebKitCookieStorageAcceptPolicy",
michael@0 353 "network.cookie.cookieBehavior",
michael@0 354 function(webkitVal) webkitVal == 0 ? 0 : webkitVal == 1 ? 2 : 1);
michael@0 355 #endif
michael@0 356
michael@0 357 this._migrateFontSettings();
michael@0 358 this._migrateDownloadsFolder();
michael@0 359 }.bind(this), aCallback));
michael@0 360 },
michael@0 361
michael@0 362 /**
michael@0 363 * Attempts to migrates a preference from Safari. Returns whether the preference
michael@0 364 * has been migrated.
michael@0 365 * @param aSafariKey
michael@0 366 * The dictionary key for the preference of Safari.
michael@0 367 * @param aMozPref
michael@0 368 * The gecko/firefox preference to which aSafariKey should be migrated
michael@0 369 * @param [optional] aConvertFunction(aSafariValue)
michael@0 370 * a function that converts the safari-preference value to the
michael@0 371 * appropriate value for aMozPref. If it's not passed, then the
michael@0 372 * Safari value is set as is.
michael@0 373 * If aConvertFunction returns undefined, then aMozPref is not set
michael@0 374 * at all.
michael@0 375 * @return whether or not aMozPref was set.
michael@0 376 */
michael@0 377 _set: function MPR_set(aSafariKey, aMozPref, aConvertFunction) {
michael@0 378 if (this._dict.has(aSafariKey)) {
michael@0 379 let safariVal = this._dict.get(aSafariKey);
michael@0 380 let mozVal = aConvertFunction !== undefined ?
michael@0 381 aConvertFunction(safariVal) : safariVal;
michael@0 382 switch (typeof(mozVal)) {
michael@0 383 case "string":
michael@0 384 Services.prefs.setCharPref(aMozPref, mozVal);
michael@0 385 break;
michael@0 386 case "number":
michael@0 387 Services.prefs.setIntPref(aMozPref, mozVal);
michael@0 388 break;
michael@0 389 case "boolean":
michael@0 390 Services.prefs.setBoolPref(aMozPref, mozVal);
michael@0 391 break;
michael@0 392 case "undefined":
michael@0 393 return false;
michael@0 394 default:
michael@0 395 throw new Error("Unexpected value type: " + typeof(mozVal));
michael@0 396 }
michael@0 397 }
michael@0 398 return true;
michael@0 399 },
michael@0 400
michael@0 401 // Fonts settings are quite problematic for migration, for a couple of
michael@0 402 // reasons:
michael@0 403 // (a) Every font preference in Gecko is set for a particular language.
michael@0 404 // In Safari, each font preference applies to all languages.
michael@0 405 // (b) The current underlying implementation of nsIFontEnumerator cannot
michael@0 406 // really tell you anything about a font: no matter what language or type
michael@0 407 // you try to enumerate with EnumerateFonts, you get an array of all
michael@0 408 // fonts in the systems (This also breaks our fonts dialog).
michael@0 409 // (c) In Gecko, each langauge has a distinct serif and sans-serif font
michael@0 410 // preference. Safari has only one default font setting. It seems that
michael@0 411 // it checks if it's a serif or sans serif font, and when a site
michael@0 412 // explicitly asks to use serif/sans-serif font, it uses the default font
michael@0 413 // only if it applies to this type.
michael@0 414 // (d) The solution of guessing the lang-group out of the default charset (as
michael@0 415 // done in the old Safari migrator) can only work when:
michael@0 416 // (1) The default charset preference is set.
michael@0 417 // (2) It's not a unicode charset.
michael@0 418 // For now, we use the language implied by the system locale as the
michael@0 419 // lang-group. The only exception is minimal font size, which is an
michael@0 420 // accessibility preference in Safari (under the Advanced tab). If it is set,
michael@0 421 // we set it for all languages.
michael@0 422 // As for the font type of the default font (serif/sans-serif), the default
michael@0 423 // type for the given language is used (set in font.default.LANGGROUP).
michael@0 424 _migrateFontSettings: function MPR__migrateFontSettings() {
michael@0 425 // If "Never use font sizes smaller than [ ] is set", migrate it for all
michael@0 426 // languages.
michael@0 427 if (this._dict.has("WebKitMinimumFontSize")) {
michael@0 428 let minimumSize = this._dict.get("WebKitMinimumFontSize");
michael@0 429 if (typeof(minimumSize) == "number") {
michael@0 430 let prefs = Services.prefs.getChildList("font.minimum-size");
michael@0 431 for (let pref of prefs) {
michael@0 432 Services.prefs.setIntPref(pref, minimumSize);
michael@0 433 }
michael@0 434 }
michael@0 435 else {
michael@0 436 Cu.reportError("WebKitMinimumFontSize was set to an invalid value: " +
michael@0 437 minimumSize);
michael@0 438 }
michael@0 439 }
michael@0 440
michael@0 441 // In theory, the lang group could be "x-unicode". This will result
michael@0 442 // in setting the fonts for "Other Languages".
michael@0 443 let lang = this._getLocaleLangGroup();
michael@0 444
michael@0 445 let anySet = false;
michael@0 446 let fontType = Services.prefs.getCharPref("font.default." + lang);
michael@0 447 anySet |= this._set("WebKitFixedFont", "font.name.monospace." + lang);
michael@0 448 anySet |= this._set("WebKitDefaultFixedFontSize", "font.size.fixed." + lang);
michael@0 449 anySet |= this._set("WebKitStandardFont",
michael@0 450 "font.name." + fontType + "." + lang);
michael@0 451 anySet |= this._set("WebKitDefaultFontSize", "font.size.variable." + lang);
michael@0 452
michael@0 453 // If we set font settings for a particular language, we'll also set the
michael@0 454 // fonts dialog to open with the fonts settings for that langauge.
michael@0 455 if (anySet)
michael@0 456 Services.prefs.setCharPref("font.language.group", lang);
michael@0 457 },
michael@0 458
michael@0 459 // Get the language group for the system locale.
michael@0 460 _getLocaleLangGroup: function MPR__getLocaleLangGroup() {
michael@0 461 let locale = Services.locale.getLocaleComponentForUserAgent();
michael@0 462
michael@0 463 // See nsLanguageAtomService::GetLanguageGroup
michael@0 464 let localeLangGroup = "x-unicode";
michael@0 465 let bundle = Services.strings.createBundle(
michael@0 466 "resource://gre/res/langGroups.properties");
michael@0 467 try {
michael@0 468 localeLangGroup = bundle.GetStringFromName(locale);
michael@0 469 }
michael@0 470 catch(ex) {
michael@0 471 let hyphenAt = locale.indexOf("-");
michael@0 472 if (hyphenAt != -1) {
michael@0 473 try {
michael@0 474 localeLangGroup = bundle.GetStringFromName(locale.substr(0, hyphenAt));
michael@0 475 }
michael@0 476 catch(ex2) { }
michael@0 477 }
michael@0 478 }
michael@0 479 return localeLangGroup;
michael@0 480 },
michael@0 481
michael@0 482 _migrateDownloadsFolder: function MPR__migrateDownloadsFolder() {
michael@0 483 // Windows Safari uses DownloadPath while Mac uses DownloadsPath.
michael@0 484 // Check both for future compatibility.
michael@0 485 let key;
michael@0 486 if (this._dict.has("DownloadsPath"))
michael@0 487 key = "DownloadsPath";
michael@0 488 else if (this._dict.has("DownloadPath"))
michael@0 489 key = "DownloadPath";
michael@0 490 else
michael@0 491 return;
michael@0 492
michael@0 493 let downloadsFolder = FileUtils.File(this._dict.get(key));
michael@0 494
michael@0 495 // If the download folder is set to the Desktop or to ~/Downloads, set the
michael@0 496 // folderList pref appropriately so that "Desktop"/Downloads is shown with
michael@0 497 // pretty name in the preferences dialog.
michael@0 498 let folderListVal = 2;
michael@0 499 if (downloadsFolder.equals(FileUtils.getDir("Desk", []))) {
michael@0 500 folderListVal = 0;
michael@0 501 }
michael@0 502 else {
michael@0 503 let dnldMgr = Cc["@mozilla.org/download-manager;1"].
michael@0 504 getService(Ci.nsIDownloadManager);
michael@0 505 if (downloadsFolder.equals(dnldMgr.defaultDownloadsDirectory))
michael@0 506 folderListVal = 1;
michael@0 507 }
michael@0 508 Services.prefs.setIntPref("browser.download.folderList", folderListVal);
michael@0 509 Services.prefs.setComplexValue("browser.download.dir", Ci.nsILocalFile,
michael@0 510 downloadsFolder);
michael@0 511 }
michael@0 512 };
michael@0 513
michael@0 514 function SearchStrings(aMainPreferencesPropertyListInstance) {
michael@0 515 this._mainPreferencesPropertyList = aMainPreferencesPropertyListInstance;
michael@0 516 }
michael@0 517 SearchStrings.prototype = {
michael@0 518 type: MigrationUtils.resourceTypes.OTHERDATA,
michael@0 519
michael@0 520 migrate: function SS_migrate(aCallback) {
michael@0 521 this._mainPreferencesPropertyList.read(MigrationUtils.wrapMigrateFunction(
michael@0 522 function migrateSearchStrings(aDict) {
michael@0 523 if (!aDict)
michael@0 524 throw new Error("Could not get preferences dictionary");
michael@0 525
michael@0 526 if (aDict.has("RecentSearchStrings")) {
michael@0 527 let recentSearchStrings = aDict.get("RecentSearchStrings");
michael@0 528 if (recentSearchStrings && recentSearchStrings.length > 0) {
michael@0 529 let changes = [{op: "add",
michael@0 530 fieldname: "searchbar-history",
michael@0 531 value: searchString}
michael@0 532 for (searchString of recentSearchStrings)];
michael@0 533 FormHistory.update(changes);
michael@0 534 }
michael@0 535 }
michael@0 536 }.bind(this), aCallback));
michael@0 537 }
michael@0 538 };
michael@0 539
michael@0 540 #ifdef XP_MACOSX
michael@0 541 // On OS X, the cookie-accept policy preference is stored in a separate
michael@0 542 // property list.
michael@0 543 // For the Windows version, check Preferences.migrate.
michael@0 544 function WebFoundationCookieBehavior(aWebFoundationFile) {
michael@0 545 this._file = aWebFoundationFile;
michael@0 546 }
michael@0 547 WebFoundationCookieBehavior.prototype = {
michael@0 548 type: MigrationUtils.resourceTypes.SETTINGS,
michael@0 549
michael@0 550 migrate: function WFPL_migrate(aCallback) {
michael@0 551 PropertyListUtils.read(this._file, MigrationUtils.wrapMigrateFunction(
michael@0 552 function migrateCookieBehavior(aDict) {
michael@0 553 if (!aDict)
michael@0 554 throw new Error("Could not read com.apple.WebFoundation.plist");
michael@0 555
michael@0 556 if (aDict.has("NSHTTPAcceptCookies")) {
michael@0 557 // Setting Safari Firefox
michael@0 558 // Always Accept always 0
michael@0 559 // Accept from Originating current page 1
michael@0 560 // Never Accept never 2
michael@0 561 let acceptCookies = aDict.get("NSHTTPAcceptCookies");
michael@0 562 let cookieValue = acceptCookies == "never" ? 2 :
michael@0 563 acceptCookies == "current page" ? 1 : 0;
michael@0 564 Services.prefs.setIntPref("network.cookie.cookieBehavior",
michael@0 565 cookieValue);
michael@0 566 }
michael@0 567 }.bind(this), aCallback));
michael@0 568 }
michael@0 569 };
michael@0 570 #endif
michael@0 571
michael@0 572 function SafariProfileMigrator() {
michael@0 573 }
michael@0 574
michael@0 575 SafariProfileMigrator.prototype = Object.create(MigratorPrototype);
michael@0 576
michael@0 577 SafariProfileMigrator.prototype.getResources = function SM_getResources() {
michael@0 578 let profileDir =
michael@0 579 #ifdef XP_MACOSX
michael@0 580 FileUtils.getDir("ULibDir", ["Safari"], false);
michael@0 581 #else
michael@0 582 FileUtils.getDir("AppData", ["Apple Computer", "Safari"], false);
michael@0 583 #endif
michael@0 584 if (!profileDir.exists())
michael@0 585 return null;
michael@0 586
michael@0 587 let resources = [];
michael@0 588 let pushProfileFileResource = function(aFileName, aConstructor) {
michael@0 589 let file = profileDir.clone();
michael@0 590 file.append(aFileName);
michael@0 591 if (file.exists())
michael@0 592 resources.push(new aConstructor(file));
michael@0 593 };
michael@0 594
michael@0 595 pushProfileFileResource("History.plist", History);
michael@0 596 pushProfileFileResource("Bookmarks.plist", Bookmarks);
michael@0 597
michael@0 598 // The Reading List feature was introduced at the same time in Windows and
michael@0 599 // Mac versions of Safari. Not surprisingly, they are stored in the same
michael@0 600 // format in both versions. Surpsingly, only on Windows there is a
michael@0 601 // separate property list for it. This isn't #ifdefed out on mac, because
michael@0 602 // Apple may fix this at some point.
michael@0 603 pushProfileFileResource("ReadingList.plist", Bookmarks);
michael@0 604
michael@0 605 let prefsDir =
michael@0 606 #ifdef XP_MACOSX
michael@0 607 FileUtils.getDir("UsrPrfs", [], false);
michael@0 608 #else
michael@0 609 FileUtils.getDir("AppData", ["Apple Computer", "Preferences"], false);
michael@0 610 #endif
michael@0 611
michael@0 612 let prefs = this.mainPreferencesPropertyList;
michael@0 613 if (prefs) {
michael@0 614 resources.push(new Preferences(prefs));
michael@0 615 resources.push(new SearchStrings(prefs));
michael@0 616 }
michael@0 617
michael@0 618 #ifdef XP_MACOSX
michael@0 619 // On OS X, the cookie-accept policy preference is stored in a separate
michael@0 620 // property list.
michael@0 621 let wfFile = FileUtils.getFile("UsrPrfs", ["com.apple.WebFoundation.plist"]);
michael@0 622 if (wfFile.exists())
michael@0 623 resources.push(new WebFoundationCookieBehavior(wfFile));
michael@0 624 #endif
michael@0 625
michael@0 626 return resources;
michael@0 627 };
michael@0 628
michael@0 629 Object.defineProperty(SafariProfileMigrator.prototype, "mainPreferencesPropertyList", {
michael@0 630 get: function get_mainPreferencesPropertyList() {
michael@0 631 if (this._mainPreferencesPropertyList === undefined) {
michael@0 632 let file =
michael@0 633 #ifdef XP_MACOSX
michael@0 634 FileUtils.getDir("UsrPrfs", [], false);
michael@0 635 #else
michael@0 636 FileUtils.getDir("AppData", ["Apple Computer", "Preferences"], false);
michael@0 637 #endif
michael@0 638 if (file.exists()) {
michael@0 639 file.append("com.apple.Safari.plist");
michael@0 640 if (file.exists()) {
michael@0 641 return this._mainPreferencesPropertyList =
michael@0 642 new MainPreferencesPropertyList(file);
michael@0 643 }
michael@0 644 }
michael@0 645 return this._mainPreferencesPropertyList = null;
michael@0 646 }
michael@0 647 return this._mainPreferencesPropertyList;
michael@0 648 }
michael@0 649 });
michael@0 650
michael@0 651 Object.defineProperty(SafariProfileMigrator.prototype, "sourceHomePageURL", {
michael@0 652 get: function get_sourceHomePageURL() {
michael@0 653 if (this.mainPreferencesPropertyList) {
michael@0 654 let dict = this.mainPreferencesPropertyList._readSync();
michael@0 655 if (dict.has("HomePage"))
michael@0 656 return dict.get("HomePage");
michael@0 657 }
michael@0 658 return "";
michael@0 659 }
michael@0 660 });
michael@0 661
michael@0 662 SafariProfileMigrator.prototype.classDescription = "Safari Profile Migrator";
michael@0 663 SafariProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=safari";
michael@0 664 SafariProfileMigrator.prototype.classID = Components.ID("{4b609ecf-60b2-4655-9df4-dc149e474da1}");
michael@0 665
michael@0 666 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SafariProfileMigrator]);

mercurial