Back to index

lightning-sunbird  0.9+nobinonly
nsAbMDBDirectory.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) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Seth Spitzer <sspitzer@netscape.com>
00024  *   Pierre Phaneuf <pp@ludusdesign.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 "nsAbMDBDirectory.h" 
00041 #include "nsIRDFService.h"
00042 #include "nsIServiceManager.h"
00043 #include "nsRDFCID.h"
00044 #include "nsXPIDLString.h"
00045 #include "nsCOMPtr.h"
00046 #include "nsAbBaseCID.h"
00047 #include "nsAddrDatabase.h"
00048 #include "nsIAbMDBCard.h"
00049 #include "nsIAbListener.h"
00050 #include "nsIAddrBookSession.h"
00051 #include "nsIAddressBook.h"
00052 #include "nsIURL.h"
00053 #include "nsNetCID.h"
00054 #include "nsAbDirectoryQuery.h"
00055 #include "nsIAbDirectoryQueryProxy.h"
00056 #include "nsAbQueryStringToExpression.h"
00057 #include "nsArrayEnumerator.h"
00058 #include "nsAbMDBCardProperty.h"
00059 
00060 #include "mdb.h"
00061 #include "prprf.h"
00062 
00063 // XXX todo
00064 // fix this -1,0,1 crap, use an enum or #define
00065 
00066 nsAbMDBDirectory::nsAbMDBDirectory(void):
00067      nsRDFResource(),
00068      mInitialized(PR_FALSE),
00069      mIsMailingList(-1),
00070      mIsQueryURI(PR_FALSE),
00071      mPerformingQuery(PR_FALSE)
00072 {
00073 }
00074 
00075 nsAbMDBDirectory::~nsAbMDBDirectory(void)
00076 {
00077   if (mDatabase) {
00078     mDatabase->RemoveListener(this);
00079   }
00080 }
00081 
00082 NS_IMPL_ISUPPORTS_INHERITED4(nsAbMDBDirectory, nsRDFResource,
00083                              nsIAbDirectory,
00084                              nsIAbMDBDirectory,
00085                              nsIAbDirectorySearch,
00086                              nsIAddrDBListener)
00087 
00088 
00089 
00090 nsresult nsAbMDBDirectory::RemoveCardFromAddressList(nsIAbCard* card)
00091 {
00092   nsresult rv = NS_OK;
00093   PRUint32 listTotal;
00094   PRInt32 i, j;
00095 
00096   // These checks ensure we don't run into null pointers
00097   // as we did when we caused bug 280463.
00098   if (!mDatabase)
00099   {
00100     rv = GetAbDatabase();
00101     NS_ENSURE_SUCCESS(rv, rv);
00102   }
00103 
00104   if (!m_AddressList)
00105   {
00106     rv = mDatabase->GetMailingListsFromDB(this);
00107     NS_ENSURE_SUCCESS(rv, rv);
00108     // Ensure that the previous call did set the address list pointer
00109     if (!m_AddressList)
00110       return NS_ERROR_NULL_POINTER;
00111   }
00112 
00113   rv = m_AddressList->Count(&listTotal);
00114   NS_ENSURE_SUCCESS(rv,rv);
00115 
00116   for (i = listTotal - 1; i >= 0; i--)
00117   {            
00118     nsCOMPtr<nsIAbDirectory> listDir(do_QueryElementAt(m_AddressList, i, &rv));
00119     if (listDir)
00120     {
00121       // First remove the instance in the database
00122       mDatabase->DeleteCardFromMailList(listDir, card, PR_FALSE);
00123 
00124       // Now remove the instance in any lists we hold.
00125       nsCOMPtr <nsISupportsArray> pAddressLists;
00126       listDir->GetAddressLists(getter_AddRefs(pAddressLists));
00127       if (pAddressLists)
00128       {  
00129         PRUint32 total;
00130         rv = pAddressLists->Count(&total);
00131         for (j = total - 1; j >= 0; j--)
00132         {
00133           nsCOMPtr<nsIAbCard> cardInList(do_QueryElementAt(pAddressLists, j, &rv));
00134           PRBool equals;
00135           nsresult rv = cardInList->Equals(card, &equals);  // should we checking email?
00136           if (NS_SUCCEEDED(rv) && equals) {
00137             pAddressLists->RemoveElementAt(j);
00138         }
00139       }
00140     }
00141   }
00142   }
00143   return NS_OK;
00144 }
00145 
00146 NS_IMETHODIMP nsAbMDBDirectory::ModifyDirectory(nsIAbDirectory *directory, nsIAbDirectoryProperties *aProperties)
00147 {
00148   return NS_ERROR_NOT_IMPLEMENTED;
00149 }
00150 
00151 
00152 NS_IMETHODIMP nsAbMDBDirectory::DeleteDirectory(nsIAbDirectory *directory)
00153 {
00154   nsresult rv = NS_OK;
00155   
00156   if (!directory)
00157     return NS_ERROR_FAILURE;
00158 
00159   nsCOMPtr<nsIAbMDBDirectory> dbdirectory(do_QueryInterface(directory, &rv));
00160   NS_ENSURE_SUCCESS(rv, rv);
00161 
00162   nsXPIDLCString uri;
00163   rv = dbdirectory->GetDirUri(getter_Copies(uri));
00164   NS_ENSURE_SUCCESS(rv, rv);
00165 
00166   nsCOMPtr<nsIAddrDatabase> database;
00167   nsCOMPtr<nsIAddressBook> addressBook = do_GetService(NS_ADDRESSBOOK_CONTRACTID, &rv);
00168   if (NS_SUCCEEDED(rv))
00169   {
00170     rv = addressBook->GetAbDatabaseFromURI(uri.get(), getter_AddRefs(database));        
00171 
00172     if (NS_SUCCEEDED(rv))
00173       rv = database->DeleteMailList(directory, PR_TRUE);
00174 
00175     if (NS_SUCCEEDED(rv))
00176       database->Commit(nsAddrDBCommitType::kLargeCommit);
00177 
00178     if (m_AddressList)
00179       m_AddressList->RemoveElement(directory);
00180     rv = mSubDirectories.RemoveObject(directory);
00181 
00182     NotifyItemDeleted(directory);
00183   }
00184   
00185 
00186   return rv;
00187 }
00188 
00189 nsresult nsAbMDBDirectory::NotifyItemChanged(nsISupports *item)
00190 {
00191   nsresult rv;
00192   nsCOMPtr<nsIAddrBookSession> abSession = do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv);
00193   NS_ENSURE_SUCCESS(rv,rv);
00194 
00195   rv = abSession->NotifyItemPropertyChanged(item, nsnull, nsnull, nsnull);
00196   NS_ENSURE_SUCCESS(rv,rv);
00197   return rv;
00198 }
00199 
00200 nsresult nsAbMDBDirectory::NotifyPropertyChanged(nsIAbDirectory *list, const char *property, const PRUnichar* oldValue, const PRUnichar* newValue)
00201 {
00202   nsresult rv;
00203   nsCOMPtr<nsISupports> supports = do_QueryInterface(list, &rv);
00204   NS_ENSURE_SUCCESS(rv,rv);
00205 
00206   nsCOMPtr<nsIAddrBookSession> abSession = do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv);
00207   NS_ENSURE_SUCCESS(rv,rv);
00208 
00209   rv = abSession->NotifyItemPropertyChanged(supports, property, oldValue, newValue);
00210   NS_ENSURE_SUCCESS(rv,rv);
00211   return rv;
00212 }
00213 
00214 nsresult nsAbMDBDirectory::NotifyItemAdded(nsISupports *item)
00215 {
00216   nsresult rv = NS_OK;
00217   nsCOMPtr<nsIAddrBookSession> abSession = do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv);
00218   if(NS_SUCCEEDED(rv))
00219     abSession->NotifyDirectoryItemAdded(this, item);
00220   return NS_OK;
00221 }
00222 
00223 nsresult nsAbMDBDirectory::NotifyItemDeleted(nsISupports *item)
00224 {
00225   nsresult rv = NS_OK;
00226   nsCOMPtr<nsIAddrBookSession> abSession = do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv);
00227   if(NS_SUCCEEDED(rv))
00228     abSession->NotifyDirectoryItemDeleted(this, item);
00229 
00230   return NS_OK;
00231 }
00232 
00233 
00234 // nsIRDFResource methods
00235 
00236 NS_IMETHODIMP nsAbMDBDirectory::Init(const char* aURI)
00237 {
00238   nsresult rv;
00239 
00240   rv = nsRDFResource::Init(aURI);
00241   NS_ENSURE_SUCCESS(rv, rv);
00242 
00243   mURINoQuery = aURI;
00244 
00245   nsCOMPtr<nsIURI> uri = do_CreateInstance (NS_STANDARDURL_CONTRACTID, &rv);
00246   NS_ENSURE_SUCCESS(rv, rv);
00247 
00248   rv = uri->SetSpec(nsDependentCString(aURI));
00249   NS_ENSURE_SUCCESS(rv, rv);
00250 
00251   mIsValidURI = PR_TRUE;
00252 
00253     nsCOMPtr<nsIURL> url = do_QueryInterface(uri);
00254   NS_ENSURE_SUCCESS(rv, rv);
00255 
00256   nsCAutoString queryString;
00257   rv = url->GetQuery (queryString);
00258 
00259   nsCAutoString path;
00260   rv = url->GetPath (path);
00261   mPath = path;
00262 
00263   if (!queryString.IsEmpty())
00264   {
00265     mPath.Truncate(path.Length() - queryString.Length() - 1);
00266 
00267     mURINoQuery.Truncate(mURINoQuery.Length() - queryString.Length() - 1);
00268 
00269     mQueryString = queryString;
00270 
00271     mIsQueryURI = PR_TRUE;
00272   }
00273   else
00274     mIsQueryURI = PR_FALSE;
00275 
00276   return rv;
00277 }
00278 
00279 
00280 // nsIAbMDBDirectory methods
00281 
00282 NS_IMETHODIMP nsAbMDBDirectory::ClearDatabase()
00283 {       
00284   if (mIsQueryURI)
00285     return NS_ERROR_NOT_IMPLEMENTED;
00286 
00287   if (mDatabase)
00288   {
00289     mDatabase->RemoveListener(this);
00290     mDatabase = nsnull; 
00291   }
00292   return NS_OK; 
00293 }
00294 
00295 NS_IMETHODIMP nsAbMDBDirectory::RemoveElementsFromAddressList()
00296 {
00297   if (mIsQueryURI)
00298     return NS_ERROR_NOT_IMPLEMENTED;
00299 
00300   if (m_AddressList)
00301   {
00302     PRUint32 count;
00303     nsresult rv;
00304     rv = m_AddressList->Count(&count);
00305     NS_ASSERTION(NS_SUCCEEDED(rv), "Count failed");
00306     PRInt32 i;
00307     for (i = count - 1; i >= 0; i--)
00308       m_AddressList->RemoveElementAt(i);
00309   }
00310   m_AddressList = nsnull;
00311   return NS_OK;
00312 }
00313 
00314 NS_IMETHODIMP nsAbMDBDirectory::RemoveEmailAddressAt(PRUint32 aIndex)
00315 {
00316   if (mIsQueryURI)
00317     return NS_ERROR_NOT_IMPLEMENTED;
00318 
00319   if (m_AddressList)
00320   {
00321     return m_AddressList->RemoveElementAt(aIndex);
00322   }
00323   else
00324     return NS_ERROR_FAILURE;
00325 }
00326 
00327 NS_IMETHODIMP nsAbMDBDirectory::AddDirectory(const char *uriName, nsIAbDirectory **childDir)
00328 {
00329   if (mIsQueryURI)
00330     return NS_ERROR_NOT_IMPLEMENTED;
00331 
00332   if (!childDir || !uriName)
00333     return NS_ERROR_NULL_POINTER;
00334 
00335   nsresult rv = NS_OK;
00336   nsCOMPtr<nsIRDFService> rdf(do_GetService("@mozilla.org/rdf/rdf-service;1", &rv));
00337   NS_ENSURE_SUCCESS(rv, rv);
00338   
00339   nsCOMPtr<nsIRDFResource> res;
00340   rv = rdf->GetResource(nsDependentCString(uriName), getter_AddRefs(res));
00341   NS_ENSURE_SUCCESS(rv, rv);
00342 
00343   nsCOMPtr<nsIAbDirectory> directory(do_QueryInterface(res, &rv));
00344   NS_ENSURE_SUCCESS(rv, rv);
00345 
00346   if (mSubDirectories.IndexOf(directory) == kNotFound)
00347     mSubDirectories.AppendObject(directory);
00348   NS_IF_ADDREF(*childDir = directory);
00349   return rv;
00350 }
00351 
00352 NS_IMETHODIMP nsAbMDBDirectory::GetDirUri(char **uri)
00353 {
00354   NS_ASSERTION(uri, "Null out param");
00355   NS_ASSERTION(!mURI.IsEmpty(), "Not initialized?");
00356 
00357   *uri = ToNewCString(mURI);
00358 
00359   if (!*uri)
00360     return NS_ERROR_OUT_OF_MEMORY;
00361 
00362   return NS_OK;
00363 }
00364 
00365 
00366 
00367 // nsIAbDirectory methods
00368 
00369 NS_IMETHODIMP nsAbMDBDirectory::GetChildNodes(nsISimpleEnumerator* *aResult)
00370 {
00371   if (mIsQueryURI)
00372   {
00373     nsCOMArray<nsIAbDirectory> children;
00374     return NS_NewArrayEnumerator(aResult, children);
00375   }
00376 
00377   mInitialized = PR_TRUE;
00378   return NS_NewArrayEnumerator(aResult, mSubDirectories);
00379 }
00380 
00381 PR_STATIC_CALLBACK(PRBool) enumerateSearchCache(nsHashKey *aKey, void *aData, void* closure)
00382 {
00383         nsISupportsArray* array = (nsISupportsArray* )closure;
00384   nsIAbCard* card = (nsIAbCard* )aData;
00385 
00386   array->AppendElement (card);
00387         return PR_TRUE;
00388 }
00389 
00390 NS_IMETHODIMP nsAbMDBDirectory::GetChildCards(nsIEnumerator* *result)
00391 {
00392   if (mIsQueryURI)
00393   {
00394     nsresult rv;
00395     rv = StartSearch();
00396     NS_ENSURE_SUCCESS(rv, rv);
00397 
00398     // TODO
00399     // Search is synchronous so need to return
00400     // results after search is complete
00401     nsCOMPtr<nsISupportsArray> array;
00402     NS_NewISupportsArray(getter_AddRefs(array));
00403     mSearchCache.Enumerate(enumerateSearchCache, (void*)array);
00404     return array->Enumerate(result);
00405   }
00406 
00407   NS_ASSERTION(!mURI.IsEmpty(), "Not Initialized?");
00408   if (mIsMailingList == -1)
00409   {
00410     /* directory URIs are of the form
00411      * moz-abmdbdirectory://foo
00412      * mailing list URIs are of the form
00413      * moz-abmdbdirectory://foo/bar
00414      */
00415     NS_ENSURE_TRUE(mURI.Length() > kMDBDirectoryRootLen, NS_ERROR_UNEXPECTED);
00416     if (strchr(mURI.get() + kMDBDirectoryRootLen, '/'))
00417       mIsMailingList = 1;
00418     else
00419       mIsMailingList = 0;
00420   }
00421 
00422   nsresult rv = GetAbDatabase();
00423 
00424   if (NS_SUCCEEDED(rv) && mDatabase)
00425   {
00426     if (mIsMailingList == 0)
00427       rv = mDatabase->EnumerateCards(this, result);
00428     else if (mIsMailingList == 1)
00429       rv = mDatabase->EnumerateListAddresses(this, result);
00430   }
00431 
00432   return rv;
00433 }
00434 
00435 NS_IMETHODIMP nsAbMDBDirectory::DeleteCards(nsISupportsArray *cards)
00436 {
00437   nsresult rv = NS_OK;
00438 
00439   if (mIsQueryURI) {
00440     // if this is a query, delete the cards from the directory (without the query)
00441     // before we do the delete, make this directory (which represents the search)
00442     // a listener on the database, so that it will get notified when the cards are deleted
00443     // after delete, remove this query as a listener.
00444     nsCOMPtr<nsIAddressBook> addressBook = do_GetService(NS_ADDRESSBOOK_CONTRACTID, &rv);
00445     NS_ENSURE_SUCCESS(rv,rv);
00446 
00447     nsCOMPtr<nsIAddrDatabase> database;
00448     rv = addressBook->GetAbDatabaseFromURI(mURINoQuery.get(), getter_AddRefs(database));
00449     NS_ENSURE_SUCCESS(rv,rv);
00450 
00451     rv = database->AddListener(this);
00452     NS_ENSURE_SUCCESS(rv, rv);
00453 
00454     nsCOMPtr<nsIRDFResource> resource;
00455     rv = gRDFService->GetResource(mURINoQuery, getter_AddRefs(resource));
00456     NS_ENSURE_SUCCESS(rv, rv);
00457     
00458     nsCOMPtr<nsIAbDirectory> directory = do_QueryInterface(resource, &rv);
00459     NS_ENSURE_SUCCESS(rv, rv);
00460 
00461     rv = directory->DeleteCards(cards);
00462     NS_ENSURE_SUCCESS(rv, rv);
00463 
00464     rv = database->RemoveListener(this);
00465     NS_ENSURE_SUCCESS(rv, rv);
00466     return rv;
00467   }
00468 
00469   if (!mDatabase)
00470     rv = GetAbDatabase();
00471 
00472   if (NS_SUCCEEDED(rv) && mDatabase)
00473   {
00474     PRUint32 cardCount;
00475     PRUint32 i;
00476     rv = cards->Count(&cardCount);
00477     NS_ENSURE_SUCCESS(rv, rv);
00478     for (i = 0; i < cardCount; i++)
00479     {
00480       nsCOMPtr<nsIAbCard> card;
00481       nsCOMPtr<nsIAbMDBCard> dbcard;
00482       card = do_QueryElementAt(cards, i, &rv);
00483       NS_ENSURE_SUCCESS(rv, rv);
00484       dbcard = do_QueryInterface(card, &rv);
00485       NS_ENSURE_SUCCESS(rv, rv);
00486       if (card)
00487       {
00488         if (IsMailingList())
00489         {
00490           mDatabase->DeleteCardFromMailList(this, card, PR_TRUE);
00491 
00492           PRUint32 cardTotal = 0;
00493           PRInt32 i;
00494           if (m_AddressList)
00495             rv = m_AddressList->Count(&cardTotal);
00496           for (i = cardTotal - 1; i >= 0; i--)
00497           {            
00498             nsCOMPtr<nsIAbMDBCard> dbarrayCard(do_QueryElementAt(m_AddressList, i, &rv));
00499             if (dbarrayCard)
00500             {
00501               PRUint32 tableID, rowID, cardTableID, cardRowID; 
00502               dbarrayCard->GetDbTableID(&tableID);
00503               dbarrayCard->GetDbRowID(&rowID);
00504               dbcard->GetDbTableID(&cardTableID);
00505               dbcard->GetDbRowID(&cardRowID);
00506               if (tableID == cardTableID && rowID == cardRowID)
00507                 m_AddressList->RemoveElementAt(i);
00508             }
00509           }
00510         }
00511         else
00512         {
00513           mDatabase->DeleteCard(card, PR_TRUE);
00514           PRBool bIsMailList = PR_FALSE;
00515           card->GetIsMailList(&bIsMailList);
00516           if (bIsMailList)
00517           {
00518             //to do, get mailing list dir side uri and notify rdf to remove it
00519             PRUint32 rowID;
00520             dbcard->GetDbRowID(&rowID);
00521             nsCAutoString listUri(mURI);
00522             listUri.AppendLiteral("/MailList");
00523             listUri.AppendInt(rowID);
00524             if (!listUri.IsEmpty())
00525             {
00526               nsresult rv = NS_OK;
00527               nsCOMPtr<nsIRDFService> rdfService = 
00528                        do_GetService("@mozilla.org/rdf/rdf-service;1", &rv);
00529 
00530               if(NS_SUCCEEDED(rv))
00531                 {
00532                 nsCOMPtr<nsIRDFResource> listResource;
00533                 rv = rdfService->GetResource(listUri,
00534                                              getter_AddRefs(listResource));
00535                 nsCOMPtr<nsIAbDirectory> listDir = do_QueryInterface(listResource, &rv);
00536                 if(NS_SUCCEEDED(rv))
00537                   {
00538                   if (m_AddressList)
00539                     m_AddressList->RemoveElement(listDir);
00540                   rv = mSubDirectories.RemoveObject(listDir);
00541 
00542                   if (listDir)
00543                     NotifyItemDeleted(listDir);
00544                   }
00545                 else 
00546                   {
00547                   return rv;
00548                   }
00549                 }
00550               else
00551                 {
00552                 return rv;
00553                 }
00554             }
00555           }
00556           else
00557           { 
00558             rv = RemoveCardFromAddressList(card);
00559             NS_ENSURE_SUCCESS(rv,rv);
00560           }
00561         }
00562       }
00563     }
00564     mDatabase->Commit(nsAddrDBCommitType::kLargeCommit);
00565   }
00566   return rv;
00567 }
00568 
00569 NS_IMETHODIMP nsAbMDBDirectory::HasCard(nsIAbCard *cards, PRBool *hasCard)
00570 {
00571   if(!hasCard)
00572     return NS_ERROR_NULL_POINTER;
00573 
00574   if (mIsQueryURI)
00575   {
00576     nsVoidKey key (NS_STATIC_CAST(void*, cards));
00577     *hasCard = mSearchCache.Exists (&key);
00578     return NS_OK;
00579   }
00580 
00581   nsresult rv = NS_OK;
00582   if (!mDatabase)
00583     rv = GetAbDatabase();
00584 
00585   if(NS_SUCCEEDED(rv) && mDatabase)
00586   {
00587     if(NS_SUCCEEDED(rv))
00588       rv = mDatabase->ContainsCard(cards, hasCard);
00589   }
00590   return rv;
00591 }
00592 
00593 NS_IMETHODIMP nsAbMDBDirectory::HasDirectory(nsIAbDirectory *dir, PRBool *hasDir)
00594 {
00595   if (!hasDir)
00596     return NS_ERROR_NULL_POINTER;
00597 
00598   nsresult rv = NS_ERROR_FAILURE;
00599 
00600   nsCOMPtr<nsIAbMDBDirectory> dbdir(do_QueryInterface(dir, &rv));
00601     NS_ENSURE_SUCCESS(rv, rv);
00602   
00603   PRBool bIsMailingList  = PR_FALSE;
00604   dir->GetIsMailList(&bIsMailingList);
00605   if (bIsMailingList)
00606   {
00607     nsXPIDLCString uri;
00608     rv = dbdir->GetDirUri(getter_Copies(uri));
00609         NS_ENSURE_SUCCESS(rv, rv);
00610     nsCOMPtr<nsIAddrDatabase> database;
00611       nsCOMPtr<nsIAddressBook> addressBook = do_GetService(NS_ADDRESSBOOK_CONTRACTID, &rv);
00612     if (NS_SUCCEEDED(rv))
00613     {
00614       rv = addressBook->GetAbDatabaseFromURI(uri.get(), getter_AddRefs(database));        
00615     }
00616     if(NS_SUCCEEDED(rv) && database)
00617     {
00618       if(NS_SUCCEEDED(rv))
00619         rv = database->ContainsMailList(dir, hasDir);
00620     }
00621   }
00622 
00623   return rv;
00624 }
00625 
00626 NS_IMETHODIMP nsAbMDBDirectory::CreateNewDirectory(nsIAbDirectoryProperties *aProperties)
00627 {
00628   return NS_ERROR_NOT_IMPLEMENTED;
00629 }
00630 
00631 NS_IMETHODIMP nsAbMDBDirectory::CreateDirectoryByURI(const PRUnichar *dirName, const char *uri, PRBool migrating)
00632 {
00633   return NS_ERROR_NOT_IMPLEMENTED;
00634 }
00635 
00636 NS_IMETHODIMP nsAbMDBDirectory::AddMailListWithKey(nsIAbDirectory *list, PRUint32 *key)
00637 {
00638   return(InternalAddMailList(list, key));
00639 }
00640 
00641 NS_IMETHODIMP nsAbMDBDirectory::AddMailList(nsIAbDirectory *list)
00642 {
00643   return(InternalAddMailList(list, nsnull));
00644 }
00645 
00646 nsresult nsAbMDBDirectory::InternalAddMailList(nsIAbDirectory *list, PRUint32 *key)
00647 {
00648   if (mIsQueryURI)
00649     return NS_ERROR_NOT_IMPLEMENTED;
00650 
00651   nsresult rv = NS_OK;
00652   if (!mDatabase)
00653     rv = GetAbDatabase();
00654 
00655   if (NS_FAILED(rv) || !mDatabase)
00656     return NS_ERROR_FAILURE;
00657 
00658   nsCOMPtr<nsIAbMDBDirectory> dblist(do_QueryInterface(list, &rv));
00659   if (NS_FAILED(rv))
00660   {
00661     // XXX fix this.
00662     nsAbMDBDirProperty* dblistproperty = new nsAbMDBDirProperty ();
00663     if (!dblistproperty)
00664       return NS_ERROR_OUT_OF_MEMORY;
00665     NS_ADDREF(dblistproperty);
00666     nsCOMPtr<nsIAbDirectory> newlist = getter_AddRefs(NS_STATIC_CAST(nsIAbDirectory*, dblistproperty));
00667     newlist->CopyMailList(list);
00668     list = newlist;
00669     dblist = do_QueryInterface(list, &rv);
00670   }
00671 
00672   if (!key)
00673     mDatabase->CreateMailListAndAddToDB(list, PR_TRUE);
00674   else
00675     mDatabase->CreateMailListAndAddToDBWithKey(list, PR_TRUE, key);
00676   mDatabase->Commit(nsAddrDBCommitType::kLargeCommit);
00677 
00678   PRUint32 dbRowID;
00679   dblist->GetDbRowID(&dbRowID);
00680 
00681   nsCAutoString listUri(mURI);
00682   listUri.AppendLiteral("/MailList");
00683   listUri.AppendInt(dbRowID);
00684 
00685   nsCOMPtr<nsIAbDirectory> newList;
00686   rv = AddDirectory(listUri.get(), getter_AddRefs(newList));
00687   nsCOMPtr<nsIAbMDBDirectory> dbnewList(do_QueryInterface(newList));
00688   if (NS_SUCCEEDED(rv) && newList)
00689   {
00690     nsCOMPtr<nsIAddrDBListener> listener(do_QueryInterface(newList, &rv));
00691     NS_ENSURE_SUCCESS(rv, rv);
00692     
00693     rv = mDatabase->AddListener(listener);
00694     NS_ENSURE_SUCCESS(rv, rv);
00695 
00696     dbnewList->CopyDBMailList (dblist);
00697     AddMailListToDirectory(newList);
00698     NotifyItemAdded(newList);
00699   }
00700 
00701   return rv;
00702 }
00703 
00704 NS_IMETHODIMP nsAbMDBDirectory::AddCard(nsIAbCard* card, nsIAbCard **addedCard)
00705 {
00706   if (mIsQueryURI)
00707     return NS_ERROR_NOT_IMPLEMENTED;
00708 
00709   nsresult rv = NS_OK;
00710   if (!mDatabase)
00711     rv = GetAbDatabase();
00712 
00713   if (NS_FAILED(rv) || !mDatabase)
00714     return NS_ERROR_FAILURE;
00715 
00716   nsCOMPtr<nsIAbCard> newCard;
00717   nsCOMPtr<nsIAbMDBCard> dbcard;
00718 
00719   dbcard = do_QueryInterface(card, &rv);
00720   if (NS_FAILED(rv) || !dbcard) {
00721     dbcard = do_CreateInstance(NS_ABMDBCARD_CONTRACTID, &rv);
00722   NS_ENSURE_SUCCESS(rv, rv);
00723 
00724     newCard = do_QueryInterface(dbcard, &rv);
00725     NS_ENSURE_SUCCESS(rv,rv);
00726   
00727     rv = newCard->Copy(card);
00728   NS_ENSURE_SUCCESS(rv, rv);
00729   }
00730   else {
00731     newCard = card;
00732   }
00733 
00734   dbcard->SetAbDatabase (mDatabase);
00735   if (mIsMailingList == 1)
00736     mDatabase->CreateNewListCardAndAddToDB(this, m_dbRowID, newCard, PR_TRUE /* notify */);
00737   else
00738     mDatabase->CreateNewCardAndAddToDB(newCard, PR_TRUE);
00739   mDatabase->Commit(nsAddrDBCommitType::kLargeCommit);
00740 
00741   NS_IF_ADDREF(*addedCard = newCard);
00742   return NS_OK;
00743 }
00744 
00745 NS_IMETHODIMP nsAbMDBDirectory::DropCard(nsIAbCard* aCard, PRBool needToCopyCard)
00746 {
00747   NS_ENSURE_ARG_POINTER(aCard);
00748 
00749   if (mIsQueryURI)
00750     return NS_ERROR_NOT_IMPLEMENTED;
00751 
00752   nsresult rv = NS_OK;
00753 
00754   // Don't add the card if it's not a normal one (ie, they can't be added as members).
00755   PRBool isNormal;
00756   rv = aCard->GetIsANormalCard(&isNormal);
00757   if (!isNormal)
00758     return NS_OK;
00759 
00760   NS_ASSERTION(!mURI.IsEmpty(), "Not initialized?");
00761   if (mIsMailingList == -1)
00762   {
00763     /* directory URIs are of the form
00764      * moz-abmdbdirectory://foo
00765      * mailing list URIs are of the form
00766      * moz-abmdbdirectory://foo/bar
00767      */
00768     NS_ENSURE_TRUE(mURI.Length() > kMDBDirectoryRootLen, NS_ERROR_UNEXPECTED);
00769     mIsMailingList = (strchr(mURI.get() + kMDBDirectoryRootLen, '/')) ? 1 : 0;
00770   }
00771   if (!mDatabase)
00772     rv = GetAbDatabase();
00773 
00774   if (NS_FAILED(rv) || !mDatabase)
00775     return NS_ERROR_FAILURE;
00776 
00777   nsCOMPtr<nsIAbCard> newCard;
00778   nsCOMPtr<nsIAbMDBCard> dbcard;
00779 
00780   if (needToCopyCard) {
00781     dbcard = do_CreateInstance(NS_ABMDBCARD_CONTRACTID, &rv);
00782   NS_ENSURE_SUCCESS(rv, rv);
00783 
00784     newCard = do_QueryInterface(dbcard, &rv);
00785     NS_ENSURE_SUCCESS(rv,rv);
00786   
00787     rv = newCard->Copy(aCard);
00788   NS_ENSURE_SUCCESS(rv, rv);
00789   }
00790   else {
00791     dbcard = do_QueryInterface(aCard, &rv);
00792     NS_ENSURE_SUCCESS(rv,rv);
00793     newCard = aCard;
00794   }  
00795 
00796   dbcard->SetAbDatabase(mDatabase);
00797 
00798   if (mIsMailingList == 1) {
00799     if (needToCopyCard) {
00800       nsCOMPtr <nsIMdbRow> cardRow;
00801       // if card doesn't exist in db, add the card to the directory that 
00802       // contains the mailing list.
00803       mDatabase->FindRowByCard(newCard, getter_AddRefs(cardRow));
00804       if (!cardRow)
00805         mDatabase->CreateNewCardAndAddToDB(newCard, PR_TRUE /* notify */);
00806       else
00807         mDatabase->InitCardFromRow(newCard, cardRow);
00808     }
00809     // since we didn't copy the card, we don't have to notify that it was inserted
00810     mDatabase->CreateNewListCardAndAddToDB(this, m_dbRowID, newCard, PR_FALSE /* notify */);
00811   }
00812   else {
00813     mDatabase->CreateNewCardAndAddToDB(newCard, PR_TRUE /* notify */);
00814   }
00815   mDatabase->Commit(nsAddrDBCommitType::kLargeCommit);
00816   return NS_OK;
00817 }
00818 
00819 NS_IMETHODIMP nsAbMDBDirectory::EditMailListToDatabase(const char *uri, nsIAbCard *listCard)
00820 {
00821   if (mIsQueryURI)
00822     return NS_ERROR_NOT_IMPLEMENTED;
00823 
00824   nsresult rv = NS_OK;
00825 
00826   nsCOMPtr<nsIAddrDatabase>  listDatabase;  
00827 
00828   nsCOMPtr<nsIAddressBook> addressBook = do_GetService(NS_ADDRESSBOOK_CONTRACTID, &rv);
00829   if (NS_SUCCEEDED(rv))
00830     rv = addressBook->GetAbDatabaseFromURI(uri, getter_AddRefs(listDatabase));
00831 
00832   if (listDatabase)
00833   {
00834     listDatabase->EditMailList(this, listCard, PR_TRUE);
00835     listDatabase->Commit(nsAddrDBCommitType::kLargeCommit);
00836     listDatabase = nsnull;
00837 
00838     return NS_OK;
00839 
00840   }
00841   else
00842     return NS_ERROR_FAILURE;
00843 }
00844 
00845 // nsIAddrDBListener methods
00846 
00847 NS_IMETHODIMP nsAbMDBDirectory::OnCardAttribChange(PRUint32 abCode)
00848 {
00849   return NS_OK;
00850 }
00851 
00852 NS_IMETHODIMP nsAbMDBDirectory::OnCardEntryChange
00853 (PRUint32 abCode, nsIAbCard *card)
00854 {
00855   NS_ENSURE_ARG_POINTER(card);
00856   nsCOMPtr<nsISupports> cardSupports(do_QueryInterface(card));
00857   nsresult rv;
00858 
00859   switch (abCode) {
00860   case AB_NotifyInserted:
00861     rv = NotifyItemAdded(cardSupports);
00862     break;
00863   case AB_NotifyDeleted:
00864     rv = NotifyItemDeleted(cardSupports);
00865     break;
00866   case AB_NotifyPropertyChanged:
00867     rv = NotifyItemChanged(cardSupports);
00868     break;
00869   default:
00870     rv = NS_ERROR_UNEXPECTED;
00871     break;
00872   }
00873     
00874           NS_ENSURE_SUCCESS(rv, rv);
00875   return rv;
00876 }
00877 
00878 NS_IMETHODIMP nsAbMDBDirectory::OnListEntryChange
00879 (PRUint32 abCode, nsIAbDirectory *list)
00880 {
00881   nsresult rv = NS_OK;
00882   
00883   if (abCode == AB_NotifyPropertyChanged && list)
00884   {
00885     PRBool bIsMailList = PR_FALSE;
00886     rv = list->GetIsMailList(&bIsMailList);
00887     NS_ENSURE_SUCCESS(rv,rv);
00888     
00889     nsCOMPtr<nsIAbMDBDirectory> dblist(do_QueryInterface(list, &rv));
00890     NS_ENSURE_SUCCESS(rv,rv);
00891 
00892     if (bIsMailList) {
00893         nsXPIDLString pListName;
00894       rv = list->GetDirName(getter_Copies(pListName));
00895       NS_ENSURE_SUCCESS(rv,rv);
00896 
00897       rv = NotifyPropertyChanged(list, "DirName", nsnull, pListName.get());
00898       NS_ENSURE_SUCCESS(rv,rv);
00899     }
00900   }
00901   return rv;
00902 }
00903 
00904 NS_IMETHODIMP nsAbMDBDirectory::OnAnnouncerGoingAway()
00905 {
00906   if (mDatabase)
00907       mDatabase->RemoveListener(this);
00908   return NS_OK;
00909 }
00910 
00911 // nsIAbDirectorySearch methods
00912 
00913 NS_IMETHODIMP nsAbMDBDirectory::StartSearch()
00914 {
00915   if (!mIsQueryURI)
00916     return NS_ERROR_FAILURE;
00917 
00918   nsresult rv;
00919 
00920   mPerformingQuery = PR_TRUE;
00921   mSearchCache.Reset();
00922 
00923   nsCOMPtr<nsIAbDirectoryQueryArguments> arguments = do_CreateInstance(NS_ABDIRECTORYQUERYARGUMENTS_CONTRACTID,&rv);
00924   NS_ENSURE_SUCCESS(rv, rv);
00925 
00926   nsCOMPtr<nsIAbBooleanExpression> expression;
00927   rv = nsAbQueryStringToExpression::Convert(mQueryString.get(),
00928     getter_AddRefs(expression));
00929   NS_ENSURE_SUCCESS(rv, rv);
00930 
00931   rv = arguments->SetExpression(expression);
00932   NS_ENSURE_SUCCESS(rv, rv);
00933 
00934   // Set the return properties to
00935   // return nsIAbCard interfaces
00936   const char *arr = "card:nsIAbCard";
00937   rv = arguments->SetReturnProperties(1, &arr);
00938   NS_ENSURE_SUCCESS(rv, rv);
00939 
00940   // don't search the subdirectories 
00941   // if the current directory is a mailing list, it won't have any subdirectories
00942   // if the current directory is a addressbook, searching both it
00943   // and the subdirectories (the mailing lists), will yield duplicate results
00944   // because every entry in a mailing list will be an entry in the parent addressbook
00945   rv = arguments->SetQuerySubDirectories(PR_FALSE);
00946   NS_ENSURE_SUCCESS(rv, rv);
00947 
00948   // Set the the query listener
00949   nsCOMPtr<nsIAbDirectoryQueryResultListener> queryListener;
00950   nsAbDirSearchListener* _queryListener =
00951     new nsAbDirSearchListener (this);
00952   queryListener = _queryListener;
00953 
00954   // Get the directory without the query
00955   nsCOMPtr<nsIRDFResource> resource;
00956   rv = gRDFService->GetResource (mURINoQuery, getter_AddRefs(resource));
00957   NS_ENSURE_SUCCESS(rv, rv);
00958 
00959   nsCOMPtr<nsIAbDirectory> directory(do_QueryInterface(resource, &rv));
00960   NS_ENSURE_SUCCESS(rv, rv);
00961 
00962   // Initiate the proxy query with the no query directory
00963   nsCOMPtr<nsIAbDirectoryQueryProxy> queryProxy = 
00964       do_CreateInstance(NS_ABDIRECTORYQUERYPROXY_CONTRACTID, &rv);
00965   NS_ENSURE_SUCCESS(rv, rv);
00966 
00967   rv = queryProxy->Initiate(directory);
00968   NS_ENSURE_SUCCESS(rv, rv);
00969 
00970   rv = queryProxy->DoQuery(arguments, queryListener, -1, 0, &mContext);
00971   return NS_OK;
00972 }
00973 
00974 NS_IMETHODIMP nsAbMDBDirectory::StopSearch()
00975 {
00976   if (!mIsQueryURI)
00977     return NS_ERROR_FAILURE;
00978 
00979   return NS_OK;
00980 }
00981 
00982 
00983 // nsAbDirSearchListenerContext methods
00984 
00985 nsresult nsAbMDBDirectory::OnSearchFinished (PRInt32 result)
00986 {
00987   mPerformingQuery = PR_FALSE;
00988   return NS_OK;
00989 }
00990 
00991 nsresult nsAbMDBDirectory::OnSearchFoundCard (nsIAbCard* card)
00992 {
00993   nsVoidKey key (NS_STATIC_CAST(void*, card));
00994   mSearchCache.Put (&key, card);
00995 
00996   // TODO
00997   // Search is synchronous so asserting on the
00998   // datasource will not work since the getChildCards
00999   // method will not have returned with results.
01000   // NotifyItemAdded (card);
01001   return NS_OK;
01002 }
01003 
01004 nsresult nsAbMDBDirectory::GetAbDatabase()
01005 {
01006   NS_ASSERTION(!mURI.IsEmpty(), "Not initialized?");
01007 
01008   nsresult rv = NS_OK;
01009 
01010   if (!mDatabase) {
01011     nsCOMPtr<nsIAddressBook> addressBook = do_GetService(NS_ADDRESSBOOK_CONTRACTID, &rv);
01012     NS_ENSURE_SUCCESS(rv,rv);
01013 
01014     rv = addressBook->GetAbDatabaseFromURI(mURI.get(), getter_AddRefs(mDatabase));
01015     if (NS_SUCCEEDED(rv))
01016       rv = mDatabase->AddListener(this);
01017   }
01018   return rv;
01019 }
01020 
01021 NS_IMETHODIMP nsAbMDBDirectory::HasCardForEmailAddress(const char * aEmailAddress, PRBool * aCardExists)
01022 {
01023   nsCOMPtr<nsIAbCard> card;
01024   nsresult rv = CardForEmailAddress(aEmailAddress, getter_AddRefs(card));
01025   NS_ENSURE_SUCCESS(rv, rv);
01026   
01027   *aCardExists = card ? PR_TRUE : PR_FALSE;
01028   return NS_OK;
01029 }
01030 
01031 NS_IMETHODIMP nsAbMDBDirectory::CardForEmailAddress(const char * aEmailAddress, nsIAbCard ** aAbCard)
01032 {
01033   NS_ENSURE_ARG_POINTER(aAbCard);
01034 
01035   *aAbCard = NULL;
01036 
01037   // Ensure that if we've not been given an email address we never match
01038   // so that we don't fail out unnecessarily and we don't match a blank email
01039   // address against random cards that the user hasn't supplied an email for.
01040   if (!aEmailAddress || !*aEmailAddress)
01041     return NS_OK;
01042 
01043   nsresult rv = NS_OK;
01044   if (!mDatabase)
01045     rv = GetAbDatabase();
01046   if (rv == NS_ERROR_FILE_NOT_FOUND)
01047   {
01048     // If file wasn't found, the card cannot exist.
01049     return NS_OK;
01050   }
01051   NS_ENSURE_SUCCESS(rv, rv);
01052 
01053   mDatabase->GetCardFromAttribute(this, kLowerPriEmailColumn /* see #196777 */, aEmailAddress, PR_TRUE /* caseInsensitive, see bug #191798 */, aAbCard);
01054   if (!*aAbCard) 
01055   {
01056     // fix for bug #187239
01057     // didn't find it as the primary email?  try again, with k2ndEmailColumn ("Additional Email")
01058     // 
01059     // TODO bug #198731
01060     // unlike the kPriEmailColumn, we don't have kLower2ndEmailColumn
01061     // so we will still suffer from bug #196777 for "additional emails"
01062     mDatabase->GetCardFromAttribute(this, k2ndEmailColumn, aEmailAddress, PR_TRUE /* caseInsensitive, see bug #191798 */, aAbCard);
01063   }
01064 
01065   return NS_OK;
01066 }