Back to index

lightning-sunbird  0.9+nobinonly
nsSubscribableServer.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Seth Spitzer <sspitzer@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsSubscribableServer.h"
00040 
00041 #include "nsCOMPtr.h"
00042 
00043 #include "nsCRT.h"
00044 #include "nsXPIDLString.h"
00045 #include "nsReadableUtils.h"
00046 #include "prmem.h"
00047 
00048 #include "rdf.h"
00049 #include "nsRDFCID.h"
00050 #include "nsIRDFService.h"
00051 #include "nsIRDFDataSource.h"
00052 #include "nsIRDFResource.h"
00053 #include "nsIRDFLiteral.h"
00054 #include "nsIServiceManager.h"
00055 
00056 #include "nsMsgI18N.h"
00057 #include "nsMsgUtils.h"
00058 
00059 static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
00060 
00061 MOZ_DECL_CTOR_COUNTER(nsSubscribableServer)
00062 
00063 nsSubscribableServer::nsSubscribableServer(void)
00064 {
00065     mDelimiter = '.';
00066     mShowFullName = PR_TRUE;
00067     mTreeRoot = nsnull;
00068     mStopped = PR_FALSE;
00069 }
00070 
00071 nsresult
00072 nsSubscribableServer::Init()
00073 {
00074     nsresult rv;
00075 
00076     rv = EnsureRDFService();
00077     NS_ENSURE_SUCCESS(rv,rv);
00078 
00079     rv = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "child"),
00080                                   getter_AddRefs(kNC_Child));
00081     NS_ENSURE_SUCCESS(rv,rv);
00082 
00083     rv = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Subscribed"),
00084                                   getter_AddRefs(kNC_Subscribed));
00085     NS_ENSURE_SUCCESS(rv,rv);
00086 
00087     rv = mRDFService->GetLiteral(NS_LITERAL_STRING("true").get(),getter_AddRefs(kTrueLiteral));
00088     NS_ENSURE_SUCCESS(rv,rv);
00089 
00090     rv = mRDFService->GetLiteral(NS_LITERAL_STRING("false").get(),getter_AddRefs(kFalseLiteral));
00091     NS_ENSURE_SUCCESS(rv,rv);
00092     return NS_OK;
00093 }
00094 
00095 nsSubscribableServer::~nsSubscribableServer(void)
00096 {
00097     nsresult rv = NS_OK;
00098 #ifdef DEBUG_seth
00099     printf("free subscribe tree\n");
00100 #endif
00101     rv = FreeSubtree(mTreeRoot);
00102     NS_ASSERTION(NS_SUCCEEDED(rv),"failed to free tree");
00103 }
00104 
00105 NS_IMPL_THREADSAFE_ISUPPORTS1(nsSubscribableServer, nsISubscribableServer)
00106 
00107 NS_IMETHODIMP
00108 nsSubscribableServer::SetIncomingServer(nsIMsgIncomingServer *aServer)
00109 {
00110   mIncomingServer = aServer;
00111   return NS_OK;
00112 }
00113 
00114 NS_IMETHODIMP
00115 nsSubscribableServer::GetDelimiter(char *aDelimiter)
00116 {
00117   if (!aDelimiter) return NS_ERROR_NULL_POINTER;
00118   *aDelimiter = mDelimiter;
00119   return NS_OK;
00120 }
00121 
00122 NS_IMETHODIMP
00123 nsSubscribableServer::SetDelimiter(char aDelimiter)
00124 {
00125   mDelimiter = aDelimiter;
00126   return NS_OK;
00127 }
00128 
00129 NS_IMETHODIMP
00130 nsSubscribableServer::SetAsSubscribed(const nsACString &path)
00131 {
00132     nsresult rv = NS_OK;
00133 
00134     SubscribeTreeNode *node = nsnull;
00135     rv = FindAndCreateNode(path, &node);
00136     NS_ENSURE_SUCCESS(rv,rv);
00137 
00138     NS_ASSERTION(node,"didn't find the node");
00139     if (!node) return NS_ERROR_FAILURE;
00140 
00141     node->isSubscribable = PR_TRUE;
00142     node->isSubscribed = PR_TRUE;
00143 
00144     rv = NotifyChange(node, kNC_Subscribed, node->isSubscribed);
00145     NS_ENSURE_SUCCESS(rv,rv);
00146 
00147     return rv;
00148 }
00149 
00150 NS_IMETHODIMP
00151 nsSubscribableServer::AddTo(const nsACString& aName, PRBool aAddAsSubscribed,
00152                             PRBool aSubscribable, PRBool aChangeIfExists)
00153 {
00154     nsresult rv = NS_OK;
00155     
00156     if (mStopped) {
00157 #ifdef DEBUG_seth
00158         printf("stopped!\n");
00159 #endif
00160         return NS_ERROR_FAILURE;
00161     }
00162 
00163     SubscribeTreeNode *node = nsnull;
00164 
00165     // todo, shouldn't we pass in aAddAsSubscribed, for the 
00166     // default value if we create it?
00167     rv = FindAndCreateNode(aName, &node);
00168     NS_ENSURE_SUCCESS(rv,rv);
00169 
00170     NS_ASSERTION(node,"didn't find the node");
00171     if (!node) return NS_ERROR_FAILURE;
00172 
00173     if (aChangeIfExists) {
00174         node->isSubscribed = aAddAsSubscribed;
00175         rv = NotifyChange(node, kNC_Subscribed, node->isSubscribed);
00176         NS_ENSURE_SUCCESS(rv,rv);
00177     }
00178 
00179     node->isSubscribable = aSubscribable;
00180     return rv;
00181 }
00182 
00183 NS_IMETHODIMP
00184 nsSubscribableServer::SetState(const nsACString &aPath, PRBool aState,
00185                                PRBool *aStateChanged)
00186 {
00187     nsresult rv = NS_OK;
00188     NS_ASSERTION(!aPath.IsEmpty() && aStateChanged, "no path or stateChanged");
00189     if (aPath.IsEmpty() || !aStateChanged) return NS_ERROR_NULL_POINTER;
00190 
00191     NS_ASSERTION(IsUTF8(aPath), "aPath is not in UTF-8");
00192 
00193     *aStateChanged = PR_FALSE;
00194 
00195     SubscribeTreeNode *node = nsnull;
00196     rv = FindAndCreateNode(aPath, &node);
00197     NS_ENSURE_SUCCESS(rv,rv);
00198 
00199     NS_ASSERTION(node,"didn't find the node");
00200     if (!node) return NS_ERROR_FAILURE;
00201 
00202     NS_ASSERTION(node->isSubscribable, "fix this");
00203     if (!node->isSubscribable) {
00204         return NS_OK;
00205     }
00206 
00207     if (node->isSubscribed == aState) {
00208         return NS_OK;
00209     }
00210     else {
00211         node->isSubscribed = aState;
00212         *aStateChanged = PR_TRUE;
00213         rv = NotifyChange(node, kNC_Subscribed, node->isSubscribed);
00214         NS_ENSURE_SUCCESS(rv,rv);
00215     }
00216 
00217     return rv;
00218 }
00219 
00220 void
00221 nsSubscribableServer::BuildURIFromNode(SubscribeTreeNode *node, nsACString &uri)
00222 {
00223     if (node->parent) {
00224         BuildURIFromNode(node->parent, uri);
00225         if (node->parent == mTreeRoot) {
00226             uri += "/";
00227         }
00228         else {
00229             uri += mDelimiter;
00230         }
00231     }
00232 
00233     uri += node->name;
00234     return;
00235 }
00236 
00237 nsresult
00238 nsSubscribableServer::NotifyAssert(SubscribeTreeNode *subjectNode, nsIRDFResource *property, SubscribeTreeNode *objectNode)
00239 {
00240     nsresult rv;
00241 
00242     PRBool hasObservers = PR_TRUE;
00243     rv = EnsureSubscribeDS();
00244     NS_ENSURE_SUCCESS(rv,rv);
00245     rv = mSubscribeDS->GetHasObservers(&hasObservers);
00246     NS_ENSURE_SUCCESS(rv,rv);
00247     // no need to do all this work, there are no observers
00248     if (!hasObservers) {
00249         return NS_OK;
00250     }
00251     
00252     nsCAutoString subjectUri;
00253     BuildURIFromNode(subjectNode, subjectUri);
00254 
00255     // we could optimize this, since we know that objectUri == subjectUri + mDelimiter + object->name
00256     // is it worth it?
00257     nsCAutoString objectUri;
00258     BuildURIFromNode(objectNode, objectUri);
00259 
00260     nsCOMPtr <nsIRDFResource> subject;
00261     nsCOMPtr <nsIRDFResource> object;
00262 
00263     rv = EnsureRDFService();
00264     NS_ENSURE_SUCCESS(rv,rv);
00265 
00266     rv = mRDFService->GetResource(subjectUri, getter_AddRefs(subject));
00267     NS_ENSURE_SUCCESS(rv,rv);
00268     rv = mRDFService->GetResource(objectUri, getter_AddRefs(object));
00269     NS_ENSURE_SUCCESS(rv,rv);
00270 
00271     rv = Notify(subject, property, object, PR_TRUE, PR_FALSE);
00272     NS_ENSURE_SUCCESS(rv,rv);
00273     return NS_OK;
00274 }
00275 
00276 nsresult
00277 nsSubscribableServer::EnsureRDFService()
00278 {
00279     nsresult rv;
00280 
00281     if (!mRDFService) {
00282         mRDFService = do_GetService(kRDFServiceCID, &rv);
00283         NS_ASSERTION(NS_SUCCEEDED(rv) && mRDFService, "failed to get rdf service");
00284         NS_ENSURE_SUCCESS(rv,rv);
00285         if (!mRDFService) return NS_ERROR_FAILURE;
00286     }
00287     return NS_OK;
00288 }
00289 
00290 nsresult
00291 nsSubscribableServer::NotifyChange(SubscribeTreeNode *subjectNode, nsIRDFResource *property, PRBool value)
00292 {
00293     nsresult rv;
00294     nsCOMPtr <nsIRDFResource> subject;
00295 
00296     PRBool hasObservers = PR_TRUE;
00297     rv = EnsureSubscribeDS();
00298     NS_ENSURE_SUCCESS(rv,rv);
00299     rv = mSubscribeDS->GetHasObservers(&hasObservers);
00300     NS_ENSURE_SUCCESS(rv,rv);
00301     // no need to do all this work, there are no observers
00302     if (!hasObservers) {
00303         return NS_OK;
00304     }
00305 
00306     nsCAutoString subjectUri;
00307     BuildURIFromNode(subjectNode, subjectUri);
00308 
00309     rv = EnsureRDFService();
00310     NS_ENSURE_SUCCESS(rv,rv);
00311 
00312     rv = mRDFService->GetResource(subjectUri, getter_AddRefs(subject));
00313     NS_ENSURE_SUCCESS(rv,rv);
00314 
00315     if (value) {
00316         rv = Notify(subject,property,kTrueLiteral,PR_FALSE,PR_TRUE);
00317     }
00318     else {
00319         rv = Notify(subject,property,kFalseLiteral,PR_FALSE,PR_TRUE);
00320     }
00321 
00322     NS_ENSURE_SUCCESS(rv,rv);
00323     return NS_OK;
00324 }
00325 
00326 nsresult
00327 nsSubscribableServer::EnsureSubscribeDS()
00328 {
00329     nsresult rv = NS_OK;
00330 
00331     if (!mSubscribeDS) {
00332         nsCOMPtr<nsIRDFDataSource> ds;
00333 
00334         rv = EnsureRDFService();
00335         NS_ENSURE_SUCCESS(rv,rv);
00336 
00337         rv = mRDFService->GetDataSource("rdf:subscribe", getter_AddRefs(ds));
00338         NS_ENSURE_SUCCESS(rv,rv);
00339         if (!ds) return NS_ERROR_FAILURE;
00340 
00341         mSubscribeDS = do_QueryInterface(ds, &rv);
00342         NS_ENSURE_SUCCESS(rv,rv);
00343         if (!mSubscribeDS) return NS_ERROR_FAILURE;
00344     }
00345     return NS_OK;
00346 }
00347 
00348 nsresult
00349 nsSubscribableServer::Notify(nsIRDFResource *subject, nsIRDFResource *property, nsIRDFNode *object, PRBool isAssert, PRBool isChange)
00350 {
00351     nsresult rv = NS_OK;
00352 
00353     rv = EnsureSubscribeDS();
00354     NS_ENSURE_SUCCESS(rv,rv);
00355 
00356     rv = mSubscribeDS->NotifyObservers(subject, property, object, isAssert, isChange);
00357     NS_ENSURE_SUCCESS(rv,rv);
00358     return rv;
00359 }
00360 
00361 NS_IMETHODIMP
00362 nsSubscribableServer::SetSubscribeListener(nsISubscribeListener *aListener)
00363 {
00364        mSubscribeListener = aListener;
00365        return NS_OK;
00366 }
00367 
00368 NS_IMETHODIMP
00369 nsSubscribableServer::GetSubscribeListener(nsISubscribeListener **aListener)
00370 {
00371        if (!aListener) return NS_ERROR_NULL_POINTER;
00372        if (mSubscribeListener) {
00373                      *aListener = mSubscribeListener;
00374                      NS_ADDREF(*aListener);
00375        }
00376        return NS_OK;
00377 }
00378 
00379 NS_IMETHODIMP
00380 nsSubscribableServer::SubscribeCleanup()
00381 {
00382        NS_ASSERTION(PR_FALSE,"override this.");
00383        return NS_ERROR_FAILURE;
00384 }
00385 
00386 NS_IMETHODIMP
00387 nsSubscribableServer::StartPopulatingWithUri(nsIMsgWindow *aMsgWindow, PRBool aForceToServer, const char *uri)
00388 {
00389     mStopped = PR_FALSE;
00390     return NS_OK;
00391 }
00392 
00393 NS_IMETHODIMP
00394 nsSubscribableServer::StartPopulating(nsIMsgWindow *aMsgWindow, PRBool aForceToServer)
00395 {
00396     nsresult rv = NS_OK;
00397 
00398     mStopped = PR_FALSE;
00399 
00400     rv = FreeSubtree(mTreeRoot);
00401     mTreeRoot = nsnull;
00402     NS_ENSURE_SUCCESS(rv,rv);
00403     return NS_OK;
00404 }
00405 
00406 NS_IMETHODIMP
00407 nsSubscribableServer::StopPopulating(nsIMsgWindow *aMsgWindow)
00408 {
00409     mStopped = PR_TRUE;
00410     return NS_OK;
00411 }
00412 
00413 
00414 NS_IMETHODIMP
00415 nsSubscribableServer::UpdateSubscribed()
00416 {
00417        NS_ASSERTION(PR_FALSE,"override this.");
00418        return NS_ERROR_FAILURE;
00419 }
00420 
00421 NS_IMETHODIMP
00422 nsSubscribableServer::Subscribe(const PRUnichar *aName)
00423 {
00424        NS_ASSERTION(PR_FALSE,"override this.");
00425        return NS_ERROR_FAILURE;
00426 }
00427 
00428 NS_IMETHODIMP
00429 nsSubscribableServer::Unsubscribe(const PRUnichar *aName)
00430 {
00431        NS_ASSERTION(PR_FALSE,"override this.");
00432        return NS_ERROR_FAILURE;
00433 }
00434 
00435 NS_IMETHODIMP
00436 nsSubscribableServer::SetShowFullName(PRBool showFullName)
00437 {
00438        mShowFullName = showFullName;
00439        return NS_OK;
00440 }
00441      
00442 nsresult 
00443 nsSubscribableServer::FreeSubtree(SubscribeTreeNode *node)
00444 {
00445     nsresult rv = NS_OK;
00446 
00447     if (node) {
00448         // recursively free the children
00449         if (node->firstChild) {
00450             // will free node->firstChild      
00451             rv = FreeSubtree(node->firstChild);
00452             NS_ENSURE_SUCCESS(rv,rv);
00453             node->firstChild = nsnull;
00454         }
00455 
00456         // recursively free the siblings
00457         if (node->nextSibling) {
00458             // will free node->nextSibling
00459             rv = FreeSubtree(node->nextSibling);
00460             NS_ENSURE_SUCCESS(rv,rv);
00461             node->nextSibling = nsnull;
00462         }
00463 
00464 #ifdef HAVE_SUBSCRIBE_DESCRIPTION
00465         NS_ASSERTION(node->description == nsnull, "you need to free the description");
00466 #endif
00467         CRTFREEIF(node->name);
00468 #if 0 
00469         node->name = nsnull;
00470         node->parent = nsnull;
00471         node->lastChild = nsnull;
00472         node->cachedChild = nsnull;
00473 #endif
00474 
00475         PR_Free(node);  
00476     }
00477 
00478     return NS_OK;
00479 }
00480 
00481 nsresult 
00482 nsSubscribableServer::CreateNode(SubscribeTreeNode *parent, const char *name, SubscribeTreeNode **result)
00483 {
00484     NS_ASSERTION(result && name, "result or name is null");
00485     if (!result || !name) return NS_ERROR_NULL_POINTER;
00486 
00487     *result = (SubscribeTreeNode *) PR_Malloc(sizeof(SubscribeTreeNode));
00488     if (!*result) return NS_ERROR_OUT_OF_MEMORY;
00489 
00490     (*result)->name = nsCRT::strdup(name);
00491     if (!(*result)->name) return NS_ERROR_OUT_OF_MEMORY;
00492 
00493     (*result)->parent = parent;
00494     (*result)->prevSibling = nsnull;
00495     (*result)->nextSibling = nsnull;
00496     (*result)->firstChild = nsnull;
00497     (*result)->lastChild = nsnull;
00498     (*result)->isSubscribed = PR_FALSE;
00499     (*result)->isSubscribable = PR_FALSE;
00500 #ifdef HAVE_SUBSCRIBE_DESCRIPTION
00501     (*result)->description = nsnull;
00502 #endif
00503 #ifdef HAVE_SUBSCRIBE_MESSAGES
00504     (*result)->messages = 0;
00505 #endif
00506     (*result)->cachedChild = nsnull;
00507 
00508     if (parent) {
00509         parent->cachedChild = *result;
00510     }
00511 
00512     return NS_OK;
00513 }
00514 
00515 nsresult
00516 nsSubscribableServer::AddChildNode(SubscribeTreeNode *parent, const char *name, SubscribeTreeNode **child)
00517 {
00518     nsresult rv = NS_OK;
00519     NS_ASSERTION(parent && child && name, "parent, child or name is null");
00520     if (!parent || !child || !name) return NS_ERROR_NULL_POINTER;
00521 
00522     if (!parent->firstChild) {
00523         // CreateNode will set the parent->cachedChild
00524         rv = CreateNode(parent, name, child);
00525         NS_ENSURE_SUCCESS(rv,rv);
00526 
00527         parent->firstChild = *child;
00528         parent->lastChild = *child;
00529 
00530         rv = NotifyAssert(parent, kNC_Child, *child);
00531         NS_ENSURE_SUCCESS(rv,rv);   
00532 
00533         return NS_OK;
00534     }
00535     else {
00536         if (parent->cachedChild) {
00537             if (nsCRT::strcmp(parent->cachedChild->name,name) == 0) {
00538                 *child = parent->cachedChild;
00539                 return NS_OK;
00540             }
00541         }
00542 
00543         SubscribeTreeNode *current = parent->firstChild;
00544 
00545         /*
00546          * insert in reverse alphabetical order
00547          * this will reduce the # of strcmps
00548          * since this is faster assuming:
00549          *  1) the hostinfo.dat feeds us the groups in alphabetical order
00550          *     since we control the hostinfo.dat file, we can guarantee this.
00551          *  2) the server gives us the groups in alphabetical order
00552          *     we can't guarantee this, but it seems to be a common thing
00553          *
00554          * because we have firstChild, lastChild, nextSibling, prevSibling
00555          * we can efficiently reverse the order when dumping to hostinfo.dat
00556          * or to GetTargets()
00557          */
00558         PRInt32 compare = nsCRT::strcmp(current->name, name);
00559 
00560         while (current && (compare != 0)) {
00561             if (compare < 0) {
00562                 // CreateNode will set the parent->cachedChild
00563                 rv = CreateNode(parent, name, child);
00564                 NS_ENSURE_SUCCESS(rv,rv);
00565 
00566                 (*child)->nextSibling = current;
00567                 (*child)->prevSibling = current->prevSibling;
00568                 current->prevSibling = (*child);
00569                 if (!(*child)->prevSibling) {
00570                     parent->firstChild = (*child);
00571                 }
00572                 else {
00573                     (*child)->prevSibling->nextSibling = (*child);
00574                 }
00575 
00576                 rv = NotifyAssert(parent, kNC_Child, *child);
00577                 NS_ENSURE_SUCCESS(rv,rv);
00578                 return NS_OK;
00579             }
00580             current = current->nextSibling;
00581             if (current) {
00582                 NS_ASSERTION(current->name, "no name!");
00583                 compare = nsCRT::strcmp(current->name,name);
00584             }
00585             else {
00586                 compare = -1; // anything but 0, since that would be a match
00587             }
00588         }
00589 
00590         if (compare == 0) {
00591             // already exists;
00592             *child = current;
00593 
00594             // set the cachedChild
00595             parent->cachedChild = *child;
00596             return NS_OK;
00597         }
00598 
00599         // CreateNode will set the parent->cachedChild
00600         rv = CreateNode(parent, name, child);
00601         NS_ENSURE_SUCCESS(rv,rv);
00602 
00603         (*child)->prevSibling = parent->lastChild;
00604         (*child)->nextSibling = nsnull;
00605         parent->lastChild->nextSibling = *child;
00606         parent->lastChild = *child;
00607 
00608         rv = NotifyAssert(parent, kNC_Child, *child);
00609         NS_ENSURE_SUCCESS(rv,rv);
00610         return NS_OK;
00611     }
00612     return NS_OK;
00613 }
00614 
00615 nsresult
00616 nsSubscribableServer::FindAndCreateNode(const nsACString &aPath,
00617                                         SubscribeTreeNode **aResult)
00618 {
00619     nsresult rv = NS_OK;
00620     NS_ASSERTION(aResult, "no result");
00621     if (!aResult) return NS_ERROR_NULL_POINTER;
00622 
00623     if (!mTreeRoot) {
00624         nsXPIDLCString serverUri;
00625         rv = mIncomingServer->GetServerURI(getter_Copies(serverUri));
00626         NS_ENSURE_SUCCESS(rv,rv);
00627         // the root has no parent, and its name is server uri
00628         rv = CreateNode(nsnull, (const char *)serverUri, &mTreeRoot);
00629         NS_ENSURE_SUCCESS(rv,rv);
00630     }
00631 
00632     if (aPath.IsEmpty()) {
00633         *aResult = mTreeRoot;
00634         return NS_OK;
00635     }
00636 
00637     char *pathStr = nsCRT::strdup(PromiseFlatCString(aPath).get());
00638     char *token = nsnull;
00639     char *rest = pathStr;
00640     
00641     // todo do this only once
00642     char delimstr[2];
00643     delimstr[0] = mDelimiter;
00644     delimstr[1] = '\0';
00645     
00646     *aResult = nsnull;
00647 
00648     SubscribeTreeNode *parent = mTreeRoot;
00649     SubscribeTreeNode *child = nsnull;
00650 
00651     token = nsCRT::strtok(rest, delimstr, &rest);
00652     while (token && *token) {
00653         rv = AddChildNode(parent, token, &child);
00654         if (NS_FAILED(rv)) {
00655             CRTFREEIF(pathStr);
00656             return rv;
00657         }
00658         token = nsCRT::strtok(rest, delimstr, &rest);
00659         parent = child;
00660     }   
00661     CRTFREEIF(pathStr);
00662 
00663     // the last child we add is the result
00664     *aResult = child;
00665     return rv;
00666 }
00667 
00668 NS_IMETHODIMP
00669 nsSubscribableServer::HasChildren(const nsACString &aPath, PRBool *aHasChildren)
00670 {
00671     nsresult rv = NS_OK;
00672     NS_ASSERTION(aHasChildren, "no hasChildren");
00673     if (!aHasChildren) return NS_ERROR_NULL_POINTER;
00674 
00675     *aHasChildren = PR_FALSE;
00676 
00677     SubscribeTreeNode *node = nsnull;
00678     rv = FindAndCreateNode(aPath, &node);
00679     NS_ENSURE_SUCCESS(rv,rv);
00680 
00681     NS_ASSERTION(node,"didn't find the node");
00682     if (!node) return NS_ERROR_FAILURE;
00683  
00684     *aHasChildren = (node->firstChild != nsnull);
00685     return NS_OK;
00686 }
00687 
00688 
00689 NS_IMETHODIMP
00690 nsSubscribableServer::IsSubscribed(const nsACString &aPath,
00691                                    PRBool *aIsSubscribed)
00692 {
00693     NS_ENSURE_ARG_POINTER(aIsSubscribed);
00694 
00695     *aIsSubscribed = PR_FALSE;
00696 
00697     SubscribeTreeNode *node = nsnull;
00698     nsresult rv = FindAndCreateNode(aPath, &node);
00699     NS_ENSURE_SUCCESS(rv,rv);
00700 
00701     NS_ASSERTION(node,"didn't find the node");
00702     if (!node) return NS_ERROR_FAILURE;
00703 
00704     *aIsSubscribed = node->isSubscribed;
00705     return NS_OK;
00706 }
00707 
00708 NS_IMETHODIMP
00709 nsSubscribableServer::IsSubscribable(const nsACString &aPath,
00710                                      PRBool *aIsSubscribable)
00711 {
00712     NS_ENSURE_ARG_POINTER(aIsSubscribable);
00713 
00714     *aIsSubscribable = PR_FALSE;
00715 
00716     SubscribeTreeNode *node = nsnull;
00717     nsresult rv = FindAndCreateNode(aPath, &node);
00718     NS_ENSURE_SUCCESS(rv,rv);
00719 
00720     NS_ASSERTION(node,"didn't find the node");
00721     if (!node) return NS_ERROR_FAILURE;
00722 
00723     *aIsSubscribable = node->isSubscribable;
00724     return NS_OK;
00725 }
00726 
00727 NS_IMETHODIMP
00728 nsSubscribableServer::GetLeafName(const nsACString &aPath, nsAString &aLeafName)
00729 {
00730     SubscribeTreeNode *node = nsnull;
00731     nsresult rv = FindAndCreateNode(aPath, &node);
00732     NS_ENSURE_SUCCESS(rv,rv);
00733 
00734     NS_ASSERTION(node,"didn't find the node");
00735     if (!node) return NS_ERROR_FAILURE;
00736 
00737     // XXX TODO FIXME
00738     // I'm assuming that mShowFullName is true for NNTP, false for IMAP.
00739     // for imap, the node name is in modified UTF7
00740     // for news, the path is escaped UTF8
00741     //
00742     // when we switch to using the tree, this hack will go away.
00743     if (mShowFullName) {
00744        return NS_MsgDecodeUnescapeURLPath(aPath, aLeafName);
00745     }
00746 
00747     return CopyMUTF7toUTF16(nsDependentCString(node->name), aLeafName);
00748 }
00749 
00750 NS_IMETHODIMP
00751 nsSubscribableServer::GetFirstChildURI(const nsACString &aPath,
00752                                        nsACString &aResult)
00753 {
00754     aResult.Truncate();
00755     
00756     SubscribeTreeNode *node = nsnull;
00757     nsresult rv = FindAndCreateNode(aPath, &node);
00758     NS_ENSURE_SUCCESS(rv,rv);
00759 
00760     NS_ASSERTION(node,"didn't find the node");
00761     if (!node) return NS_ERROR_FAILURE;
00762 
00763     // no children
00764     if (!node->firstChild) return NS_ERROR_FAILURE;
00765     
00766     BuildURIFromNode(node->firstChild, aResult); 
00767 
00768     return NS_OK;
00769 }
00770 
00771 NS_IMETHODIMP
00772 nsSubscribableServer::GetChildren(const nsACString &aPath,
00773                                   nsISupportsArray *array)
00774 {
00775     nsresult rv = NS_OK;
00776     if (!array) return NS_ERROR_NULL_POINTER;
00777 
00778     SubscribeTreeNode *node = nsnull;
00779     rv = FindAndCreateNode(aPath, &node);
00780     NS_ENSURE_SUCCESS(rv,rv);
00781 
00782     NS_ASSERTION(node,"didn't find the node");
00783     if (!node) return NS_ERROR_FAILURE;
00784 
00785     nsCAutoString uriPrefix;
00786     NS_ASSERTION(mTreeRoot, "no tree root!");
00787     if (!mTreeRoot) return NS_ERROR_UNEXPECTED;
00788     uriPrefix = mTreeRoot->name; // the root's name is the server uri
00789     uriPrefix += "/";
00790     if (!aPath.IsEmpty()) {
00791         uriPrefix += aPath;
00792         uriPrefix += mDelimiter;
00793     }
00794 
00795     // we inserted them in reverse alphabetical order.
00796     // so pull them out in reverse to get the right order
00797     // in the subscribe dialog
00798     SubscribeTreeNode *current = node->lastChild;
00799     // return failure if there are no children.
00800     if (!current) return NS_ERROR_FAILURE;  
00801 
00802     while (current) {
00803         nsCAutoString uri;
00804         uri = uriPrefix;
00805         NS_ASSERTION(current->name, "no name");
00806         if (!current->name) return NS_ERROR_FAILURE;
00807         uri += current->name;
00808 
00809         nsCOMPtr <nsIRDFResource> res;
00810         rv = EnsureRDFService();
00811         NS_ENSURE_SUCCESS(rv,rv);
00812 
00813         // todo, is this creating nsMsgFolders?
00814         mRDFService->GetResource(uri, getter_AddRefs(res));
00815         array->AppendElement(res);
00816     
00817         current = current->prevSibling;
00818     }
00819 
00820     return NS_OK;
00821 }
00822 
00823 NS_IMETHODIMP
00824 nsSubscribableServer::CommitSubscribeChanges()
00825 {
00826     NS_ASSERTION(PR_FALSE,"override this.");
00827     return NS_ERROR_FAILURE;
00828 }
00829 
00830 NS_IMETHODIMP
00831 nsSubscribableServer::SetSearchValue(const nsAString &aSearchValue)
00832 {
00833     return NS_ERROR_NOT_IMPLEMENTED;
00834 }
00835 
00836 NS_IMETHODIMP
00837 nsSubscribableServer::GetSupportsSubscribeSearch(PRBool *retVal)
00838 {
00839     return NS_ERROR_NOT_IMPLEMENTED;
00840 }