Back to index

lightning-sunbird  0.9+nobinonly
nsDirectoryDataSource.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *   Seth Spitzer <sspitzer@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsDirectoryDataSource.h"
00041 #include "nsAbBaseCID.h"
00042 #include "nsIAbDirectory.h"
00043 #include "nsIAddrBookSession.h"
00044 #include "nsIAbCard.h"
00045 
00046 #include "rdf.h"
00047 #include "nsIRDFService.h"
00048 #include "nsRDFCID.h"
00049 #include "nsIRDFNode.h"
00050 #include "nsEnumeratorUtils.h"
00051 #include "nsAdapterEnumerator.h"
00052 #include "nsIObserverService.h"
00053 
00054 #include "nsString.h"
00055 #include "nsCOMPtr.h"
00056 #include "nsXPIDLString.h"
00057 
00058 #include "nsMsgRDFUtils.h"
00059 #include "nsILocaleService.h"
00060 #include "nsCollationCID.h"
00061 #include "prmem.h"
00062                 
00063 static NS_DEFINE_CID(kCollationFactoryCID, NS_COLLATIONFACTORY_CID);
00064                                 
00065 #define NC_RDF_DIRNAME                        "http://home.netscape.com/NC-rdf#DirName"
00066 #define NC_RDF_CARDCHILD                  "http://home.netscape.com/NC-rdf#CardChild"
00067 #define NC_RDF_DIRURI                            "http://home.netscape.com/NC-rdf#DirUri"
00068 #define NC_RDF_ISMAILLIST                 "http://home.netscape.com/NC-rdf#IsMailList"
00069 #define NC_RDF_ISREMOTE                          "http://home.netscape.com/NC-rdf#IsRemote"
00070 #define NC_RDF_ISWRITEABLE                "http://home.netscape.com/NC-rdf#IsWriteable"
00071 #define NC_RDF_DIRTREENAMESORT  "http://home.netscape.com/NC-rdf#DirTreeNameSort"
00072 
00073 //Directory Commands
00074 #define NC_RDF_MODIFY                            "http://home.netscape.com/NC-rdf#Modify"
00075 #define NC_RDF_DELETECARDS                "http://home.netscape.com/NC-rdf#DeleteCards"
00076 
00078 
00079 nsAbDirectoryDataSource::nsAbDirectoryDataSource()
00080 {
00081 }
00082 
00083 nsAbDirectoryDataSource::~nsAbDirectoryDataSource()
00084 {
00085 }
00086 
00087 nsresult nsAbDirectoryDataSource::Cleanup()
00088 {
00089   nsresult rv;
00090   nsCOMPtr <nsIRDFService> rdf = do_GetService("@mozilla.org/rdf/rdf-service;1", &rv);
00091   NS_ENSURE_SUCCESS(rv,rv);
00092 
00093   rv = rdf->UnregisterDataSource(this);
00094   NS_ENSURE_SUCCESS(rv,rv);
00095 
00096   nsCOMPtr<nsIAddrBookSession> abSession = do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv);
00097   NS_ENSURE_SUCCESS(rv,rv);
00098 
00099   rv = abSession->RemoveAddressBookListener(this);
00100   NS_ENSURE_SUCCESS(rv,rv);
00101   
00102   return NS_OK;
00103 }
00104 
00105 NS_IMETHODIMP
00106 nsAbDirectoryDataSource::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
00107 {
00108   if (!strcmp(aTopic,"profile-do-change")) {
00109     /* the nsDirPrefs code caches all the directories that it got 
00110      * from the first profiles prefs.js
00111      * When we profile switch, we need to force it to shut down.
00112      * we'll re-load all the directories from the second profiles prefs.js 
00113      * that happens in nsAbBSDirectory::GetChildNodes()
00114      * when we call DIR_GetDirectories()
00115      */
00116     DIR_ShutDown();
00117     return NS_OK;
00118   }
00119   else if (!strcmp(aTopic,NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
00120     DIR_ShutDown();
00121     return Cleanup();
00122   }
00123   return NS_OK;
00124 }
00125 
00126 nsresult
00127 nsAbDirectoryDataSource::Init()
00128 {
00129   nsresult rv;
00130   nsCOMPtr<nsIAddrBookSession> abSession = 
00131     do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv); 
00132   NS_ENSURE_SUCCESS(rv,rv);
00133   
00134   // this listener cares about all events
00135   rv = abSession->AddAddressBookListener(this, nsIAddrBookSession::all);
00136   NS_ENSURE_SUCCESS(rv,rv);
00137 
00138   nsCOMPtr <nsIRDFService> rdf = do_GetService("@mozilla.org/rdf/rdf-service;1", &rv);
00139   NS_ENSURE_SUCCESS(rv,rv);
00140   
00141   rv = rdf->RegisterDataSource(this, PR_FALSE);
00142   NS_ENSURE_SUCCESS(rv,rv);
00143  
00144   rv = rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_CHILD),
00145                         getter_AddRefs(kNC_Child));
00146   NS_ENSURE_SUCCESS(rv,rv);
00147   rv = rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_DIRNAME),
00148                         getter_AddRefs(kNC_DirName));
00149   NS_ENSURE_SUCCESS(rv,rv);
00150   rv = rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_CARDCHILD),
00151                         getter_AddRefs(kNC_CardChild));
00152   NS_ENSURE_SUCCESS(rv,rv);
00153   rv = rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_DIRURI),
00154                         getter_AddRefs(kNC_DirUri));
00155   NS_ENSURE_SUCCESS(rv,rv);
00156   rv = rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_ISMAILLIST),
00157                         getter_AddRefs(kNC_IsMailList));
00158   NS_ENSURE_SUCCESS(rv,rv);
00159   rv = rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_ISREMOTE),
00160                         getter_AddRefs(kNC_IsRemote));
00161   NS_ENSURE_SUCCESS(rv,rv);
00162   rv = rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_ISSECURE),
00163                         getter_AddRefs(kNC_IsSecure));
00164   NS_ENSURE_SUCCESS(rv,rv);
00165   rv = rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_ISWRITEABLE),
00166                         getter_AddRefs(kNC_IsWriteable));
00167   NS_ENSURE_SUCCESS(rv,rv);
00168   rv = rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_DIRTREENAMESORT), getter_AddRefs(kNC_DirTreeNameSort));
00169   NS_ENSURE_SUCCESS(rv,rv);
00170   rv = rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_MODIFY), getter_AddRefs(kNC_Modify));  
00171   NS_ENSURE_SUCCESS(rv,rv);
00172   rv = rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_DELETE),
00173                         getter_AddRefs(kNC_Delete));  
00174   NS_ENSURE_SUCCESS(rv,rv);
00175   rv = rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_DELETECARDS),
00176                         getter_AddRefs(kNC_DeleteCards));
00177   NS_ENSURE_SUCCESS(rv,rv);
00178   rv = createNode(NS_LITERAL_STRING("true").get(), getter_AddRefs(kTrueLiteral));
00179   NS_ENSURE_SUCCESS(rv,rv);
00180   rv = createNode(NS_LITERAL_STRING("false").get(), getter_AddRefs(kFalseLiteral));
00181   NS_ENSURE_SUCCESS(rv,rv);
00182 
00183   nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1", &rv);
00184   NS_ENSURE_SUCCESS(rv,rv);
00185 
00186   // since the observer (this) supports weak ref, 
00187   // and we call AddObserver() with PR_TRUE for ownsWeak
00188   // we don't need to remove our observer from the from the observer service
00189   rv = observerService->AddObserver(this, "profile-do-change", PR_TRUE);
00190   NS_ENSURE_SUCCESS(rv,rv);
00191   rv = observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE);
00192   NS_ENSURE_SUCCESS(rv,rv);
00193   
00194   return NS_OK;
00195 }
00196 
00197 NS_IMPL_ISUPPORTS_INHERITED3(nsAbDirectoryDataSource, nsAbRDFDataSource, nsIAbListener, nsIObserver, nsISupportsWeakReference)
00198 
00199  // nsIRDFDataSource methods
00200 NS_IMETHODIMP nsAbDirectoryDataSource::GetURI(char* *uri)
00201 {
00202   if ((*uri = nsCRT::strdup("rdf:addressdirectory")) == nsnull)
00203     return NS_ERROR_OUT_OF_MEMORY;
00204   else
00205     return NS_OK;
00206 }
00207 
00208 NS_IMETHODIMP nsAbDirectoryDataSource::GetTarget(nsIRDFResource* source,
00209                                                nsIRDFResource* property,
00210                                                PRBool tv,
00211                                                nsIRDFNode** target)
00212 {
00213   nsresult rv = NS_RDF_NO_VALUE;
00214   // we only have positive assertions in the mail data source.
00215   if (! tv)
00216     return NS_RDF_NO_VALUE;
00217 
00218   nsCOMPtr<nsIAbDirectory> directory(do_QueryInterface(source, &rv));
00219   if (NS_SUCCEEDED(rv) && directory)
00220     rv = createDirectoryNode(directory, property, target);
00221   else
00222     return NS_RDF_NO_VALUE;
00223   return rv;
00224 }
00225 
00226 
00227 NS_IMETHODIMP nsAbDirectoryDataSource::GetTargets(nsIRDFResource* source,
00228                                                   nsIRDFResource* property,    
00229                                                   PRBool tv,
00230                                                   nsISimpleEnumerator** targets)
00231 {
00232   nsresult rv = NS_RDF_NO_VALUE;
00233   NS_ENSURE_ARG_POINTER(targets);
00234   
00235   nsCOMPtr<nsIAbDirectory> directory(do_QueryInterface(source, &rv));
00236   if (NS_SUCCEEDED(rv) && directory)
00237   {
00238     if ((kNC_Child == property))
00239     {
00240       return directory->GetChildNodes(targets);
00241     }
00242     else if((kNC_DirName == property) ||
00243       (kNC_DirUri == property) ||
00244       (kNC_IsMailList == property) ||
00245       (kNC_IsRemote == property) ||
00246       (kNC_IsSecure == property) ||
00247       (kNC_IsWriteable == property) ||
00248       (kNC_DirTreeNameSort == property)) 
00249     { 
00250       nsSingletonEnumerator* cursor =
00251         new nsSingletonEnumerator(property);
00252       if (cursor == nsnull)
00253         return NS_ERROR_OUT_OF_MEMORY;
00254       NS_ADDREF(cursor);
00255       *targets = cursor;
00256       return NS_OK;
00257     }
00258     else if((kNC_CardChild == property))
00259     { 
00260       nsCOMPtr<nsIEnumerator> cardChild;
00261       
00262       rv = directory->GetChildCards(getter_AddRefs(cardChild));
00263       if (NS_SUCCEEDED(rv) && cardChild)
00264       {
00265         nsAdapterEnumerator* cursor =
00266           new nsAdapterEnumerator(cardChild);
00267         if (cursor == nsnull)
00268           return NS_ERROR_OUT_OF_MEMORY;
00269         NS_ADDREF(cursor);
00270         *targets = cursor;
00271         return NS_OK;
00272       }
00273     }
00274   }
00275   return NS_NewEmptyEnumerator(targets);
00276 }
00277 
00278 NS_IMETHODIMP nsAbDirectoryDataSource::Assert(nsIRDFResource* source,
00279                       nsIRDFResource* property, 
00280                       nsIRDFNode* target,
00281                       PRBool tv)
00282 {
00283        nsresult rv;
00284        nsCOMPtr<nsIAbDirectory> directory(do_QueryInterface(source, &rv));
00285        //We don't handle tv = PR_FALSE at the moment.
00286        if(NS_SUCCEEDED(rv) && tv)
00287               return DoDirectoryAssert(directory, property, target);
00288        else
00289               return NS_ERROR_FAILURE;
00290 }
00291 
00292 NS_IMETHODIMP nsAbDirectoryDataSource::HasAssertion(nsIRDFResource* source,
00293                             nsIRDFResource* property,
00294                             nsIRDFNode* target,
00295                             PRBool tv,
00296                             PRBool* hasAssertion)
00297 {
00298        nsresult rv;
00299        nsCOMPtr<nsIAbDirectory> directory(do_QueryInterface(source, &rv));
00300        if(NS_SUCCEEDED(rv))
00301               return DoDirectoryHasAssertion(directory, property, target, tv, hasAssertion);
00302        else
00303               *hasAssertion = PR_FALSE;
00304        return NS_OK;
00305 }
00306 
00307 NS_IMETHODIMP 
00308 nsAbDirectoryDataSource::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, PRBool *result)
00309 {
00310   nsresult rv;
00311   nsCOMPtr<nsIAbDirectory> directory(do_QueryInterface(aSource, &rv));
00312   if (NS_SUCCEEDED(rv)) {
00313     *result = (aArc == kNC_DirName ||
00314                aArc == kNC_Child ||
00315                aArc == kNC_CardChild ||
00316                aArc == kNC_DirUri ||
00317                aArc == kNC_IsMailList ||
00318                aArc == kNC_IsRemote ||
00319                aArc == kNC_IsSecure ||
00320                aArc == kNC_IsWriteable ||
00321                aArc == kNC_DirTreeNameSort);
00322   }
00323   else {
00324     *result = PR_FALSE;
00325   }
00326   return NS_OK;
00327 }
00328 
00329 NS_IMETHODIMP nsAbDirectoryDataSource::ArcLabelsOut(nsIRDFResource* source,
00330                                                  nsISimpleEnumerator** labels)
00331 {
00332   nsCOMPtr<nsISupportsArray> arcs;
00333   nsresult rv = NS_RDF_NO_VALUE;
00334 
00335   nsCOMPtr<nsIAbDirectory> directory(do_QueryInterface(source, &rv));
00336   if (NS_SUCCEEDED(rv)) {
00337     rv = getDirectoryArcLabelsOut(directory, getter_AddRefs(arcs));
00338   }
00339   else {
00340     // how to return an empty cursor?
00341     // for now return a 0-length nsISupportsArray
00342     NS_NewISupportsArray(getter_AddRefs(arcs));
00343   }
00344 
00345   nsArrayEnumerator* cursor =
00346     new nsArrayEnumerator(arcs);
00347   
00348   if (cursor == nsnull)
00349     return NS_ERROR_OUT_OF_MEMORY;
00350   NS_ADDREF(cursor);
00351   *labels = cursor;
00352   
00353   return NS_OK;
00354 }
00355 
00356 nsresult
00357 nsAbDirectoryDataSource::getDirectoryArcLabelsOut(nsIAbDirectory *directory,
00358                                              nsISupportsArray **arcs)
00359 {
00360   nsresult rv;
00361   rv = NS_NewISupportsArray(arcs);
00362   NS_ENSURE_SUCCESS(rv, rv);
00363   
00364   (*arcs)->AppendElement(kNC_DirName);
00365   (*arcs)->AppendElement(kNC_Child);
00366   (*arcs)->AppendElement(kNC_CardChild);
00367   (*arcs)->AppendElement(kNC_DirUri);
00368   (*arcs)->AppendElement(kNC_IsMailList);
00369   (*arcs)->AppendElement(kNC_IsRemote);
00370   (*arcs)->AppendElement(kNC_IsSecure);
00371   (*arcs)->AppendElement(kNC_IsWriteable);
00372   (*arcs)->AppendElement(kNC_DirTreeNameSort);
00373   return NS_OK;
00374 }
00375 
00376 NS_IMETHODIMP
00377 nsAbDirectoryDataSource::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
00378                                         nsIRDFResource*   aCommand,
00379                                         nsISupportsArray/*<nsIRDFResource>*/* aArguments,
00380                                         PRBool* aResult)
00381 {
00382   nsresult rv;
00383   nsCOMPtr<nsIAbDirectory> directory;
00384 
00385   PRUint32 i, cnt;
00386   rv = aSources->Count(&cnt);
00387   for (i = 0; i < cnt; i++) {
00388               directory = do_QueryElementAt(aSources, i, &rv);
00389     if (NS_SUCCEEDED(rv)) {
00390       // we don't care about the arguments -- directory commands are always enabled
00391       if (!((aCommand == kNC_Delete) || (aCommand == kNC_DeleteCards) 
00392             ||(aCommand == kNC_Modify))) {
00393         *aResult = PR_FALSE;
00394         return NS_OK;
00395       }
00396     }
00397   }
00398   *aResult = PR_TRUE;
00399   return NS_OK; // succeeded for all sources
00400 }
00401 
00402 NS_IMETHODIMP
00403 nsAbDirectoryDataSource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
00404                                  nsIRDFResource*   aCommand,
00405                                  nsISupportsArray/*<nsIRDFResource>*/* aArguments)
00406 {
00407        PRUint32 i, cnt;
00408        nsresult rv = aSources->Count(&cnt);
00409        NS_ENSURE_SUCCESS(rv, rv);
00410 
00411        if (aCommand == kNC_Modify) {
00412        rv = DoModifyDirectory(aSources,aArguments);
00413   }
00414   else
00415   {
00416        if ((aCommand == kNC_Delete))  
00417               rv = DoDeleteFromDirectory(aSources, aArguments);
00418   else {
00419     for (i = 0; i < cnt; i++) {
00420       nsCOMPtr<nsIAbDirectory> directory = do_QueryElementAt(aSources, i, &rv);
00421       if (NS_SUCCEEDED(rv)) {
00422         NS_ASSERTION(aCommand == kNC_DeleteCards, "unknown command");
00423         if ((aCommand == kNC_DeleteCards))  
00424           rv = DoDeleteCardsFromDirectory(directory, aArguments);
00425       }
00426     }
00427   }
00428   }
00429        //for the moment return NS_OK, because failure stops entire DoCommand process.
00430        return NS_OK;
00431 }
00432 
00433 NS_IMETHODIMP nsAbDirectoryDataSource::OnItemAdded(nsISupports *parentDirectory, nsISupports *item)
00434 {
00435        nsresult rv;
00436        nsCOMPtr<nsIAbCard> card;
00437        nsCOMPtr<nsIAbDirectory> directory;
00438        nsCOMPtr<nsIRDFResource> parentResource;
00439 
00440        if(NS_SUCCEEDED(parentDirectory->QueryInterface(NS_GET_IID(nsIRDFResource), getter_AddRefs(parentResource))))
00441        { 
00442               //If we are adding a card
00443               if(NS_SUCCEEDED(item->QueryInterface(NS_GET_IID(nsIAbCard), getter_AddRefs(card))))
00444               {
00445                      nsCOMPtr<nsIRDFNode> itemNode(do_QueryInterface(item, &rv));
00446                      if (NS_SUCCEEDED(rv))
00447                      {
00448                             //Notify directories that a message was added.
00449                             NotifyObservers(parentResource, kNC_CardChild, itemNode, PR_TRUE, PR_FALSE);
00450                      }
00451               }
00452               //If we are adding a directory
00453               else if(NS_SUCCEEDED(item->QueryInterface(NS_GET_IID(nsIAbDirectory), getter_AddRefs(directory))))
00454               {
00455                      nsCOMPtr<nsIRDFNode> itemNode(do_QueryInterface(item, &rv));
00456                      if(NS_SUCCEEDED(rv))
00457                      {
00458                             //Notify a directory was added.
00459                             NotifyObservers(parentResource, kNC_Child, itemNode, PR_TRUE, PR_FALSE);
00460                      }
00461               }
00462        }
00463 
00464        return NS_OK;
00465 }
00466 
00467 nsresult nsAbDirectoryDataSource::DoModifyDirectory(nsISupportsArray *parentDir, nsISupportsArray *arguments)
00468 {
00469   PRUint32 itemCount;
00470   // Parent dir count should be 1.
00471   nsresult rv = parentDir->Count(&itemCount);
00472   NS_ENSURE_SUCCESS(rv, rv);
00473   NS_ASSERTION(itemCount == 1, "DoModifyDirectory() must have parent directory count = 1.");
00474   if (itemCount != 1)
00475     return NS_ERROR_FAILURE;
00476 
00477   nsCOMPtr<nsIAbDirectory> parent = do_QueryElementAt(parentDir, 0, &rv);
00478   NS_ENSURE_SUCCESS(rv, rv);
00479 
00480   // Argument count should be 2. 1st one is nsIAbDirectory and 2nd is nsIAbDirectoryProperties.
00481   nsCOMPtr<nsISupportsArray> resourceArray = do_QueryElementAt(arguments, 0, &rv);
00482   NS_ENSURE_SUCCESS(rv, rv);
00483   rv = resourceArray->Count(&itemCount);
00484   NS_ENSURE_SUCCESS(rv, rv);
00485   NS_ASSERTION(itemCount == 2, "DoModifyDirectory() must have resource argument count = 2.");
00486   if (itemCount != 2)
00487     return NS_ERROR_FAILURE;
00488 
00489   nsCOMPtr<nsIAbDirectory> modifiedDir = do_QueryElementAt(resourceArray, 0, &rv);
00490   NS_ENSURE_SUCCESS(rv, rv);
00491   nsCOMPtr<nsIAbDirectoryProperties> properties = do_QueryElementAt(resourceArray, 1, &rv);
00492   NS_ENSURE_SUCCESS(rv, rv);
00493   if (modifiedDir && properties)
00494     rv = parent->ModifyDirectory(modifiedDir, properties);
00495   return rv;
00496 }
00497 
00498 NS_IMETHODIMP nsAbDirectoryDataSource::OnItemRemoved(nsISupports *parentDirectory, nsISupports *item)
00499 {
00500        nsresult rv;
00501        nsCOMPtr<nsIAbCard> card;
00502        nsCOMPtr<nsIAbDirectory> directory;
00503        nsCOMPtr<nsIRDFResource> parentResource;
00504 
00505        if(NS_SUCCEEDED(parentDirectory->QueryInterface(NS_GET_IID(nsIRDFResource), getter_AddRefs(parentResource))))
00506        {
00507               //If we are removing a card
00508               if(NS_SUCCEEDED(item->QueryInterface(NS_GET_IID(nsIAbCard), getter_AddRefs(card))))
00509               {
00510                      nsCOMPtr<nsIRDFNode> itemNode(do_QueryInterface(item, &rv));
00511                      if(NS_SUCCEEDED(rv))
00512                      {
00513                             //Notify directories that a card was deleted.
00514                             NotifyObservers(parentResource, kNC_CardChild, itemNode, PR_FALSE, PR_FALSE);
00515                      }
00516               }
00517               //If we are removing a directory
00518               else if(NS_SUCCEEDED(item->QueryInterface(NS_GET_IID(nsIAbDirectory), getter_AddRefs(directory))))
00519               {
00520                      nsCOMPtr<nsIRDFNode> itemNode(do_QueryInterface(item, &rv));
00521                      if(NS_SUCCEEDED(rv))
00522                      {
00523                             //Notify a directory was deleted.
00524                             NotifyObservers(parentResource, kNC_Child, itemNode, PR_FALSE, PR_FALSE);
00525                      }
00526               }
00527        }
00528        return NS_OK;
00529 }
00530 
00531 NS_IMETHODIMP nsAbDirectoryDataSource::OnItemPropertyChanged(nsISupports *item, const char *property,
00532                                                                                                      const PRUnichar *oldValue, const PRUnichar *newValue)
00533 
00534 {
00535        nsresult rv;
00536        nsCOMPtr<nsIRDFResource> resource(do_QueryInterface(item, &rv));
00537 
00538        if(NS_SUCCEEDED(rv))
00539        {
00540               if(PL_strcmp("DirName", property) == 0)
00541               {
00542                      NotifyPropertyChanged(resource, kNC_DirName, oldValue, newValue);
00543               }
00544        }
00545        return NS_OK;
00546 }
00547 
00548 nsresult nsAbDirectoryDataSource::createDirectoryNode(nsIAbDirectory* directory,
00549                                                  nsIRDFResource* property,
00550                                                  nsIRDFNode** target)
00551 {
00552   nsresult rv = NS_RDF_NO_VALUE;
00553   
00554   if ((kNC_DirName == property))
00555          rv = createDirectoryNameNode(directory, target);
00556   else if ((kNC_DirUri == property))
00557          rv = createDirectoryUriNode(directory, target);
00558   else if ((kNC_Child == property))
00559          rv = createDirectoryChildNode(directory, target);
00560   else if ((kNC_IsMailList == property))
00561          rv = createDirectoryIsMailListNode(directory, target);
00562   else if ((kNC_IsRemote == property))
00563          rv = createDirectoryIsRemoteNode(directory, target);
00564   else if ((kNC_IsSecure == property))
00565          rv = createDirectoryIsSecureNode(directory, target);
00566   else if ((kNC_IsWriteable == property))
00567          rv = createDirectoryIsWriteableNode(directory, target);
00568   else if ((kNC_DirTreeNameSort == property))
00569     rv = createDirectoryTreeNameSortNode(directory, target);
00570   return rv;
00571 }
00572 
00573 
00574 nsresult nsAbDirectoryDataSource::createDirectoryNameNode(nsIAbDirectory *directory,
00575                                                      nsIRDFNode **target)
00576 {
00577        nsresult rv = NS_OK;
00578 
00579         nsXPIDLString name;
00580        rv = directory->GetDirName(getter_Copies(name));
00581        NS_ENSURE_SUCCESS(rv, rv);
00582        rv = createNode(name.get(), target);
00583   NS_ENSURE_SUCCESS(rv,rv);
00584   return rv;
00585 }
00586 
00587 nsresult nsAbDirectoryDataSource::createDirectoryUriNode(nsIAbDirectory *directory,
00588                                                      nsIRDFNode **target)
00589 {
00590   nsCOMPtr<nsIRDFResource> source(do_QueryInterface(directory));
00591 
00592   nsXPIDLCString uri;
00593   nsresult rv = source->GetValue(getter_Copies(uri));
00594   NS_ENSURE_SUCCESS(rv, rv);
00595   nsAutoString nameString; nameString.AssignWithConversion(uri);
00596   rv = createNode(nameString.get(), target);
00597   NS_ENSURE_SUCCESS(rv,rv);
00598   return rv;
00599 }
00600 
00601 nsresult
00602 nsAbDirectoryDataSource::createDirectoryChildNode(nsIAbDirectory *directory,
00603                                              nsIRDFNode **target)
00604 {
00605        nsCOMPtr<nsISupportsArray> pAddressLists;
00606        directory->GetAddressLists(getter_AddRefs(pAddressLists));
00607 
00608        if (pAddressLists)
00609        {
00610               PRUint32 total = 0;
00611               pAddressLists->Count(&total);
00612 
00613               if (total)
00614               {
00615                      PRBool isMailList = PR_FALSE;
00616                      directory->GetIsMailList(&isMailList);
00617                      if (!isMailList)
00618       {
00619         // fetch the last element 
00620         nsCOMPtr<nsIRDFResource> mailList = do_QueryElementAt(pAddressLists, total - 1);
00621         NS_IF_ADDREF(*target = mailList);
00622       } 
00623     } // if total
00624   } // if pAddressLists
00625        
00626   return (*target ? NS_OK : NS_RDF_NO_VALUE);
00627 }
00628 
00629 nsresult
00630 nsAbDirectoryDataSource::createDirectoryIsRemoteNode(nsIAbDirectory* directory,
00631                                                      nsIRDFNode **target)
00632 {
00633   PRBool isRemote;
00634   nsresult rv = directory->GetIsRemote(&isRemote);
00635   NS_ENSURE_SUCCESS(rv, rv);
00636   
00637   NS_IF_ADDREF(*target = (isRemote ? kTrueLiteral : kFalseLiteral));
00638   return NS_OK;
00639 }
00640 
00641 nsresult
00642 nsAbDirectoryDataSource::createDirectoryIsSecureNode(nsIAbDirectory* directory,
00643                                                      nsIRDFNode **target)
00644 {
00645   PRBool IsSecure;
00646   nsresult rv = directory->GetIsSecure(&IsSecure);
00647   NS_ENSURE_SUCCESS(rv, rv);
00648   
00649   NS_IF_ADDREF(*target = (IsSecure ? kTrueLiteral : kFalseLiteral));
00650   return NS_OK;
00651 }
00652 
00653 nsresult
00654 nsAbDirectoryDataSource::createDirectoryIsWriteableNode(nsIAbDirectory* directory,
00655                                                         nsIRDFNode **target)
00656 {
00657   PRBool isWriteable;
00658   nsresult rv = directory->GetOperations(&isWriteable);
00659   NS_ENSURE_SUCCESS(rv, rv);
00660   
00661   NS_IF_ADDREF(*target = ((isWriteable & nsIAbDirectory::opWrite) ? kTrueLiteral : kFalseLiteral));
00662   return NS_OK;
00663 }
00664 
00665 nsresult
00666 nsAbDirectoryDataSource::createDirectoryIsMailListNode(nsIAbDirectory* directory,
00667                                                        nsIRDFNode **target)
00668 {
00669   nsresult rv;
00670   PRBool isMailList;
00671   rv = directory->GetIsMailList(&isMailList);
00672   NS_ENSURE_SUCCESS(rv, rv);
00673   
00674   NS_IF_ADDREF(*target = (isMailList ? kTrueLiteral : kFalseLiteral));
00675   return NS_OK;
00676 }
00677  
00678 nsresult
00679 nsAbDirectoryDataSource::createDirectoryTreeNameSortNode(nsIAbDirectory* directory, nsIRDFNode **target)
00680 {
00681   nsXPIDLString name;
00682   nsresult rv = directory->GetDirName(getter_Copies(name));
00683        NS_ENSURE_SUCCESS(rv, rv);
00684 
00685   /* sort addressbooks in this order - Personal Addressbook, Collected Addresses, MDB, LDAP -
00686    * by prefixing address book names with numbers and using the xul sort service.
00687    *
00688    *  0Personal Address Book
00689    *  1Collected Address Book
00690    *  2MAB1
00691    *    5MAB1LIST1
00692    *    5MAB1LIST2
00693    *  2MAB2
00694    *    5MAB2LIST1
00695    *    5MAB2LIST2
00696    *  3LDAP1
00697    *  3LDAP2
00698    *  4MAPI1
00699    *  4MAPI2
00700    */
00701 
00702   // Get isMailList
00703   PRBool isMailList = PR_FALSE;
00704   rv = directory->GetIsMailList(&isMailList);
00705   NS_ENSURE_SUCCESS(rv, rv);
00706 
00707   nsAutoString sortString;
00708 
00709   if (isMailList)
00710     // Mailing Lists don't need a top level sort position.
00711     sortString.AppendInt(5);
00712   else
00713   {
00714     // If its not a mailing list, find out what else we need to know.
00715     nsCOMPtr<nsIRDFResource> resource = do_QueryInterface(directory);
00716     const char *uri = nsnull;
00717     rv = resource->GetValueConst(&uri);
00718     NS_ENSURE_SUCCESS(rv,rv);
00719 
00720     // Get directory type.
00721     nsCOMPtr <nsIAbDirectoryProperties> properties;
00722     rv = directory->GetDirectoryProperties(getter_AddRefs(properties));
00723     NS_ENSURE_SUCCESS(rv, rv);
00724 
00725     PRUint32 dirType;
00726     rv = properties->GetDirType(&dirType);
00727     NS_ENSURE_SUCCESS(rv, rv);
00728 
00729     PRInt32 position;
00730     rv = properties->GetPosition(&position);
00731     NS_ENSURE_SUCCESS(rv, rv);
00732 
00733     // top level sort will be by position. Sort by type under that...
00734     sortString.Append((PRUnichar) (position + 'a'));
00735 
00736     if (dirType == PABDirectory)
00737     {
00738       if (strcmp(uri, kPersonalAddressbookUri) == 0)
00739         sortString.AppendInt(0);  // Personal addrbook
00740       else if (strcmp(uri, kCollectedAddressbookUri) == 0)
00741         sortString.AppendInt(1);  // Collected addrbook
00742       else
00743         sortString.AppendInt(2);  // Normal addrbook 
00744     }
00745     else if (dirType == LDAPDirectory)
00746       sortString.AppendInt(3);    // LDAP addrbook
00747     else if (dirType == MAPIDirectory)
00748       sortString.AppendInt(4);    // MAPI addrbook
00749     else
00750       sortString.AppendInt(6);    // everything else comes last
00751   }
00752 
00753   sortString += name;
00754   PRUint8 *sortKey = nsnull;
00755   PRUint32 sortKeyLength;
00756   rv = CreateCollationKey(sortString, &sortKey, &sortKeyLength);
00757   NS_ENSURE_SUCCESS(rv, rv);
00758   nsCOMPtr <nsIRDFService> rdfService = do_GetService (NS_RDF_CONTRACTID "/rdf-service;1", &rv);
00759   NS_ENSURE_SUCCESS(rv, rv);
00760   createBlobNode(sortKey, sortKeyLength, target, rdfService);
00761   NS_ENSURE_SUCCESS(rv, rv);
00762   PR_Free(sortKey);
00763 
00764   return NS_OK;
00765 
00766 }
00767 
00768 nsresult nsAbDirectoryDataSource::CreateCollationKey(const nsString &aSource,  PRUint8 **aKey, PRUint32 *aLength)
00769 {
00770   NS_ENSURE_ARG_POINTER(aKey);
00771   NS_ENSURE_ARG_POINTER(aLength);
00772 
00773   nsresult rv;
00774   if (!mCollationKeyGenerator)
00775   {
00776     nsCOMPtr<nsILocaleService> localeSvc = do_GetService(NS_LOCALESERVICE_CONTRACTID,&rv); 
00777     NS_ENSURE_SUCCESS(rv, rv);
00778 
00779     nsCOMPtr<nsILocale> locale; 
00780     rv = localeSvc->GetApplicationLocale(getter_AddRefs(locale));
00781     NS_ENSURE_SUCCESS(rv, rv);
00782 
00783     nsCOMPtr <nsICollationFactory> factory = do_CreateInstance(kCollationFactoryCID, &rv); 
00784     NS_ENSURE_SUCCESS(rv, rv);
00785 
00786     rv = factory->CreateCollation(locale, getter_AddRefs(mCollationKeyGenerator));
00787     NS_ENSURE_SUCCESS(rv, rv);
00788   }
00789 
00790   return mCollationKeyGenerator->AllocateRawSortKey(nsICollation::kCollationCaseInSensitive, aSource, aKey, aLength);
00791 }
00792 
00793 nsresult nsAbDirectoryDataSource::DoDeleteFromDirectory(nsISupportsArray *parentDirs, nsISupportsArray *delDirs)
00794 {
00795        PRUint32 item, itemCount;
00796        nsresult rv = parentDirs->Count(&itemCount);
00797        NS_ENSURE_SUCCESS(rv, rv);
00798 
00799        for (item = 0; item < itemCount; item++) 
00800        {
00801               nsCOMPtr<nsIAbDirectory> parent = do_QueryElementAt(parentDirs, item, &rv);
00802               if (NS_SUCCEEDED(rv)) 
00803               {
00804                      nsCOMPtr<nsIAbDirectory> deletedDir(do_QueryElementAt(delDirs, item));
00805                      if(deletedDir)
00806                      {
00807                             rv = parent->DeleteDirectory(deletedDir);
00808                      }
00809               }
00810        }
00811        return rv;
00812 }
00813 
00814 nsresult nsAbDirectoryDataSource::DoDeleteCardsFromDirectory(nsIAbDirectory *directory, nsISupportsArray *arguments)
00815 {
00816        nsresult rv = NS_OK;
00817        PRUint32 itemCount;
00818        rv = arguments->Count(&itemCount);
00819        NS_ENSURE_SUCCESS(rv, rv);
00820        
00821        nsCOMPtr<nsISupportsArray> cardArray;
00822        NS_NewISupportsArray(getter_AddRefs(cardArray));
00823 
00824        //Split up deleted items into different type arrays to be passed to the folder
00825        //for deletion.
00826        PRUint32 item;
00827        for(item = 0; item < itemCount; item++)
00828        {
00829     nsCOMPtr<nsIAbCard> deletedCard(do_QueryElementAt(arguments, item));
00830               if (deletedCard)
00831               {
00832       rv = cardArray->AppendElement(deletedCard);
00833       NS_ENSURE_SUCCESS(rv, rv);
00834               }
00835        }
00836        PRUint32 cnt;
00837        rv = cardArray->Count(&cnt);
00838        NS_ENSURE_SUCCESS(rv, rv);
00839        if (cnt > 0)
00840               rv = directory->DeleteCards(cardArray);
00841        return rv;
00842 }
00843 
00844 
00845 nsresult nsAbDirectoryDataSource::DoDirectoryAssert(nsIAbDirectory *directory, nsIRDFResource *property, nsIRDFNode *target)
00846 {
00847        nsresult rv = NS_ERROR_FAILURE;
00848        return rv;
00849 }
00850 
00851 
00852 nsresult nsAbDirectoryDataSource::DoDirectoryHasAssertion(nsIAbDirectory *directory, nsIRDFResource *property, nsIRDFNode *target,
00853                                                                                             PRBool tv, PRBool *hasAssertion)
00854 {
00855        nsresult rv = NS_OK;
00856        if (!hasAssertion)
00857               return NS_ERROR_NULL_POINTER;
00858 
00859        //We're not keeping track of negative assertions on directory.
00860        if (!tv)
00861        {
00862               *hasAssertion = PR_FALSE;
00863               return NS_OK;
00864        }
00865 
00866        if ((kNC_CardChild == property))
00867        {
00868               nsCOMPtr<nsIAbCard> card(do_QueryInterface(target, &rv));
00869               if(NS_SUCCEEDED(rv))
00870                      rv = directory->HasCard(card, hasAssertion);
00871        }
00872        else if ((kNC_Child == property))
00873        {
00874               nsCOMPtr<nsIAbDirectory> newDirectory(do_QueryInterface(target, &rv));
00875               if(NS_SUCCEEDED(rv))
00876                      rv = directory->HasDirectory(newDirectory, hasAssertion);
00877        }
00878        else if ((kNC_IsMailList == property) || (kNC_IsRemote == property) ||
00879                      (kNC_IsSecure == property) || (kNC_IsWriteable == property))
00880        {
00881               nsCOMPtr<nsIRDFResource> dirResource(do_QueryInterface(directory, &rv));
00882               NS_ENSURE_SUCCESS(rv, rv);
00883               rv = GetTargetHasAssertion(this, dirResource, property, tv, target, hasAssertion);
00884        }
00885        else 
00886               *hasAssertion = PR_FALSE;
00887 
00888        return rv;
00889 
00890 }
00891 
00892 nsresult nsAbDirectoryDataSource::GetTargetHasAssertion(nsIRDFDataSource *dataSource, nsIRDFResource* dirResource,
00893                                                     nsIRDFResource *property,PRBool tv, nsIRDFNode *target,PRBool* hasAssertion)
00894 {
00895        nsresult rv;
00896        if(!hasAssertion)
00897               return NS_ERROR_NULL_POINTER;
00898 
00899        nsCOMPtr<nsIRDFNode> currentTarget;
00900 
00901        rv = dataSource->GetTarget(dirResource, property,tv, getter_AddRefs(currentTarget));
00902        if(NS_SUCCEEDED(rv))
00903        {
00904               nsCOMPtr<nsIRDFLiteral> value1(do_QueryInterface(target));
00905               nsCOMPtr<nsIRDFLiteral> value2(do_QueryInterface(currentTarget));
00906               if(value1 && value2)
00907                      //If the two values are equal then it has this assertion
00908                      *hasAssertion = (value1 == value2);
00909        }
00910        else
00911               rv = NS_NOINTERFACE;
00912 
00913        return rv;
00914 
00915 }
00916 
00917 nsresult NS_NewAbDirectoryDataSource(const nsIID& iid, void **result)
00918 {
00919     NS_PRECONDITION(result != nsnull, "null ptr");
00920     if (! result)
00921         return NS_ERROR_NULL_POINTER;
00922 
00923     nsAbDirectoryDataSource* datasource = new nsAbDirectoryDataSource();
00924     if (! datasource)
00925         return NS_ERROR_OUT_OF_MEMORY;
00926 
00927     nsresult rv;
00928     rv = datasource->Init();
00929     if (NS_FAILED(rv)) {
00930         delete datasource;
00931         return rv;
00932     }
00933 
00934        return datasource->QueryInterface(iid, result);
00935 }
00936 
00937