From 302bf1b523012e11b60425d6eee1221ebc2724eb Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Sun, 3 Nov 2019 00:17:46 -0400 Subject: Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1 --- mailnews/base/src/nsSubscribableServer.cpp | 805 +++++++++++++++++++++++++++++ 1 file changed, 805 insertions(+) create mode 100644 mailnews/base/src/nsSubscribableServer.cpp (limited to 'mailnews/base/src/nsSubscribableServer.cpp') diff --git a/mailnews/base/src/nsSubscribableServer.cpp b/mailnews/base/src/nsSubscribableServer.cpp new file mode 100644 index 000000000..80f9c9b64 --- /dev/null +++ b/mailnews/base/src/nsSubscribableServer.cpp @@ -0,0 +1,805 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +#include "nsSubscribableServer.h" +#include "nsIMsgIncomingServer.h" +#include "prmem.h" +#include "rdf.h" +#include "nsRDFCID.h" +#include "nsIServiceManager.h" +#include "nsMsgI18N.h" +#include "nsMsgUtils.h" +#include "nsCOMArray.h" +#include "nsArrayEnumerator.h" +#include "nsServiceManagerUtils.h" + +static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); + +nsSubscribableServer::nsSubscribableServer(void) +{ + mDelimiter = '.'; + mShowFullName = true; + mTreeRoot = nullptr; + mStopped = false; +} + +nsresult +nsSubscribableServer::Init() +{ + nsresult rv; + + rv = EnsureRDFService(); + NS_ENSURE_SUCCESS(rv,rv); + + 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 "Subscribed"), + getter_AddRefs(kNC_Subscribed)); + NS_ENSURE_SUCCESS(rv,rv); + + rv = mRDFService->GetLiteral(u"true", getter_AddRefs(kTrueLiteral)); + NS_ENSURE_SUCCESS(rv,rv); + + rv = mRDFService->GetLiteral(u"false", getter_AddRefs(kFalseLiteral)); + NS_ENSURE_SUCCESS(rv,rv); + return NS_OK; +} + +nsSubscribableServer::~nsSubscribableServer(void) +{ + mozilla::DebugOnly rv = FreeSubtree(mTreeRoot); + NS_ASSERTION(NS_SUCCEEDED(rv),"failed to free tree"); +} + +NS_IMPL_ISUPPORTS(nsSubscribableServer, nsISubscribableServer) + +NS_IMETHODIMP +nsSubscribableServer::SetIncomingServer(nsIMsgIncomingServer *aServer) +{ + if (!aServer) { + mIncomingServerUri.AssignLiteral(""); + return NS_OK; + } + + // We intentionally do not store a pointer to the aServer here + // as it would create reference loops, because nsIImapIncomingServer + // and nsINntpIncomingServer keep a reference to an internal + // nsISubscribableServer object. + // We only need the URI of the server anyway. + return aServer->GetServerURI(mIncomingServerUri); +} + +NS_IMETHODIMP +nsSubscribableServer::GetDelimiter(char *aDelimiter) +{ + if (!aDelimiter) return NS_ERROR_NULL_POINTER; + *aDelimiter = mDelimiter; + return NS_OK; +} + +NS_IMETHODIMP +nsSubscribableServer::SetDelimiter(char aDelimiter) +{ + mDelimiter = aDelimiter; + return NS_OK; +} + +NS_IMETHODIMP +nsSubscribableServer::SetAsSubscribed(const nsACString &path) +{ + nsresult rv = NS_OK; + + SubscribeTreeNode *node = nullptr; + rv = FindAndCreateNode(path, &node); + NS_ENSURE_SUCCESS(rv,rv); + + NS_ASSERTION(node,"didn't find the node"); + if (!node) return NS_ERROR_FAILURE; + + node->isSubscribable = true; + node->isSubscribed = true; + + rv = NotifyChange(node, kNC_Subscribed, node->isSubscribed); + NS_ENSURE_SUCCESS(rv,rv); + + return rv; +} + +NS_IMETHODIMP +nsSubscribableServer::AddTo(const nsACString& aName, bool aAddAsSubscribed, + bool aSubscribable, bool aChangeIfExists) +{ + nsresult rv = NS_OK; + + if (mStopped) { +#ifdef DEBUG_seth + printf("stopped!\n"); +#endif + return NS_ERROR_FAILURE; + } + + SubscribeTreeNode *node = nullptr; + + // todo, shouldn't we pass in aAddAsSubscribed, for the + // default value if we create it? + rv = FindAndCreateNode(aName, &node); + NS_ENSURE_SUCCESS(rv,rv); + + NS_ASSERTION(node,"didn't find the node"); + if (!node) return NS_ERROR_FAILURE; + + if (aChangeIfExists) { + node->isSubscribed = aAddAsSubscribed; + rv = NotifyChange(node, kNC_Subscribed, node->isSubscribed); + NS_ENSURE_SUCCESS(rv,rv); + } + + node->isSubscribable = aSubscribable; + return rv; +} + +NS_IMETHODIMP +nsSubscribableServer::SetState(const nsACString &aPath, bool aState, + bool *aStateChanged) +{ + nsresult rv = NS_OK; + NS_ASSERTION(!aPath.IsEmpty() && aStateChanged, "no path or stateChanged"); + if (aPath.IsEmpty() || !aStateChanged) return NS_ERROR_NULL_POINTER; + + NS_ASSERTION(MsgIsUTF8(aPath), "aPath is not in UTF-8"); + + *aStateChanged = false; + + SubscribeTreeNode *node = nullptr; + rv = FindAndCreateNode(aPath, &node); + NS_ENSURE_SUCCESS(rv,rv); + + NS_ASSERTION(node,"didn't find the node"); + if (!node) return NS_ERROR_FAILURE; + + NS_ASSERTION(node->isSubscribable, "fix this"); + if (!node->isSubscribable) { + return NS_OK; + } + + if (node->isSubscribed == aState) { + return NS_OK; + } + else { + node->isSubscribed = aState; + *aStateChanged = true; + rv = NotifyChange(node, kNC_Subscribed, node->isSubscribed); + NS_ENSURE_SUCCESS(rv,rv); + } + + return rv; +} + +void +nsSubscribableServer::BuildURIFromNode(SubscribeTreeNode *node, nsACString &uri) +{ + if (node->parent) { + BuildURIFromNode(node->parent, uri); + if (node->parent == mTreeRoot) { + uri += "/"; + } + else { + uri += mDelimiter; + } + } + + uri += node->name; + return; +} + +nsresult +nsSubscribableServer::NotifyAssert(SubscribeTreeNode *subjectNode, nsIRDFResource *property, SubscribeTreeNode *objectNode) +{ + nsresult rv; + + bool hasObservers = true; + rv = EnsureSubscribeDS(); + NS_ENSURE_SUCCESS(rv,rv); + rv = mSubscribeDS->GetHasObservers(&hasObservers); + NS_ENSURE_SUCCESS(rv,rv); + // no need to do all this work, there are no observers + if (!hasObservers) { + return NS_OK; + } + + nsAutoCString subjectUri; + BuildURIFromNode(subjectNode, subjectUri); + + // we could optimize this, since we know that objectUri == subjectUri + mDelimiter + object->name + // is it worth it? + nsAutoCString objectUri; + BuildURIFromNode(objectNode, objectUri); + + nsCOMPtr subject; + nsCOMPtr object; + + rv = EnsureRDFService(); + NS_ENSURE_SUCCESS(rv,rv); + + rv = mRDFService->GetResource(subjectUri, getter_AddRefs(subject)); + NS_ENSURE_SUCCESS(rv,rv); + rv = mRDFService->GetResource(objectUri, getter_AddRefs(object)); + NS_ENSURE_SUCCESS(rv,rv); + + rv = Notify(subject, property, object, true, false); + NS_ENSURE_SUCCESS(rv,rv); + return NS_OK; +} + +nsresult +nsSubscribableServer::EnsureRDFService() +{ + nsresult rv; + + if (!mRDFService) { + 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; + } + return NS_OK; +} + +nsresult +nsSubscribableServer::NotifyChange(SubscribeTreeNode *subjectNode, nsIRDFResource *property, bool value) +{ + nsresult rv; + nsCOMPtr subject; + + bool hasObservers = true; + rv = EnsureSubscribeDS(); + NS_ENSURE_SUCCESS(rv,rv); + rv = mSubscribeDS->GetHasObservers(&hasObservers); + NS_ENSURE_SUCCESS(rv,rv); + // no need to do all this work, there are no observers + if (!hasObservers) { + return NS_OK; + } + + nsAutoCString subjectUri; + BuildURIFromNode(subjectNode, subjectUri); + + rv = EnsureRDFService(); + NS_ENSURE_SUCCESS(rv,rv); + + rv = mRDFService->GetResource(subjectUri, getter_AddRefs(subject)); + NS_ENSURE_SUCCESS(rv,rv); + + if (value) { + rv = Notify(subject,property,kTrueLiteral,false,true); + } + else { + rv = Notify(subject,property,kFalseLiteral,false,true); + } + + NS_ENSURE_SUCCESS(rv,rv); + return NS_OK; +} + +nsresult +nsSubscribableServer::EnsureSubscribeDS() +{ + nsresult rv = NS_OK; + + if (!mSubscribeDS) { + nsCOMPtr ds; + + rv = EnsureRDFService(); + NS_ENSURE_SUCCESS(rv,rv); + + rv = mRDFService->GetDataSource("rdf:subscribe", getter_AddRefs(ds)); + NS_ENSURE_SUCCESS(rv,rv); + if (!ds) return NS_ERROR_FAILURE; + + mSubscribeDS = do_QueryInterface(ds, &rv); + NS_ENSURE_SUCCESS(rv,rv); + if (!mSubscribeDS) return NS_ERROR_FAILURE; + } + return NS_OK; +} + +nsresult +nsSubscribableServer::Notify(nsIRDFResource *subject, nsIRDFResource *property, nsIRDFNode *object, bool isAssert, bool isChange) +{ + nsresult rv = NS_OK; + + rv = EnsureSubscribeDS(); + NS_ENSURE_SUCCESS(rv,rv); + + rv = mSubscribeDS->NotifyObservers(subject, property, object, isAssert, isChange); + NS_ENSURE_SUCCESS(rv,rv); + return rv; +} + +NS_IMETHODIMP +nsSubscribableServer::SetSubscribeListener(nsISubscribeListener *aListener) +{ + mSubscribeListener = aListener; + return NS_OK; +} + +NS_IMETHODIMP +nsSubscribableServer::GetSubscribeListener(nsISubscribeListener **aListener) +{ + if (!aListener) return NS_ERROR_NULL_POINTER; + if (mSubscribeListener) { + *aListener = mSubscribeListener; + NS_ADDREF(*aListener); + } + return NS_OK; +} + +NS_IMETHODIMP +nsSubscribableServer::SubscribeCleanup() +{ + NS_ASSERTION(false,"override this."); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsSubscribableServer::StartPopulatingWithUri(nsIMsgWindow *aMsgWindow, bool aForceToServer, const char *uri) +{ + mStopped = false; + return NS_OK; +} + +NS_IMETHODIMP +nsSubscribableServer::StartPopulating(nsIMsgWindow *aMsgWindow, bool aForceToServer, bool aGetOnlyNew /*ignored*/) +{ + nsresult rv = NS_OK; + + mStopped = false; + + rv = FreeSubtree(mTreeRoot); + mTreeRoot = nullptr; + NS_ENSURE_SUCCESS(rv,rv); + return NS_OK; +} + +NS_IMETHODIMP +nsSubscribableServer::StopPopulating(nsIMsgWindow *aMsgWindow) +{ + mStopped = true; + return NS_OK; +} + + +NS_IMETHODIMP +nsSubscribableServer::UpdateSubscribed() +{ + NS_ASSERTION(false,"override this."); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsSubscribableServer::Subscribe(const char16_t *aName) +{ + NS_ASSERTION(false,"override this."); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsSubscribableServer::Unsubscribe(const char16_t *aName) +{ + NS_ASSERTION(false,"override this."); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsSubscribableServer::SetShowFullName(bool showFullName) +{ + mShowFullName = showFullName; + return NS_OK; +} + +nsresult +nsSubscribableServer::FreeSubtree(SubscribeTreeNode *node) +{ + nsresult rv = NS_OK; + + if (node) { + // recursively free the children + if (node->firstChild) { + // will free node->firstChild + rv = FreeSubtree(node->firstChild); + NS_ENSURE_SUCCESS(rv,rv); + node->firstChild = nullptr; + } + + // recursively free the siblings + if (node->nextSibling) { + // will free node->nextSibling + rv = FreeSubtree(node->nextSibling); + NS_ENSURE_SUCCESS(rv,rv); + node->nextSibling = nullptr; + } + +#ifdef HAVE_SUBSCRIBE_DESCRIPTION + NS_ASSERTION(node->description == nullptr, "you need to free the description"); +#endif + NS_Free(node->name); +#if 0 + node->name = nullptr; + node->parent = nullptr; + node->lastChild = nullptr; + node->cachedChild = nullptr; +#endif + + PR_Free(node); + } + + return NS_OK; +} + +nsresult +nsSubscribableServer::CreateNode(SubscribeTreeNode *parent, const char *name, SubscribeTreeNode **result) +{ + NS_ASSERTION(result && name, "result or name is null"); + if (!result || !name) return NS_ERROR_NULL_POINTER; + + *result = (SubscribeTreeNode *) PR_Malloc(sizeof(SubscribeTreeNode)); + if (!*result) return NS_ERROR_OUT_OF_MEMORY; + + (*result)->name = strdup(name); + if (!(*result)->name) return NS_ERROR_OUT_OF_MEMORY; + + (*result)->parent = parent; + (*result)->prevSibling = nullptr; + (*result)->nextSibling = nullptr; + (*result)->firstChild = nullptr; + (*result)->lastChild = nullptr; + (*result)->isSubscribed = false; + (*result)->isSubscribable = false; +#ifdef HAVE_SUBSCRIBE_DESCRIPTION + (*result)->description = nullptr; +#endif +#ifdef HAVE_SUBSCRIBE_MESSAGES + (*result)->messages = 0; +#endif + (*result)->cachedChild = nullptr; + + if (parent) { + parent->cachedChild = *result; + } + + return NS_OK; +} + +nsresult +nsSubscribableServer::AddChildNode(SubscribeTreeNode *parent, const char *name, SubscribeTreeNode **child) +{ + nsresult rv = NS_OK; + NS_ASSERTION(parent && child && name, "parent, child or name is null"); + if (!parent || !child || !name) return NS_ERROR_NULL_POINTER; + + if (!parent->firstChild) { + // CreateNode will set the parent->cachedChild + rv = CreateNode(parent, name, child); + NS_ENSURE_SUCCESS(rv,rv); + + parent->firstChild = *child; + parent->lastChild = *child; + + rv = NotifyAssert(parent, kNC_Child, *child); + NS_ENSURE_SUCCESS(rv,rv); + + return NS_OK; + } + else { + if (parent->cachedChild) { + if (strcmp(parent->cachedChild->name,name) == 0) { + *child = parent->cachedChild; + return NS_OK; + } + } + + SubscribeTreeNode *current = parent->firstChild; + + /* + * insert in reverse alphabetical order + * this will reduce the # of strcmps + * since this is faster assuming: + * 1) the hostinfo.dat feeds us the groups in alphabetical order + * since we control the hostinfo.dat file, we can guarantee this. + * 2) the server gives us the groups in alphabetical order + * we can't guarantee this, but it seems to be a common thing + * + * because we have firstChild, lastChild, nextSibling, prevSibling + * we can efficiently reverse the order when dumping to hostinfo.dat + * or to GetTargets() + */ + int32_t compare = strcmp(current->name, name); + + while (current && (compare != 0)) { + if (compare < 0) { + // CreateNode will set the parent->cachedChild + rv = CreateNode(parent, name, child); + NS_ENSURE_SUCCESS(rv,rv); + + (*child)->nextSibling = current; + (*child)->prevSibling = current->prevSibling; + current->prevSibling = (*child); + if (!(*child)->prevSibling) { + parent->firstChild = (*child); + } + else { + (*child)->prevSibling->nextSibling = (*child); + } + + rv = NotifyAssert(parent, kNC_Child, *child); + NS_ENSURE_SUCCESS(rv,rv); + return NS_OK; + } + current = current->nextSibling; + if (current) { + NS_ASSERTION(current->name, "no name!"); + compare = strcmp(current->name,name); + } + else { + compare = -1; // anything but 0, since that would be a match + } + } + + if (compare == 0) { + // already exists; + *child = current; + + // set the cachedChild + parent->cachedChild = *child; + return NS_OK; + } + + // CreateNode will set the parent->cachedChild + rv = CreateNode(parent, name, child); + NS_ENSURE_SUCCESS(rv,rv); + + (*child)->prevSibling = parent->lastChild; + (*child)->nextSibling = nullptr; + parent->lastChild->nextSibling = *child; + parent->lastChild = *child; + + rv = NotifyAssert(parent, kNC_Child, *child); + NS_ENSURE_SUCCESS(rv,rv); + return NS_OK; + } + return NS_OK; +} + +nsresult +nsSubscribableServer::FindAndCreateNode(const nsACString &aPath, + SubscribeTreeNode **aResult) +{ + nsresult rv = NS_OK; + NS_ASSERTION(aResult, "no result"); + if (!aResult) return NS_ERROR_NULL_POINTER; + + if (!mTreeRoot) { + // the root has no parent, and its name is server uri + rv = CreateNode(nullptr, mIncomingServerUri.get(), &mTreeRoot); + NS_ENSURE_SUCCESS(rv,rv); + } + + if (aPath.IsEmpty()) { + *aResult = mTreeRoot; + return NS_OK; + } + + char *token = nullptr; + nsCString pathStr(aPath); + char *rest = pathStr.BeginWriting(); + + // todo do this only once + char delimstr[2]; + delimstr[0] = mDelimiter; + delimstr[1] = '\0'; + + *aResult = nullptr; + + SubscribeTreeNode *parent = mTreeRoot; + SubscribeTreeNode *child = nullptr; + + token = NS_strtok(delimstr, &rest); + // special case paths that start with the hierarchy delimiter. + // We want to include that delimiter in the first token name. + if (token && pathStr[0] == mDelimiter) + --token; + while (token && *token) { + rv = AddChildNode(parent, token, &child); + if (NS_FAILED(rv)) + return rv; + token = NS_strtok(delimstr, &rest); + parent = child; + } + + // the last child we add is the result + *aResult = child; + return rv; +} + +NS_IMETHODIMP +nsSubscribableServer::HasChildren(const nsACString &aPath, bool *aHasChildren) +{ + nsresult rv = NS_OK; + NS_ASSERTION(aHasChildren, "no hasChildren"); + if (!aHasChildren) return NS_ERROR_NULL_POINTER; + + *aHasChildren = false; + + SubscribeTreeNode *node = nullptr; + rv = FindAndCreateNode(aPath, &node); + NS_ENSURE_SUCCESS(rv,rv); + + NS_ASSERTION(node,"didn't find the node"); + if (!node) return NS_ERROR_FAILURE; + + *aHasChildren = (node->firstChild != nullptr); + return NS_OK; +} + + +NS_IMETHODIMP +nsSubscribableServer::IsSubscribed(const nsACString &aPath, + bool *aIsSubscribed) +{ + NS_ENSURE_ARG_POINTER(aIsSubscribed); + + *aIsSubscribed = false; + + SubscribeTreeNode *node = nullptr; + nsresult rv = FindAndCreateNode(aPath, &node); + NS_ENSURE_SUCCESS(rv,rv); + + NS_ASSERTION(node,"didn't find the node"); + if (!node) return NS_ERROR_FAILURE; + + *aIsSubscribed = node->isSubscribed; + return NS_OK; +} + +NS_IMETHODIMP +nsSubscribableServer::IsSubscribable(const nsACString &aPath, + bool *aIsSubscribable) +{ + NS_ENSURE_ARG_POINTER(aIsSubscribable); + + *aIsSubscribable = false; + + SubscribeTreeNode *node = nullptr; + nsresult rv = FindAndCreateNode(aPath, &node); + NS_ENSURE_SUCCESS(rv,rv); + + NS_ASSERTION(node,"didn't find the node"); + if (!node) return NS_ERROR_FAILURE; + + *aIsSubscribable = node->isSubscribable; + return NS_OK; +} + +NS_IMETHODIMP +nsSubscribableServer::GetLeafName(const nsACString &aPath, nsAString &aLeafName) +{ + SubscribeTreeNode *node = nullptr; + nsresult rv = FindAndCreateNode(aPath, &node); + NS_ENSURE_SUCCESS(rv,rv); + + NS_ASSERTION(node,"didn't find the node"); + if (!node) return NS_ERROR_FAILURE; + + // XXX TODO FIXME + // I'm assuming that mShowFullName is true for NNTP, false for IMAP. + // for imap, the node name is in modified UTF7 + // for news, the path is escaped UTF8 + // + // when we switch to using the tree, this hack will go away. + if (mShowFullName) { + return NS_MsgDecodeUnescapeURLPath(aPath, aLeafName); + } + + return CopyMUTF7toUTF16(nsDependentCString(node->name), aLeafName); +} + +NS_IMETHODIMP +nsSubscribableServer::GetFirstChildURI(const nsACString &aPath, + nsACString &aResult) +{ + aResult.Truncate(); + + SubscribeTreeNode *node = nullptr; + nsresult rv = FindAndCreateNode(aPath, &node); + NS_ENSURE_SUCCESS(rv,rv); + + NS_ASSERTION(node,"didn't find the node"); + if (!node) return NS_ERROR_FAILURE; + + // no children + if (!node->firstChild) return NS_ERROR_FAILURE; + + BuildURIFromNode(node->firstChild, aResult); + + return NS_OK; +} + +NS_IMETHODIMP +nsSubscribableServer::GetChildren(const nsACString &aPath, + nsISimpleEnumerator **aResult) +{ + SubscribeTreeNode *node = nullptr; + nsresult rv = FindAndCreateNode(aPath, &node); + NS_ENSURE_SUCCESS(rv, rv); + + NS_ASSERTION(node,"didn't find the node"); + if (!node) + return NS_ERROR_FAILURE; + + nsAutoCString uriPrefix; + NS_ASSERTION(mTreeRoot, "no tree root!"); + if (!mTreeRoot) + return NS_ERROR_UNEXPECTED; + + uriPrefix = mTreeRoot->name; // the root's name is the server uri + uriPrefix += "/"; + if (!aPath.IsEmpty()) { + uriPrefix += aPath; + uriPrefix += mDelimiter; + } + + // we inserted them in reverse alphabetical order. + // so pull them out in reverse to get the right order + // in the subscribe dialog + SubscribeTreeNode *current = node->lastChild; + // return failure if there are no children. + if (!current) + return NS_ERROR_FAILURE; + + nsCOMArray result; + + while (current) { + nsAutoCString uri; + uri = uriPrefix; + NS_ASSERTION(current->name, "no name"); + if (!current->name) + return NS_ERROR_FAILURE; + + uri += current->name; + + nsCOMPtr res; + rv = EnsureRDFService(); + NS_ENSURE_SUCCESS(rv,rv); + + // todo, is this creating nsMsgFolders? + mRDFService->GetResource(uri, getter_AddRefs(res)); + result.AppendObject(res); + + current = current->prevSibling; + } + + return NS_NewArrayEnumerator(aResult, result); +} + +NS_IMETHODIMP +nsSubscribableServer::CommitSubscribeChanges() +{ + NS_ASSERTION(false,"override this."); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsSubscribableServer::SetSearchValue(const nsAString &aSearchValue) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsSubscribableServer::GetSupportsSubscribeSearch(bool *retVal) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} -- cgit v1.2.3