Mozilla/mozilla/xpfe/components/bookmarks/src/nsBookmarksService.cpp
waterson%netscape.com 7b94de64b6 Initial revision. Not yet in the build.
git-svn-id: svn://10.0.0.236/trunk@34741 18797224-902f-48f8-a5cc-f745e15eee43
1999-06-11 02:50:47 +00:00

1619 lines
46 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; c-file-style: "stroustrup" -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
The global bookmarks service.
*/
#include "nsCOMPtr.h"
#include "nsFileSpec.h"
#include "nsFileStream.h"
#include "nsIBookmarksService.h"
#include "nsIComponentManager.h"
#include "nsIGenericFactory.h"
#include "nsIRDFContainer.h"
#include "nsIRDFContainerUtils.h"
#include "nsIRDFDataSource.h"
#include "nsIRDFNode.h"
#include "nsIRDFService.h"
#include "nsIServiceManager.h"
#include "nsRDFCID.h"
#include "nsSpecialSystemDirectory.h"
#include "nsString.h"
#include "nsVoidArray.h"
#include "nsXPIDLString.h"
#include "prio.h"
#include "prlog.h"
#include "rdf.h"
#include "xp_core.h"
////////////////////////////////////////////////////////////////////////
static NS_DEFINE_CID(kBookmarksServiceCID, NS_BOOKMARKS_SERVICE_CID);
static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID);
static NS_DEFINE_CID(kGenericFactoryCID, NS_GENERICFACTORY_CID);
static NS_DEFINE_CID(kRDFInMemoryDataSourceCID, NS_RDFINMEMORYDATASOURCE_CID);
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
static NS_DEFINE_CID(kRDFContainerCID, NS_RDFCONTAINER_CID);
static NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID);
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static const char kURINC_BookmarksRoot[] = "NC:BookmarksRoot"; // XXX?
static const char kURINC_IEFavoritesRoot[] = "NC:IEFavoritesRoot"; // XXX?
static const char kURINC_PersonalToolbarFolder[] = "NC:PersonalToolbarFolder"; // XXX?
static const char kPersonalToolbarFolder[] = "Personal Toolbar Folder";
////////////////////////////////////////////////////////////////////////
PRInt32 gRefCnt;
nsIRDFService* gRDF;
nsIRDFContainerUtils* gRDFC;
nsIRDFResource* kNC_Bookmark;
nsIRDFResource* kNC_BookmarkSeparator;
nsIRDFResource* kNC_BookmarkAddDate;
nsIRDFResource* kNC_BookmarksRoot;
nsIRDFResource* kNC_Description;
nsIRDFResource* kNC_Folder;
nsIRDFResource* kNC_IEFavorite;
nsIRDFResource* kNC_IEFavoritesRoot;
nsIRDFResource* kNC_Name;
nsIRDFResource* kNC_PersonalToolbarFolder;
nsIRDFResource* kNC_ShortcutURL;
nsIRDFResource* kNC_URL;
nsIRDFResource* kRDF_type;
nsIRDFResource* kWEB_LastModifiedDate;
nsIRDFResource* kWEB_LastVisitDate;
static nsresult
bm_AddRefGlobals()
{
if (gRefCnt++ == 0) {
nsresult rv;
rv = nsServiceManager::GetService(kRDFServiceCID,
nsIRDFService::GetIID(),
(nsISupports**) &gRDF);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service");
if (NS_FAILED(rv)) return rv;
rv = nsServiceManager::GetService(kRDFContainerUtilsCID,
nsIRDFContainerUtils::GetIID(),
(nsISupports**) &gRDFC);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF container utils");
if (NS_FAILED(rv)) return rv;
gRDF->GetResource(NC_NAMESPACE_URI "Bookmark", &kNC_Bookmark);
gRDF->GetResource(NC_NAMESPACE_URI "BookmarkSeparator", &kNC_BookmarkSeparator);
gRDF->GetResource(NC_NAMESPACE_URI "BookmarkAddDate", &kNC_BookmarkAddDate);
gRDF->GetResource(NC_NAMESPACE_URI "BookmarksRoot", &kNC_BookmarksRoot);
gRDF->GetResource(NC_NAMESPACE_URI "Description", &kNC_Description);
gRDF->GetResource(NC_NAMESPACE_URI "Folder", &kNC_Folder);
gRDF->GetResource(NC_NAMESPACE_URI "IEFavorite", &kNC_IEFavorite);
gRDF->GetResource(NC_NAMESPACE_URI "IEFavoritesRoot", &kNC_IEFavoritesRoot);
gRDF->GetResource(NC_NAMESPACE_URI "Name", &kNC_Name);
gRDF->GetResource(NC_NAMESPACE_URI "PersonalToolbarFolder", &kNC_PersonalToolbarFolder);
gRDF->GetResource(NC_NAMESPACE_URI "ShortcutURL", &kNC_ShortcutURL);
gRDF->GetResource(NC_NAMESPACE_URI "URL", &kNC_URL);
gRDF->GetResource(RDF_NAMESPACE_URI "type", &kRDF_type);
gRDF->GetResource(WEB_NAMESPACE_URI "LastModifiedDate", &kWEB_LastModifiedDate);
gRDF->GetResource(WEB_NAMESPACE_URI "LastVisitDate", &kWEB_LastVisitDate);
}
return NS_OK;
}
static void
bm_ReleaseGlobals()
{
if (--gRefCnt == 0)
{
if (gRDF)
nsServiceManager::ReleaseService(kRDFServiceCID, gRDF);
if (gRDFC)
nsServiceManager::ReleaseService(kRDFContainerUtilsCID, gRDFC);
NS_IF_RELEASE(kNC_Bookmark);
NS_IF_RELEASE(kNC_BookmarkSeparator);
NS_IF_RELEASE(kNC_BookmarkAddDate);
NS_IF_RELEASE(kNC_BookmarksRoot);
NS_IF_RELEASE(kNC_Description);
NS_IF_RELEASE(kNC_Folder);
NS_IF_RELEASE(kNC_IEFavorite);
NS_IF_RELEASE(kNC_IEFavoritesRoot);
NS_IF_RELEASE(kNC_Name);
NS_IF_RELEASE(kNC_PersonalToolbarFolder);
NS_IF_RELEASE(kNC_ShortcutURL);
NS_IF_RELEASE(kNC_URL);
NS_IF_RELEASE(kRDF_type);
NS_IF_RELEASE(kWEB_LastModifiedDate);
NS_IF_RELEASE(kWEB_LastVisitDate);
}
}
////////////////////////////////////////////////////////////////////////
/**
* The bookmark parser knows how to read <tt>bookmarks.html</tt> and convert it
* into an RDF graph.
*/
class BookmarkParser {
private:
nsInputFileStream *mStream;
nsIRDFDataSource *mDataSource;
const char *mIEFavoritesRoot;
PRBool mFoundIEFavoritesRoot;
protected:
nsresult AssertTime(nsIRDFResource* aSource,
nsIRDFResource* aLabel,
PRInt32 aTime);
nsresult CreateAnonymousResource(nsCOMPtr<nsIRDFResource>* aResult);
nsresult ParseBookmark(const nsString& aLine, nsIRDFResource* aContainer, nsIRDFResource *nodeType);
nsresult ParseBookmarkHeader(const nsString& aLine, nsIRDFResource* aContainer, nsIRDFResource *nodeType);
nsresult ParseBookmarkSeparator(const nsString& aLine, nsIRDFResource* aContainer);
nsresult ParseHeaderBegin(const nsString& aLine, nsIRDFResource* aContainer);
nsresult ParseHeaderEnd(const nsString& aLine);
nsresult ParseAttribute(const nsString& aLine,
const char* aAttribute,
PRInt32 aAttributeLen,
nsString& aResult);
public:
BookmarkParser();
~BookmarkParser();
nsresult Init(nsInputFileStream *aStream, nsIRDFDataSource *aDataSource);
nsresult Parse(nsIRDFResource* aContainer, nsIRDFResource *nodeType);
nsresult AddBookmark(nsIRDFResource* aContainer,
const char* aURL,
const PRUnichar* aOptionalTitle,
PRInt32 aAddDate,
PRInt32 aLastVisitDate,
PRInt32 aLastModifiedDate,
const char* aShortcutURL,
nsIRDFResource* aNodeType);
nsresult SetIEFavoritesRoot(const char *IEFavoritesRootURL)
{
mIEFavoritesRoot = IEFavoritesRootURL;
return(NS_OK);
}
nsresult ParserFoundIEFavoritesRoot(PRBool *foundIEFavoritesRoot)
{
*foundIEFavoritesRoot = mFoundIEFavoritesRoot;
return(NS_OK);
}
};
BookmarkParser::BookmarkParser()
{
bm_AddRefGlobals();
}
nsresult
BookmarkParser::Init(nsInputFileStream *aStream, nsIRDFDataSource *aDataSource)
{
mStream = aStream;
mDataSource = aDataSource;
mIEFavoritesRoot = nsnull;
mFoundIEFavoritesRoot = PR_FALSE;
return(NS_OK);
}
BookmarkParser::~BookmarkParser()
{
bm_ReleaseGlobals();
}
static const char kHREFEquals[] = "HREF=\"";
static const char kCloseAnchor[] = "</A>";
static const char kOpenHeading[] = "<H";
static const char kCloseHeading[] = "</H";
static const char kSeparator[] = "<HR>";
static const char kOpenUL[] = "<UL>";
static const char kCloseUL[] = "</UL>";
static const char kOpenMenu[] = "<MENU>";
static const char kCloseMenu[] = "</MENU>";
static const char kOpenDL[] = "<DL>";
static const char kCloseDL[] = "</DL>";
static const char kTargetEquals[] = "TARGET=\"";
static const char kAddDateEquals[] = "ADD_DATE=\"";
static const char kLastVisitEquals[] = "LAST_VISIT=\"";
static const char kLastModifiedEquals[] = "LAST_MODIFIED=\"";
static const char kShortcutURLEquals[] = "SHORTCUTURL=\"";
static const char kIDEquals[] = "ID=\"";
nsresult
BookmarkParser::Parse(nsIRDFResource* aContainer, nsIRDFResource *nodeType)
{
// tokenize the input stream.
// XXX this needs to handle quotes, etc. it'd be nice to use the real parser for this...
nsRandomAccessInputStream in(*mStream);
nsresult rv = NS_OK;
nsAutoString line;
while (NS_SUCCEEDED(rv) && !in.eof() && !in.failed()) {
line.Truncate();
while (1) {
char buf[256];
PRBool untruncated = in.readline(buf, sizeof(buf));
// in.readline() return PR_FALSE if there was buffer overflow,
// or there was a catastrophe. Check to see if we're here
// because of the latter...
NS_ASSERTION (! in.failed(), "error reading file");
if (in.failed()) return NS_ERROR_FAILURE;
// XXX Bug 5871. What charset conversion should we be
// applying here?
line.Append(buf);
if (untruncated)
break;
}
PRInt32 offset;
if ((offset = line.Find(kHREFEquals)) >= 0) {
rv = ParseBookmark(line, aContainer, nodeType);
}
else if ((offset = line.Find(kOpenHeading)) >= 0 &&
nsString::IsDigit(line.CharAt(offset + 2))) {
// XXX Ignore <H1> so that bookmarks root _is_ <H1>
if (line.CharAt(offset + 2) != PRUnichar('1'))
rv = ParseBookmarkHeader(line, aContainer, nodeType);
}
else if ((offset = line.Find(kSeparator)) >= 0) {
rv = ParseBookmarkSeparator(line, aContainer);
}
else if ((offset = line.Find(kCloseUL)) >= 0 ||
(offset = line.Find(kCloseMenu)) >= 0 ||
(offset = line.Find(kCloseDL)) >= 0) {
return ParseHeaderEnd(line);
}
else if ((offset = line.Find(kOpenUL)) >= 0 ||
(offset = line.Find(kOpenMenu)) >= 0 ||
(offset = line.Find(kOpenDL)) >= 0) {
rv = ParseHeaderBegin(line, aContainer);
}
else {
// XXX Discard the line. We should be treating this as the
// description.
}
}
return rv;
}
nsresult
BookmarkParser::CreateAnonymousResource(nsCOMPtr<nsIRDFResource>* aResult)
{
static PRInt32 gNext = 0;
if (! gNext) {
LL_L2I(gNext, PR_Now());
}
nsAutoString uri(kURINC_BookmarksRoot);
uri.Append("$");
uri.Append(gNext, 16);
return gRDF->GetUnicodeResource(uri.GetUnicode(), getter_AddRefs(*aResult));
}
nsresult
BookmarkParser::ParseBookmark(const nsString& aLine, nsIRDFResource* aContainer, nsIRDFResource *nodeType)
{
NS_PRECONDITION(aContainer != nsnull, "null ptr");
if (! aContainer)
return NS_ERROR_NULL_POINTER;
PRInt32 start = aLine.Find(kHREFEquals);
NS_ASSERTION(start >= 0, "no 'HREF=\"' string: how'd we get here?");
if (start < 0)
return NS_ERROR_UNEXPECTED;
// 1. Crop out the URL
// Skip past the first double-quote
start += (sizeof(kHREFEquals) - 1);
// ...and find the next so we can chop the URL.
PRInt32 end = aLine.Find(PRUnichar('"'), start);
NS_ASSERTION(end >= 0, "unterminated string");
if (end < 0)
return NS_ERROR_UNEXPECTED;
nsAutoString url;
aLine.Mid(url, start, end - start);
{
// Now do properly replace %22's (this is what 4.5 did, anyway...)
static const char kEscape22[] = "%22";
PRInt32 offset;
while ((offset = url.Find(kEscape22)) >= 0) {
url.SetCharAt(' ',offset);
url.Cut(offset + 1, sizeof(kEscape22) - 2);
}
}
// XXX At this point, the URL may be relative. 4.5 called into
// netlib to make an absolute URL, and there was some magic
// "relative_URL" parameter that got sent down as well. We punt on
// that stuff.
// 2. Parse the name
start = aLine.Find(PRUnichar('>'), end + 1); // 'end' still points to the end of the URL
NS_ASSERTION(start >= 0, "open anchor tag not terminated");
if (start < 0)
return NS_ERROR_UNEXPECTED;
nsAutoString name;
aLine.Right(name, aLine.Length() - (start + 1));
end = name.Find(kCloseAnchor);
NS_ASSERTION(end >= 0, "anchor tag not terminated");
if (end < 0)
return NS_ERROR_UNEXPECTED;
name.Truncate(end);
// 3. Parse the target
nsAutoString target;
start = aLine.Find(kTargetEquals);
if (start >= 0) {
start += (sizeof(kTargetEquals) - 1);
end = aLine.Find(PRUnichar('"'), start);
aLine.Mid(target, start, end - start);
}
// 4. Parse the addition date
PRInt32 addDate = 0;
{
nsAutoString s;
ParseAttribute(aLine, kAddDateEquals, sizeof(kAddDateEquals) - 1, s);
if (s.Length() > 0) {
PRInt32 err;
addDate = s.ToInteger(&err); // ignored.
}
}
// 5. Parse the last visit date
PRInt32 lastVisitDate = 0;
{
nsAutoString s;
ParseAttribute(aLine, kLastVisitEquals, sizeof(kLastVisitEquals) - 1, s);
if (s.Length() > 0) {
PRInt32 err;
lastVisitDate = s.ToInteger(&err); // ignored.
}
}
// 6. Parse the last modified date
PRInt32 lastModifiedDate;
{
nsAutoString s;
ParseAttribute(aLine, kLastModifiedEquals, sizeof(kLastModifiedEquals) - 1, s);
if (s.Length() > 0) {
PRInt32 err;
lastModifiedDate = s.ToInteger(&err); // ignored.
}
}
// 7. Parse the shortcut URL
nsAutoString shortcut;
ParseAttribute(aLine, kShortcutURLEquals, sizeof(kShortcutURLEquals) -1, shortcut);
// Dunno. 4.5 did it, so will we.
if (!lastModifiedDate)
lastModifiedDate = lastVisitDate;
// XXX There was some other cruft here to deal with aliases, but
// since I have no clue what those are, I'll punt.
char *cURL = url.ToNewCString();
if (cURL)
{
char *cShortcutURL = shortcut.ToNewCString();
if (! cShortcutURL)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = AddBookmark(aContainer,
cURL,
name.GetUnicode(),
addDate,
lastVisitDate,
lastModifiedDate,
cShortcutURL,
nodeType);
delete [] cURL;
if (cShortcutURL) delete [] cShortcutURL;
}
return(NS_OK);
}
// Now create the bookmark
nsresult
BookmarkParser::AddBookmark(nsIRDFResource* aContainer,
const char* aURL,
const PRUnichar* aOptionalTitle,
PRInt32 aAddDate,
PRInt32 aLastVisitDate,
PRInt32 aLastModifiedDate,
const char* aShortcutURL,
nsIRDFResource* aNodeType)
{
nsresult rv;
nsCOMPtr<nsIRDFResource> bookmark;
if (NS_FAILED(rv = gRDF->GetResource(aURL, getter_AddRefs(bookmark) )))
{
NS_ERROR("unable to get bookmark resource");
return rv;
}
PRBool result = PR_FALSE;
if (nsnull != mIEFavoritesRoot)
{
if (!PL_strcmp(aURL, mIEFavoritesRoot))
{
mFoundIEFavoritesRoot = PR_TRUE;
}
}
nsCOMPtr<nsIRDFContainer> container;
rv = nsComponentManager::CreateInstance(kRDFContainerCID,
nsnull,
nsIRDFContainer::GetIID(),
getter_AddRefs(container));
if (NS_FAILED(rv)) return rv;
rv = container->AppendElement(bookmark);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to add bookmark to container");
if (NS_FAILED(rv)) return rv;
rv = mDataSource->Assert(bookmark, kRDF_type, aNodeType, PR_TRUE);
if (rv != NS_RDF_ASSERTION_ACCEPTED)
{
NS_ERROR("unable to add bookmark to data source");
return rv;
}
if ((nsnull != aOptionalTitle) && (*aOptionalTitle != PRUnichar('\0')))
{
nsCOMPtr<nsIRDFLiteral> literal;
if (NS_FAILED(rv = gRDF->GetLiteral(aOptionalTitle, getter_AddRefs(literal))))
{
NS_ERROR("unable to create literal for bookmark name");
return rv;
}
rv = mDataSource->Assert(bookmark, kNC_Name, literal, PR_TRUE);
if (rv != NS_RDF_ASSERTION_ACCEPTED)
{
NS_ERROR("unable to set bookmark name");
return rv;
}
}
AssertTime(bookmark, kNC_BookmarkAddDate, aAddDate);
AssertTime(bookmark, kWEB_LastVisitDate, aLastVisitDate);
AssertTime(bookmark, kWEB_LastModifiedDate, aLastModifiedDate);
if ((nsnull != aShortcutURL) && (*aShortcutURL != '\0'))
{
nsCOMPtr<nsIRDFLiteral> shortcutLiteral;
if (NS_FAILED(rv = gRDF->GetLiteral(nsAutoString(aShortcutURL).GetUnicode(),
getter_AddRefs(shortcutLiteral))))
{
NS_ERROR("unable to get literal for bookmark shortcut URL");
return(rv);
}
if (rv != NS_RDF_NO_VALUE)
{
rv = mDataSource->Assert(bookmark,
kNC_ShortcutURL,
shortcutLiteral,
PR_TRUE);
if (rv != NS_RDF_ASSERTION_ACCEPTED)
{
NS_ERROR("unable to set bookmark shortcut URL");
return(rv);
}
}
}
return(NS_OK);
}
nsresult
BookmarkParser::ParseBookmarkHeader(const nsString& aLine, nsIRDFResource* aContainer, nsIRDFResource *nodeType)
{
// Snip out the header
PRInt32 start = aLine.Find(kOpenHeading);
NS_ASSERTION(start >= 0, "couldn't find '<H'; why am I here?");
if (start < 0)
return NS_ERROR_UNEXPECTED;
start += (sizeof(kOpenHeading) - 1);
start = aLine.Find(PRUnichar('>'), start); // skip to the end of the '<Hn>' tag
if (start < 0) {
NS_WARNING("couldn't find end of header tag");
return NS_OK;
}
nsAutoString name;
aLine.Right(name, aLine.Length() - (start + 1));
PRInt32 end = name.Find(kCloseHeading);
if (end < 0)
NS_WARNING("No '</H' found to close the heading");
if (end >= 0)
name.Truncate(end);
// Find the add date
PRInt32 addDate = 0;
nsAutoString s;
ParseAttribute(aLine, kAddDateEquals, sizeof(kAddDateEquals) - 1, s);
if (s.Length() > 0) {
PRInt32 err;
addDate = s.ToInteger(&err); // ignored
}
nsAutoString id;
ParseAttribute(aLine, kIDEquals, sizeof(kIDEquals) - 1, id);
// Make the necessary assertions
nsresult rv;
nsCOMPtr<nsIRDFResource> folder;
if (id.Length() > 0) {
// Use the ID attribute, if one is set.
rv = gRDF->GetUnicodeResource(id.GetUnicode(), getter_AddRefs(folder));
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create resource for folder");
if (NS_FAILED(rv)) return rv;
}
else if (name.Equals(kPersonalToolbarFolder)) { // XXX I18n!!!
folder = dont_QueryInterface( kNC_PersonalToolbarFolder );
}
else {
// We've never seen this folder before. Assign it an anonymous ID
rv = CreateAnonymousResource(&folder);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create anonymous resource for folder");
if (NS_FAILED(rv)) return rv;
}
nsCOMPtr<nsIRDFLiteral> literal;
rv = gRDF->GetLiteral(name.GetUnicode(), getter_AddRefs(literal));
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create literal for folder name");
if (NS_FAILED(rv)) return rv;
rv = mDataSource->Assert(folder, kNC_Name, literal, PR_TRUE);
if (rv != NS_RDF_ASSERTION_ACCEPTED) {
NS_ERROR("unable to set folder name");
return rv;
}
nsCOMPtr<nsIRDFContainer> container;
rv = nsComponentManager::CreateInstance(kRDFContainerCID,
nsnull,
nsIRDFContainer::GetIID(),
getter_AddRefs(container));
if (NS_FAILED(rv)) return rv;
rv = container->AppendElement(folder);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to add bookmark to container");
if (NS_FAILED(rv)) return rv;
rv = gRDFC->MakeSeq(mDataSource, folder, nsnull);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to make new folder as sequence");
if (NS_FAILED(rv)) return rv;
rv = mDataSource->Assert(folder, kRDF_type, kNC_Folder, PR_TRUE);
if (rv != NS_RDF_ASSERTION_ACCEPTED) {
NS_ERROR("unable to mark new folder as folder");
return rv;
}
if (NS_FAILED(rv = AssertTime(folder, kNC_BookmarkAddDate, addDate))) {
NS_ERROR("unable to mark add date");
return rv;
}
// And now recursively parse the rest of the file...
if (NS_FAILED(rv = Parse(folder, nodeType))) {
NS_ERROR("recursive parse of bookmarks file failed");
return rv;
}
return NS_OK;
}
nsresult
BookmarkParser::ParseBookmarkSeparator(const nsString& aLine, nsIRDFResource* aContainer)
{
nsresult rv;
nsCOMPtr<nsIRDFResource> separator;
if (NS_SUCCEEDED(rv = CreateAnonymousResource(&separator)))
{
nsAutoString defaultSeparatorName("-----");
nsCOMPtr<nsIRDFLiteral> nameLiteral;
if (NS_SUCCEEDED(rv = gRDF->GetLiteral(defaultSeparatorName.GetUnicode(), getter_AddRefs(nameLiteral))))
{
if (NS_SUCCEEDED(rv = mDataSource->Assert(separator, kNC_Name, nameLiteral, PR_TRUE)))
{
}
}
if (NS_SUCCEEDED(rv = mDataSource->Assert(separator, kRDF_type, kNC_BookmarkSeparator, PR_TRUE)))
{
nsCOMPtr<nsIRDFContainer> container;
rv = nsComponentManager::CreateInstance(kRDFContainerCID,
nsnull,
nsIRDFContainer::GetIID(),
getter_AddRefs(container));
if (NS_SUCCEEDED(rv))
{
rv = container->AppendElement(separator);
}
}
}
return(rv);
}
nsresult
BookmarkParser::ParseHeaderBegin(const nsString& aLine, nsIRDFResource* aContainer)
{
return NS_OK;
}
nsresult
BookmarkParser::ParseHeaderEnd(const nsString& aLine)
{
return NS_OK;
}
nsresult
BookmarkParser::ParseAttribute(const nsString& aLine,
const char* aAttributeName,
PRInt32 aAttributeLen,
nsString& aResult)
{
aResult.Truncate();
PRInt32 start = aLine.Find(aAttributeName);
if (start < 0)
return NS_OK;
start += aAttributeLen;
PRInt32 end = aLine.Find(PRUnichar('"'), start);
aLine.Mid(aResult, start, end - start);
return NS_OK;
}
nsresult
BookmarkParser::AssertTime(nsIRDFResource* aSource,
nsIRDFResource* aLabel,
PRInt32 aTime)
{
// XXX TO DO: Convert to a date literal
nsAutoString time;
time.Append(aTime, 10);
nsresult rv;
nsIRDFLiteral* literal;
if (NS_FAILED(rv = gRDF->GetLiteral(time.GetUnicode(), &literal))) {
NS_ERROR("unable to get literal for time");
return rv;
}
rv = mDataSource->Assert(aSource, aLabel, literal, PR_TRUE);
NS_ASSERTION(rv == NS_RDF_ASSERTION_ACCEPTED, "unable to assert time");
NS_RELEASE(literal);
return rv;
}
////////////////////////////////////////////////////////////////////////
// BookmarkDataSourceImpl
class nsBookmarksService : public nsIBookmarksService,
public nsIRDFDataSource
{
protected:
nsIRDFDataSource* mInner;
nsresult ReadBookmarks();
nsresult WriteBookmarks(nsIRDFDataSource *ds, nsIRDFResource *root);
nsresult WriteBookmarksContainer(nsIRDFDataSource *ds, nsOutputFileStream strm, nsIRDFResource *container, PRInt32 level);
nsresult WriteBookmarkProperties(nsIRDFDataSource *ds, nsOutputFileStream strm, nsIRDFResource *node,
nsIRDFResource *property, const char *htmlAttrib, PRBool isFirst);
PRBool CanAccept(nsIRDFResource* aSource, nsIRDFResource* aProperty, nsIRDFNode* aTarget);
nsBookmarksService();
virtual ~nsBookmarksService();
nsresult Init();
friend NS_IMETHODIMP
NS_NewBookmarksService(nsISupports* aOuter, REFNSIID aIID, void** aResult);
public:
// nsISupports
NS_DECL_ISUPPORTS
// nsIRDFBookmarkDataSource
NS_IMETHOD AddBookmark(const char *aURI, const PRUnichar *aOptionalTitle);
NS_IMETHOD FindShortcut(const PRUnichar *aUserInput, char **aShortcutURL);
// nsIRDFDataSource
NS_IMETHOD Init(const char* uri) {
return mInner->Init(uri);
}
NS_IMETHOD GetURI(char* *uri) {
return mInner->GetURI(uri);
}
NS_IMETHOD GetSource(nsIRDFResource* property,
nsIRDFNode* target,
PRBool tv,
nsIRDFResource** source) {
return mInner->GetSource(property, target, tv, source);
}
NS_IMETHOD GetSources(nsIRDFResource* property,
nsIRDFNode* target,
PRBool tv,
nsISimpleEnumerator** sources) {
return mInner->GetSources(property, target, tv, sources);
}
NS_IMETHOD GetTarget(nsIRDFResource* source,
nsIRDFResource* property,
PRBool tv,
nsIRDFNode** target);
NS_IMETHOD GetTargets(nsIRDFResource* source,
nsIRDFResource* property,
PRBool tv,
nsISimpleEnumerator** targets) {
return mInner->GetTargets(source, property, tv, targets);
}
NS_IMETHOD Assert(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget,
PRBool aTruthValue);
NS_IMETHOD Unassert(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget);
NS_IMETHOD HasAssertion(nsIRDFResource* source,
nsIRDFResource* property,
nsIRDFNode* target,
PRBool tv,
PRBool* hasAssertion) {
return mInner->HasAssertion(source, property, target, tv, hasAssertion);
}
NS_IMETHOD AddObserver(nsIRDFObserver* n) {
return mInner->AddObserver(n);
}
NS_IMETHOD RemoveObserver(nsIRDFObserver* n) {
return mInner->RemoveObserver(n);
}
NS_IMETHOD ArcLabelsIn(nsIRDFNode* node,
nsISimpleEnumerator** labels) {
return mInner->ArcLabelsIn(node, labels);
}
NS_IMETHOD ArcLabelsOut(nsIRDFResource* source,
nsISimpleEnumerator** labels) {
return mInner->ArcLabelsOut(source, labels);
}
NS_IMETHOD GetAllResources(nsISimpleEnumerator** aResult) {
return mInner->GetAllResources(aResult);
}
NS_IMETHOD Flush();
NS_IMETHOD GetAllCommands(nsIRDFResource* source,
nsIEnumerator/*<nsIRDFResource>*/** commands);
NS_IMETHOD IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
nsIRDFResource* aCommand,
nsISupportsArray/*<nsIRDFResource>*/* aArguments,
PRBool* aResult);
NS_IMETHOD DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
nsIRDFResource* aCommand,
nsISupportsArray/*<nsIRDFResource>*/* aArguments);
};
////////////////////////////////////////////////////////////////////////
nsBookmarksService::nsBookmarksService()
{
NS_INIT_REFCNT();
}
nsBookmarksService::~nsBookmarksService()
{
Flush();
NS_RELEASE(mInner);
bm_ReleaseGlobals();
}
nsresult
nsBookmarksService::Init()
{
nsresult rv;
rv = bm_AddRefGlobals();
if (NS_FAILED(rv)) return rv;
rv = nsComponentManager::CreateInstance(kRDFInMemoryDataSourceCID,
nsnull,
nsIRDFDataSource::GetIID(),
(void**) &mInner);
if (NS_FAILED(rv)) return rv;
rv = mInner->Init("rdf:bookmarks");
if (NS_FAILED(rv)) return rv;
rv = ReadBookmarks();
if (NS_FAILED(rv)) return rv;
// register this as a named data source with the RDF service
rv = gRDF->RegisterDataSource(this, PR_FALSE);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
NS_IMETHODIMP
NS_NewBookmarksService(nsISupports* aOuter, REFNSIID aIID, void** aResult)
{
NS_PRECONDITION(aResult != nsnull, "null ptr");
if (! aResult)
return NS_ERROR_NULL_POINTER;
NS_PRECONDITION(aOuter == nsnull, "no aggregation");
if (aOuter)
return NS_ERROR_NO_AGGREGATION;
nsresult rv = NS_OK;
nsBookmarksService* result = new nsBookmarksService();
if (! result)
return NS_ERROR_OUT_OF_MEMORY;
rv = result->Init();
if (NS_SUCCEEDED(rv))
rv = result->QueryInterface(aIID, aResult);
if (NS_FAILED(rv)) {
delete result;
*aResult = nsnull;
return rv;
}
return rv;
}
////////////////////////////////////////////////////////////////////////
NS_IMPL_ADDREF(nsBookmarksService);
NS_IMPL_RELEASE(nsBookmarksService);
NS_IMETHODIMP
nsBookmarksService::QueryInterface(REFNSIID aIID, void **aResult)
{
NS_PRECONDITION(aResult != nsnull, "null ptr");
if (! aResult)
return NS_ERROR_NULL_POINTER;
if (aIID.Equals(nsIBookmarksService::GetIID()) ||
aIID.Equals(kISupportsIID))
{
*aResult = NS_STATIC_CAST(nsIBookmarksService*, this);
}
else if (aIID.Equals(nsIRDFDataSource::GetIID())) {
*aResult = NS_STATIC_CAST(nsIRDFDataSource*, this);
}
else {
*aResult = nsnull;
return NS_NOINTERFACE;
}
NS_ADDREF(this);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
// nsIBookmarksService
NS_IMETHODIMP
nsBookmarksService::AddBookmark(const char *aURI, const PRUnichar *aOptionalTitle)
{
// XXX for the moment, just add it as a child of BookmarksRoot
BookmarkParser parser;
parser.Init(nsnull, NS_STATIC_CAST(nsIRDFDataSource *, this));
nsresult rv = parser.AddBookmark(kNC_BookmarksRoot, aURI, aOptionalTitle,
0L, 0L, 0L, nsnull, kNC_Bookmark);
if (NS_SUCCEEDED(rv))
{
Flush();
}
return(rv);
}
NS_IMETHODIMP
nsBookmarksService::FindShortcut(const PRUnichar *aUserInput, char **aShortcutURL)
{
NS_PRECONDITION(aUserInput != nsnull, "null ptr");
if (! aUserInput)
return NS_ERROR_NULL_POINTER;
NS_PRECONDITION(aShortcutURL != nsnull, "null ptr");
if (! aShortcutURL)
return NS_ERROR_NULL_POINTER;
nsresult rv;
nsCOMPtr<nsIRDFLiteral> literalTarget;
rv = gRDF->GetLiteral(aUserInput, getter_AddRefs(literalTarget));
if (NS_FAILED(rv)) return rv;
if (rv != NS_RDF_NO_VALUE)
{
nsCOMPtr<nsIRDFResource> source;
rv = GetSource(kNC_ShortcutURL, literalTarget,
PR_TRUE, getter_AddRefs(source));
if (NS_FAILED(rv)) return rv;
if (rv != NS_RDF_NO_VALUE)
{
rv = source->GetValue(aShortcutURL);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
}
*aShortcutURL = nsnull;
return NS_RDF_NO_VALUE;
}
////////////////////////////////////////////////////////////////////////
// nsIRDFDataSource
NS_IMETHODIMP
nsBookmarksService::GetTarget(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
PRBool aTruthValue,
nsIRDFNode** aTarget)
{
nsresult rv;
// If they want the URL...
if (aTruthValue && aProperty == kNC_URL) {
// ...and it is in fact a bookmark...
PRBool hasAssertion;
if (NS_SUCCEEDED(mInner->HasAssertion(aSource, kRDF_type, kNC_Bookmark, PR_TRUE, &hasAssertion))
&& hasAssertion) {
nsXPIDLCString uri;
if (NS_FAILED(rv = aSource->GetValue( getter_Copies(uri) ))) {
NS_ERROR("unable to get source's URI");
return rv;
}
nsAutoString ncURI(uri);
if (ncURI.Find("NC:") == 0)
{
return(NS_RDF_NO_VALUE);
}
nsIRDFLiteral* literal;
if (NS_FAILED(rv = gRDF->GetLiteral(nsAutoString(uri).GetUnicode(), &literal))) {
NS_ERROR("unable to construct literal for URL");
return rv;
}
*aTarget = (nsIRDFNode*)literal;
return NS_OK;
}
}
return mInner->GetTarget(aSource, aProperty, aTruthValue, aTarget);
}
NS_IMETHODIMP
nsBookmarksService::Assert(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget,
PRBool aTruthValue)
{
if (CanAccept(aSource, aProperty, aTarget)) {
return mInner->Assert(aSource, aProperty, aTarget, aTruthValue);
}
else {
return NS_RDF_ASSERTION_REJECTED;
}
}
NS_IMETHODIMP
nsBookmarksService::Unassert(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget)
{
if (CanAccept(aSource, aProperty, aTarget)) {
return mInner->Unassert(aSource, aProperty, aTarget);
}
else {
return NS_RDF_ASSERTION_REJECTED;
}
}
NS_IMETHODIMP
nsBookmarksService::Flush()
{
return WriteBookmarks(mInner, kNC_BookmarksRoot);
}
NS_IMETHODIMP
nsBookmarksService::GetAllCommands(nsIRDFResource* source,
nsIEnumerator/*<nsIRDFResource>*/** commands)
{
NS_NOTYETIMPLEMENTED("write me!");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsBookmarksService::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
nsIRDFResource* aCommand,
nsISupportsArray/*<nsIRDFResource>*/* aArguments,
PRBool* aResult)
{
NS_NOTYETIMPLEMENTED("write me!");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsBookmarksService::DoCommand(nsISupportsArray* aSources,
nsIRDFResource* aCommand,
nsISupportsArray* aArguments)
{
NS_NOTYETIMPLEMENTED("write me!");
return NS_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////
// Implementation methods
nsresult
nsBookmarksService::ReadBookmarks()
{
nsresult rv;
rv = gRDFC->MakeSeq(mInner, kNC_BookmarksRoot, nsnull);
NS_ASSERTION(NS_SUCCEEDED(rv), "Unable to make NC:BookmarksRoot a sequence");
if (NS_FAILED(rv)) return rv;
nsSpecialSystemDirectory bookmarksFile(nsSpecialSystemDirectory::OS_CurrentProcessDirectory);
// XXX we should get this from prefs.
bookmarksFile += "res";
bookmarksFile += "rdf";
bookmarksFile += "bookmarks.html";
PRBool foundIERoot = PR_FALSE;
#ifdef XP_WIN
nsCOMPtr<nsIRDFResource> ieFolder;
const char *ieFavoritesURL;
#endif
{ // <-- scope the stream to get the open/close automatically.
nsInputFileStream strm(bookmarksFile);
if (! strm.is_open())
{
NS_ERROR("unable to open file");
return NS_ERROR_FAILURE;
}
BookmarkParser parser;
parser.Init(&strm, NS_STATIC_CAST(nsIRDFDataSource *, this));
#ifdef XP_MAC
parser.SetIEFavoritesRoot(kURINC_IEFavoritesRoot);
#endif
#ifdef XP_WIN
nsSpecialSystemDirectory ieFavoritesFile(nsSpecialSystemDirectory::Win_Favorites);
nsFileURL ieFavoritesURLSpec(ieFavoritesFile);
ieFavoritesURL = ieFavoritesURLSpec.GetAsString();
parser.SetIEFavoritesRoot(ieFavoritesURL);
#endif
parser.Parse(kNC_BookmarksRoot, kNC_Bookmark);
parser.ParserFoundIEFavoritesRoot(&foundIERoot);
} // <-- scope the stream to get the open/close automatically.
// look for and import any IE Favorites
nsAutoString ieTitle("Imported IE Favorites"); // XXX localization?
#ifdef XP_MAC
nsSpecialSystemDirectory ieFavoritesFile(nsSpecialSystemDirectory::Mac_PreferencesDirectory);
ieFavoritesFile += "Explorer";
ieFavoritesFile += "Favorites.html";
nsInputFileStream ieStream(ieFavoritesFile);
if (ieStream.is_open())
{
if (NS_SUCCEEDED(rv = gRDFC->MakeSeq(mInner, kNC_IEFavoritesRoot, nsnull)))
{
BookmarkParser parser;
parser.Init(&ieStream, this);
parser.Parse(kNC_IEFavoritesRoot, kNC_IEFavorite);
nsCOMPtr<nsIRDFLiteral> ieTitleLiteral;
if (NS_SUCCEEDED(rv = gRDF->GetLiteral(ieTitle.GetUnicode(), getter_AddRefs(ieTitleLiteral))))
{
rv = mInner->Assert(kNC_IEFavoritesRoot, kNC_Name, ieTitleLiteral, PR_TRUE);
}
// if the IE Favorites root isn't somewhere in bookmarks.html, add it
if (!foundIERoot)
{
nsCOMPtr<nsIRDFContainer> bookmarksRoot;
rv = nsComponentManager::CreateInstance(kRDFContainerCID,
nsnull,
nsIRDFContainer::GetIID(),
getter_AddRefs(container));
if (NS_SUCCEEDED(rv))
{
rv = bookmarksRoot->AppendElement(kNC_IEFavoritesRoot);
}
}
}
}
#endif
#ifdef XP_WIN
if (NS_SUCCEEDED(rv = gRDF->GetResource(ieFavoritesURL, getter_AddRefs(ieFolder))))
{
nsCOMPtr<nsIRDFLiteral> ieTitleLiteral;
if (NS_SUCCEEDED(rv = gRDF->GetLiteral(ieTitle.GetUnicode(), getter_AddRefs(ieTitleLiteral))))
{
rv = mInner->Assert(ieFolder, kNC_Name, ieTitleLiteral, PR_TRUE);
}
// if the IE Favorites root isn't somewhere in bookmarks.html, add it
if (!foundIERoot)
{
nsCOMPtr<nsIRDFContainer> container;
rv = nsComponentManager::CreateInstance(kRDFContainerCID,
nsnull,
nsIRDFContainer::GetIID(),
getter_AddRefs(container));
if (NS_SUCCEEDED(rv))
{
rv = container->AppendElement(ieFolder);
}
}
}
#endif
return NS_OK;
}
nsresult
nsBookmarksService::WriteBookmarks(nsIRDFDataSource *ds, nsIRDFResource *root)
{
nsSpecialSystemDirectory bookmarksFile(nsSpecialSystemDirectory::OS_CurrentProcessDirectory);
// XXX we should get this from prefs.
bookmarksFile += "res";
bookmarksFile += "rdf";
bookmarksFile += "bookmarks.html";
nsresult rv = NS_ERROR_FAILURE;
nsOutputFileStream strm(bookmarksFile);
if (strm.is_open())
{
strm << "<!DOCTYPE NETSCAPE-Bookmark-file-1>\n";
strm << "<!-- This is an automatically generated file.\n";
strm << "It will be read and overwritten.\n";
strm << "Do Not Edit! -->\n";
strm << "<TITLE>Bookmarks</TITLE>\n";
strm << "<H1>Bookmarks</H1>\n\n";
rv = WriteBookmarksContainer(ds, strm, root, 0);
}
return(rv);
}
nsresult
nsBookmarksService::WriteBookmarksContainer(nsIRDFDataSource *ds, nsOutputFileStream strm, nsIRDFResource *parent, PRInt32 level)
{
nsresult rv = NS_OK;
nsAutoString indentationString("");
for (PRInt32 loop=0; loop<level; loop++) indentationString += " ";
char *indentation = indentationString.ToNewCString();
if (nsnull == indentation) return(NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<nsIRDFContainer> container;
rv = nsComponentManager::CreateInstance(kRDFContainerCID,
nsnull,
nsIRDFContainer::GetIID(),
getter_AddRefs(container));
if (NS_SUCCEEDED(rv))
{
strm << indentation;
strm << "<DL><p>\n";
nsCOMPtr<nsISimpleEnumerator> children;
if (NS_SUCCEEDED(rv = container->GetElements(getter_AddRefs(children))))
{
PRBool more = PR_TRUE;
while (more == PR_TRUE)
{
if (NS_FAILED(rv = children->HasMoreElements(&more))) break;
if (more != PR_TRUE) break;
nsCOMPtr<nsISupports> iSupports;
if (NS_FAILED(rv = children->GetNext(getter_AddRefs(iSupports)))) break;
nsCOMPtr<nsIRDFResource> child = do_QueryInterface(iSupports);
if (!child) break;
PRBool isIERoot = PR_FALSE, isContainer = PR_FALSE;
if (NS_SUCCEEDED(child->EqualsResource(kNC_IEFavoritesRoot, &isIERoot)))
{
if (isIERoot == PR_FALSE)
{
if (NS_SUCCEEDED(rv = gRDFC->IsContainer(ds, child, &isContainer)))
{
}
}
}
nsCOMPtr<nsIRDFNode> nameNode;
nsAutoString nameString("");
char *name = nsnull;
if (NS_SUCCEEDED(rv = ds->GetTarget(child, kNC_Name, PR_TRUE, getter_AddRefs(nameNode))))
{
nsCOMPtr<nsIRDFLiteral> nameLiteral = do_QueryInterface(nameNode);
PRUnichar *title = nsnull;
if (NS_SUCCEEDED(rv = nameLiteral->GetValue(&title)))
{
nameString = title;
name = nameString.ToNewCString();
}
}
strm << indentation;
strm << " ";
if (isContainer == PR_TRUE)
{
strm << "<DT><H3";
// output ADD_DATE
WriteBookmarkProperties(ds, strm, child, kNC_BookmarkAddDate, kAddDateEquals, PR_FALSE);
// output ID
strm << " " << kIDEquals;
nsXPIDLCString id;
rv = child->GetValue(getter_Copies(id));
if (NS_SUCCEEDED(rv) && (id)) {
strm << (const char*) id;
}
strm << "\"";
strm << ">";
// output title
if (name) strm << name;
strm << "</H3>\n";
rv = WriteBookmarksContainer(ds, strm, child, level+1);
}
else
{
char *url = nsnull;
if (NS_SUCCEEDED(rv = child->GetValue(&url)))
{
if (url)
{
nsAutoString uri(url);
// XXX What's the best way to determine if its a separator?
if (uri.Find(kURINC_BookmarksRoot) == 0)
{
// its a separator
strm << "<HR>\n";
}
else
{
strm << "<DT><A HREF=\"";
// output URL
strm << url;
strm << "\"";
// output ADD_DATE
WriteBookmarkProperties(ds, strm, child, kNC_BookmarkAddDate, kAddDateEquals, PR_FALSE);
// output LAST_VISIT
WriteBookmarkProperties(ds, strm, child, kWEB_LastVisitDate, kLastVisitEquals, PR_FALSE);
// output LAST_MODIFIED
WriteBookmarkProperties(ds, strm, child, kWEB_LastModifiedDate, kLastModifiedEquals, PR_FALSE);
// output SHORTCUTURL
WriteBookmarkProperties(ds, strm, child, kNC_ShortcutURL, kShortcutURLEquals, PR_FALSE);
strm << ">";
// output title
if (name) strm << name;
strm << "</A>\n";
}
}
}
}
if (nsnull != name)
{
delete []name;
name = nsnull;
}
if (NS_FAILED(rv)) break;
}
strm << indentation;
strm << "</DL><p>\n";
}
}
delete [] indentation;
return(rv);
}
nsresult
nsBookmarksService::WriteBookmarkProperties(nsIRDFDataSource *ds, nsOutputFileStream strm,
nsIRDFResource *child, nsIRDFResource *property, const char *htmlAttrib, PRBool isFirst)
{
nsresult rv;
nsCOMPtr<nsIRDFNode> node;
if (NS_SUCCEEDED(rv = ds->GetTarget(child, property, PR_TRUE, getter_AddRefs(node))))
{
nsCOMPtr<nsIRDFLiteral> literal = do_QueryInterface(node);
if (literal)
{
PRUnichar *literalUni = nsnull;
if (NS_SUCCEEDED(rv = literal->GetValue(&literalUni)))
{
nsAutoString literalString = literalUni;
char *attribute = literalString.ToNewCString();
if (nsnull != attribute)
{
if (isFirst == PR_FALSE)
{
strm << " ";
}
strm << htmlAttrib;
strm << attribute;
strm << "\"";
delete [] attribute;
attribute = nsnull;
}
}
}
}
return(rv);
}
PRBool
nsBookmarksService::CanAccept(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget)
{
// XXX This is really crippled, and needs to be stricter. We want
// to exclude any property that isn't talking about a known
// bookmark.
nsresult rv;
PRBool isOrdinal;
rv = gRDFC->IsOrdinalProperty(aProperty, &isOrdinal);
if (NS_FAILED(rv))
return PR_FALSE;
if (isOrdinal) {
return PR_TRUE;
}
else if ((aProperty != kRDF_type) ||
(aProperty != kWEB_LastModifiedDate) ||
(aProperty != kWEB_LastVisitDate) ||
(aProperty != kNC_Name) ||
(aProperty != kNC_BookmarkAddDate)) {
return PR_TRUE;
}
else {
return PR_FALSE;
}
}
////////////////////////////////////////////////////////////////////////
// Component Exports
extern "C" PR_IMPLEMENT(nsresult)
NSGetFactory(nsISupports* aServiceMgr,
const nsCID &aClass,
const char *aClassName,
const char *aProgID,
nsIFactory **aFactory)
{
NS_PRECONDITION(aFactory != nsnull, "null ptr");
if (! aFactory)
return NS_ERROR_NULL_POINTER;
nsIGenericFactory::ConstructorProcPtr constructor;
if (aClass.Equals(kBookmarksServiceCID)) {
constructor = NS_NewBookmarksService;
}
else {
*aFactory = nsnull;
return NS_NOINTERFACE; // XXX
}
nsresult rv;
NS_WITH_SERVICE1(nsIComponentManager, compMgr, aServiceMgr, kComponentManagerCID, &rv);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIGenericFactory> factory;
rv = compMgr->CreateInstance(kGenericFactoryCID,
nsnull,
nsIGenericFactory::GetIID(),
getter_AddRefs(factory));
if (NS_FAILED(rv)) return rv;
rv = factory->SetConstructor(constructor);
if (NS_FAILED(rv)) return rv;
*aFactory = factory;
NS_ADDREF(*aFactory);
return NS_OK;
}
extern "C" PR_IMPLEMENT(nsresult)
NSRegisterSelf(nsISupports* aServMgr , const char* aPath)
{
nsresult rv;
nsCOMPtr<nsIServiceManager> servMgr(do_QueryInterface(aServMgr, &rv));
if (NS_FAILED(rv)) return rv;
NS_WITH_SERVICE1(nsIComponentManager, compMgr, servMgr, kComponentManagerCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = compMgr->RegisterComponent(kBookmarksServiceCID, "Bookmarks",
NS_BOOKMARKS_SERVICE_PROGID,
aPath, PR_TRUE, PR_TRUE);
rv = compMgr->RegisterComponent(kBookmarksServiceCID, "Bookmarks",
NS_BOOKMARKS_DATASOURCE_PROGID,
aPath, PR_TRUE, PR_TRUE);
return NS_OK;
}
extern "C" PR_IMPLEMENT(nsresult)
NSUnregisterSelf(nsISupports* aServMgr, const char* aPath)
{
nsresult rv;
nsCOMPtr<nsIServiceManager> servMgr(do_QueryInterface(aServMgr, &rv));
if (NS_FAILED(rv)) return rv;
NS_WITH_SERVICE1(nsIComponentManager, compMgr, servMgr, kComponentManagerCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = compMgr->UnregisterComponent(kBookmarksServiceCID, aPath);
return NS_OK;
}