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.

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

mercurial