Wed, 31 Dec 2014 06:09:35 +0100
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]); |