Back out changeset d2693e86769d (bug 482911) due to crashes on Mac xpcshell tests. r=orange.

This commit is contained in:
Henri Sivonen 2012-03-23 11:28:21 +02:00
commit 3b8d2e2eb7
23 changed files with 2809 additions and 2248 deletions

View File

@ -163,3 +163,20 @@ GetProfilePath(nsIProfileStartup* aStartup, nsCOMPtr<nsIFile>& aProfileDir)
}
}
nsresult
ImportDefaultBookmarks()
{
nsCOMPtr<nsIPlacesImportExportService> importer =
do_GetService(NS_PLACESIMPORTEXPORTSERVICE_CONTRACTID);
NS_ENSURE_STATE(importer);
nsCOMPtr<nsIIOService> ioService = mozilla::services::GetIOService();
NS_ENSURE_STATE(ioService);
nsCOMPtr<nsIURI> bookmarksURI;
nsresult rv = ioService->NewURI(DEFAULT_BOOKMARKS, nsnull, nsnull,
getter_AddRefs(bookmarksURI));
if (NS_FAILED(rv))
return rv;
return importer->ImportHTMLFromURI(bookmarksURI, true);
}

View File

@ -99,5 +99,10 @@ void GetMigrateDataFromArray(MigrationData* aDataArray,
// this is already cloned, modify it to your heart's content
void GetProfilePath(nsIProfileStartup* aStartup, nsCOMPtr<nsIFile>& aProfileDir);
/**
* Imports default bookmarks to the profile.
*/
nsresult ImportDefaultBookmarks();
#endif

View File

@ -1398,6 +1398,11 @@ nsIEProfileMigrator::CopyFavoritesBatched(bool aReplace)
NS_ENSURE_SUCCESS(rv, rv);
}
else {
// If importing defaults fails for whatever reason, let the import process
// continue.
DebugOnly<nsresult> rv = ImportDefaultBookmarks();
MOZ_ASSERT(NS_SUCCEEDED(rv), "Should be able to import default bookmarks");
// Locate the Links toolbar folder, we want to replace the Personal Toolbar
// content with Favorites in this folder.
// On versions minor or equal to IE6 the folder name is stored in the

View File

@ -974,6 +974,11 @@ nsSafariProfileMigrator::CopyBookmarksBatched(bool aReplace)
NS_ENSURE_SUCCESS(rv, rv);
}
else {
// If importing defaults fails for whatever reason, let the import process
// continue.
DebugOnly<nsresult> rv = ImportDefaultBookmarks();
MOZ_ASSERT(NS_SUCCEEDED(rv), "Should be able to import default bookmarks");
// In replace mode we are merging at the top level.
folder = bookmarksMenuFolderId;
}

View File

@ -62,9 +62,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BookmarkHTMLUtils",
"resource://gre/modules/BookmarkHTMLUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "KeywordURLResetPrompter",
"resource:///modules/KeywordURLResetPrompter.jsm");
@ -231,6 +228,10 @@ BrowserGlue.prototype = {
// no longer needed, since history was initialized completely.
Services.obs.removeObserver(this, "places-database-locked");
this._isPlacesLockedObserver = false;
// Now apply distribution customized bookmarks.
// This should always run after Places initialization.
this._distributionCustomizer.applyBookmarks();
break;
case "places-database-locked":
this._isPlacesDatabaseLocked = true;
@ -256,6 +257,13 @@ BrowserGlue.prototype = {
// Customization has finished, we don't need the customizer anymore.
delete this._distributionCustomizer;
break;
case "bookmarks-restore-success":
case "bookmarks-restore-failed":
Services.obs.removeObserver(this, "bookmarks-restore-success");
Services.obs.removeObserver(this, "bookmarks-restore-failed");
if (topic == "bookmarks-restore-success" && data == "html-initial")
this.ensurePlacesDefaultQueriesInitialized();
break;
case "browser-glue-test": // used by tests
if (data == "post-update-notification") {
if (Services.prefs.prefHasUserValue("app.update.postupdate"))
@ -280,9 +288,6 @@ BrowserGlue.prototype = {
keywordURI);
}
break;
case "initial-migration":
this._initialMigrationPerformed = true;
break;
}
},
@ -985,9 +990,18 @@ BrowserGlue.prototype = {
// If the database is corrupt or has been newly created we should
// import bookmarks.
var dbStatus = PlacesUtils.history.databaseStatus;
var importBookmarks = !this._initialMigrationPerformed &&
(dbStatus == PlacesUtils.history.DATABASE_STATUS_CREATE ||
dbStatus == PlacesUtils.history.DATABASE_STATUS_CORRUPT);
var importBookmarks = dbStatus == PlacesUtils.history.DATABASE_STATUS_CREATE ||
dbStatus == PlacesUtils.history.DATABASE_STATUS_CORRUPT;
if (dbStatus == PlacesUtils.history.DATABASE_STATUS_CREATE) {
// If the database has just been created, but we already have any
// bookmark, this is not the initial import. This can happen after a
// migration from a different browser since migrators run before us.
// In such a case we should not import, unless some pref has been set.
if (PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.bookmarksMenuFolderId, 0) != -1 ||
PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId, 0) != -1)
importBookmarks = false;
}
// Check if user or an extension has required to import bookmarks.html
var importBookmarksHTML = false;
@ -1044,9 +1058,6 @@ BrowserGlue.prototype = {
// delayed till the import operations has finished. Not doing so would
// cause them to be overwritten by the newly imported bookmarks.
if (!importBookmarks) {
// Now apply distribution customized bookmarks.
// This should always run after Places initialization.
this._distributionCustomizer.applyBookmarks();
this.ensurePlacesDefaultQueriesInitialized();
}
else {
@ -1080,28 +1091,25 @@ BrowserGlue.prototype = {
}
if (bookmarksURI) {
// Add an import observer. It will ensure that smart bookmarks are
// created once the operation is complete.
Services.obs.addObserver(this, "bookmarks-restore-success", false);
Services.obs.addObserver(this, "bookmarks-restore-failed", false);
// Import from bookmarks.html file.
try {
BookmarkHTMLUtils.importFromURL(bookmarksURI.spec, true, (function (success) {
if (success) {
// Now apply distribution customized bookmarks.
// This should always run after Places initialization.
this._distributionCustomizer.applyBookmarks();
// Ensure that smart bookmarks are created once the operation is
// complete.
this.ensurePlacesDefaultQueriesInitialized();
}
else {
Cu.reportError("Bookmarks.html file could be corrupt.");
}
}).bind(this));
var importer = Cc["@mozilla.org/browser/places/import-export-service;1"].
getService(Ci.nsIPlacesImportExportService);
importer.importHTMLFromURI(bookmarksURI, true /* overwrite existing */);
} catch (err) {
// Report the error, but ignore it.
Cu.reportError("Bookmarks.html file could be corrupt. " + err);
Services.obs.removeObserver(this, "bookmarks-restore-success");
Services.obs.removeObserver(this, "bookmarks-restore-failed");
}
}
else {
else
Cu.reportError("Unable to find bookmarks.html file.");
}
// Reset preferences, so we won't try to import again at next run
if (importBookmarksHTML)

View File

@ -400,9 +400,10 @@ var PlacesOrganizer = {
Ci.nsIFilePicker.modeOpen);
fp.appendFilters(Ci.nsIFilePicker.filterHTML);
if (fp.show() != Ci.nsIFilePicker.returnCancel) {
if (fp.fileURL) {
Components.utils.import("resource://gre/modules/BookmarkHTMLUtils.jsm");
BookmarkHTMLUtils.importFromURL(fp.fileURL.spec, false);
if (fp.file) {
var importer = Cc["@mozilla.org/browser/places/import-export-service;1"].
getService(Ci.nsIPlacesImportExportService);
importer.importHTMLFromFile(fp.file, false);
}
}
},

View File

@ -57,8 +57,8 @@ function run_test() {
- export as json, import, test
*/
// import the importer
Cu.import("resource://gre/modules/BookmarkHTMLUtils.jsm");
// get places import/export service
var importer = Cc["@mozilla.org/browser/places/import-export-service;1"].getService(Ci.nsIPlacesImportExportService);
// avoid creating the places smart folder during tests
Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch).
@ -83,14 +83,8 @@ function run_test() {
// 2. run the test-suite
// Note: we do not empty the db before this import to catch bugs like 380999
try {
BookmarkHTMLUtils.importFromFile(bookmarksFileOld, true, after_import);
importer.importHTMLFromFile(bookmarksFileOld, true);
} catch(ex) { do_throw("couldn't import legacy bookmarks file: " + ex); }
}
function after_import(success) {
if (!success) {
do_throw("Couldn't import legacy bookmarks file.");
}
populate();
validate();
@ -101,8 +95,6 @@ function after_import(success) {
// 3. import bookmarks.exported.json
// 4. run the test-suite
try {
var jsonFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
jsonFile.append("bookmarks.exported.json");
PlacesUtils.backups.saveBookmarksToJSONFile(jsonFile);
} catch(ex) { do_throw("couldn't export to file: " + ex); }
LOG("exported json");

View File

@ -55,7 +55,6 @@ var ps = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
var ies = Cc["@mozilla.org/browser/places/import-export-service;1"].
getService(Ci.nsIPlacesImportExportService);
Cu.import("resource://gre/modules/BookmarkHTMLUtils.jsm");
const DESCRIPTION_ANNO = "bookmarkProperties/description";
const LOAD_IN_SIDEBAR_ANNO = "bookmarkProperties/loadInSidebar";
@ -73,14 +72,8 @@ function run_test() {
// import bookmarks from corrupt file
var corruptBookmarksFile = do_get_file("bookmarks.corrupt.html");
try {
BookmarkHTMLUtils.importFromFile(corruptBookmarksFile, true, after_import);
ies.importHTMLFromFile(corruptBookmarksFile, true);
} catch(ex) { do_throw("couldn't import corrupt bookmarks file: " + ex); }
}
function after_import(success) {
if (!success) {
do_throw("Couldn't import corrupt bookmarks file.");
}
// Check that every bookmark is correct
// Corrupt bookmarks should not have been imported
@ -112,16 +105,14 @@ function after_import(success) {
// Import bookmarks
try {
BookmarkHTMLUtils.importFromFile(bookmarksFile, true, before_database_check);
ies.importHTMLFromFile(bookmarksFile, true);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
});
}
function before_database_check(success) {
// Check that every bookmark is correct
database_check();
waitForAsyncUpdates(do_test_finished);
});
}
/*

View File

@ -36,8 +36,6 @@
*
* ***** END LICENSE BLOCK ***** */
Cu.import("resource://gre/modules/BookmarkHTMLUtils.jsm");
/**
* Tests the bookmarks-restore-* nsIObserver notifications after restoring
* bookmarks from JSON and HTML. See bug 470314.
@ -136,14 +134,10 @@ var tests = [
run: function () {
this.file = createFile("bookmarks-test_restoreNotification.html");
addBookmarks();
exporter.exportHTMLToFile(this.file);
importer.exportHTMLToFile(this.file);
remove_all_bookmarks();
try {
BookmarkHTMLUtils.importFromFile(this.file, false, function (success) {
if (!success) {
do_throw(" Restore should not have failed");
}
});
importer.importHTMLFromFile(this.file, false);
}
catch (e) {
do_throw(" Restore should not have failed");
@ -160,11 +154,7 @@ var tests = [
run: function () {
this.file = createFile("bookmarks-test_restoreNotification.init.html");
try {
BookmarkHTMLUtils.importFromFile(this.file, false, function (success) {
if (!success) {
do_throw(" Restore should not have failed");
}
});
importer.importHTMLFromFile(this.file, false);
}
catch (e) {
do_throw(" Restore should not have failed");
@ -182,13 +172,9 @@ var tests = [
this.file = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
this.file.append("this file doesn't exist because nobody created it");
try {
BookmarkHTMLUtils.importFromFile(this.file, false, function (success) {
print("callback");
if (success) {
importer.importHTMLFromFile(this.file, false);
do_throw(" Restore should have failed");
}
});
}
catch (e) {}
}
},
@ -202,14 +188,10 @@ var tests = [
run: function () {
this.file = createFile("bookmarks-test_restoreNotification.init.html");
addBookmarks();
exporter.exportHTMLToFile(this.file);
importer.exportHTMLToFile(this.file);
remove_all_bookmarks();
try {
BookmarkHTMLUtils.importFromFile(this.file, true, function (success) {
if (!success) {
do_throw(" Restore should not have failed");
}
});
importer.importHTMLFromFile(this.file, true);
}
catch (e) {
do_throw(" Restore should not have failed");
@ -226,11 +208,7 @@ var tests = [
run: function () {
this.file = createFile("bookmarks-test_restoreNotification.init.html");
try {
BookmarkHTMLUtils.importFromFile(this.file, true, function (success) {
if (!success) {
do_throw(" Restore should not have failed");
}
});
importer.importHTMLFromFile(this.file, true);
}
catch (e) {
do_throw(" Restore should not have failed");
@ -248,15 +226,13 @@ var tests = [
this.file = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
this.file.append("this file doesn't exist because nobody created it");
try {
BookmarkHTMLUtils.importFromFile(this.file, true, function (success) {
if (success) {
importer.importHTMLFromFile(this.file, true);
do_throw(" Restore should have failed");
}
});
}
catch (e) {}
}
}
];
// nsIObserver that observes bookmarks-restore-begin.
@ -305,7 +281,7 @@ var successAndFailedObserver = {
do_check_eq(test.folderId, null);
remove_all_bookmarks();
do_execute_soon(doNextTest);
doNextTest();
}
};
@ -318,7 +294,7 @@ var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
var obssvc = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
var exporter = Cc["@mozilla.org/browser/places/import-export-service;1"].
var importer = Cc["@mozilla.org/browser/places/import-export-service;1"].
getService(Ci.nsIPlacesImportExportService);
///////////////////////////////////////////////////////////////////////////////

View File

@ -99,11 +99,9 @@ let gBookmarksFileOld;
// Places bookmarks.html file pointer.
let gBookmarksFileNew;
let exporter = Cc["@mozilla.org/browser/places/import-export-service;1"].
let importer = Cc["@mozilla.org/browser/places/import-export-service;1"].
getService(Ci.nsIPlacesImportExportService);
Cu.import("resource://gre/modules/BookmarkHTMLUtils.jsm");
function run_test()
{
run_next_test();
@ -133,14 +131,15 @@ add_test(function setup() {
// 2. run the test-suite
// Note: we do not empty the db before this import to catch bugs like 380999
try {
BookmarkHTMLUtils.importFromFile(gBookmarksFileOld, true, function(success) {
if (success) {
importer.importHTMLFromFile(gBookmarksFileOld, true);
} catch(ex) { do_throw("couldn't import legacy bookmarks file: " + ex); }
waitForAsyncUpdates(function () {
testImportedBookmarks();
// Prepare for next tests.
try {
exporter.exportHTMLToFile(gBookmarksFileNew);
importer.exportHTMLToFile(gBookmarksFileNew);
} catch(ex) { do_throw("couldn't export to file: " + ex); }
waitForAsyncUpdates(function () {
@ -148,11 +147,6 @@ add_test(function setup() {
run_next_test();
});
});
} else {
do_throw("couldn't import legacy bookmarks file.");
}
});
} catch(ex) { do_throw("couldn't import legacy bookmarks file: " + ex); }
});
add_test(function test_import_new()
@ -162,8 +156,9 @@ add_test(function test_import_new()
// 2. run the test-suite
try {
BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true, function(success) {
if (success) {
importer.importHTMLFromFile(gBookmarksFileNew, true);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
waitForAsyncUpdates(function () {
testImportedBookmarks();
@ -172,11 +167,6 @@ add_test(function test_import_new()
run_next_test();
});
});
} else {
do_throw("couldn't import the exported file.");
}
});
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
});
add_test(function test_emptytitle_export()
@ -190,8 +180,9 @@ add_test(function test_emptytitle_export()
// 5. run the test-suite
try {
BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true, function(success) {
if (success) {
importer.importHTMLFromFile(gBookmarksFileNew, true);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
const NOTITLE_URL = "http://notitle.mozilla.org/";
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
NetUtil.newURI(NOTITLE_URL),
@ -200,14 +191,15 @@ add_test(function test_emptytitle_export()
test_bookmarks.unfiled.push({ title: "", url: NOTITLE_URL });
try {
exporter.exportHTMLToFile(gBookmarksFileNew);
importer.exportHTMLToFile(gBookmarksFileNew);
} catch(ex) { do_throw("couldn't export to file: " + ex); }
remove_all_bookmarks();
try {
BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true, function(success) {
if (success) {
importer.importHTMLFromFile(gBookmarksFileNew, true);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
waitForAsyncUpdates(function () {
testImportedBookmarks();
@ -216,7 +208,7 @@ add_test(function test_emptytitle_export()
PlacesUtils.bookmarks.removeItem(id);
try {
exporter.exportHTMLToFile(gBookmarksFileNew);
importer.exportHTMLToFile(gBookmarksFileNew);
} catch(ex) { do_throw("couldn't export to file: " + ex); }
waitForAsyncUpdates(function () {
@ -224,16 +216,6 @@ add_test(function test_emptytitle_export()
run_next_test();
});
});
} else {
do_throw("couldn't import the exported file.");
}
});
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
} else {
do_throw("couldn't import the exported file.");
}
});
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
});
add_test(function test_import_ontop()
@ -247,14 +229,15 @@ add_test(function test_import_ontop()
// 4. run the test-suite
try {
BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true, function(success) {
if (success) {
importer.importHTMLFromFile(gBookmarksFileNew, true);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
try {
exporter.exportHTMLToFile(gBookmarksFileNew);
importer.exportHTMLToFile(gBookmarksFileNew);
} catch(ex) { do_throw("couldn't export to file: " + ex); }
try {
BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true, function(success) {
if (success) {
importer.importHTMLFromFile(gBookmarksFileNew, true);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
waitForAsyncUpdates(function () {
testImportedBookmarks();
@ -263,17 +246,6 @@ add_test(function test_import_ontop()
run_next_test();
});
});
} else {
do_throw("couldn't import the exported file.");
}
});
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
} else {
do_throw("couldn't import the exported file.");
}
});
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
});
function testImportedBookmarks()

View File

@ -29,15 +29,14 @@ function run_test() {
do_check_eq(PlacesUtils.history.databaseStatus,
PlacesUtils.history.DATABASE_STATUS_CREATE);
//A migrator would run before nsBrowserGlue Places initialization, so mimic
//that behavior adding a bookmark and notifying the migration.
// A migrator would run before nsBrowserGlue, so we mimic that behavior
// adding a bookmark.
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.bookmarks.bookmarksMenuFolder, uri("http://mozilla.org/"),
PlacesUtils.bookmarks.DEFAULT_INDEX, "migrated");
// Initialize nsBrowserGlue.
let bg = Cc["@mozilla.org/browser/browserglue;1"].
getService(Ci.nsIObserver);
bg.observe(null, "initial-migration", null)
getService(Ci.nsIBrowserGlue);
let bookmarksObserver = {
onBeginUpdateBatch: function() {},

View File

@ -17,16 +17,6 @@ const TOPICDATA_FORCE_PLACES_INIT = "force-places-init";
let bg = Cc["@mozilla.org/browser/browserglue;1"].
getService(Ci.nsIBrowserGlue);
function waitForImportAndSmartBookmarks(aCallback) {
Services.obs.addObserver(function waitImport() {
Services.obs.removeObserver(waitImport, "bookmarks-restore-success");
// Delay to test eventual smart bookmarks creation.
do_execute_soon(function () {
waitForAsyncUpdates(aCallback);
});
}, "bookmarks-restore-success", false);
}
let gTests = [
// This test must be the first one.
@ -76,7 +66,10 @@ let gTests = [
// Force nsBrowserGlue::_initPlaces().
print("Simulate Places init");
waitForImportAndSmartBookmarks(function () {
bg.QueryInterface(Ci.nsIObserver).observe(null,
TOPIC_BROWSERGLUE_TEST,
TOPICDATA_FORCE_PLACES_INIT);
// Check bookmarks.html has been imported, and a smart bookmark has been
// created.
itemId = PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId,
@ -86,10 +79,6 @@ let gTests = [
do_check_false(Services.prefs.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML));
run_next_test();
});
bg.QueryInterface(Ci.nsIObserver).observe(null,
TOPIC_BROWSERGLUE_TEST,
TOPICDATA_FORCE_PLACES_INIT);
},
function test_import_noSmartBookmarks()
@ -109,7 +98,10 @@ let gTests = [
// Force nsBrowserGlue::_initPlaces().
print("Simulate Places init");
waitForImportAndSmartBookmarks(function () {
bg.QueryInterface(Ci.nsIObserver).observe(null,
TOPIC_BROWSERGLUE_TEST,
TOPICDATA_FORCE_PLACES_INIT);
// Check bookmarks.html has been imported, but smart bookmarks have not
// been created.
itemId =
@ -119,10 +111,6 @@ let gTests = [
do_check_false(Services.prefs.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML));
run_next_test();
});
bg.QueryInterface(Ci.nsIObserver).observe(null,
TOPIC_BROWSERGLUE_TEST,
TOPICDATA_FORCE_PLACES_INIT);
},
function test_import_autoExport_updatedSmartBookmarks()
@ -143,7 +131,10 @@ let gTests = [
// Force nsBrowserGlue::_initPlaces()
print("Simulate Places init");
waitForImportAndSmartBookmarks(function () {
bg.QueryInterface(Ci.nsIObserver).observe(null,
TOPIC_BROWSERGLUE_TEST,
TOPICDATA_FORCE_PLACES_INIT);
// Check bookmarks.html has been imported, but smart bookmarks have not
// been created.
itemId =
@ -154,10 +145,6 @@ let gTests = [
Services.prefs.setBoolPref(PREF_AUTO_EXPORT_HTML, false);
run_next_test();
});
bg.QueryInterface(Ci.nsIObserver).observe(null,
TOPIC_BROWSERGLUE_TEST,
TOPICDATA_FORCE_PLACES_INIT);
},
function test_import_autoExport_oldSmartBookmarks()
@ -178,7 +165,10 @@ let gTests = [
// Force nsBrowserGlue::_initPlaces()
print("Simulate Places init");
waitForImportAndSmartBookmarks(function () {
bg.QueryInterface(Ci.nsIObserver).observe(null,
TOPIC_BROWSERGLUE_TEST,
TOPICDATA_FORCE_PLACES_INIT);
// Check bookmarks.html has been imported, but smart bookmarks have not
// been created.
itemId =
@ -190,10 +180,6 @@ let gTests = [
Services.prefs.setBoolPref(PREF_AUTO_EXPORT_HTML, false);
run_next_test();
});
bg.QueryInterface(Ci.nsIObserver).observe(null,
TOPIC_BROWSERGLUE_TEST,
TOPICDATA_FORCE_PLACES_INIT);
},
function test_restore()
@ -212,7 +198,10 @@ let gTests = [
// Force nsBrowserGlue::_initPlaces()
print("Simulate Places init");
waitForImportAndSmartBookmarks(function () {
bg.QueryInterface(Ci.nsIObserver).observe(null,
TOPIC_BROWSERGLUE_TEST,
TOPICDATA_FORCE_PLACES_INIT);
// Check bookmarks.html has been restored.
itemId =
PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId,
@ -222,11 +211,6 @@ let gTests = [
do_check_false(Services.prefs.getBoolPref(PREF_RESTORE_DEFAULT_BOOKMARKS));
run_next_test();
});
bg.QueryInterface(Ci.nsIObserver).observe(null,
TOPIC_BROWSERGLUE_TEST,
TOPICDATA_FORCE_PLACES_INIT);
},
function test_restore_import()
@ -246,7 +230,10 @@ let gTests = [
// Force nsBrowserGlue::_initPlaces()
print("Simulate Places init");
waitForImportAndSmartBookmarks(function () {
bg.QueryInterface(Ci.nsIObserver).observe(null,
TOPIC_BROWSERGLUE_TEST,
TOPICDATA_FORCE_PLACES_INIT);
// Check bookmarks.html has been restored.
itemId =
PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.toolbarFolderId,
@ -257,10 +244,6 @@ let gTests = [
do_check_false(Services.prefs.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML));
run_next_test();
});
bg.QueryInterface(Ci.nsIObserver).observe(null,
TOPIC_BROWSERGLUE_TEST,
TOPICDATA_FORCE_PLACES_INIT);
}
];

View File

@ -364,15 +364,6 @@ function run_test() {
}
catch(ex) {}
waitForImportAndSmartBookmarks(next_test);
}
function waitForImportAndSmartBookmarks(aCallback) {
Services.obs.addObserver(function waitImport() {
Services.obs.removeObserver(waitImport, "bookmarks-restore-success");
// Delay to test eventual smart bookmarks creation.
do_execute_soon(function () {
waitForAsyncUpdates(aCallback);
});
}, "bookmarks-restore-success", false);
// Kick-off tests.
next_test();
}

View File

@ -1,775 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
const EXPORTED_SYMBOLS = [ "BookmarkHTMLUtils" ];
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/PlacesUtils.jsm");
const Container_Normal = 0;
const Container_Toolbar = 1;
const Container_Menu = 2;
const Container_Unfiled = 3;
const Container_Places = 4;
const RESTORE_BEGIN_NSIOBSERVER_TOPIC = "bookmarks-restore-begin";
const RESTORE_SUCCESS_NSIOBSERVER_TOPIC = "bookmarks-restore-success";
const RESTORE_FAILED_NSIOBSERVER_TOPIC = "bookmarks-restore-failed";
const RESTORE_NSIOBSERVER_DATA = "html";
const RESTORE_INITIAL_NSIOBSERVER_DATA = "html-initial";
const LOAD_IN_SIDEBAR_ANNO = "bookmarkProperties/loadInSidebar";
const DESCRIPTION_ANNO = "bookmarkProperties/description";
const POST_DATA_ANNO = "bookmarkProperties/POSTData";
let serialNumber = 0; // for favicons
let BookmarkHTMLUtils = Object.freeze({
importFromURL: function importFromFile(aUrlString,
aInitialImport,
aCallback) {
let importer = new BookmarkImporter(aInitialImport);
importer.importFromURL(aUrlString, aCallback);
},
importFromFile: function importFromFile(aLocalFile,
aInitialImport,
aCallback) {
let importer = new BookmarkImporter(aInitialImport);
importer.importFromFile(aLocalFile, aCallback);
},
});
function Frame(aFrameId) {
this.containerId = aFrameId;
/**
* How many <dl>s have been nested. Each frame/container should start
* with a heading, and is then followed by a <dl>, <ul>, or <menu>. When
* that list is complete, then it is the end of this container and we need
* to pop back up one level for new items. If we never get an open tag for
* one of these things, we should assume that the container is empty and
* that things we find should be siblings of it. Normally, these <dl>s won't
* be nested so this will be 0 or 1.
*/
this.containerNesting = 0;
/**
* when we find a heading tag, it actually affects the title of the NEXT
* container in the list. This stores that heading tag and whether it was
* special. 'consumeHeading' resets this._
*/
this.lastContainerType = Container_Normal;
/**
* this contains the text from the last begin tag until now. It is reset
* at every begin tag. We can check it when we see a </a>, or </h3>
* to see what the text content of that node should be.
*/
this.previousText = "";
/**
* true when we hit a <dd>, which contains the description for the preceding
* <a> tag. We can't just check for </dd> like we can for </a> or </h3>
* because if there is a sub-folder, it is actually a child of the <dd>
* because the tag is never explicitly closed. If this is true and we see a
* new open tag, that means to commit the description to the previous
* bookmark.
*
* Additional weirdness happens when the previous <dt> tag contains a <h3>:
* this means there is a new folder with the given description, and whose
* children are contained in the following <dl> list.
*
* This is handled in openContainer(), which commits previous text if
* necessary.
*/
this.inDescription = false;
/**
* contains the URL of the previous bookmark created. This is used so that
* when we encounter a <dd>, we know what bookmark to associate the text with.
* This is cleared whenever we hit a <h3>, so that we know NOT to save this
* with a bookmark, but to keep it until
*/
this.previousLink = null; // nsIURI
/**
* contains the URL of the previous livemark, so that when the link ends,
* and the livemark title is known, we can create it.
*/
this.previousFeed = null; // nsIURI
/**
* Contains the id of an imported, or newly created bookmark.
*/
this.previousId = 0;
/**
* Contains the date-added and last-modified-date of an imported item.
* Used to override the values set by insertBookmark, createFolder, etc.
*/
this.previousDateAdded = 0;
this.previousLastModifiedDate = 0;
}
function BookmarkImporter(aInitialImport) {
this._isImportDefaults = aInitialImport;
this._frames = new Array();
this._frames.push(new Frame(PlacesUtils.bookmarksMenuFolderId));
}
BookmarkImporter.prototype = {
_safeTrim: function safeTrim(aStr) {
return aStr ? aStr.trim() : aStr;
},
get _curFrame() {
return this._frames[this._frames.length - 1];
},
get _previousFrame() {
return this._frames[this._frames.length - 2];
},
/**
* This is called when there is a new folder found. The folder takes the
* name from the previous frame's heading.
*/
_newFrame: function newFrame() {
let containerId = -1;
let frame = this._curFrame;
let containerTitle = frame.previousText;
frame.previousText = "";
let containerType = frame.lastContainerType;
switch (containerType) {
case Container_Normal:
// append a new folder
containerId =
PlacesUtils.bookmarks.createFolder(frame.containerId,
containerTitle,
PlacesUtils.bookmarks.DEFAULT_INDEX);
break;
case Container_Places:
containerId = PlacesUtils.placesRootId;
break;
case Container_Menu:
containerId = PlacesUtils.bookmarksMenuFolderId;
break;
case Container_Unfiled:
containerId = PlacesUtils.unfiledBookmarksFolderId;
break;
case Container_Toolbar:
containerId = PlacesUtils.toolbarFolderId;
break;
default:
// NOT REACHED
throw new Error("Unreached");
}
if (frame.previousDateAdded > 0) {
try {
PlacesUtils.bookmarks.setItemDateAdded(containerId, frame.previousDateAdded);
} catch(e) {
}
frame.previousDateAdded = 0;
}
if (frame.previousLastModifiedDate > 0) {
try {
PlacesUtils.bookmarks.setItemLastModified(containerId, frame.previousLastModifiedDate);
} catch(e) {
}
// don't clear last-modified, in case there's a description
}
frame.previousId = containerId;
this._frames.push(new Frame(containerId));
},
/**
* Handles <H1>. We check for the attribute PLACES_ROOT and reset the
* container id if it's found. Otherwise, the default bookmark menu
* root is assumed and imported things will go into the bookmarks menu.
*/
_handleHead1Begin: function handleHead1Begin(aElt) {
if (this._frames.length > 1) {
return;
}
if (aElt.hasAttribute("places_root")) {
this._curFrame.containerId = PlacesUtils.placesRootId;
}
},
/**
* Called for h2,h3,h4,h5,h6. This just stores the correct information in
* the current frame; the actual new frame corresponding to the container
* associated with the heading will be created when the tag has been closed
* and we know the title (we don't know to create a new folder or to merge
* with an existing one until we have the title).
*/
_handleHeadBegin: function handleHeadBegin(aElt) {
let frame = this._curFrame;
// after a heading, a previous bookmark is not applicable (for example, for
// the descriptions contained in a <dd>). Neither is any previous head type
frame.previousLink = null;
frame.lastContainerType = Container_Normal;
// It is syntactically possible for a heading to appear after another heading
// but before the <dl> that encloses that folder's contents. This should not
// happen in practice, as the file will contain "<dl></dl>" sequence for
// empty containers.
//
// Just to be on the safe side, if we encounter
// <h3>FOO</h3>
// <h3>BAR</h3>
// <dl>...content 1...</dl>
// <dl>...content 2...</dl>
// we'll pop the stack when we find the h3 for BAR, treating that as an
// implicit ending of the FOO container. The output will be FOO and BAR as
// siblings. If there's another <dl> following (as in "content 2"), those
// items will be treated as further siblings of FOO and BAR
if (frame.containerNesting == 0) {
this._frames.pop();
}
// We have to check for some attributes to see if this is a "special"
// folder, which will have different creation rules when the end tag is
// processed.
if (aElt.hasAttribute("personal_toolbar_folder")) {
if (this._isImportDefaults) {
frame.lastContainerType = Container_Toolbar;
}
} else if (aElt.hasAttribute("bookmarks_menu")) {
if (this._isImportDefaults) {
frame.lastContainerType = Container_Menu;
}
} else if (aElt.hasAttribute("unfiled_bookmarks_folder")) {
if (this._isImportDefaults) {
frame.lastContainerType = Container_Unfiled;
}
} else if (aElt.hasAttribute("places_root")) {
if (this._isImportDefaults) {
frame.lastContainerType = Container_Places;
}
} else {
let addDate = aElt.getAttribute("add_date");
if (addDate) {
frame.previousDateAdded =
this._convertImportedDateToInternalDate(addDate);
}
let modDate = aElt.getAttribute("last_modified");
if (modDate) {
frame.previousLastModifiedDate =
this._convertImportedDateToInternalDate(modDate);
}
}
this._curFrame.previousText = "";
},
/*
* Handles "<a" tags by creating a new bookmark. The title of the bookmark
* will be the text content, which will be stuffed in previousText for us
* and which will be saved by handleLinkEnd
*/
_handleLinkBegin: function handleLinkBegin(aElt) {
let frame = this._curFrame;
// Make sure that the feed URIs from previous frames are emptied.
frame.previousFeed = null;
// Make sure that the bookmark id from previous frames are emptied.
frame.previousId = 0;
// mPreviousText will hold link text, clear it.
frame.previousText = "";
// Get the attributes we care about.
let href = this._safeTrim(aElt.getAttribute("href"));
let feedUrl = this._safeTrim(aElt.getAttribute("feedurl"));
let icon = this._safeTrim(aElt.getAttribute("icon"));
let iconUri = this._safeTrim(aElt.getAttribute("icon_uri"));
let lastCharset = this._safeTrim(aElt.getAttribute("last_charset"));
let keyword = this._safeTrim(aElt.getAttribute("shortcuturl"));
let postData = this._safeTrim(aElt.getAttribute("post_data"));
let webPanel = this._safeTrim(aElt.getAttribute("web_panel"));
let micsumGenURI = this._safeTrim(aElt.getAttribute("micsum_gen_uri"));
let generatedTitle = this._safeTrim(aElt.getAttribute("generated_title"));
let dateAdded = this._safeTrim(aElt.getAttribute("add_date"));
let lastModified = this._safeTrim(aElt.getAttribute("last_modified"));
// For feeds, get the feed URL. If it is invalid, mPreviousFeed will be
// NULL and we'll create it as a normal bookmark.
if (feedUrl) {
frame.previousFeed = NetUtil.newURI(feedUrl);
}
// Ignore <a> tags that have no href.
if (href) {
// Save the address if it's valid. Note that we ignore errors if this is a
// feed since href is optional for them.
try {
frame.previousLink = NetUtil.newURI(href);
} catch(e) {
if (!frame.previousFeed) {
frame.previousLink = null;
return;
}
}
} else {
frame.previousLink = null;
// The exception is for feeds, where the href is an optional component
// indicating the source web site.
if (!frame.previousFeed) {
return;
}
}
// Save bookmark's last modified date.
if (lastModified) {
frame.previousLastModifiedDate =
this._convertImportedDateToInternalDate(lastModified);
}
// If this is a live bookmark, we will handle it in HandleLinkEnd(), so we
// can skip bookmark creation.
if (frame.previousFeed) {
return;
}
// Create the bookmark. The title is unknown for now, we will set it later.
try {
frame.previousId =
PlacesUtils.bookmarks.insertBookmark(frame.containerId,
frame.previousLink,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"");
} catch(e) {
return;
}
// Set the date added value, if we have it.
if (dateAdded) {
try {
PlacesUtils.bookmarks.setItemDateAdded(frame.previousId,
this._convertImportedDateToInternalDate(dateAdded));
} catch(e) {
}
}
// Save the favicon.
if (icon || iconUri) {
let iconUriObject;
try {
iconUriObject = NetUtil.newURI(iconUri);
} catch(e) {
}
if (icon || iconUriObject) {
try {
this._setFaviconForURI(frame.previousLink, iconUriObject, icon);
} catch(e) {
}
}
}
// Save the keyword.
if (keyword) {
try {
PlacesUtils.bookmarks.setKeywordForBookmark(frame.previousId, keyword);
if (postData) {
PlacesUtils.annotations.setItemAnnotation(frame.previousId,
POST_DATA_ANNO,
postData,
0,
PlacesUtils.annotations.EXPIRE_NEVER);
}
} catch(e) {
}
}
// Set load-in-sidebar annotation for the bookmark.
if (webPanel && webPanel.toLowerCase() == "true") {
try {
PlacesUtils.annotations.setItemAnnotation(frame.previousId,
LOAD_IN_SIDEBAR_ANNO,
1,
0,
PlacesUtils.annotations.EXPIRE_NEVER);
} catch(e) {
}
}
// Import last charset.
if (lastCharset) {
try {
PlacesUtils.history.setCharsetForURI(frame.previousLink, lastCharset);
} catch(e) {
}
}
},
_handleContainerBegin: function handleContainerBegin() {
this._curFrame.containerNesting++;
},
/**
* Our "indent" count has decreased, and when we hit 0 that means that this
* container is complete and we need to pop back to the outer frame. Never
* pop the toplevel frame
*/
_handleContainerEnd: function handleContainerEnd() {
let frame = this._curFrame;
if (frame.containerNesting > 0)
frame.containerNesting --;
if (this._frames.length > 1 && frame.containerNesting == 0) {
// we also need to re-set the imported last-modified date here. Otherwise
// the addition of items will override the imported field.
let prevFrame = this._previousFrame;
if (prevFrame.previousLastModifiedDate > 0) {
PlacesUtils.bookmarks.setItemLastModified(frame.containerId,
prevFrame.previousLastModifiedDate);
}
this._frames.pop();
}
},
/**
* Creates the new frame for this heading now that we know the name of the
* container (tokens since the heading open tag will have been placed in
* previousText).
*/
_handleHeadEnd: function handleHeadEnd() {
this._newFrame();
},
/**
* Saves the title for the given bookmark.
*/
_handleLinkEnd: function handleLinkEnd() {
let frame = this._curFrame;
frame.previousText = frame.previousText.trim();
try {
if (frame.previousFeed) {
// The is a live bookmark. We create it here since in HandleLinkBegin we
// don't know the title.
PlacesUtils.livemarks.addLivemark({
"title": frame.previousText,
"parentId": frame.containerId,
"index": PlacesUtils.bookmarks.DEFAULT_INDEX,
"feedURI": frame.previousFeed,
"siteURI": frame.previousLink,
});
} else if (frame.previousLink) {
// This is a common bookmark.
PlacesUtils.bookmarks.setItemTitle(frame.previousId,
frame.previousText);
}
} catch(e) {
}
// Set last modified date as the last change.
if (frame.previousId > 0 && frame.previousLastModifiedDate > 0) {
try {
PlacesUtils.bookmarks.setItemLastModified(frame.previousId,
frame.previousLastModifiedDate);
} catch(e) {
}
// Note: don't clear previousLastModifiedDate, because if this item has a
// description, we'll need to set it again.
}
frame.previousText = "";
},
_openContainer: function openContainer(aElt) {
if (aElt.namespaceURI != "http://www.w3.org/1999/xhtml") {
return;
}
switch(aElt.localName) {
case "h1":
this._handleHead1Begin(aElt);
break;
case "h2":
case "h3":
case "h4":
case "h5":
case "h6":
this._handleHeadBegin(aElt);
break;
case "a":
this._handleLinkBegin(aElt);
break;
case "dl":
case "ul":
case "menu":
this._handleContainerBegin();
break;
case "dd":
this._curFrame.inDescription = true;
break;
}
},
_closeContainer: function closeContainer(aElt) {
let frame = this._curFrame;
// see the comment for the definition of inDescription. Basically, we commit
// any text in previousText to the description of the node/folder if there
// is any.
if (frame.inDescription) {
// NOTE ES5 trim trims more than the previous C++ trim.
frame.previousText = frame.previousText.trim(); // important
if (frame.previousText) {
let itemId = !frame.previousLink ? frame.containerId
: frame.previousId;
try {
if (!PlacesUtils.annotations.itemHasAnnotation(itemId, DESCRIPTION_ANNO)) {
PlacesUtils.annotations.setItemAnnotation(itemId,
DESCRIPTION_ANNO,
frame.previousText,
0,
PlacesUtils.annotations.EXPIRE_NEVER);
}
} catch(e) {
}
frame.previousText = "";
// Set last-modified a 2nd time for all items with descriptions
// we need to set last-modified as the *last* step in processing
// any item type in the bookmarks.html file, so that we do
// not overwrite the imported value. for items without descriptions,
// setting this value after setting the item title is that
// last point at which we can save this value before it gets reset.
// for items with descriptions, it must set after that point.
// however, at the point at which we set the title, there's no way
// to determine if there will be a description following,
// so we need to set the last-modified-date at both places.
let lastModified;
if (!frame.previousLink) {
lastModified = this._previousFrame.previousLastModifiedDate;
} else {
lastModified = frame.previousLastModifiedDate;
}
if (itemId > 0 && lastModified > 0) {
PlacesUtils.bookmarks.setItemLastModified(itemId, lastModified);
}
}
frame.inDescription = false;
}
if (aElt.namespaceURI != "http://www.w3.org/1999/xhtml") {
return;
}
switch(aElt.localName) {
case "dl":
case "ul":
case "menu":
this._handleContainerEnd();
break;
case "dt":
break;
case "h1":
// ignore
break;
case "h2":
case "h3":
case "h4":
case "h5":
case "h6":
this._handleHeadEnd();
break;
case "a":
this._handleLinkEnd();
break;
default:
break;
}
},
_appendText: function appendText(str) {
this._curFrame.previousText += str;
},
/**
* data is a string that is a data URI for the favicon. Our job is to
* decode it and store it in the favicon service.
*
* When aIconURI is non-null, we will use that as the URI of the favicon
* when storing in the favicon service.
*
* When aIconURI is null, we have to make up a URI for this favicon so that
* it can be stored in the service. The real one will be set the next time
* the user visits the page. Our made up one should get expired when the
* page no longer references it.
*/
_setFaviconForURI: function setFaviconForURI(aPageURI, aIconURI, aData) {
// if the input favicon URI is a chrome: URI, then we just save it and don't
// worry about data
if (aIconURI) {
if (aIconURI.scheme == "chrome") {
PlacesUtils.favicons.setFaviconUrlForPage(aPageURI, aIconURI);
return;
}
}
// some bookmarks have placeholder URIs that contain just "data:"
// ignore these
if (aData.length <= 5) {
return;
}
let faviconURI;
if (aIconURI) {
faviconURI = aIconURI;
} else {
// make up favicon URL
let faviconSpec = "http://www.mozilla.org/2005/made-up-favicon/"
+ serialNumber
+ "-"
+ new Date().getTime();
faviconURI = NetUtil.newURI(faviconSpec);
serialNumber++;
}
// save the favicon data
// This could fail if the favicon is bigger than defined limit, in such a
// case data will not be saved to the db but we will still continue.
PlacesUtils.favicons.setFaviconDataFromDataURL(faviconURI, aData, 0);
PlacesUtils.favicons.setFaviconUrlForPage(aPageURI, faviconURI);
},
/**
* Converts a string date in seconds to an int date in microseconds
*/
_convertImportedDateToInternalDate: function convertImportedDateToInternalDate(aDate) {
if (aDate && !isNaN(aDate)) {
return parseInt(aDate) * 1000000; // in bookmarks.html this value is in seconds, not microseconds
} else {
return Date.now();
}
},
runBatched: function runBatched(aDoc) {
if (!aDoc) {
return;
}
if (this._isImportDefaults) {
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.bookmarksMenuFolderId);
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.toolbarFolderId);
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
}
let current = aDoc;
let next;
for (;;) {
switch (current.nodeType) {
case Ci.nsIDOMNode.ELEMENT_NODE:
this._openContainer(current);
break;
case Ci.nsIDOMNode.TEXT_NODE:
this._appendText(current.data);
break;
}
if ((next = current.firstChild)) {
current = next;
continue;
}
for (;;) {
if (current.nodeType == Ci.nsIDOMNode.ELEMENT_NODE) {
this._closeContainer(current);
}
if (current == aDoc) {
return;
}
if ((next = current.nextSibling)) {
current = next;
break;
}
current = current.parentNode;
}
}
},
_walkTreeForImport: function walkTreeForImport(aDoc) {
PlacesUtils.bookmarks.runInBatchMode(this, aDoc);
},
_notifyObservers: function notifyObservers(topic) {
Services.obs.notifyObservers(null,
topic,
this._isImportDefaults ?
RESTORE_INITIAL_NSIOBSERVER_DATA :
RESTORE_NSIOBSERVER_DATA);
},
importFromURL: function importFromURL(aUrlString, aCallback) {
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
xhr.onload = (function onload() {
try {
this._walkTreeForImport(xhr.responseXML);
this._notifyObservers(RESTORE_SUCCESS_NSIOBSERVER_TOPIC);
if (aCallback) {
try {
aCallback(true);
} catch(ex) {
}
}
} catch(e) {
this._notifyObservers(RESTORE_FAILED_NSIOBSERVER_TOPIC);
if (aCallback) {
try {
aCallback(false);
} catch(ex) {
}
}
throw e;
}
}).bind(this);
xhr.onabort = xhr.onerror = xhr.ontimeout = (function handleFail() {
this._notifyObservers(RESTORE_FAILED_NSIOBSERVER_TOPIC);
if (aCallback) {
try {
aCallback(false);
} catch(ex) {
}
}
}).bind(this);
this._notifyObservers(RESTORE_BEGIN_NSIOBSERVER_TOPIC);
try {
xhr.open("GET", aUrlString);
xhr.responseType = "document";
xhr.overrideMimeType("text/html");
xhr.send();
} catch (e) {
this._notifyObservers(RESTORE_FAILED_NSIOBSERVER_TOPIC);
if (aCallback) {
try {
aCallback(false);
} catch(ex) {
}
}
}
},
importFromFile: function importFromFile(aLocalFile, aCallback) {
let url = NetUtil.newURI(aLocalFile);
this.importFromURL(url.spec, aCallback);
},
};

View File

@ -445,5 +445,64 @@ AsyncStatementTelemetryTimer::HandleCompletion(PRUint16 aReason)
return NS_OK;
}
// This is a temporary converter used by nsPlacesImportExportService until
// bug 482911 completes its js rewrite.
jsval
livemarkInfoToJSVal(PRInt64 aId,
const nsACString& aGUID,
const nsAString& aTitle,
PRInt64 aParentId,
PRInt32 aIndex,
nsCOMPtr<nsIURI>& aFeedURI,
nsCOMPtr<nsIURI>& aSiteURI)
{
nsCOMPtr<nsIXPConnect> xpc = mozilla::services::GetXPConnect();
NS_ENSURE_TRUE(xpc, JSVAL_NULL);
nsAXPCNativeCallContext *ncc;
nsresult rv = xpc->GetCurrentNativeCallContext(&ncc);
NS_ENSURE_SUCCESS(rv, JSVAL_NULL);
JSContext *cx = nsnull;
rv = ncc->GetJSContext(&cx);
NS_ENSURE_SUCCESS(rv, JSVAL_NULL);
JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
NS_ENSURE_TRUE(obj, JSVAL_NULL);
jsval id;
NS_ENSURE_TRUE(JS_NewNumberValue(cx, double(aId), &id), JSVAL_NULL);
JSString* guid = JS_NewStringCopyN(cx, PromiseFlatCString(aGUID).get(),
aGUID.Length());
NS_ENSURE_TRUE(guid, JSVAL_NULL);
JSString* title = JS_NewUCStringCopyN(cx, PromiseFlatString(aTitle).get(),
aTitle.Length());
NS_ENSURE_TRUE(title, JSVAL_NULL);
jsval parentId;
NS_ENSURE_TRUE(JS_NewNumberValue(cx, double(aParentId), &parentId), JSVAL_NULL);
jsval feedURI;
rv = nsContentUtils::WrapNative(cx, JS_GetGlobalForScopeChain(cx),
NS_ISUPPORTS_CAST(nsIURI*, aFeedURI), &feedURI);
NS_ENSURE_SUCCESS(rv, JSVAL_NULL);
jsval siteURI;
rv = nsContentUtils::WrapNative(cx, JS_GetGlobalForScopeChain(cx),
NS_ISUPPORTS_CAST(nsIURI*, aSiteURI), &siteURI);
NS_ENSURE_SUCCESS(rv, JSVAL_NULL);
if (!JS_DefineProperty(cx, obj, "id", id, NULL, NULL, JSPROP_ENUMERATE) ||
!JS_DefineProperty(cx, obj, "guid", STRING_TO_JSVAL(guid), NULL, NULL, JSPROP_ENUMERATE) ||
!JS_DefineProperty(cx, obj, "title", STRING_TO_JSVAL(title), NULL, NULL, JSPROP_ENUMERATE) ||
!JS_DefineProperty(cx, obj, "parentId", parentId, NULL, NULL, JSPROP_ENUMERATE) ||
!JS_DefineProperty(cx, obj, "index", INT_TO_JSVAL(aIndex), NULL, NULL, JSPROP_ENUMERATE) ||
!JS_DefineProperty(cx, obj, "feedURI", feedURI, NULL, NULL, JSPROP_ENUMERATE) ||
!JS_DefineProperty(cx, obj, "siteURI", siteURI, NULL, NULL, JSPROP_ENUMERATE)) {
return JSVAL_NULL;
}
return OBJECT_TO_JSVAL(obj);
}
} // namespace places
} // namespace mozilla

View File

@ -297,6 +297,15 @@ private:
const TimeStamp mStart;
};
jsval
livemarkInfoToJSVal(PRInt64 aId,
const nsACString& aGUID,
const nsAString& aTitle,
PRInt64 aParentId,
PRInt32 aIndex,
nsCOMPtr<nsIURI>& aFeedURI,
nsCOMPtr<nsIURI>& aSiteURI);
} // namespace places
} // namespace mozilla

View File

@ -92,7 +92,7 @@ CPPSRCS = \
SQLFunctions.cpp \
Helpers.cpp \
History.cpp \
nsPlacesExportService.cpp \
nsPlacesImportExportService.cpp \
AsyncFaviconHelpers.cpp \
PlaceInfo.cpp \
VisitInfo.cpp \
@ -123,7 +123,6 @@ endif
EXTRA_JS_MODULES = \
PlacesDBUtils.jsm \
BookmarkHTMLUtils.jsm \
$(NULL)
EXTRA_PP_JS_MODULES = \

View File

@ -85,7 +85,7 @@ XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
const MIN_TRANSACTIONS_FOR_BATCH = 5;
// The RESTORE_*_NSIOBSERVER_TOPIC constants should match the #defines of the
// same names in browser/components/places/src/nsPlacesExportService.cpp
// same names in browser/components/places/src/nsPlacesImportExportService.cpp
const RESTORE_BEGIN_NSIOBSERVER_TOPIC = "bookmarks-restore-begin";
const RESTORE_SUCCESS_NSIOBSERVER_TOPIC = "bookmarks-restore-success";
const RESTORE_FAILED_NSIOBSERVER_TOPIC = "bookmarks-restore-failed";

View File

@ -41,15 +41,34 @@ interface nsILocalFile;
interface nsIURI;
/**
* The PlacesImportExport interface provides methods for exporting Places data.
* The word "Import" is in the name for legacy reasons and was kept to avoid
* disrupting potential extension code using the export part. The new importer
* lives in BookmarkHTMLUtils.jsm.
* The PlacesImportExport interface provides methods for importing
* and exporting Places data.
*/
[scriptable, uuid(47a4a09e-c708-4e68-b2f2-664d982ce026)]
[scriptable, uuid(08f4626e-af3f-4e84-bd01-cf09175c4f94)]
interface nsIPlacesImportExportService: nsISupports
{
/**
* Loads the given bookmarks.html file and replaces it with the current
* bookmarks hierarchy (if aIsInitialImport is true) or appends it
* (if aIsInitialImport is false).
*
* Three nsIObserverService notifications are fired as a result of the
* import. "bookmarks-restore-begin" is fired just before the import is
* started. "bookmarks-restore-success" is fired right after the
* bookmarks are successfully imported. "bookmarks-restore-failed" is
* fired right after a failure occurs when importing the bookmarks.
* Observers will be passed through their data parameters either "html"
* if aIsInitialImport is false or "html-initial" if aIsInitialImport is
* true. The observer subject will be null.
*/
void importHTMLFromFile(in nsILocalFile aFile, in boolean aIsInitialImport);
/**
* Same thing as importHTMLFromFile, but takes a URI instead
*/
void importHTMLFromURI(in nsIURI aURI, in boolean aIsInitialImport);
/**
* Saves the current bookmarks hierarchy to a bookmarks.html file.
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
#ifndef nsPlacesExportService_h_
#define nsPlacesExportService_h_
#ifndef nsPlacesImportExportService_h__
#define nsPlacesImportExportService_h__
#include "nsIPlacesImportExportService.h"
@ -13,17 +13,19 @@
#include "nsINavBookmarksService.h"
#include "nsIChannel.h"
class nsPlacesExportService : public nsIPlacesImportExportService
class nsPlacesImportExportService : public nsIPlacesImportExportService,
public nsINavHistoryBatchCallback
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPLACESIMPORTEXPORTSERVICE
nsPlacesExportService();
NS_DECL_NSINAVHISTORYBATCHCALLBACK
nsPlacesImportExportService();
/**
* Obtains the service's object.
*/
static nsPlacesExportService* GetSingleton();
static nsPlacesImportExportService* GetSingleton();
/**
* Initializes the service's object. This should only be called once.
@ -31,8 +33,8 @@ class nsPlacesExportService : public nsIPlacesImportExportService
nsresult Init();
private:
static nsPlacesExportService* gExportService;
virtual ~nsPlacesExportService();
static nsPlacesImportExportService* gImportExportService;
virtual ~nsPlacesImportExportService();
protected:
nsCOMPtr<nsIFaviconService> mFaviconService;
@ -41,6 +43,13 @@ class nsPlacesExportService : public nsIPlacesImportExportService
nsCOMPtr<nsINavHistoryService> mHistoryService;
nsCOMPtr<mozIAsyncLivemarks> mLivemarkService;
nsCOMPtr<nsIChannel> mImportChannel;
bool mIsImportDefaults;
nsresult ImportHTMLFromFileInternal(nsILocalFile* aFile, bool aAllowRootChanges,
PRInt64 aFolder, bool aIsImportDefaults);
nsresult ImportHTMLFromURIInternal(nsIURI* aURI, bool aAllowRootChanges,
PRInt64 aFolder, bool aIsImportDefaults);
nsresult WriteContainer(nsINavHistoryResultNode* aFolder, const nsACString& aIndent, nsIOutputStream* aOutput);
nsresult WriteContainerHeader(nsINavHistoryResultNode* aFolder, const nsACString& aIndent, nsIOutputStream* aOutput);
nsresult WriteTitle(nsINavHistoryResultNode* aItem, nsIOutputStream* aOutput);
@ -60,4 +69,4 @@ class nsPlacesExportService : public nsIPlacesImportExportService
}
};
#endif // nsPlacesExportService_h_
#endif // nsPlacesImportExportService_h__

View File

@ -6,7 +6,7 @@
#include "nsNavHistory.h"
#include "nsNavBookmarks.h"
#include "nsFaviconService.h"
#include "nsPlacesExportService.h"
#include "nsPlacesImportExportService.h"
#include "History.h"
#include "nsDocShellCID.h"
@ -24,8 +24,8 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsNavBookmarks,
nsNavBookmarks::GetSingleton)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsFaviconService,
nsFaviconService::GetSingleton)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsPlacesExportService,
nsPlacesExportService::GetSingleton)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsPlacesImportExportService,
nsPlacesImportExportService::GetSingleton)
#ifdef MOZ_ANDROID_HISTORY
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsAndroidHistory, nsAndroidHistory::GetSingleton)
#else
@ -57,7 +57,7 @@ const mozilla::Module::CIDEntry kPlacesCIDs[] = {
#else
{ &kNS_HISTORYSERVICE_CID, false, NULL, HistoryConstructor },
#endif
{ &kNS_PLACESIMPORTEXPORTSERVICE_CID, false, NULL, nsPlacesExportServiceConstructor },
{ &kNS_PLACESIMPORTEXPORTSERVICE_CID, false, NULL, nsPlacesImportExportServiceConstructor },
{ NULL }
};