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 michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: let Cc = Components.classes; michael@0: let Ci = Components.interfaces; michael@0: let Cu = Components.utils; michael@0: michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: Cu.import("resource://gre/modules/FileUtils.jsm"); michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: Cu.import("resource:///modules/MigrationUtils.jsm"); michael@0: michael@0: XPCOMUtils.defineLazyModuleGetter(this, "PropertyListUtils", michael@0: "resource://gre/modules/PropertyListUtils.jsm"); michael@0: XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", michael@0: "resource://gre/modules/PlacesUtils.jsm"); michael@0: XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", michael@0: "resource://gre/modules/NetUtil.jsm"); michael@0: XPCOMUtils.defineLazyModuleGetter(this, "FormHistory", michael@0: "resource://gre/modules/FormHistory.jsm"); michael@0: michael@0: function Bookmarks(aBookmarksFile) { michael@0: this._file = aBookmarksFile; michael@0: } michael@0: Bookmarks.prototype = { michael@0: type: MigrationUtils.resourceTypes.BOOKMARKS, michael@0: michael@0: migrate: function B_migrate(aCallback) { michael@0: PropertyListUtils.read(this._file, michael@0: MigrationUtils.wrapMigrateFunction(function migrateBookmarks(aDict) { michael@0: if (!aDict) michael@0: throw new Error("Could not read Bookmarks.plist"); michael@0: michael@0: let children = aDict.get("Children");; michael@0: if (!children) michael@0: throw new Error("Invalid Bookmarks.plist format"); michael@0: michael@0: PlacesUtils.bookmarks.runInBatchMode({ michael@0: runBatched: function() { michael@0: let collection = aDict.get("Title") == "com.apple.ReadingList" ? michael@0: this.READING_LIST_COLLECTION : this.ROOT_COLLECTION; michael@0: this._migrateCollection(children, collection); michael@0: }.bind(this) michael@0: }, null); michael@0: }.bind(this), aCallback)); michael@0: }, michael@0: michael@0: // Bookmarks collections in Safari. Constants for migrateCollection. michael@0: ROOT_COLLECTION: 0, michael@0: MENU_COLLECTION: 1, michael@0: TOOLBAR_COLLECTION: 2, michael@0: READING_LIST_COLLECTION: 3, michael@0: michael@0: /** michael@0: * Recursively migrate a Safari collection of bookmarks. michael@0: * michael@0: * @param aEntries michael@0: * the collection's children michael@0: * @param aCollection michael@0: * one of the values above. michael@0: */ michael@0: _migrateCollection: function B__migrateCollection(aEntries, aCollection) { michael@0: // A collection of bookmarks in Safari resembles places roots. In the michael@0: // property list files (Bookmarks.plist, ReadingList.plist) they are michael@0: // stored as regular bookmarks folders, and thus can only be distinguished michael@0: // from by their names and places in the hierarchy. michael@0: michael@0: let entriesFiltered = []; michael@0: if (aCollection == this.ROOT_COLLECTION) { michael@0: for (let entry of aEntries) { michael@0: let type = entry.get("WebBookmarkType"); michael@0: if (type == "WebBookmarkTypeList" && entry.has("Children")) { michael@0: let title = entry.get("Title"); michael@0: let children = entry.get("Children"); michael@0: if (title == "BookmarksBar") michael@0: this._migrateCollection(children, this.TOOLBAR_COLLECTION); michael@0: else if (title == "BookmarksMenu") michael@0: this._migrateCollection(children, this.MENU_COLLECTION); michael@0: else if (title == "com.apple.ReadingList") michael@0: this._migrateCollection(children, this.READING_LIST_COLLECTION); michael@0: else if (entry.get("ShouldOmitFromUI") !== true) michael@0: entriesFiltered.push(entry); michael@0: } michael@0: else if (type == "WebBookmarkTypeLeaf") { michael@0: entriesFiltered.push(entry); michael@0: } michael@0: } michael@0: } michael@0: else { michael@0: entriesFiltered = aEntries; michael@0: } michael@0: michael@0: if (entriesFiltered.length == 0) michael@0: return; michael@0: michael@0: let folder = -1; michael@0: switch (aCollection) { michael@0: case this.ROOT_COLLECTION: { michael@0: // In Safari, it is possible (though quite cumbersome) to move michael@0: // bookmarks to the bookmarks root, which is the parent folder of michael@0: // all bookmarks "collections". That is somewhat in parallel with michael@0: // both the places root and the unfiled-bookmarks root. michael@0: // Because the former is only an implementation detail in our UI, michael@0: // the unfiled root seems to be the best choice. michael@0: folder = PlacesUtils.unfiledBookmarksFolderId; michael@0: break; michael@0: } michael@0: case this.MENU_COLLECTION: { michael@0: folder = PlacesUtils.bookmarksMenuFolderId; michael@0: if (!MigrationUtils.isStartupMigration) { michael@0: folder = MigrationUtils.createImportedBookmarksFolder("Safari", michael@0: folder); michael@0: } michael@0: break; michael@0: } michael@0: case this.TOOLBAR_COLLECTION: { michael@0: folder = PlacesUtils.toolbarFolderId; michael@0: if (!MigrationUtils.isStartupMigration) { michael@0: folder = MigrationUtils.createImportedBookmarksFolder("Safari", michael@0: folder); michael@0: } michael@0: break; michael@0: } michael@0: case this.READING_LIST_COLLECTION: { michael@0: // Reading list items are imported as regular bookmarks. michael@0: // They are imported under their own folder, created either under the michael@0: // bookmarks menu (in the case of startup migration). michael@0: folder = PlacesUtils.bookmarks.createFolder( michael@0: PlacesUtils.bookmarksMenuFolderId, michael@0: MigrationUtils.getLocalizedString("importedSafariReadingList"), michael@0: PlacesUtils.bookmarks.DEFAULT_INDEX); michael@0: break; michael@0: } michael@0: default: michael@0: throw new Error("Unexpected value for aCollection!"); michael@0: } michael@0: michael@0: this._migrateEntries(entriesFiltered, folder); michael@0: }, michael@0: michael@0: // migrate the given array of safari bookmarks to the given places michael@0: // folder. michael@0: _migrateEntries: function B__migrateEntries(aEntries, aFolderId) { michael@0: for (let entry of aEntries) { michael@0: let type = entry.get("WebBookmarkType"); michael@0: if (type == "WebBookmarkTypeList" && entry.has("Children")) { michael@0: let title = entry.get("Title"); michael@0: let folderId = PlacesUtils.bookmarks.createFolder( michael@0: aFolderId, title, PlacesUtils.bookmarks.DEFAULT_INDEX); michael@0: michael@0: // Empty folders may not have a children array. michael@0: if (entry.has("Children")) michael@0: this._migrateEntries(entry.get("Children"), folderId, false); michael@0: } michael@0: else if (type == "WebBookmarkTypeLeaf" && entry.has("URLString")) { michael@0: let title, uri; michael@0: if (entry.has("URIDictionary")) michael@0: title = entry.get("URIDictionary").get("title"); michael@0: michael@0: try { michael@0: uri = NetUtil.newURI(entry.get("URLString")); michael@0: } michael@0: catch(ex) { michael@0: Cu.reportError("Invalid uri set for Safari bookmark: " + entry.get("URLString")); michael@0: } michael@0: if (uri) { michael@0: PlacesUtils.bookmarks.insertBookmark(aFolderId, uri, michael@0: PlacesUtils.bookmarks.DEFAULT_INDEX, title); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: michael@0: function History(aHistoryFile) { michael@0: this._file = aHistoryFile; michael@0: } michael@0: History.prototype = { michael@0: type: MigrationUtils.resourceTypes.HISTORY, michael@0: michael@0: // Helper method for converting the visit date property to a PRTime value. michael@0: // The visit date is stored as a string, so it's not read as a Date michael@0: // object by PropertyListUtils. michael@0: _parseCocoaDate: function H___parseCocoaDate(aCocoaDateStr) { michael@0: let asDouble = parseFloat(aCocoaDateStr); michael@0: if (!isNaN(asDouble)) { michael@0: // reference date of NSDate. michael@0: let date = new Date("1 January 2001, GMT"); michael@0: date.setMilliseconds(asDouble * 1000); michael@0: return date * 1000; michael@0: } michael@0: return 0; michael@0: }, michael@0: michael@0: migrate: function H_migrate(aCallback) { michael@0: PropertyListUtils.read(this._file, function migrateHistory(aDict) { michael@0: try { michael@0: if (!aDict) michael@0: throw new Error("Could not read history property list"); michael@0: if (!aDict.has("WebHistoryDates")) michael@0: throw new Error("Unexpected history-property list format"); michael@0: michael@0: // Safari's History file contains only top-level urls. It does not michael@0: // distinguish between typed urls and linked urls. michael@0: let transType = PlacesUtils.history.TRANSITION_LINK; michael@0: michael@0: let places = []; michael@0: let entries = aDict.get("WebHistoryDates"); michael@0: for (let entry of entries) { michael@0: if (entry.has("lastVisitedDate")) { michael@0: let visitDate = this._parseCocoaDate(entry.get("lastVisitedDate")); michael@0: try { michael@0: places.push({ uri: NetUtil.newURI(entry.get("")), michael@0: title: entry.get("title"), michael@0: visits: [{ transitionType: transType, michael@0: visitDate: visitDate }] }); michael@0: } michael@0: catch(ex) { michael@0: // Safari's History file may contain malformed URIs which michael@0: // will be ignored. michael@0: Cu.reportError(ex) michael@0: } michael@0: } michael@0: } michael@0: if (places.length > 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: else { michael@0: aCallback(false); michael@0: } michael@0: } michael@0: catch(ex) { michael@0: Cu.reportError(ex); michael@0: aCallback(false); michael@0: } michael@0: }.bind(this)); michael@0: } michael@0: }; michael@0: michael@0: /** michael@0: * Safari's preferences property list is independently used for three purposes: michael@0: * (a) importation of preferences michael@0: * (b) importation of search strings michael@0: * (c) retrieving the home page. michael@0: * michael@0: * So, rather than reading it three times, it's cached and managed here. michael@0: */ michael@0: function MainPreferencesPropertyList(aPreferencesFile) { michael@0: this._file = aPreferencesFile; michael@0: this._callbacks = []; michael@0: } michael@0: MainPreferencesPropertyList.prototype = { michael@0: /** michael@0: * @see PropertyListUtils.read michael@0: */ michael@0: read: function MPPL_read(aCallback) { michael@0: if ("_dict" in this) { michael@0: aCallback(this._dict); michael@0: return; michael@0: } michael@0: michael@0: let alreadyReading = this._callbacks.length > 0; michael@0: this._callbacks.push(aCallback); michael@0: if (!alreadyReading) { michael@0: PropertyListUtils.read(this._file, function readPrefs(aDict) { michael@0: this._dict = aDict; michael@0: for (let callback of this._callbacks) { michael@0: try { michael@0: callback(aDict); michael@0: } michael@0: catch(ex) { michael@0: Cu.reportError(ex); michael@0: } michael@0: } michael@0: this._callbacks.splice(0); michael@0: }.bind(this)); michael@0: } michael@0: }, michael@0: michael@0: // Workaround for nsIBrowserProfileMigrator.sourceHomePageURL until michael@0: // it's replaced with an async method. michael@0: _readSync: function MPPL__readSync() { michael@0: if ("_dict" in this) michael@0: return this._dict; michael@0: michael@0: let inputStream = Cc["@mozilla.org/network/file-input-stream;1"]. michael@0: createInstance(Ci.nsIFileInputStream); michael@0: inputStream.init(this._file, -1, -1, 0); michael@0: let binaryStream = Cc["@mozilla.org/binaryinputstream;1"]. michael@0: createInstance(Ci.nsIBinaryInputStream); michael@0: binaryStream.setInputStream(inputStream); michael@0: let bytes = binaryStream.readByteArray(inputStream.available()); michael@0: this._dict = PropertyListUtils._readFromArrayBufferSync( michael@0: new Uint8Array(bytes).buffer); michael@0: return this._dict; michael@0: } michael@0: }; michael@0: michael@0: function Preferences(aMainPreferencesPropertyListInstance) { michael@0: this._mainPreferencesPropertyList = aMainPreferencesPropertyListInstance; michael@0: } michael@0: Preferences.prototype = { michael@0: type: MigrationUtils.resourceTypes.SETTINGS, michael@0: michael@0: migrate: function MPR_migrate(aCallback) { michael@0: this._mainPreferencesPropertyList.read( michael@0: MigrationUtils.wrapMigrateFunction(function migratePrefs(aDict) { michael@0: if (!aDict) michael@0: throw new Error("Could not read preferences file"); michael@0: michael@0: this._dict = aDict; michael@0: michael@0: let invert = function(webkitVal) !webkitVal; michael@0: this._set("AutoFillPasswords", "signon.rememberSignons"); michael@0: this._set("OpenNewTabsInFront", "browser.tabs.loadInBackground", invert); michael@0: this._set("WebKitJavaScriptCanOpenWindowsAutomatically", michael@0: "dom.disable_open_during_load", invert); michael@0: michael@0: // layout.spellcheckDefault is a boolean stored as a number. michael@0: this._set("WebContinuousSpellCheckingEnabled", michael@0: "layout.spellcheckDefault", Number); michael@0: michael@0: // Auto-load images michael@0: // Firefox has an elaborate set of Image preferences. The correlation is: michael@0: // Mode: Safari Firefox michael@0: // Blocked FALSE 2 michael@0: // Allowed TRUE 1 michael@0: // Allowed, originating site only -- 3 michael@0: this._set("WebKitDisplayImagesKey", "permissions.default.image", michael@0: function(webkitVal) webkitVal ? 1 : 2); michael@0: michael@0: #ifdef XP_WIN michael@0: // Cookie-accept policy. michael@0: // For the OS X version, see WebFoundationCookieBehavior. michael@0: // Setting Safari Firefox michael@0: // Always Accept 0 0 michael@0: // Accept from Originating 2 1 michael@0: // Never Accept 1 2 michael@0: this._set("WebKitCookieStorageAcceptPolicy", michael@0: "network.cookie.cookieBehavior", michael@0: function(webkitVal) webkitVal == 0 ? 0 : webkitVal == 1 ? 2 : 1); michael@0: #endif michael@0: michael@0: this._migrateFontSettings(); michael@0: this._migrateDownloadsFolder(); michael@0: }.bind(this), aCallback)); michael@0: }, michael@0: michael@0: /** michael@0: * Attempts to migrates a preference from Safari. Returns whether the preference michael@0: * has been migrated. michael@0: * @param aSafariKey michael@0: * The dictionary key for the preference of Safari. michael@0: * @param aMozPref michael@0: * The gecko/firefox preference to which aSafariKey should be migrated michael@0: * @param [optional] aConvertFunction(aSafariValue) michael@0: * a function that converts the safari-preference value to the michael@0: * appropriate value for aMozPref. If it's not passed, then the michael@0: * Safari value is set as is. michael@0: * If aConvertFunction returns undefined, then aMozPref is not set michael@0: * at all. michael@0: * @return whether or not aMozPref was set. michael@0: */ michael@0: _set: function MPR_set(aSafariKey, aMozPref, aConvertFunction) { michael@0: if (this._dict.has(aSafariKey)) { michael@0: let safariVal = this._dict.get(aSafariKey); michael@0: let mozVal = aConvertFunction !== undefined ? michael@0: aConvertFunction(safariVal) : safariVal; michael@0: switch (typeof(mozVal)) { michael@0: case "string": michael@0: Services.prefs.setCharPref(aMozPref, mozVal); michael@0: break; michael@0: case "number": michael@0: Services.prefs.setIntPref(aMozPref, mozVal); michael@0: break; michael@0: case "boolean": michael@0: Services.prefs.setBoolPref(aMozPref, mozVal); michael@0: break; michael@0: case "undefined": michael@0: return false; michael@0: default: michael@0: throw new Error("Unexpected value type: " + typeof(mozVal)); michael@0: } michael@0: } michael@0: return true; michael@0: }, michael@0: michael@0: // Fonts settings are quite problematic for migration, for a couple of michael@0: // reasons: michael@0: // (a) Every font preference in Gecko is set for a particular language. michael@0: // In Safari, each font preference applies to all languages. michael@0: // (b) The current underlying implementation of nsIFontEnumerator cannot michael@0: // really tell you anything about a font: no matter what language or type michael@0: // you try to enumerate with EnumerateFonts, you get an array of all michael@0: // fonts in the systems (This also breaks our fonts dialog). michael@0: // (c) In Gecko, each langauge has a distinct serif and sans-serif font michael@0: // preference. Safari has only one default font setting. It seems that michael@0: // it checks if it's a serif or sans serif font, and when a site michael@0: // explicitly asks to use serif/sans-serif font, it uses the default font michael@0: // only if it applies to this type. michael@0: // (d) The solution of guessing the lang-group out of the default charset (as michael@0: // done in the old Safari migrator) can only work when: michael@0: // (1) The default charset preference is set. michael@0: // (2) It's not a unicode charset. michael@0: // For now, we use the language implied by the system locale as the michael@0: // lang-group. The only exception is minimal font size, which is an michael@0: // accessibility preference in Safari (under the Advanced tab). If it is set, michael@0: // we set it for all languages. michael@0: // As for the font type of the default font (serif/sans-serif), the default michael@0: // type for the given language is used (set in font.default.LANGGROUP). michael@0: _migrateFontSettings: function MPR__migrateFontSettings() { michael@0: // If "Never use font sizes smaller than [ ] is set", migrate it for all michael@0: // languages. michael@0: if (this._dict.has("WebKitMinimumFontSize")) { michael@0: let minimumSize = this._dict.get("WebKitMinimumFontSize"); michael@0: if (typeof(minimumSize) == "number") { michael@0: let prefs = Services.prefs.getChildList("font.minimum-size"); michael@0: for (let pref of prefs) { michael@0: Services.prefs.setIntPref(pref, minimumSize); michael@0: } michael@0: } michael@0: else { michael@0: Cu.reportError("WebKitMinimumFontSize was set to an invalid value: " + michael@0: minimumSize); michael@0: } michael@0: } michael@0: michael@0: // In theory, the lang group could be "x-unicode". This will result michael@0: // in setting the fonts for "Other Languages". michael@0: let lang = this._getLocaleLangGroup(); michael@0: michael@0: let anySet = false; michael@0: let fontType = Services.prefs.getCharPref("font.default." + lang); michael@0: anySet |= this._set("WebKitFixedFont", "font.name.monospace." + lang); michael@0: anySet |= this._set("WebKitDefaultFixedFontSize", "font.size.fixed." + lang); michael@0: anySet |= this._set("WebKitStandardFont", michael@0: "font.name." + fontType + "." + lang); michael@0: anySet |= this._set("WebKitDefaultFontSize", "font.size.variable." + lang); michael@0: michael@0: // If we set font settings for a particular language, we'll also set the michael@0: // fonts dialog to open with the fonts settings for that langauge. michael@0: if (anySet) michael@0: Services.prefs.setCharPref("font.language.group", lang); michael@0: }, michael@0: michael@0: // Get the language group for the system locale. michael@0: _getLocaleLangGroup: function MPR__getLocaleLangGroup() { michael@0: let locale = Services.locale.getLocaleComponentForUserAgent(); michael@0: michael@0: // See nsLanguageAtomService::GetLanguageGroup michael@0: let localeLangGroup = "x-unicode"; michael@0: let bundle = Services.strings.createBundle( michael@0: "resource://gre/res/langGroups.properties"); michael@0: try { michael@0: localeLangGroup = bundle.GetStringFromName(locale); michael@0: } michael@0: catch(ex) { michael@0: let hyphenAt = locale.indexOf("-"); michael@0: if (hyphenAt != -1) { michael@0: try { michael@0: localeLangGroup = bundle.GetStringFromName(locale.substr(0, hyphenAt)); michael@0: } michael@0: catch(ex2) { } michael@0: } michael@0: } michael@0: return localeLangGroup; michael@0: }, michael@0: michael@0: _migrateDownloadsFolder: function MPR__migrateDownloadsFolder() { michael@0: // Windows Safari uses DownloadPath while Mac uses DownloadsPath. michael@0: // Check both for future compatibility. michael@0: let key; michael@0: if (this._dict.has("DownloadsPath")) michael@0: key = "DownloadsPath"; michael@0: else if (this._dict.has("DownloadPath")) michael@0: key = "DownloadPath"; michael@0: else michael@0: return; michael@0: michael@0: let downloadsFolder = FileUtils.File(this._dict.get(key)); michael@0: michael@0: // If the download folder is set to the Desktop or to ~/Downloads, set the michael@0: // folderList pref appropriately so that "Desktop"/Downloads is shown with michael@0: // pretty name in the preferences dialog. michael@0: let folderListVal = 2; michael@0: if (downloadsFolder.equals(FileUtils.getDir("Desk", []))) { michael@0: folderListVal = 0; michael@0: } michael@0: else { michael@0: let dnldMgr = Cc["@mozilla.org/download-manager;1"]. michael@0: getService(Ci.nsIDownloadManager); michael@0: if (downloadsFolder.equals(dnldMgr.defaultDownloadsDirectory)) michael@0: folderListVal = 1; michael@0: } michael@0: Services.prefs.setIntPref("browser.download.folderList", folderListVal); michael@0: Services.prefs.setComplexValue("browser.download.dir", Ci.nsILocalFile, michael@0: downloadsFolder); michael@0: } michael@0: }; michael@0: michael@0: function SearchStrings(aMainPreferencesPropertyListInstance) { michael@0: this._mainPreferencesPropertyList = aMainPreferencesPropertyListInstance; michael@0: } michael@0: SearchStrings.prototype = { michael@0: type: MigrationUtils.resourceTypes.OTHERDATA, michael@0: michael@0: migrate: function SS_migrate(aCallback) { michael@0: this._mainPreferencesPropertyList.read(MigrationUtils.wrapMigrateFunction( michael@0: function migrateSearchStrings(aDict) { michael@0: if (!aDict) michael@0: throw new Error("Could not get preferences dictionary"); michael@0: michael@0: if (aDict.has("RecentSearchStrings")) { michael@0: let recentSearchStrings = aDict.get("RecentSearchStrings"); michael@0: if (recentSearchStrings && recentSearchStrings.length > 0) { michael@0: let changes = [{op: "add", michael@0: fieldname: "searchbar-history", michael@0: value: searchString} michael@0: for (searchString of recentSearchStrings)]; michael@0: FormHistory.update(changes); michael@0: } michael@0: } michael@0: }.bind(this), aCallback)); michael@0: } michael@0: }; michael@0: michael@0: #ifdef XP_MACOSX michael@0: // On OS X, the cookie-accept policy preference is stored in a separate michael@0: // property list. michael@0: // For the Windows version, check Preferences.migrate. michael@0: function WebFoundationCookieBehavior(aWebFoundationFile) { michael@0: this._file = aWebFoundationFile; michael@0: } michael@0: WebFoundationCookieBehavior.prototype = { michael@0: type: MigrationUtils.resourceTypes.SETTINGS, michael@0: michael@0: migrate: function WFPL_migrate(aCallback) { michael@0: PropertyListUtils.read(this._file, MigrationUtils.wrapMigrateFunction( michael@0: function migrateCookieBehavior(aDict) { michael@0: if (!aDict) michael@0: throw new Error("Could not read com.apple.WebFoundation.plist"); michael@0: michael@0: if (aDict.has("NSHTTPAcceptCookies")) { michael@0: // Setting Safari Firefox michael@0: // Always Accept always 0 michael@0: // Accept from Originating current page 1 michael@0: // Never Accept never 2 michael@0: let acceptCookies = aDict.get("NSHTTPAcceptCookies"); michael@0: let cookieValue = acceptCookies == "never" ? 2 : michael@0: acceptCookies == "current page" ? 1 : 0; michael@0: Services.prefs.setIntPref("network.cookie.cookieBehavior", michael@0: cookieValue); michael@0: } michael@0: }.bind(this), aCallback)); michael@0: } michael@0: }; michael@0: #endif michael@0: michael@0: function SafariProfileMigrator() { michael@0: } michael@0: michael@0: SafariProfileMigrator.prototype = Object.create(MigratorPrototype); michael@0: michael@0: SafariProfileMigrator.prototype.getResources = function SM_getResources() { michael@0: let profileDir = michael@0: #ifdef XP_MACOSX michael@0: FileUtils.getDir("ULibDir", ["Safari"], false); michael@0: #else michael@0: FileUtils.getDir("AppData", ["Apple Computer", "Safari"], false); michael@0: #endif michael@0: if (!profileDir.exists()) michael@0: return null; michael@0: michael@0: let resources = []; michael@0: let pushProfileFileResource = function(aFileName, aConstructor) { michael@0: let file = profileDir.clone(); michael@0: file.append(aFileName); michael@0: if (file.exists()) michael@0: resources.push(new aConstructor(file)); michael@0: }; michael@0: michael@0: pushProfileFileResource("History.plist", History); michael@0: pushProfileFileResource("Bookmarks.plist", Bookmarks); michael@0: michael@0: // The Reading List feature was introduced at the same time in Windows and michael@0: // Mac versions of Safari. Not surprisingly, they are stored in the same michael@0: // format in both versions. Surpsingly, only on Windows there is a michael@0: // separate property list for it. This isn't #ifdefed out on mac, because michael@0: // Apple may fix this at some point. michael@0: pushProfileFileResource("ReadingList.plist", Bookmarks); michael@0: michael@0: let prefsDir = michael@0: #ifdef XP_MACOSX michael@0: FileUtils.getDir("UsrPrfs", [], false); michael@0: #else michael@0: FileUtils.getDir("AppData", ["Apple Computer", "Preferences"], false); michael@0: #endif michael@0: michael@0: let prefs = this.mainPreferencesPropertyList; michael@0: if (prefs) { michael@0: resources.push(new Preferences(prefs)); michael@0: resources.push(new SearchStrings(prefs)); michael@0: } michael@0: michael@0: #ifdef XP_MACOSX michael@0: // On OS X, the cookie-accept policy preference is stored in a separate michael@0: // property list. michael@0: let wfFile = FileUtils.getFile("UsrPrfs", ["com.apple.WebFoundation.plist"]); michael@0: if (wfFile.exists()) michael@0: resources.push(new WebFoundationCookieBehavior(wfFile)); michael@0: #endif michael@0: michael@0: return resources; michael@0: }; michael@0: michael@0: Object.defineProperty(SafariProfileMigrator.prototype, "mainPreferencesPropertyList", { michael@0: get: function get_mainPreferencesPropertyList() { michael@0: if (this._mainPreferencesPropertyList === undefined) { michael@0: let file = michael@0: #ifdef XP_MACOSX michael@0: FileUtils.getDir("UsrPrfs", [], false); michael@0: #else michael@0: FileUtils.getDir("AppData", ["Apple Computer", "Preferences"], false); michael@0: #endif michael@0: if (file.exists()) { michael@0: file.append("com.apple.Safari.plist"); michael@0: if (file.exists()) { michael@0: return this._mainPreferencesPropertyList = michael@0: new MainPreferencesPropertyList(file); michael@0: } michael@0: } michael@0: return this._mainPreferencesPropertyList = null; michael@0: } michael@0: return this._mainPreferencesPropertyList; michael@0: } michael@0: }); michael@0: michael@0: Object.defineProperty(SafariProfileMigrator.prototype, "sourceHomePageURL", { michael@0: get: function get_sourceHomePageURL() { michael@0: if (this.mainPreferencesPropertyList) { michael@0: let dict = this.mainPreferencesPropertyList._readSync(); michael@0: if (dict.has("HomePage")) michael@0: return dict.get("HomePage"); michael@0: } michael@0: return ""; michael@0: } michael@0: }); michael@0: michael@0: SafariProfileMigrator.prototype.classDescription = "Safari Profile Migrator"; michael@0: SafariProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=safari"; michael@0: SafariProfileMigrator.prototype.classID = Components.ID("{4b609ecf-60b2-4655-9df4-dc149e474da1}"); michael@0: michael@0: this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SafariProfileMigrator]);