/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Seth Spitzer * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsSubscribeDataSource.h" #include "nsIRDFService.h" #include "nsRDFCID.h" #include "nsIComponentManager.h" #include "nsXPIDLString.h" #include "rdf.h" #include "nsIServiceManager.h" #include "nsEnumeratorUtils.h" #include "nsString.h" #include "nsCOMPtr.h" #include "nsIMsgFolder.h" #include "nsIMsgIncomingServer.h" static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); // this is used for notification of observers using nsVoidArray typedef struct _nsSubscribeNotification { nsIRDFDataSource *datasource; nsIRDFResource *subject; nsIRDFResource *property; nsIRDFNode *object; } nsSubscribeNotification; nsSubscribeDataSource::nsSubscribeDataSource() { } nsSubscribeDataSource::~nsSubscribeDataSource() { } NS_IMPL_THREADSAFE_ADDREF(nsSubscribeDataSource) NS_IMPL_THREADSAFE_RELEASE(nsSubscribeDataSource) NS_IMPL_QUERY_INTERFACE2(nsSubscribeDataSource, nsIRDFDataSource, nsISubscribeDataSource) nsresult nsSubscribeDataSource::Init() { nsresult rv; mRDFService = do_GetService(kRDFServiceCID, &rv); NS_ASSERTION(NS_SUCCEEDED(rv) && mRDFService, "failed to get rdf service"); NS_ENSURE_SUCCESS(rv,rv); if (!mRDFService) return NS_ERROR_FAILURE; rv = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "child"), getter_AddRefs(kNC_Child)); NS_ENSURE_SUCCESS(rv,rv); rv = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Name"), getter_AddRefs(kNC_Name)); NS_ENSURE_SUCCESS(rv,rv); rv = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "LeafName"), getter_AddRefs(kNC_LeafName)); NS_ENSURE_SUCCESS(rv,rv); rv = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Subscribed"), getter_AddRefs(kNC_Subscribed)); NS_ENSURE_SUCCESS(rv,rv); rv = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Subscribable"), getter_AddRefs(kNC_Subscribable)); NS_ENSURE_SUCCESS(rv,rv); rv = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "ServerType"), getter_AddRefs(kNC_ServerType)); NS_ENSURE_SUCCESS(rv,rv); rv = mRDFService->GetLiteral(NS_LITERAL_STRING("true").get(),getter_AddRefs(kTrueLiteral)); NS_ENSURE_SUCCESS(rv,rv); rv = mRDFService->GetLiteral(NS_LITERAL_STRING("false").get(),getter_AddRefs(kFalseLiteral)); NS_ENSURE_SUCCESS(rv,rv); return NS_OK; } NS_IMETHODIMP nsSubscribeDataSource::GetURI(char * *aURI) { if ((*aURI = nsCRT::strdup("rdf:subscribe")) == nsnull) return NS_ERROR_OUT_OF_MEMORY; else return NS_OK; } NS_IMETHODIMP nsSubscribeDataSource::GetSource(nsIRDFResource *property, nsIRDFNode *target, PRBool tv, nsIRDFResource **source) { NS_PRECONDITION(property != nsnull, "null ptr"); if (! property) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(target != nsnull, "null ptr"); if (! target) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(source != nsnull, "null ptr"); if (! source) return NS_ERROR_NULL_POINTER; *source = nsnull; return NS_RDF_NO_VALUE; } NS_IMETHODIMP nsSubscribeDataSource::GetTarget(nsIRDFResource *source, nsIRDFResource *property, PRBool tv, nsIRDFNode **target /* out */) { nsresult rv = NS_RDF_NO_VALUE; NS_PRECONDITION(source != nsnull, "null ptr"); if (! source) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(property != nsnull, "null ptr"); if (! property) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(target != nsnull, "null ptr"); if (! target) return NS_ERROR_NULL_POINTER; *target = nsnull; // we only have positive assertions in the subscribe data source. if (! tv) return NS_RDF_NO_VALUE; nsCOMPtr server; nsXPIDLCString relativePath; rv = GetServerAndRelativePathFromResource(source, getter_AddRefs(server), getter_Copies(relativePath)); if (NS_FAILED(rv) || !server) { return NS_RDF_NO_VALUE; } if (property == kNC_Name.get()) { nsCOMPtr name; rv = mRDFService->GetLiteral(NS_ConvertUTF8toUTF16(relativePath).get(), getter_AddRefs(name)); NS_ENSURE_SUCCESS(rv,rv); if (!name) rv = NS_RDF_NO_VALUE; if (rv == NS_RDF_NO_VALUE) return(rv); return name->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) target); } else if (property == kNC_Child.get()) { nsXPIDLCString childUri; rv = server->GetFirstChildURI(relativePath, childUri); if (NS_FAILED(rv)) return NS_RDF_NO_VALUE; if (childUri.IsEmpty()) return NS_RDF_NO_VALUE; nsCOMPtr childResource; rv = mRDFService->GetResource(childUri, getter_AddRefs(childResource)); NS_ENSURE_SUCCESS(rv,rv); return childResource->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) target); } else if (property == kNC_Subscribed.get()) { PRBool isSubscribed; rv = server->IsSubscribed(relativePath, &isSubscribed); NS_ENSURE_SUCCESS(rv,rv); NS_IF_ADDREF(*target = (isSubscribed ? kTrueLiteral : kFalseLiteral)); return NS_OK; } else if (property == kNC_Subscribable.get()) { PRBool isSubscribable; rv = server->IsSubscribable(relativePath, &isSubscribable); NS_ENSURE_SUCCESS(rv,rv); NS_IF_ADDREF(*target = (isSubscribable ? kTrueLiteral : kFalseLiteral)); return NS_OK; } else if (property == kNC_ServerType.get()) { nsXPIDLCString serverTypeStr; rv = GetServerType(server, getter_Copies(serverTypeStr)); NS_ENSURE_SUCCESS(rv,rv); nsCOMPtr serverType; rv = mRDFService->GetLiteral(NS_ConvertASCIItoUTF16(serverTypeStr).get(), getter_AddRefs(serverType)); NS_ENSURE_SUCCESS(rv,rv); if (!serverType) rv = NS_RDF_NO_VALUE; if (rv == NS_RDF_NO_VALUE) return(rv); return serverType->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) target); } else if (property == kNC_LeafName.get()) { nsXPIDLString leafNameStr; rv = server->GetLeafName(relativePath, leafNameStr); NS_ENSURE_SUCCESS(rv,rv); nsCOMPtr leafName; rv = mRDFService->GetLiteral(leafNameStr, getter_AddRefs(leafName)); NS_ENSURE_SUCCESS(rv,rv); if (!leafName) rv = NS_RDF_NO_VALUE; if (rv == NS_RDF_NO_VALUE) return(rv); return leafName->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) target); } else { // do nothing } return(NS_RDF_NO_VALUE); } nsresult nsSubscribeDataSource::GetChildren(nsISubscribableServer *aServer, const nsACString &aRelativePath, nsISimpleEnumerator** aResult) { nsresult rv = NS_OK; NS_ASSERTION(aServer && aResult, "no server or result"); if (!aServer || !aResult) return NS_ERROR_NULL_POINTER; nsCOMPtr children; rv = NS_NewISupportsArray(getter_AddRefs(children)); NS_ENSURE_SUCCESS(rv,rv); if (!children) return NS_ERROR_FAILURE; rv = aServer->GetChildren(aRelativePath, children); // GetChildren() can fail if there are no children if (NS_FAILED(rv)) return rv; nsISimpleEnumerator* result = new nsArrayEnumerator(children); if (!result) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(result); *aResult = result; return NS_OK; } NS_IMETHODIMP nsSubscribeDataSource::GetTargets(nsIRDFResource *source, nsIRDFResource *property, PRBool tv, nsISimpleEnumerator **targets /* out */) { nsresult rv = NS_OK; NS_PRECONDITION(source != nsnull, "null ptr"); if (! source) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(property != nsnull, "null ptr"); if (! property) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(targets != nsnull, "null ptr"); if (! targets) return NS_ERROR_NULL_POINTER; *targets = nsnull; // we only have positive assertions in the subscribe data source. if (!tv) return NS_RDF_NO_VALUE; nsCOMPtr server; nsXPIDLCString relativePath; // UTF-8 rv = GetServerAndRelativePathFromResource(source, getter_AddRefs(server), getter_Copies(relativePath)); if (NS_FAILED(rv) || !server) { return NS_NewEmptyEnumerator(targets); } if (property == kNC_Child.get()) { rv = GetChildren(server, relativePath, targets); if (NS_FAILED(rv)) { return NS_NewEmptyEnumerator(targets); } return rv; } else if (property == kNC_LeafName.get()) { nsXPIDLString leafNameStr; rv = server->GetLeafName(relativePath, leafNameStr); NS_ENSURE_SUCCESS(rv,rv); nsCOMPtr leafName; rv = mRDFService->GetLiteral(leafNameStr, getter_AddRefs(leafName)); NS_ENSURE_SUCCESS(rv,rv); nsISimpleEnumerator* result = new nsSingletonEnumerator(leafName); if (!result) return NS_ERROR_OUT_OF_MEMORY; NS_IF_ADDREF(*targets = result); return NS_OK; } else if (property == kNC_Subscribed.get()) { PRBool isSubscribed; rv = server->IsSubscribed(relativePath, &isSubscribed); NS_ENSURE_SUCCESS(rv,rv); nsISimpleEnumerator* result = new nsSingletonEnumerator(isSubscribed ? kTrueLiteral : kFalseLiteral); if (!result) return NS_ERROR_OUT_OF_MEMORY; NS_IF_ADDREF(*targets = result); return NS_OK; } else if (property == kNC_Subscribable.get()) { PRBool isSubscribable; rv = server->IsSubscribable(relativePath, &isSubscribable); NS_ENSURE_SUCCESS(rv,rv); nsISimpleEnumerator* result = new nsSingletonEnumerator(isSubscribable ? kTrueLiteral : kFalseLiteral); if (!result) return NS_ERROR_OUT_OF_MEMORY; NS_IF_ADDREF(*targets = result); return NS_OK; } else if (property == kNC_Name.get()) { nsCOMPtr name; rv = mRDFService->GetLiteral(NS_ConvertUTF8toUTF16(relativePath).get(), getter_AddRefs(name)); NS_ENSURE_SUCCESS(rv,rv); nsISimpleEnumerator* result = new nsSingletonEnumerator(name); if (!result) return NS_ERROR_OUT_OF_MEMORY; NS_IF_ADDREF(*targets = result); return NS_OK; } else if (property == kNC_ServerType.get()) { nsXPIDLCString serverTypeStr; rv = GetServerType(server, getter_Copies(serverTypeStr)); NS_ENSURE_SUCCESS(rv,rv); nsCOMPtr serverType; rv = mRDFService->GetLiteral(NS_ConvertASCIItoUTF16(serverTypeStr).get(), getter_AddRefs(serverType)); NS_ENSURE_SUCCESS(rv,rv); nsISimpleEnumerator* result = new nsSingletonEnumerator(serverType); if (!result) return NS_ERROR_OUT_OF_MEMORY; NS_IF_ADDREF(*targets = result); return NS_OK; } else { // do nothing } return NS_NewEmptyEnumerator(targets); } NS_IMETHODIMP nsSubscribeDataSource::Assert(nsIRDFResource *source, nsIRDFResource *property, nsIRDFNode *target, PRBool tv) { return NS_RDF_ASSERTION_REJECTED; } NS_IMETHODIMP nsSubscribeDataSource::Unassert(nsIRDFResource *source, nsIRDFResource *property, nsIRDFNode *target) { return NS_RDF_ASSERTION_REJECTED; } NS_IMETHODIMP nsSubscribeDataSource::Change(nsIRDFResource* aSource, nsIRDFResource* aProperty, nsIRDFNode* aOldTarget, nsIRDFNode* aNewTarget) { return NS_RDF_ASSERTION_REJECTED; } NS_IMETHODIMP nsSubscribeDataSource::Move(nsIRDFResource* aOldSource, nsIRDFResource* aNewSource, nsIRDFResource* aProperty, nsIRDFNode* aTarget) { return NS_RDF_ASSERTION_REJECTED; } nsresult nsSubscribeDataSource::GetServerType(nsISubscribableServer *server, char **serverType) { nsresult rv; if (!server || !serverType) return NS_ERROR_NULL_POINTER; nsCOMPtr incomingServer(do_QueryInterface(server, &rv)); NS_ENSURE_SUCCESS(rv,rv); if (!incomingServer) return NS_ERROR_FAILURE; rv = incomingServer->GetType(serverType); NS_ENSURE_SUCCESS(rv,rv); return NS_OK; } nsresult nsSubscribeDataSource::GetServerAndRelativePathFromResource(nsIRDFResource *source, nsISubscribableServer **server, char **relativePath) { nsresult rv = NS_OK; const char *sourceURI = nsnull; rv = source->GetValueConst(&sourceURI); NS_ENSURE_SUCCESS(rv,rv); nsCOMPtr folder(do_QueryInterface(source, &rv)); // we expect this to fail sometimes, so don't assert if (NS_FAILED(rv)) return rv; if (!folder) return NS_ERROR_FAILURE; nsCOMPtr incomingServer; rv = folder->GetServer(getter_AddRefs(incomingServer)); NS_ENSURE_SUCCESS(rv,rv); if (!incomingServer) return NS_ERROR_FAILURE; rv = incomingServer->QueryInterface(NS_GET_IID(nsISubscribableServer), (void**)server); NS_ENSURE_SUCCESS(rv,rv); if (!*server) return NS_ERROR_FAILURE; nsXPIDLCString serverURI; rv = incomingServer->GetServerURI(getter_Copies(serverURI)); NS_ENSURE_SUCCESS(rv,rv); PRUint32 serverURILen = strlen((const char *)serverURI); if (serverURILen == strlen(sourceURI)) { *relativePath = nsnull; } else { // XXX : perhaps, have to unescape before returning *relativePath = nsCRT::strdup(sourceURI + serverURILen + 1); NS_ASSERTION(*relativePath,"no relative path"); if (!*relativePath) return NS_ERROR_OUT_OF_MEMORY; } return NS_OK; } NS_IMETHODIMP nsSubscribeDataSource::HasAssertion(nsIRDFResource *source, nsIRDFResource *property, nsIRDFNode *target, PRBool tv, PRBool *hasAssertion /* out */) { nsresult rv = NS_OK; NS_PRECONDITION(source != nsnull, "null ptr"); if (! source) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(property != nsnull, "null ptr"); if (! property) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(target != nsnull, "null ptr"); if (! target) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(hasAssertion != nsnull, "null ptr"); if (! hasAssertion) return NS_ERROR_NULL_POINTER; *hasAssertion = PR_FALSE; // we only have positive assertions in the subscribe data source. if (!tv) return NS_OK; if (property == kNC_Child.get()) { nsCOMPtr server; nsXPIDLCString relativePath; rv = GetServerAndRelativePathFromResource(source, getter_AddRefs(server), getter_Copies(relativePath)); if (NS_FAILED(rv) || !server) { *hasAssertion = PR_FALSE; return NS_OK; } // not everything has children rv = server->HasChildren(relativePath, hasAssertion); NS_ENSURE_SUCCESS(rv,rv); } else if (property == kNC_Name.get()) { // everything has a name *hasAssertion = PR_TRUE; } else if (property == kNC_LeafName.get()) { // everything has a leaf name *hasAssertion = PR_TRUE; } else if (property == kNC_Subscribed.get()) { // everything is subscribed or not *hasAssertion = PR_TRUE; } else if (property == kNC_Subscribable.get()) { // everything is subscribable or not *hasAssertion = PR_TRUE; } else if (property == kNC_ServerType.get()) { // everything has a server type *hasAssertion = PR_TRUE; } else { // do nothing } return NS_OK; } NS_IMETHODIMP nsSubscribeDataSource::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, PRBool *result) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsSubscribeDataSource::HasArcOut(nsIRDFResource *source, nsIRDFResource *aArc, PRBool *result) { nsresult rv = NS_OK; nsCOMPtr server; nsXPIDLCString relativePath; if (aArc == kNC_Child.get()) { rv = GetServerAndRelativePathFromResource(source, getter_AddRefs(server), getter_Copies(relativePath)); if (NS_FAILED(rv) || !server) { *result = PR_FALSE; return NS_OK; } PRBool hasChildren = PR_FALSE; rv = server->HasChildren(relativePath, &hasChildren); NS_ENSURE_SUCCESS(rv,rv); *result = hasChildren; return NS_OK; } else if ((aArc == kNC_Subscribed.get()) || (aArc == kNC_Subscribable.get()) || (aArc == kNC_LeafName.get()) || (aArc == kNC_ServerType.get()) || (aArc == kNC_Name.get())) { *result = PR_TRUE; return NS_OK; } *result = PR_FALSE; return NS_OK; } NS_IMETHODIMP nsSubscribeDataSource::ArcLabelsIn(nsIRDFNode *node, nsISimpleEnumerator ** labels /* out */) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsSubscribeDataSource::ArcLabelsOut(nsIRDFResource *source, nsISimpleEnumerator **labels /* out */) { nsresult rv = NS_OK; NS_PRECONDITION(source != nsnull, "null ptr"); if (! source) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(labels != nsnull, "null ptr"); if (! labels) return NS_ERROR_NULL_POINTER; nsCOMPtr server; nsXPIDLCString relativePath; rv = GetServerAndRelativePathFromResource(source, getter_AddRefs(server), getter_Copies(relativePath)); if (NS_FAILED(rv) || !server) { return NS_NewEmptyEnumerator(labels); } nsCOMPtr array; rv = NS_NewISupportsArray(getter_AddRefs(array)); NS_ENSURE_SUCCESS(rv,rv); array->AppendElement(kNC_Subscribed); array->AppendElement(kNC_Subscribable); array->AppendElement(kNC_Name); array->AppendElement(kNC_ServerType); array->AppendElement(kNC_LeafName); PRBool hasChildren = PR_FALSE; rv = server->HasChildren(relativePath, &hasChildren); NS_ENSURE_SUCCESS(rv,rv); if (hasChildren) { array->AppendElement(kNC_Child); } nsISimpleEnumerator* result = new nsArrayEnumerator(array); if (! result) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(result); *labels = result; return NS_OK; } NS_IMETHODIMP nsSubscribeDataSource::GetAllResources(nsISimpleEnumerator** aCursor) { NS_NOTYETIMPLEMENTED("sorry!"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsSubscribeDataSource::AddObserver(nsIRDFObserver *n) { NS_PRECONDITION(n != nsnull, "null ptr"); if (! n) return NS_ERROR_NULL_POINTER; if (! mObservers) { nsresult rv; rv = NS_NewISupportsArray(getter_AddRefs(mObservers)); if (NS_FAILED(rv)) return rv; } mObservers->AppendElement(n); return NS_OK; } NS_IMETHODIMP nsSubscribeDataSource::RemoveObserver(nsIRDFObserver *n) { NS_PRECONDITION(n != nsnull, "null ptr"); if (! n) return NS_ERROR_NULL_POINTER; if (! mObservers) return NS_OK; mObservers->RemoveElement(n); return NS_OK; } NS_IMETHODIMP nsSubscribeDataSource::GetHasObservers(PRBool *hasObservers) { nsresult rv = NS_OK; NS_ASSERTION(hasObservers, "null ptr"); if (!hasObservers) return NS_ERROR_NULL_POINTER; if (!mObservers) { *hasObservers = PR_FALSE; return NS_OK; } PRUint32 count = 0; rv = mObservers->Count(&count); NS_ENSURE_SUCCESS(rv,rv); *hasObservers = (count > 0); return NS_OK; } NS_IMETHODIMP nsSubscribeDataSource::GetAllCmds(nsIRDFResource* source, nsISimpleEnumerator/**/** commands) { return(NS_NewEmptyEnumerator(commands)); } NS_IMETHODIMP nsSubscribeDataSource::IsCommandEnabled(nsISupportsArray/**/* aSources, nsIRDFResource* aCommand, nsISupportsArray/**/* aArguments, PRBool* aResult) { return(NS_ERROR_NOT_IMPLEMENTED); } NS_IMETHODIMP nsSubscribeDataSource::DoCommand(nsISupportsArray/**/* aSources, nsIRDFResource* aCommand, nsISupportsArray/**/* aArguments) { return(NS_ERROR_NOT_IMPLEMENTED); } NS_IMETHODIMP nsSubscribeDataSource::BeginUpdateBatch() { return NS_OK; } NS_IMETHODIMP nsSubscribeDataSource::EndUpdateBatch() { return NS_OK; } NS_IMETHODIMP nsSubscribeDataSource::GetSources(nsIRDFResource *aProperty, nsIRDFNode *aTarget, PRBool aTruthValue, nsISimpleEnumerator **_retval) { NS_ASSERTION(PR_FALSE, "Not implemented"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsSubscribeDataSource::NotifyObservers(nsIRDFResource *subject, nsIRDFResource *property, nsIRDFNode *object, PRBool assert, PRBool change) { NS_ASSERTION(!(change && assert), "Can't change and assert at the same time!\n"); if(mObservers) { nsSubscribeNotification note = { this, subject, property, object }; if(change) mObservers->EnumerateForwards(changeEnumFunc, ¬e); else if (assert) mObservers->EnumerateForwards(assertEnumFunc, ¬e); else mObservers->EnumerateForwards(unassertEnumFunc, ¬e); } return NS_OK; } PRBool nsSubscribeDataSource::changeEnumFunc(nsISupports *aElement, void *aData) { nsSubscribeNotification* note = (nsSubscribeNotification*)aData; nsIRDFObserver* observer = (nsIRDFObserver *)aElement; observer->OnChange(note->datasource, note->subject, note->property, nsnull, note->object); return PR_TRUE; } PRBool nsSubscribeDataSource::assertEnumFunc(nsISupports *aElement, void *aData) { nsSubscribeNotification* note = (nsSubscribeNotification*)aData; nsIRDFObserver* observer = (nsIRDFObserver *)aElement; observer->OnAssert(note->datasource, note->subject, note->property, note->object); return PR_TRUE; } PRBool nsSubscribeDataSource::unassertEnumFunc(nsISupports *aElement, void *aData) { nsSubscribeNotification* note = (nsSubscribeNotification*)aData; nsIRDFObserver* observer = (nsIRDFObserver *)aElement; observer->OnUnassert(note->datasource, note->subject, note->property, note->object); return PR_TRUE; }