fix for bug #383840: problems when manually importing bookmarks exported from places based bookmark builds

fix for bug #381225:  on import, places bookmarks builds attempt to merge in bookmarks.html, where firefox 2 appends bookmarks

fix for bug #380449:  potential data loss on export of LAST_MODIFIED, DATE_ADDED and ICON_URI attributes

r=dietrich
This commit is contained in:
sspitzer@mozilla.org 2007-06-25 19:38:34 -07:00
parent 3b82cc8fa8
commit 590f31b086

View File

@ -102,11 +102,12 @@
#include "nsToolkitCompsCID.h"
#include "nsIHTMLContentSink.h"
#include "nsIParser.h"
#include "prprf.h"
static NS_DEFINE_CID(kParserCID, NS_PARSER_CID);
#define KEY_TOOLBARFOLDER_LOWER "personal_toolbar_folder"
#define KEY_BOOKMARKSSMENU_LOWER "bookmarks_menu"
#define KEY_BOOKMARKSMENU_LOWER "bookmarks_menu"
#define KEY_PLACESROOT_LOWER "places_root"
#define KEY_HREF_LOWER "href"
#define KEY_FEEDURL_LOWER "feedurl"
@ -116,7 +117,6 @@ static NS_DEFINE_CID(kParserCID, NS_PARSER_CID);
#define KEY_ICON_URI_LOWER "icon_uri"
#define KEY_SHORTCUTURL_LOWER "shortcuturl"
#define KEY_POST_DATA_LOWER "post_data"
#define KEY_ITEM_ID_LOWER "item_id"
#define KEY_NAME_LOWER "name"
#define KEY_MICSUM_GEN_URI_LOWER "micsum_gen_uri"
#define KEY_GENERATED_TITLE_LOWER "generated_title"
@ -128,7 +128,7 @@ static NS_DEFINE_CID(kParserCID, NS_PARSER_CID);
#define POST_DATA_ANNO NS_LITERAL_CSTRING("URIProperties/POSTData")
#define GENERATED_TITLE_ANNO NS_LITERAL_CSTRING("bookmarks/generatedTitle")
#define BOOKMARKSS_MENU_ICON_URI "chrome://browser/skin/places/bookmarksMenu.png"
#define BOOKMARKS_MENU_ICON_URI "chrome://browser/skin/places/bookmarksMenu.png"
// define to get debugging messages on console about import/export
//#define DEBUG_IMPORT
@ -179,9 +179,6 @@ public:
// special. 'ConsumeHeading' resets this.
ContainerType mLastContainerType;
// Container Id, see above
PRInt64 mLastContainerId;
// 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.
@ -212,11 +209,10 @@ public:
// and the livemark title is known, we can create it.
nsCOMPtr<nsIURI> mPreviousFeed;
void ConsumeHeading(nsAString* aHeading, ContainerType* aContainerType, PRInt64* aContainerId)
void ConsumeHeading(nsAString* aHeading, ContainerType* aContainerType)
{
*aHeading = mPreviousText;
*aContainerType = mLastContainerType;
*aContainerId = mLastContainerId;
mPreviousText.Truncate();
}
@ -371,12 +367,15 @@ protected:
// in the hierarchy, to where we find them in the bookmarks file
// being imported. This should be set when we are loading
// the default places html file, and should be unset when doing
// normal imports so that root folders will not get moved when
// normal imports so that root folders will not get moved when
// importing bookmarks.html files.
PRBool mAllowRootChanges;
// if set, this is an import of initial bookmarks.html content,
// so we don't want to kick off HTTP traffic
// and we want the imported personal toolbar folder
// to be set as the personal toolbar folder. (if not set
// we will treat it as a normal folder.)
PRBool mIsImportDefaults;
// If a folder was specified to import into, then ignore flags to put
@ -700,7 +699,6 @@ BookmarkContentSink::HandleHeadBegin(const nsIParserNode& node)
// the descriptions contained in a <dd>). Neither is any previous head type
frame.mPreviousLink = nsnull;
frame.mLastContainerType = BookmarkImportFrame::Container_Normal;
frame.mLastContainerId = 0;
// 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
@ -727,17 +725,17 @@ BookmarkContentSink::HandleHeadBegin(const nsIParserNode& node)
if (!mFolderSpecified) {
for (PRInt32 i = 0; i < attrCount; i ++) {
if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_TOOLBARFOLDER_LOWER)) {
frame.mLastContainerType = BookmarkImportFrame::Container_Toolbar;
if (mIsImportDefaults)
frame.mLastContainerType = BookmarkImportFrame::Container_Toolbar;
break;
} else if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_BOOKMARKSSMENU_LOWER)) {
frame.mLastContainerType = BookmarkImportFrame::Container_Menu;
} else if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_BOOKMARKSMENU_LOWER)) {
if (mIsImportDefaults)
frame.mLastContainerType = BookmarkImportFrame::Container_Menu;
break;
} else if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_PLACESROOT_LOWER)) {
frame.mLastContainerType = BookmarkImportFrame::Container_Places;
if (mIsImportDefaults)
frame.mLastContainerType = BookmarkImportFrame::Container_Places;
break;
} else if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_ITEM_ID_LOWER)) {
frame.mLastContainerId =
ConvertImportedIdToInternalId(NS_ConvertUTF16toUTF8(node.GetValueAt(i)));
} else if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_DATE_ADDED_LOWER)) {
frame.mPreviousDateAdded =
ConvertImportedDateToInternalDate(NS_ConvertUTF16toUTF8(node.GetValueAt(i)));
@ -820,8 +818,6 @@ BookmarkContentSink::HandleLinkBegin(const nsIParserNode& node)
postData = node.GetValueAt(i);
} else if (key.LowerCaseEqualsLiteral(KEY_WEB_PANEL_LOWER)) {
webPanel = node.GetValueAt(i);
} else if (key.LowerCaseEqualsLiteral(KEY_ITEM_ID_LOWER)) {
itemId = node.GetValueAt(i);
} else if (key.LowerCaseEqualsLiteral(KEY_MICSUM_GEN_URI_LOWER)) {
micsumGenURI = node.GetValueAt(i);
} else if (key.LowerCaseEqualsLiteral(KEY_GENERATED_TITLE_LOWER)) {
@ -1072,67 +1068,34 @@ BookmarkContentSink::HandleSeparator(const nsIParserNode& aNode)
{
BookmarkImportFrame& frame = CurFrame();
// check for pre-existing id
PRInt64 id = 0;
nsAutoString itemIdAttr;
// create the separator
#ifdef DEBUG_IMPORT
PrintNesting();
printf("--------\n");
#endif
PRInt64 itemId;
mBookmarksService->InsertSeparator(frame.mContainerID,
mBookmarksService->DEFAULT_INDEX,
&itemId);
// Import separator title if set
nsAutoString name;
PRInt32 attrCount = aNode.GetAttributeCount();
for (PRInt32 i = 0; i < attrCount; i ++) {
const nsAString& key = aNode.GetKeyAt(i);
if (key.LowerCaseEqualsLiteral(KEY_ITEM_ID_LOWER)) {
itemIdAttr = aNode.GetValueAt(i);
}
if (key.LowerCaseEqualsLiteral(KEY_NAME_LOWER))
name = aNode.GetValueAt(i);
}
name.Trim(kWhitespace);
itemIdAttr.Trim(kWhitespace);
id = ConvertImportedIdToInternalId(NS_ConvertUTF16toUTF8(itemIdAttr));
if (!name.IsEmpty())
mBookmarksService->SetItemTitle(itemId, name);
// check id validity
if (id > 0) {
PRInt64 parent;
nsresult rv = mBookmarksService->GetFolderIdForItem(id, &parent);
if (NS_FAILED(rv) || parent != frame.mContainerID) {
id = 0;
}
}
if (id > 0) {
PRUint16 type;
nsresult rv = mBookmarksService->GetItemType(id, &type);
if (NS_FAILED(rv) || type != mBookmarksService->TYPE_SEPARATOR) {
id = 0;
}
}
if (id == 0) {
// create the separator
#ifdef DEBUG_IMPORT
PrintNesting();
printf("--------\n");
#endif
PRInt64 itemId;
mBookmarksService->InsertSeparator(frame.mContainerID,
mBookmarksService->DEFAULT_INDEX,
&itemId);
// Import separator title if set
nsAutoString name;
PRInt32 attrCount = aNode.GetAttributeCount();
for (PRInt32 i = 0; i < attrCount; i ++) {
const nsAString& key = aNode.GetKeyAt(i);
if (key.LowerCaseEqualsLiteral(KEY_NAME_LOWER))
name = aNode.GetValueAt(i);
}
name.Trim(kWhitespace);
if (!name.IsEmpty())
mBookmarksService->SetItemTitle(itemId, name);
// Note: we do not need to import ADD_DATE or LAST_MODIFIED for separators
// because pre-Places bookmarks does not support them.
// and we can't write them out because attributes other than NAME make Firefox 2.x
// crash/hang - see bug #381129
}
// Note: we do not need to import ADD_DATE or LAST_MODIFIED for separators
// because pre-Places bookmarks does not support them.
// and we can't write them out because attributes other than NAME
// will make Firefox 2.x crash/hang - see bug #381129
}
@ -1149,73 +1112,58 @@ BookmarkContentSink::NewFrame()
PRInt64 ourID = 0;
nsString containerName;
BookmarkImportFrame::ContainerType containerType;
CurFrame().ConsumeHeading(&containerName, &containerType, &ourID);
CurFrame().ConsumeHeading(&containerName, &containerType);
PRBool updateFolder = PR_FALSE;
if (ourID > 0) {
// Check that folder id is valid.
PRInt64 ourParentId;
rv = mBookmarksService->GetFolderIdForItem(ourID, &ourParentId);
if (NS_FAILED(rv) || ourParentId != CurFrame().mContainerID) {
ourID = 0;
}
switch (containerType) {
case BookmarkImportFrame::Container_Normal:
// append a new folder
rv = mBookmarksService->CreateFolder(CurFrame().mContainerID,
containerName,
mBookmarksService->DEFAULT_INDEX,
&ourID);
NS_ENSURE_SUCCESS(rv, rv);
break;
case BookmarkImportFrame::Container_Places:
// places root, never reparent here, when we're building the initial
// hierarchy, it will only be defined at the top level
rv = mBookmarksService->GetPlacesRoot(&ourID);
NS_ENSURE_SUCCESS(rv, rv);
break;
case BookmarkImportFrame::Container_Menu:
// menu root
rv = mBookmarksService->GetBookmarksRoot(&ourID);
NS_ENSURE_SUCCESS(rv, rv);
if (mAllowRootChanges) {
updateFolder = PR_TRUE;
rv = SetFaviconForFolder(ourID, NS_LITERAL_CSTRING(BOOKMARKS_MENU_ICON_URI));
NS_ENSURE_SUCCESS(rv, rv);
}
break;
case BookmarkImportFrame::Container_Toolbar:
// get toolbar folder
PRInt64 toolbarFolder;
rv = mBookmarksService->GetToolbarFolder(&toolbarFolder);
NS_ENSURE_SUCCESS(rv, rv);
if (!toolbarFolder) {
// create new folder
rv = mBookmarksService->CreateFolder(CurFrame().mContainerID,
containerName,
mBookmarksService->DEFAULT_INDEX, &ourID);
NS_ENSURE_SUCCESS(rv, rv);
// there's no toolbar folder, so make us the toolbar folder
rv = mBookmarksService->SetToolbarFolder(ourID);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
ourID = toolbarFolder;
}
break;
default:
NS_NOTREACHED("Unknown container type");
}
if (ourID == 0) {
switch (containerType) {
case BookmarkImportFrame::Container_Normal:
// regular folder: use an existing folder if that name already exists
rv = mBookmarksService->GetChildFolder(CurFrame().mContainerID,
containerName, &ourID);
NS_ENSURE_SUCCESS(rv, rv);
if (ourID == 0) {
// need to append a new folder
rv = mBookmarksService->CreateFolder(CurFrame().mContainerID,
containerName,
mBookmarksService->DEFAULT_INDEX, &ourID);
NS_ENSURE_SUCCESS(rv, rv);
}
break;
case BookmarkImportFrame::Container_Places:
// places root, never reparent here, when we're building the initial
// hierarchy, it will only be defined at the top level
rv = mBookmarksService->GetPlacesRoot(&ourID);
NS_ENSURE_SUCCESS(rv, rv);
break;
case BookmarkImportFrame::Container_Menu:
// menu root
rv = mBookmarksService->GetBookmarksRoot(&ourID);
NS_ENSURE_SUCCESS(rv, rv);
if (mAllowRootChanges) {
updateFolder = PR_TRUE;
rv = SetFaviconForFolder(ourID, NS_LITERAL_CSTRING(BOOKMARKSS_MENU_ICON_URI));
NS_ENSURE_SUCCESS(rv, rv);
}
break;
case BookmarkImportFrame::Container_Toolbar:
// get toolbar folder
PRInt64 toolbarFolder;
rv = mBookmarksService->GetToolbarFolder(&toolbarFolder);
NS_ENSURE_SUCCESS(rv, rv);
if (!toolbarFolder) {
// create new folder
rv = mBookmarksService->CreateFolder(CurFrame().mContainerID,
containerName,
mBookmarksService->DEFAULT_INDEX, &ourID);
NS_ENSURE_SUCCESS(rv, rv);
// there's no toolbar folder, so make us the toolbar folder
rv = mBookmarksService->SetToolbarFolder(ourID);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
ourID = toolbarFolder;
}
break;
default:
NS_NOTREACHED("Unknown container type");
}
}
#ifdef DEBUG_IMPORT
PrintNesting();
printf("Folder %lld \'%s\'", ourID, NS_ConvertUTF16toUTF8(containerName).get());
@ -1315,10 +1263,12 @@ BookmarkContentSink::SetFaviconForURI(nsIURI* aPageURI, nsIURI* aIconURI,
faviconSpec.AssignLiteral("http://www.mozilla.org/2005/made-up-favicon/");
faviconSpec.AppendInt(serialNumber);
faviconSpec.AppendLiteral("-");
faviconSpec.AppendInt(PR_Now()); // casting from PRInt64 -> PRInt32, data loss, fix me
char buf[32];
PR_snprintf(buf, sizeof(buf), "%lld", PR_Now());
faviconSpec.Append(buf);
rv = NS_NewURI(getter_AddRefs(faviconURI), faviconSpec);
NS_ENSURE_SUCCESS(rv, rv);
serialNumber ++;
serialNumber++;
}
nsCOMPtr<nsIURI> dataURI;
@ -1477,7 +1427,7 @@ static const char kDescriptionIntro[] = "<DD>";
static const char kDescriptionClose[] = NS_LINEBREAK;
static const char kPlacesRootAttribute[] = " PLACES_ROOT=\"true\"";
static const char kBookmarksRootAttribute[] = " BOOKMARKSS_MENU=\"true\"";
static const char kBookmarksRootAttribute[] = " BOOKMARKS_MENU=\"true\"";
static const char kToolbarFolderAttribute[] = " PERSONAL_TOOLBAR_FOLDER=\"true\"";
static const char kIconAttribute[] = " ICON=\"";
static const char kIconURIAttribute[] = " ICON_URI=\"";
@ -1628,11 +1578,15 @@ WriteDateAttribute(const char aAttributeStart[], PRInt32 aLength, PRTime aAttrib
PRUint32 dummy;
nsresult rv = aOutput->Write(aAttributeStart, aLength, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
// in bookmarks.html this value is in seconds, not microseconds
aAttributeValue /= 1000000;
// write attribute value
nsCAutoString dateInSeconds;
aAttributeValue/= 1000000; // in bookmarks.html this value is in seconds, not microseconds
dateInSeconds.AppendInt(aAttributeValue); // casting from PRInt64 -> PRInt32, data loss, fix me
rv = aOutput->Write(dateInSeconds.get(), dateInSeconds.Length(), &dummy);
char dateInSeconds[32];
PR_snprintf(dateInSeconds, sizeof(dateInSeconds), "%lld", aAttributeValue);
rv = aOutput->Write(dateInSeconds, strlen(dateInSeconds), &dummy);
NS_ENSURE_SUCCESS(rv, rv);
return aOutput->Write(kQuoteStr, sizeof(kQuoteStr)-1, &dummy);
}
@ -1728,17 +1682,7 @@ nsPlacesImportExportService::WriteContainerHeader(nsINavHistoryResultNode* aFold
rv = aOutput->Write(kToolbarFolderAttribute, sizeof(kToolbarFolderAttribute)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
}
// write id as ITEM_ID as non-rdf IDs can confuse Firefox 2
rv = aOutput->Write(kItemIdAttribute, sizeof(kItemIdAttribute)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString itemIdAttr;
itemIdAttr.AppendInt(folderId); // casting from PRInt64 -> PRInt32, data loss, fix me
rv = aOutput->Write(itemIdAttr.get(), itemIdAttr.Length(), &dummy);
NS_ENSURE_SUCCESS(rv, rv);
rv = aOutput->Write(kQuoteStr, sizeof(kQuoteStr)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
// favicon (most folders won't have one)
nsCOMPtr<nsIURI> folderURI;
rv = mBookmarksService->GetFolderURI(folderId, getter_AddRefs(folderURI));
@ -1897,16 +1841,6 @@ nsPlacesImportExportService::WriteItem(nsINavHistoryResultNode* aItem,
rv = aItem->GetItemId(&itemId);
NS_ENSURE_SUCCESS(rv, rv);
// write id as ITEM_ID as non-rdf IDs can confuse Firefox 2
rv = aOutput->Write(kItemIdAttribute, sizeof(kItemIdAttribute)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString itemIdAttr;
itemIdAttr.AppendInt(itemId); // casting from PRInt64 -> PRInt32, data loss, fix me
rv = aOutput->Write(itemIdAttr.get(), itemIdAttr.Length(), &dummy);
NS_ENSURE_SUCCESS(rv, rv);
rv = aOutput->Write(kQuoteStr, sizeof(kQuoteStr)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
// keyword (shortcuturl)
nsAutoString keyword;
rv = mBookmarksService->GetKeywordForBookmark(itemId, keyword);
@ -2071,16 +2005,6 @@ nsPlacesImportExportService::WriteLivemark(nsINavHistoryResultNode* aFolder, con
NS_ENSURE_SUCCESS(rv, rv);
}
// write id as ITEM_ID as non-rdf IDs can confuse Firefox 2
rv = aOutput->Write(kItemIdAttribute, sizeof(kItemIdAttribute)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString itemIdAttr;
itemIdAttr.AppendInt(folderId); // casting from PRInt64 -> PRInt32, data loss, fix me
rv = aOutput->Write(itemIdAttr.get(), itemIdAttr.Length(), &dummy);
NS_ENSURE_SUCCESS(rv, rv);
rv = aOutput->Write(kQuoteStr, sizeof(kQuoteStr)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
// '>'
rv = aOutput->Write(kCloseAngle, sizeof(kCloseAngle)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);