1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/components/migration/src/SafariProfileMigrator.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,666 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +let Cc = Components.classes; 1.11 +let Ci = Components.interfaces; 1.12 +let Cu = Components.utils; 1.13 + 1.14 +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 1.15 +Cu.import("resource://gre/modules/FileUtils.jsm"); 1.16 +Cu.import("resource://gre/modules/Services.jsm"); 1.17 +Cu.import("resource:///modules/MigrationUtils.jsm"); 1.18 + 1.19 +XPCOMUtils.defineLazyModuleGetter(this, "PropertyListUtils", 1.20 + "resource://gre/modules/PropertyListUtils.jsm"); 1.21 +XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", 1.22 + "resource://gre/modules/PlacesUtils.jsm"); 1.23 +XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", 1.24 + "resource://gre/modules/NetUtil.jsm"); 1.25 +XPCOMUtils.defineLazyModuleGetter(this, "FormHistory", 1.26 + "resource://gre/modules/FormHistory.jsm"); 1.27 + 1.28 +function Bookmarks(aBookmarksFile) { 1.29 + this._file = aBookmarksFile; 1.30 +} 1.31 +Bookmarks.prototype = { 1.32 + type: MigrationUtils.resourceTypes.BOOKMARKS, 1.33 + 1.34 + migrate: function B_migrate(aCallback) { 1.35 + PropertyListUtils.read(this._file, 1.36 + MigrationUtils.wrapMigrateFunction(function migrateBookmarks(aDict) { 1.37 + if (!aDict) 1.38 + throw new Error("Could not read Bookmarks.plist"); 1.39 + 1.40 + let children = aDict.get("Children");; 1.41 + if (!children) 1.42 + throw new Error("Invalid Bookmarks.plist format"); 1.43 + 1.44 + PlacesUtils.bookmarks.runInBatchMode({ 1.45 + runBatched: function() { 1.46 + let collection = aDict.get("Title") == "com.apple.ReadingList" ? 1.47 + this.READING_LIST_COLLECTION : this.ROOT_COLLECTION; 1.48 + this._migrateCollection(children, collection); 1.49 + }.bind(this) 1.50 + }, null); 1.51 + }.bind(this), aCallback)); 1.52 + }, 1.53 + 1.54 + // Bookmarks collections in Safari. Constants for migrateCollection. 1.55 + ROOT_COLLECTION: 0, 1.56 + MENU_COLLECTION: 1, 1.57 + TOOLBAR_COLLECTION: 2, 1.58 + READING_LIST_COLLECTION: 3, 1.59 + 1.60 + /** 1.61 + * Recursively migrate a Safari collection of bookmarks. 1.62 + * 1.63 + * @param aEntries 1.64 + * the collection's children 1.65 + * @param aCollection 1.66 + * one of the values above. 1.67 + */ 1.68 + _migrateCollection: function B__migrateCollection(aEntries, aCollection) { 1.69 + // A collection of bookmarks in Safari resembles places roots. In the 1.70 + // property list files (Bookmarks.plist, ReadingList.plist) they are 1.71 + // stored as regular bookmarks folders, and thus can only be distinguished 1.72 + // from by their names and places in the hierarchy. 1.73 + 1.74 + let entriesFiltered = []; 1.75 + if (aCollection == this.ROOT_COLLECTION) { 1.76 + for (let entry of aEntries) { 1.77 + let type = entry.get("WebBookmarkType"); 1.78 + if (type == "WebBookmarkTypeList" && entry.has("Children")) { 1.79 + let title = entry.get("Title"); 1.80 + let children = entry.get("Children"); 1.81 + if (title == "BookmarksBar") 1.82 + this._migrateCollection(children, this.TOOLBAR_COLLECTION); 1.83 + else if (title == "BookmarksMenu") 1.84 + this._migrateCollection(children, this.MENU_COLLECTION); 1.85 + else if (title == "com.apple.ReadingList") 1.86 + this._migrateCollection(children, this.READING_LIST_COLLECTION); 1.87 + else if (entry.get("ShouldOmitFromUI") !== true) 1.88 + entriesFiltered.push(entry); 1.89 + } 1.90 + else if (type == "WebBookmarkTypeLeaf") { 1.91 + entriesFiltered.push(entry); 1.92 + } 1.93 + } 1.94 + } 1.95 + else { 1.96 + entriesFiltered = aEntries; 1.97 + } 1.98 + 1.99 + if (entriesFiltered.length == 0) 1.100 + return; 1.101 + 1.102 + let folder = -1; 1.103 + switch (aCollection) { 1.104 + case this.ROOT_COLLECTION: { 1.105 + // In Safari, it is possible (though quite cumbersome) to move 1.106 + // bookmarks to the bookmarks root, which is the parent folder of 1.107 + // all bookmarks "collections". That is somewhat in parallel with 1.108 + // both the places root and the unfiled-bookmarks root. 1.109 + // Because the former is only an implementation detail in our UI, 1.110 + // the unfiled root seems to be the best choice. 1.111 + folder = PlacesUtils.unfiledBookmarksFolderId; 1.112 + break; 1.113 + } 1.114 + case this.MENU_COLLECTION: { 1.115 + folder = PlacesUtils.bookmarksMenuFolderId; 1.116 + if (!MigrationUtils.isStartupMigration) { 1.117 + folder = MigrationUtils.createImportedBookmarksFolder("Safari", 1.118 + folder); 1.119 + } 1.120 + break; 1.121 + } 1.122 + case this.TOOLBAR_COLLECTION: { 1.123 + folder = PlacesUtils.toolbarFolderId; 1.124 + if (!MigrationUtils.isStartupMigration) { 1.125 + folder = MigrationUtils.createImportedBookmarksFolder("Safari", 1.126 + folder); 1.127 + } 1.128 + break; 1.129 + } 1.130 + case this.READING_LIST_COLLECTION: { 1.131 + // Reading list items are imported as regular bookmarks. 1.132 + // They are imported under their own folder, created either under the 1.133 + // bookmarks menu (in the case of startup migration). 1.134 + folder = PlacesUtils.bookmarks.createFolder( 1.135 + PlacesUtils.bookmarksMenuFolderId, 1.136 + MigrationUtils.getLocalizedString("importedSafariReadingList"), 1.137 + PlacesUtils.bookmarks.DEFAULT_INDEX); 1.138 + break; 1.139 + } 1.140 + default: 1.141 + throw new Error("Unexpected value for aCollection!"); 1.142 + } 1.143 + 1.144 + this._migrateEntries(entriesFiltered, folder); 1.145 + }, 1.146 + 1.147 + // migrate the given array of safari bookmarks to the given places 1.148 + // folder. 1.149 + _migrateEntries: function B__migrateEntries(aEntries, aFolderId) { 1.150 + for (let entry of aEntries) { 1.151 + let type = entry.get("WebBookmarkType"); 1.152 + if (type == "WebBookmarkTypeList" && entry.has("Children")) { 1.153 + let title = entry.get("Title"); 1.154 + let folderId = PlacesUtils.bookmarks.createFolder( 1.155 + aFolderId, title, PlacesUtils.bookmarks.DEFAULT_INDEX); 1.156 + 1.157 + // Empty folders may not have a children array. 1.158 + if (entry.has("Children")) 1.159 + this._migrateEntries(entry.get("Children"), folderId, false); 1.160 + } 1.161 + else if (type == "WebBookmarkTypeLeaf" && entry.has("URLString")) { 1.162 + let title, uri; 1.163 + if (entry.has("URIDictionary")) 1.164 + title = entry.get("URIDictionary").get("title"); 1.165 + 1.166 + try { 1.167 + uri = NetUtil.newURI(entry.get("URLString")); 1.168 + } 1.169 + catch(ex) { 1.170 + Cu.reportError("Invalid uri set for Safari bookmark: " + entry.get("URLString")); 1.171 + } 1.172 + if (uri) { 1.173 + PlacesUtils.bookmarks.insertBookmark(aFolderId, uri, 1.174 + PlacesUtils.bookmarks.DEFAULT_INDEX, title); 1.175 + } 1.176 + } 1.177 + } 1.178 + } 1.179 +}; 1.180 + 1.181 +function History(aHistoryFile) { 1.182 + this._file = aHistoryFile; 1.183 +} 1.184 +History.prototype = { 1.185 + type: MigrationUtils.resourceTypes.HISTORY, 1.186 + 1.187 + // Helper method for converting the visit date property to a PRTime value. 1.188 + // The visit date is stored as a string, so it's not read as a Date 1.189 + // object by PropertyListUtils. 1.190 + _parseCocoaDate: function H___parseCocoaDate(aCocoaDateStr) { 1.191 + let asDouble = parseFloat(aCocoaDateStr); 1.192 + if (!isNaN(asDouble)) { 1.193 + // reference date of NSDate. 1.194 + let date = new Date("1 January 2001, GMT"); 1.195 + date.setMilliseconds(asDouble * 1000); 1.196 + return date * 1000; 1.197 + } 1.198 + return 0; 1.199 + }, 1.200 + 1.201 + migrate: function H_migrate(aCallback) { 1.202 + PropertyListUtils.read(this._file, function migrateHistory(aDict) { 1.203 + try { 1.204 + if (!aDict) 1.205 + throw new Error("Could not read history property list"); 1.206 + if (!aDict.has("WebHistoryDates")) 1.207 + throw new Error("Unexpected history-property list format"); 1.208 + 1.209 + // Safari's History file contains only top-level urls. It does not 1.210 + // distinguish between typed urls and linked urls. 1.211 + let transType = PlacesUtils.history.TRANSITION_LINK; 1.212 + 1.213 + let places = []; 1.214 + let entries = aDict.get("WebHistoryDates"); 1.215 + for (let entry of entries) { 1.216 + if (entry.has("lastVisitedDate")) { 1.217 + let visitDate = this._parseCocoaDate(entry.get("lastVisitedDate")); 1.218 + try { 1.219 + places.push({ uri: NetUtil.newURI(entry.get("")), 1.220 + title: entry.get("title"), 1.221 + visits: [{ transitionType: transType, 1.222 + visitDate: visitDate }] }); 1.223 + } 1.224 + catch(ex) { 1.225 + // Safari's History file may contain malformed URIs which 1.226 + // will be ignored. 1.227 + Cu.reportError(ex) 1.228 + } 1.229 + } 1.230 + } 1.231 + if (places.length > 0) { 1.232 + PlacesUtils.asyncHistory.updatePlaces(places, { 1.233 + _success: false, 1.234 + handleResult: function() { 1.235 + // Importing any entry is considered a successful import. 1.236 + this._success = true; 1.237 + }, 1.238 + handleError: function() {}, 1.239 + handleCompletion: function() { 1.240 + aCallback(this._success); 1.241 + } 1.242 + }); 1.243 + } 1.244 + else { 1.245 + aCallback(false); 1.246 + } 1.247 + } 1.248 + catch(ex) { 1.249 + Cu.reportError(ex); 1.250 + aCallback(false); 1.251 + } 1.252 + }.bind(this)); 1.253 + } 1.254 +}; 1.255 + 1.256 +/** 1.257 + * Safari's preferences property list is independently used for three purposes: 1.258 + * (a) importation of preferences 1.259 + * (b) importation of search strings 1.260 + * (c) retrieving the home page. 1.261 + * 1.262 + * So, rather than reading it three times, it's cached and managed here. 1.263 + */ 1.264 +function MainPreferencesPropertyList(aPreferencesFile) { 1.265 + this._file = aPreferencesFile; 1.266 + this._callbacks = []; 1.267 +} 1.268 +MainPreferencesPropertyList.prototype = { 1.269 + /** 1.270 + * @see PropertyListUtils.read 1.271 + */ 1.272 + read: function MPPL_read(aCallback) { 1.273 + if ("_dict" in this) { 1.274 + aCallback(this._dict); 1.275 + return; 1.276 + } 1.277 + 1.278 + let alreadyReading = this._callbacks.length > 0; 1.279 + this._callbacks.push(aCallback); 1.280 + if (!alreadyReading) { 1.281 + PropertyListUtils.read(this._file, function readPrefs(aDict) { 1.282 + this._dict = aDict; 1.283 + for (let callback of this._callbacks) { 1.284 + try { 1.285 + callback(aDict); 1.286 + } 1.287 + catch(ex) { 1.288 + Cu.reportError(ex); 1.289 + } 1.290 + } 1.291 + this._callbacks.splice(0); 1.292 + }.bind(this)); 1.293 + } 1.294 + }, 1.295 + 1.296 + // Workaround for nsIBrowserProfileMigrator.sourceHomePageURL until 1.297 + // it's replaced with an async method. 1.298 + _readSync: function MPPL__readSync() { 1.299 + if ("_dict" in this) 1.300 + return this._dict; 1.301 + 1.302 + let inputStream = Cc["@mozilla.org/network/file-input-stream;1"]. 1.303 + createInstance(Ci.nsIFileInputStream); 1.304 + inputStream.init(this._file, -1, -1, 0); 1.305 + let binaryStream = Cc["@mozilla.org/binaryinputstream;1"]. 1.306 + createInstance(Ci.nsIBinaryInputStream); 1.307 + binaryStream.setInputStream(inputStream); 1.308 + let bytes = binaryStream.readByteArray(inputStream.available()); 1.309 + this._dict = PropertyListUtils._readFromArrayBufferSync( 1.310 + new Uint8Array(bytes).buffer); 1.311 + return this._dict; 1.312 + } 1.313 +}; 1.314 + 1.315 +function Preferences(aMainPreferencesPropertyListInstance) { 1.316 + this._mainPreferencesPropertyList = aMainPreferencesPropertyListInstance; 1.317 +} 1.318 +Preferences.prototype = { 1.319 + type: MigrationUtils.resourceTypes.SETTINGS, 1.320 + 1.321 + migrate: function MPR_migrate(aCallback) { 1.322 + this._mainPreferencesPropertyList.read( 1.323 + MigrationUtils.wrapMigrateFunction(function migratePrefs(aDict) { 1.324 + if (!aDict) 1.325 + throw new Error("Could not read preferences file"); 1.326 + 1.327 + this._dict = aDict; 1.328 + 1.329 + let invert = function(webkitVal) !webkitVal; 1.330 + this._set("AutoFillPasswords", "signon.rememberSignons"); 1.331 + this._set("OpenNewTabsInFront", "browser.tabs.loadInBackground", invert); 1.332 + this._set("WebKitJavaScriptCanOpenWindowsAutomatically", 1.333 + "dom.disable_open_during_load", invert); 1.334 + 1.335 + // layout.spellcheckDefault is a boolean stored as a number. 1.336 + this._set("WebContinuousSpellCheckingEnabled", 1.337 + "layout.spellcheckDefault", Number); 1.338 + 1.339 + // Auto-load images 1.340 + // Firefox has an elaborate set of Image preferences. The correlation is: 1.341 + // Mode: Safari Firefox 1.342 + // Blocked FALSE 2 1.343 + // Allowed TRUE 1 1.344 + // Allowed, originating site only -- 3 1.345 + this._set("WebKitDisplayImagesKey", "permissions.default.image", 1.346 + function(webkitVal) webkitVal ? 1 : 2); 1.347 + 1.348 +#ifdef XP_WIN 1.349 + // Cookie-accept policy. 1.350 + // For the OS X version, see WebFoundationCookieBehavior. 1.351 + // Setting Safari Firefox 1.352 + // Always Accept 0 0 1.353 + // Accept from Originating 2 1 1.354 + // Never Accept 1 2 1.355 + this._set("WebKitCookieStorageAcceptPolicy", 1.356 + "network.cookie.cookieBehavior", 1.357 + function(webkitVal) webkitVal == 0 ? 0 : webkitVal == 1 ? 2 : 1); 1.358 +#endif 1.359 + 1.360 + this._migrateFontSettings(); 1.361 + this._migrateDownloadsFolder(); 1.362 + }.bind(this), aCallback)); 1.363 + }, 1.364 + 1.365 + /** 1.366 + * Attempts to migrates a preference from Safari. Returns whether the preference 1.367 + * has been migrated. 1.368 + * @param aSafariKey 1.369 + * The dictionary key for the preference of Safari. 1.370 + * @param aMozPref 1.371 + * The gecko/firefox preference to which aSafariKey should be migrated 1.372 + * @param [optional] aConvertFunction(aSafariValue) 1.373 + * a function that converts the safari-preference value to the 1.374 + * appropriate value for aMozPref. If it's not passed, then the 1.375 + * Safari value is set as is. 1.376 + * If aConvertFunction returns undefined, then aMozPref is not set 1.377 + * at all. 1.378 + * @return whether or not aMozPref was set. 1.379 + */ 1.380 + _set: function MPR_set(aSafariKey, aMozPref, aConvertFunction) { 1.381 + if (this._dict.has(aSafariKey)) { 1.382 + let safariVal = this._dict.get(aSafariKey); 1.383 + let mozVal = aConvertFunction !== undefined ? 1.384 + aConvertFunction(safariVal) : safariVal; 1.385 + switch (typeof(mozVal)) { 1.386 + case "string": 1.387 + Services.prefs.setCharPref(aMozPref, mozVal); 1.388 + break; 1.389 + case "number": 1.390 + Services.prefs.setIntPref(aMozPref, mozVal); 1.391 + break; 1.392 + case "boolean": 1.393 + Services.prefs.setBoolPref(aMozPref, mozVal); 1.394 + break; 1.395 + case "undefined": 1.396 + return false; 1.397 + default: 1.398 + throw new Error("Unexpected value type: " + typeof(mozVal)); 1.399 + } 1.400 + } 1.401 + return true; 1.402 + }, 1.403 + 1.404 + // Fonts settings are quite problematic for migration, for a couple of 1.405 + // reasons: 1.406 + // (a) Every font preference in Gecko is set for a particular language. 1.407 + // In Safari, each font preference applies to all languages. 1.408 + // (b) The current underlying implementation of nsIFontEnumerator cannot 1.409 + // really tell you anything about a font: no matter what language or type 1.410 + // you try to enumerate with EnumerateFonts, you get an array of all 1.411 + // fonts in the systems (This also breaks our fonts dialog). 1.412 + // (c) In Gecko, each langauge has a distinct serif and sans-serif font 1.413 + // preference. Safari has only one default font setting. It seems that 1.414 + // it checks if it's a serif or sans serif font, and when a site 1.415 + // explicitly asks to use serif/sans-serif font, it uses the default font 1.416 + // only if it applies to this type. 1.417 + // (d) The solution of guessing the lang-group out of the default charset (as 1.418 + // done in the old Safari migrator) can only work when: 1.419 + // (1) The default charset preference is set. 1.420 + // (2) It's not a unicode charset. 1.421 + // For now, we use the language implied by the system locale as the 1.422 + // lang-group. The only exception is minimal font size, which is an 1.423 + // accessibility preference in Safari (under the Advanced tab). If it is set, 1.424 + // we set it for all languages. 1.425 + // As for the font type of the default font (serif/sans-serif), the default 1.426 + // type for the given language is used (set in font.default.LANGGROUP). 1.427 + _migrateFontSettings: function MPR__migrateFontSettings() { 1.428 + // If "Never use font sizes smaller than [ ] is set", migrate it for all 1.429 + // languages. 1.430 + if (this._dict.has("WebKitMinimumFontSize")) { 1.431 + let minimumSize = this._dict.get("WebKitMinimumFontSize"); 1.432 + if (typeof(minimumSize) == "number") { 1.433 + let prefs = Services.prefs.getChildList("font.minimum-size"); 1.434 + for (let pref of prefs) { 1.435 + Services.prefs.setIntPref(pref, minimumSize); 1.436 + } 1.437 + } 1.438 + else { 1.439 + Cu.reportError("WebKitMinimumFontSize was set to an invalid value: " + 1.440 + minimumSize); 1.441 + } 1.442 + } 1.443 + 1.444 + // In theory, the lang group could be "x-unicode". This will result 1.445 + // in setting the fonts for "Other Languages". 1.446 + let lang = this._getLocaleLangGroup(); 1.447 + 1.448 + let anySet = false; 1.449 + let fontType = Services.prefs.getCharPref("font.default." + lang); 1.450 + anySet |= this._set("WebKitFixedFont", "font.name.monospace." + lang); 1.451 + anySet |= this._set("WebKitDefaultFixedFontSize", "font.size.fixed." + lang); 1.452 + anySet |= this._set("WebKitStandardFont", 1.453 + "font.name." + fontType + "." + lang); 1.454 + anySet |= this._set("WebKitDefaultFontSize", "font.size.variable." + lang); 1.455 + 1.456 + // If we set font settings for a particular language, we'll also set the 1.457 + // fonts dialog to open with the fonts settings for that langauge. 1.458 + if (anySet) 1.459 + Services.prefs.setCharPref("font.language.group", lang); 1.460 + }, 1.461 + 1.462 + // Get the language group for the system locale. 1.463 + _getLocaleLangGroup: function MPR__getLocaleLangGroup() { 1.464 + let locale = Services.locale.getLocaleComponentForUserAgent(); 1.465 + 1.466 + // See nsLanguageAtomService::GetLanguageGroup 1.467 + let localeLangGroup = "x-unicode"; 1.468 + let bundle = Services.strings.createBundle( 1.469 + "resource://gre/res/langGroups.properties"); 1.470 + try { 1.471 + localeLangGroup = bundle.GetStringFromName(locale); 1.472 + } 1.473 + catch(ex) { 1.474 + let hyphenAt = locale.indexOf("-"); 1.475 + if (hyphenAt != -1) { 1.476 + try { 1.477 + localeLangGroup = bundle.GetStringFromName(locale.substr(0, hyphenAt)); 1.478 + } 1.479 + catch(ex2) { } 1.480 + } 1.481 + } 1.482 + return localeLangGroup; 1.483 + }, 1.484 + 1.485 + _migrateDownloadsFolder: function MPR__migrateDownloadsFolder() { 1.486 + // Windows Safari uses DownloadPath while Mac uses DownloadsPath. 1.487 + // Check both for future compatibility. 1.488 + let key; 1.489 + if (this._dict.has("DownloadsPath")) 1.490 + key = "DownloadsPath"; 1.491 + else if (this._dict.has("DownloadPath")) 1.492 + key = "DownloadPath"; 1.493 + else 1.494 + return; 1.495 + 1.496 + let downloadsFolder = FileUtils.File(this._dict.get(key)); 1.497 + 1.498 + // If the download folder is set to the Desktop or to ~/Downloads, set the 1.499 + // folderList pref appropriately so that "Desktop"/Downloads is shown with 1.500 + // pretty name in the preferences dialog. 1.501 + let folderListVal = 2; 1.502 + if (downloadsFolder.equals(FileUtils.getDir("Desk", []))) { 1.503 + folderListVal = 0; 1.504 + } 1.505 + else { 1.506 + let dnldMgr = Cc["@mozilla.org/download-manager;1"]. 1.507 + getService(Ci.nsIDownloadManager); 1.508 + if (downloadsFolder.equals(dnldMgr.defaultDownloadsDirectory)) 1.509 + folderListVal = 1; 1.510 + } 1.511 + Services.prefs.setIntPref("browser.download.folderList", folderListVal); 1.512 + Services.prefs.setComplexValue("browser.download.dir", Ci.nsILocalFile, 1.513 + downloadsFolder); 1.514 + } 1.515 +}; 1.516 + 1.517 +function SearchStrings(aMainPreferencesPropertyListInstance) { 1.518 + this._mainPreferencesPropertyList = aMainPreferencesPropertyListInstance; 1.519 +} 1.520 +SearchStrings.prototype = { 1.521 + type: MigrationUtils.resourceTypes.OTHERDATA, 1.522 + 1.523 + migrate: function SS_migrate(aCallback) { 1.524 + this._mainPreferencesPropertyList.read(MigrationUtils.wrapMigrateFunction( 1.525 + function migrateSearchStrings(aDict) { 1.526 + if (!aDict) 1.527 + throw new Error("Could not get preferences dictionary"); 1.528 + 1.529 + if (aDict.has("RecentSearchStrings")) { 1.530 + let recentSearchStrings = aDict.get("RecentSearchStrings"); 1.531 + if (recentSearchStrings && recentSearchStrings.length > 0) { 1.532 + let changes = [{op: "add", 1.533 + fieldname: "searchbar-history", 1.534 + value: searchString} 1.535 + for (searchString of recentSearchStrings)]; 1.536 + FormHistory.update(changes); 1.537 + } 1.538 + } 1.539 + }.bind(this), aCallback)); 1.540 + } 1.541 +}; 1.542 + 1.543 +#ifdef XP_MACOSX 1.544 +// On OS X, the cookie-accept policy preference is stored in a separate 1.545 +// property list. 1.546 +// For the Windows version, check Preferences.migrate. 1.547 +function WebFoundationCookieBehavior(aWebFoundationFile) { 1.548 + this._file = aWebFoundationFile; 1.549 +} 1.550 +WebFoundationCookieBehavior.prototype = { 1.551 + type: MigrationUtils.resourceTypes.SETTINGS, 1.552 + 1.553 + migrate: function WFPL_migrate(aCallback) { 1.554 + PropertyListUtils.read(this._file, MigrationUtils.wrapMigrateFunction( 1.555 + function migrateCookieBehavior(aDict) { 1.556 + if (!aDict) 1.557 + throw new Error("Could not read com.apple.WebFoundation.plist"); 1.558 + 1.559 + if (aDict.has("NSHTTPAcceptCookies")) { 1.560 + // Setting Safari Firefox 1.561 + // Always Accept always 0 1.562 + // Accept from Originating current page 1 1.563 + // Never Accept never 2 1.564 + let acceptCookies = aDict.get("NSHTTPAcceptCookies"); 1.565 + let cookieValue = acceptCookies == "never" ? 2 : 1.566 + acceptCookies == "current page" ? 1 : 0; 1.567 + Services.prefs.setIntPref("network.cookie.cookieBehavior", 1.568 + cookieValue); 1.569 + } 1.570 + }.bind(this), aCallback)); 1.571 + } 1.572 +}; 1.573 +#endif 1.574 + 1.575 +function SafariProfileMigrator() { 1.576 +} 1.577 + 1.578 +SafariProfileMigrator.prototype = Object.create(MigratorPrototype); 1.579 + 1.580 +SafariProfileMigrator.prototype.getResources = function SM_getResources() { 1.581 + let profileDir = 1.582 +#ifdef XP_MACOSX 1.583 + FileUtils.getDir("ULibDir", ["Safari"], false); 1.584 +#else 1.585 + FileUtils.getDir("AppData", ["Apple Computer", "Safari"], false); 1.586 +#endif 1.587 + if (!profileDir.exists()) 1.588 + return null; 1.589 + 1.590 + let resources = []; 1.591 + let pushProfileFileResource = function(aFileName, aConstructor) { 1.592 + let file = profileDir.clone(); 1.593 + file.append(aFileName); 1.594 + if (file.exists()) 1.595 + resources.push(new aConstructor(file)); 1.596 + }; 1.597 + 1.598 + pushProfileFileResource("History.plist", History); 1.599 + pushProfileFileResource("Bookmarks.plist", Bookmarks); 1.600 + 1.601 + // The Reading List feature was introduced at the same time in Windows and 1.602 + // Mac versions of Safari. Not surprisingly, they are stored in the same 1.603 + // format in both versions. Surpsingly, only on Windows there is a 1.604 + // separate property list for it. This isn't #ifdefed out on mac, because 1.605 + // Apple may fix this at some point. 1.606 + pushProfileFileResource("ReadingList.plist", Bookmarks); 1.607 + 1.608 + let prefsDir = 1.609 +#ifdef XP_MACOSX 1.610 + FileUtils.getDir("UsrPrfs", [], false); 1.611 +#else 1.612 + FileUtils.getDir("AppData", ["Apple Computer", "Preferences"], false); 1.613 +#endif 1.614 + 1.615 + let prefs = this.mainPreferencesPropertyList; 1.616 + if (prefs) { 1.617 + resources.push(new Preferences(prefs)); 1.618 + resources.push(new SearchStrings(prefs)); 1.619 + } 1.620 + 1.621 +#ifdef XP_MACOSX 1.622 + // On OS X, the cookie-accept policy preference is stored in a separate 1.623 + // property list. 1.624 + let wfFile = FileUtils.getFile("UsrPrfs", ["com.apple.WebFoundation.plist"]); 1.625 + if (wfFile.exists()) 1.626 + resources.push(new WebFoundationCookieBehavior(wfFile)); 1.627 +#endif 1.628 + 1.629 + return resources; 1.630 +}; 1.631 + 1.632 +Object.defineProperty(SafariProfileMigrator.prototype, "mainPreferencesPropertyList", { 1.633 + get: function get_mainPreferencesPropertyList() { 1.634 + if (this._mainPreferencesPropertyList === undefined) { 1.635 + let file = 1.636 +#ifdef XP_MACOSX 1.637 + FileUtils.getDir("UsrPrfs", [], false); 1.638 +#else 1.639 + FileUtils.getDir("AppData", ["Apple Computer", "Preferences"], false); 1.640 +#endif 1.641 + if (file.exists()) { 1.642 + file.append("com.apple.Safari.plist"); 1.643 + if (file.exists()) { 1.644 + return this._mainPreferencesPropertyList = 1.645 + new MainPreferencesPropertyList(file); 1.646 + } 1.647 + } 1.648 + return this._mainPreferencesPropertyList = null; 1.649 + } 1.650 + return this._mainPreferencesPropertyList; 1.651 + } 1.652 +}); 1.653 + 1.654 +Object.defineProperty(SafariProfileMigrator.prototype, "sourceHomePageURL", { 1.655 + get: function get_sourceHomePageURL() { 1.656 + if (this.mainPreferencesPropertyList) { 1.657 + let dict = this.mainPreferencesPropertyList._readSync(); 1.658 + if (dict.has("HomePage")) 1.659 + return dict.get("HomePage"); 1.660 + } 1.661 + return ""; 1.662 + } 1.663 +}); 1.664 + 1.665 +SafariProfileMigrator.prototype.classDescription = "Safari Profile Migrator"; 1.666 +SafariProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=safari"; 1.667 +SafariProfileMigrator.prototype.classID = Components.ID("{4b609ecf-60b2-4655-9df4-dc149e474da1}"); 1.668 + 1.669 +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SafariProfileMigrator]);