/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsAbMDBDirectory.h" #include "nsStringGlue.h" #include "nsCOMPtr.h" #include "nsAbBaseCID.h" #include "nsAddrDatabase.h" #include "nsIAbListener.h" #include "nsIAbManager.h" #include "nsIURL.h" #include "nsNetCID.h" #include "nsAbDirectoryQuery.h" #include "nsIAbDirectoryQueryProxy.h" #include "nsAbQueryStringToExpression.h" #include "nsIMutableArray.h" #include "nsArrayEnumerator.h" #include "nsEnumeratorUtils.h" #include "mdb.h" #include "prprf.h" #include "nsIPrefService.h" #include "nsAppDirectoryServiceDefs.h" #include "nsDirectoryServiceUtils.h" #include "nsIFile.h" #include "nsComponentManagerUtils.h" #include "nsMemory.h" #include "nsArrayUtils.h" #include "nsUnicharUtils.h" #include "mozilla/DebugOnly.h" nsAbMDBDirectory::nsAbMDBDirectory(void): nsAbMDBDirProperty(), mPerformingQuery(false) { } nsAbMDBDirectory::~nsAbMDBDirectory(void) { if (mDatabase) { mDatabase->RemoveListener(this); } } NS_IMPL_ISUPPORTS_INHERITED(nsAbMDBDirectory, nsAbMDBDirProperty, nsIAbDirSearchListener, nsIAbDirectorySearch, nsIAddrDBListener) NS_IMETHODIMP nsAbMDBDirectory::Init(const char *aUri) { // We need to ensure that the m_DirPrefId is initialized properly nsDependentCString uri(aUri); // Find the first ? (of the search params) if there is one. // We know we can start at the end of the moz-abmdbdirectory:// because // that's the URI we should have been passed. int32_t searchCharLocation = uri.FindChar('?', kMDBDirectoryRootLen); nsAutoCString URINoQuery; if (searchCharLocation != kNotFound) { URINoQuery = Substring(uri, 0, searchCharLocation); } else { URINoQuery.Assign(uri); } // In the non-query part of the URI, check if we are a mailinglist if (URINoQuery.Find("MailList") != kNotFound) m_IsMailList = true; // Mailing lists don't have their own prefs. if (m_DirPrefId.IsEmpty() && !m_IsMailList) { nsAutoCString filename; // Extract the filename from the uri. filename = Substring(URINoQuery, kMDBDirectoryRootLen); // Get the pref servers and the address book directory branch nsresult rv; nsCOMPtr prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr prefBranch; rv = prefService->GetBranch(NS_LITERAL_CSTRING(PREF_LDAP_SERVER_TREE_NAME ".").get(), getter_AddRefs(prefBranch)); NS_ENSURE_SUCCESS(rv, rv); char** childArray; uint32_t childCount, i; int32_t dotOffset; nsCString childValue; nsDependentCString child; rv = prefBranch->GetChildList("", &childCount, &childArray); NS_ENSURE_SUCCESS(rv, rv); for (i = 0; i < childCount; ++i) { child.Assign(childArray[i]); if (StringEndsWith(child, NS_LITERAL_CSTRING(".filename"))) { if (NS_SUCCEEDED(prefBranch->GetCharPref(child.get(), getter_Copies(childValue)))) { if (childValue == filename) { dotOffset = child.RFindChar('.'); if (dotOffset != -1) { nsAutoCString prefName(StringHead(child, dotOffset)); m_DirPrefId.AssignLiteral(PREF_LDAP_SERVER_TREE_NAME "."); m_DirPrefId.Append(prefName); } } } } } NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(childCount, childArray); NS_ASSERTION(!m_DirPrefId.IsEmpty(), "Error, Could not set m_DirPrefId in nsAbMDBDirectory::Init"); } return nsAbDirProperty::Init(aUri); } //////////////////////////////////////////////////////////////////////////////// nsresult nsAbMDBDirectory::RemoveCardFromAddressList(nsIAbCard* card) { nsresult rv = NS_OK; uint32_t listTotal; int32_t i, j; // These checks ensure we don't run into null pointers // as we did when we caused bug 280463. if (!mDatabase) { rv = GetAbDatabase(); NS_ENSURE_SUCCESS(rv, rv); } if (!m_AddressList) { rv = mDatabase->GetMailingListsFromDB(this); NS_ENSURE_SUCCESS(rv, rv); // If the previous call didn't gives us an m_AddressList (and succeeded) // then we haven't got any mailing lists to try and remove the card from. // So just return without doing anything if (!m_AddressList) return NS_OK; } rv = m_AddressList->GetLength(&listTotal); NS_ENSURE_SUCCESS(rv,rv); for (i = listTotal - 1; i >= 0; i--) { nsCOMPtr listDir(do_QueryElementAt(m_AddressList, i, &rv)); if (listDir) { // First remove the instance in the database mDatabase->DeleteCardFromMailList(listDir, card, false); // Now remove the instance in any lists we hold. nsCOMPtr pAddressLists; listDir->GetAddressLists(getter_AddRefs(pAddressLists)); if (pAddressLists) { uint32_t total; rv = pAddressLists->GetLength(&total); for (j = total - 1; j >= 0; j--) { nsCOMPtr cardInList(do_QueryElementAt(pAddressLists, j, &rv)); bool equals; rv = cardInList->Equals(card, &equals); // should we checking email? if (NS_SUCCEEDED(rv) && equals) pAddressLists->RemoveElementAt(j); } } } } return NS_OK; } NS_IMETHODIMP nsAbMDBDirectory::DeleteDirectory(nsIAbDirectory *directory) { NS_ENSURE_ARG_POINTER(directory); nsCOMPtr database; nsresult rv = GetDatabase(getter_AddRefs(database)); NS_ENSURE_SUCCESS(rv, rv); rv = database->DeleteMailList(directory, this); if (NS_SUCCEEDED(rv)) database->Commit(nsAddrDBCommitType::kLargeCommit); uint32_t dirIndex; if (m_AddressList && NS_SUCCEEDED(m_AddressList->IndexOf(0, directory, &dirIndex))) m_AddressList->RemoveElementAt(dirIndex); // XXX Cast from bool to nsresult rv = static_cast(mSubDirectories.RemoveObject(directory)); NotifyItemDeleted(directory); return rv; } nsresult nsAbMDBDirectory::NotifyItemChanged(nsISupports *item) { nsresult rv; nsCOMPtr abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv,rv); rv = abManager->NotifyItemPropertyChanged(item, nullptr, nullptr, nullptr); NS_ENSURE_SUCCESS(rv,rv); return rv; } nsresult nsAbMDBDirectory::NotifyPropertyChanged(nsIAbDirectory *list, const char *property, const char16_t* oldValue, const char16_t* newValue) { nsresult rv; nsCOMPtr supports = do_QueryInterface(list, &rv); NS_ENSURE_SUCCESS(rv,rv); nsCOMPtr abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv,rv); rv = abManager->NotifyItemPropertyChanged(supports, property, oldValue, newValue); NS_ENSURE_SUCCESS(rv,rv); return rv; } nsresult nsAbMDBDirectory::NotifyItemAdded(nsISupports *item) { nsresult rv = NS_OK; nsCOMPtr abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv); if(NS_SUCCEEDED(rv)) abManager->NotifyDirectoryItemAdded(this, item); return NS_OK; } nsresult nsAbMDBDirectory::NotifyItemDeleted(nsISupports *item) { nsresult rv = NS_OK; nsCOMPtr abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv); if(NS_SUCCEEDED(rv)) abManager->NotifyDirectoryItemDeleted(this, item); return NS_OK; } // nsIAbMDBDirectory methods NS_IMETHODIMP nsAbMDBDirectory::ClearDatabase() { if (mIsQueryURI) return NS_ERROR_NOT_IMPLEMENTED; if (mDatabase) { mDatabase->RemoveListener(this); mDatabase = nullptr; } return NS_OK; } NS_IMETHODIMP nsAbMDBDirectory::RemoveElementsFromAddressList() { if (mIsQueryURI) return NS_ERROR_NOT_IMPLEMENTED; if (m_AddressList) { uint32_t count; mozilla::DebugOnly rv = m_AddressList->GetLength(&count); NS_ASSERTION(NS_SUCCEEDED(rv), "Count failed"); int32_t i; for (i = count - 1; i >= 0; i--) m_AddressList->RemoveElementAt(i); } m_AddressList = nullptr; return NS_OK; } NS_IMETHODIMP nsAbMDBDirectory::RemoveEmailAddressAt(uint32_t aIndex) { if (mIsQueryURI) return NS_ERROR_NOT_IMPLEMENTED; if (m_AddressList) { return m_AddressList->RemoveElementAt(aIndex); } else return NS_ERROR_FAILURE; } NS_IMETHODIMP nsAbMDBDirectory::AddDirectory(const char *uriName, nsIAbDirectory **childDir) { if (mIsQueryURI) return NS_ERROR_NOT_IMPLEMENTED; if (!childDir || !uriName) return NS_ERROR_NULL_POINTER; if (mURI.IsEmpty()) return NS_ERROR_NOT_INITIALIZED; nsresult rv = NS_OK; nsCOMPtr abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr directory; rv = abManager->GetDirectory(nsDependentCString(uriName), getter_AddRefs(directory)); NS_ENSURE_SUCCESS(rv, rv); if (mSubDirectories.IndexOf(directory) == -1) mSubDirectories.AppendObject(directory); NS_IF_ADDREF(*childDir = directory); return rv; } NS_IMETHODIMP nsAbMDBDirectory::GetDatabaseFile(nsIFile **aResult) { NS_ENSURE_ARG_POINTER(aResult); nsCString fileName; nsresult rv = GetStringValue("filename", EmptyCString(), fileName); NS_ENSURE_SUCCESS(rv, rv); if (fileName.IsEmpty()) return NS_ERROR_NOT_INITIALIZED; nsCOMPtr dbFile; rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(dbFile)); NS_ENSURE_SUCCESS(rv, rv); rv = dbFile->AppendNative(fileName); NS_ENSURE_SUCCESS(rv, rv); NS_ADDREF(*aResult = dbFile); return NS_OK; } NS_IMETHODIMP nsAbMDBDirectory::GetDatabase(nsIAddrDatabase **aResult) { NS_ENSURE_ARG_POINTER(aResult); nsresult rv; nsCOMPtr databaseFile; rv = GetDatabaseFile(getter_AddRefs(databaseFile)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr addrDBFactory = do_GetService(NS_ADDRDATABASE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); return addrDBFactory->Open(databaseFile, false /* no create */, true, aResult); } // nsIAbDirectory methods NS_IMETHODIMP nsAbMDBDirectory::GetURI(nsACString &aURI) { if (mURI.IsEmpty()) return NS_ERROR_NOT_INITIALIZED; aURI = mURI; return NS_OK; } NS_IMETHODIMP nsAbMDBDirectory::GetChildNodes(nsISimpleEnumerator* *aResult) { if (mIsQueryURI) return NS_NewEmptyEnumerator(aResult); return NS_NewArrayEnumerator(aResult, mSubDirectories); } NS_IMETHODIMP nsAbMDBDirectory::GetChildCards(nsISimpleEnumerator* *result) { nsresult rv; if (mIsQueryURI) { rv = StartSearch(); NS_ENSURE_SUCCESS(rv, rv); // TODO // Search is synchronous so need to return // results after search is complete nsCOMPtr array(do_CreateInstance(NS_ARRAY_CONTRACTID)); for (auto iter = mSearchCache.Iter(); !iter.Done(); iter.Next()) { array->AppendElement(iter.Data(), false); } return NS_NewArrayEnumerator(result, array); } rv = GetAbDatabase(); if (NS_FAILED(rv) || !mDatabase) return rv; return m_IsMailList ? mDatabase->EnumerateListAddresses(this, result) : mDatabase->EnumerateCards(this, result); } NS_IMETHODIMP nsAbMDBDirectory::GetIsQuery(bool *aResult) { NS_ENSURE_ARG_POINTER(aResult); *aResult = mIsQueryURI; return NS_OK; } NS_IMETHODIMP nsAbMDBDirectory::DeleteCards(nsIArray *aCards) { NS_ENSURE_ARG_POINTER(aCards); nsresult rv = NS_OK; if (mIsQueryURI) { // if this is a query, delete the cards from the directory (without the query) // before we do the delete, make this directory (which represents the search) // a listener on the database, so that it will get notified when the cards are deleted // after delete, remove this query as a listener. nsCOMPtr database; rv = GetDatabase(getter_AddRefs(database)); NS_ENSURE_SUCCESS(rv,rv); rv = database->AddListener(this); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr directory; rv = abManager->GetDirectory(mURINoQuery, getter_AddRefs(directory)); NS_ENSURE_SUCCESS(rv, rv); rv = directory->DeleteCards(aCards); NS_ENSURE_SUCCESS(rv, rv); rv = database->RemoveListener(this); NS_ENSURE_SUCCESS(rv, rv); return rv; } if (!mDatabase) rv = GetAbDatabase(); if (NS_SUCCEEDED(rv) && mDatabase) { uint32_t cardCount; uint32_t i; rv = aCards->GetLength(&cardCount); NS_ENSURE_SUCCESS(rv, rv); for (i = 0; i < cardCount; i++) { nsCOMPtr card(do_QueryElementAt(aCards, i, &rv)); NS_ENSURE_SUCCESS(rv, rv); if (card) { uint32_t rowID; rv = card->GetPropertyAsUint32("DbRowID", &rowID); NS_ENSURE_SUCCESS(rv, rv); if (m_IsMailList) { mDatabase->DeleteCardFromMailList(this, card, true); uint32_t cardTotal = 0; int32_t i; if (m_AddressList) rv = m_AddressList->GetLength(&cardTotal); for (i = cardTotal - 1; i >= 0; i--) { nsCOMPtr arrayCard(do_QueryElementAt(m_AddressList, i, &rv)); if (arrayCard) { // No card can have a row ID of 0 uint32_t arrayRowID = 0; arrayCard->GetPropertyAsUint32("DbRowID", &arrayRowID); if (rowID == arrayRowID) m_AddressList->RemoveElementAt(i); } } } else { mDatabase->DeleteCard(card, true, this); bool bIsMailList = false; card->GetIsMailList(&bIsMailList); if (bIsMailList) { //to do, get mailing list dir side uri and notify nsIAbManager to remove it nsAutoCString listUri(mURI); listUri.AppendLiteral("/MailList"); listUri.AppendInt(rowID); if (!listUri.IsEmpty()) { nsresult rv = NS_OK; nsCOMPtr abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr listDir; rv = abManager->GetDirectory(listUri, getter_AddRefs(listDir)); NS_ENSURE_SUCCESS(rv, rv); uint32_t dirIndex; if (m_AddressList && NS_SUCCEEDED(m_AddressList->IndexOf(0, listDir, &dirIndex))) m_AddressList->RemoveElementAt(dirIndex); mSubDirectories.RemoveObject(listDir); if (listDir) NotifyItemDeleted(listDir); } } else { rv = RemoveCardFromAddressList(card); NS_ENSURE_SUCCESS(rv,rv); } } } } mDatabase->Commit(nsAddrDBCommitType::kLargeCommit); } return rv; } NS_IMETHODIMP nsAbMDBDirectory::HasCard(nsIAbCard *cards, bool *hasCard) { if(!hasCard) return NS_ERROR_NULL_POINTER; if (mIsQueryURI) { *hasCard = mSearchCache.Get(cards, nullptr); return NS_OK; } nsresult rv = NS_OK; if (!mDatabase) rv = GetAbDatabase(); if(NS_SUCCEEDED(rv) && mDatabase) { if(NS_SUCCEEDED(rv)) rv = mDatabase->ContainsCard(cards, hasCard); } return rv; } NS_IMETHODIMP nsAbMDBDirectory::HasDirectory(nsIAbDirectory *dir, bool *hasDir) { if (!hasDir) return NS_ERROR_NULL_POINTER; nsresult rv; nsCOMPtr dbdir(do_QueryInterface(dir, &rv)); NS_ENSURE_SUCCESS(rv, rv); bool bIsMailingList = false; dir->GetIsMailList(&bIsMailingList); if (bIsMailingList) { nsCOMPtr database; rv = GetDatabase(getter_AddRefs(database)); if (NS_SUCCEEDED(rv)) rv = database->ContainsMailList(dir, hasDir); } return rv; } NS_IMETHODIMP nsAbMDBDirectory::HasMailListWithName(const char16_t *aName, bool *aHasList) { NS_ENSURE_ARG_POINTER(aHasList); nsCOMPtr database; nsresult rv = GetDatabase(getter_AddRefs(database)); if (NS_SUCCEEDED(rv)) { rv = database->FindMailListbyUnicodeName(aName, aHasList); if (NS_SUCCEEDED(rv) && *aHasList) return NS_OK; } return rv; } NS_IMETHODIMP nsAbMDBDirectory::AddMailList(nsIAbDirectory *list, nsIAbDirectory **addedList) { NS_ENSURE_ARG_POINTER(addedList); if (mIsQueryURI) return NS_ERROR_NOT_IMPLEMENTED; nsresult rv = NS_OK; if (!mDatabase) rv = GetAbDatabase(); if (NS_FAILED(rv) || !mDatabase) return NS_ERROR_FAILURE; nsCOMPtr dblist(do_QueryInterface(list, &rv)); if (NS_FAILED(rv)) { nsCOMPtr newlist(new nsAbMDBDirProperty); if (!newlist) return NS_ERROR_OUT_OF_MEMORY; rv = newlist->CopyMailList(list); NS_ENSURE_SUCCESS(rv, rv); dblist = do_QueryInterface(newlist, &rv); NS_ENSURE_SUCCESS(rv, rv); mDatabase->CreateMailListAndAddToDB(newlist, true, this); } else mDatabase->CreateMailListAndAddToDB(list, true, this); mDatabase->Commit(nsAddrDBCommitType::kLargeCommit); uint32_t dbRowID; dblist->GetDbRowID(&dbRowID); nsAutoCString listUri(mURI); listUri.AppendLiteral("/MailList"); listUri.AppendInt(dbRowID); nsCOMPtr newList; rv = AddDirectory(listUri.get(), getter_AddRefs(newList)); if (NS_SUCCEEDED(rv) && newList) { nsCOMPtr dbnewList(do_QueryInterface(newList, &rv)); NS_ENSURE_SUCCESS(rv, rv); dbnewList->CopyDBMailList(dblist); AddMailListToDirectory(newList); NotifyItemAdded(newList); } NS_IF_ADDREF(*addedList = newList); return rv; } NS_IMETHODIMP nsAbMDBDirectory::AddCard(nsIAbCard* card, nsIAbCard **addedCard) { if (mIsQueryURI) return NS_ERROR_NOT_IMPLEMENTED; nsresult rv = NS_OK; if (!mDatabase) rv = GetAbDatabase(); if (NS_FAILED(rv) || !mDatabase) return NS_ERROR_FAILURE; if (m_IsMailList) rv = mDatabase->CreateNewListCardAndAddToDB(this, m_dbRowID, card, true /* notify */); else rv = mDatabase->CreateNewCardAndAddToDB(card, true, this); NS_ENSURE_SUCCESS(rv, rv); mDatabase->Commit(nsAddrDBCommitType::kLargeCommit); NS_IF_ADDREF(*addedCard = card); return NS_OK; } NS_IMETHODIMP nsAbMDBDirectory::ModifyCard(nsIAbCard *aModifiedCard) { NS_ENSURE_ARG_POINTER(aModifiedCard); nsresult rv; if (!mDatabase) { rv = GetAbDatabase(); NS_ENSURE_SUCCESS(rv, rv); } rv = mDatabase->EditCard(aModifiedCard, true, this); NS_ENSURE_SUCCESS(rv, rv); return mDatabase->Commit(nsAddrDBCommitType::kLargeCommit); } NS_IMETHODIMP nsAbMDBDirectory::DropCard(nsIAbCard* aCard, bool needToCopyCard) { NS_ENSURE_ARG_POINTER(aCard); if (mIsQueryURI) return NS_ERROR_NOT_IMPLEMENTED; nsresult rv = NS_OK; if (!mDatabase) rv = GetAbDatabase(); if (NS_FAILED(rv) || !mDatabase) return NS_ERROR_FAILURE; nsCOMPtr newCard; if (needToCopyCard) { newCard = do_CreateInstance(NS_ABMDBCARD_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = newCard->Copy(aCard); NS_ENSURE_SUCCESS(rv, rv); } else { newCard = aCard; } if (m_IsMailList) { if (needToCopyCard) { nsCOMPtr cardRow; // if card doesn't exist in db, add the card to the directory that // contains the mailing list. mDatabase->FindRowByCard(newCard, getter_AddRefs(cardRow)); if (!cardRow) mDatabase->CreateNewCardAndAddToDB(newCard, true /* notify */, this); else mDatabase->InitCardFromRow(newCard, cardRow); } // since we didn't copy the card, we don't have to notify that it was inserted mDatabase->CreateNewListCardAndAddToDB(this, m_dbRowID, newCard, false /* notify */); } else { mDatabase->CreateNewCardAndAddToDB(newCard, true /* notify */, this); } mDatabase->Commit(nsAddrDBCommitType::kLargeCommit); return NS_OK; } NS_IMETHODIMP nsAbMDBDirectory::EditMailListToDatabase(nsIAbCard *listCard) { if (mIsQueryURI) return NS_ERROR_NOT_IMPLEMENTED; if (!m_IsMailList) return NS_ERROR_UNEXPECTED; nsresult rv = GetAbDatabase(); NS_ENSURE_SUCCESS(rv, rv); mDatabase->EditMailList(this, listCard, true); mDatabase->Commit(nsAddrDBCommitType::kLargeCommit); return NS_OK; } static bool ContainsDirectory(nsIAbDirectory *parent, nsIAbDirectory *directory) { // If parent is a maillist, 'addressLists' contains AbCards. bool bIsMailList = false; nsresult rv = parent->GetIsMailList(&bIsMailList); NS_ENSURE_SUCCESS(rv, false); if (bIsMailList) return false; nsCOMPtr pAddressLists; parent->GetAddressLists(getter_AddRefs(pAddressLists)); if (pAddressLists) { uint32_t total; rv = pAddressLists->GetLength(&total); for (uint32_t i = 0; i < total; ++i) { nsCOMPtr pList(do_QueryElementAt(pAddressLists, i, &rv)); if (directory == pList) return true; } } return false; } // nsIAddrDBListener methods NS_IMETHODIMP nsAbMDBDirectory::OnCardAttribChange(uint32_t abCode) { return NS_OK; } NS_IMETHODIMP nsAbMDBDirectory::OnCardEntryChange (uint32_t aAbCode, nsIAbCard *aCard, nsIAbDirectory *aParent) { // Don't notify AbManager unless we have the parent if (!aParent) return NS_OK; NS_ENSURE_ARG_POINTER(aCard); nsCOMPtr cardSupports(do_QueryInterface(aCard)); nsresult rv; // Notify when // - any operation is done to a card belonging to this // => if is , or // - a card belonging to a directory which is parent of this is deleted // => if aAbCode is AB_NotifyDeleted && is child of , or // - a card belonging to a directory which is child of this is added/modified // => if aAbCode is !AB_NotifyDeleted && is parent of if (aParent != this) { bool isChild = false; if (aAbCode != AB_NotifyDeleted) isChild = ContainsDirectory(this, aParent); else isChild = ContainsDirectory(aParent, this); if (!isChild) return NS_OK; } switch (aAbCode) { case AB_NotifyInserted: rv = NotifyItemAdded(cardSupports); break; case AB_NotifyDeleted: rv = NotifyItemDeleted(cardSupports); break; case AB_NotifyPropertyChanged: rv = NotifyItemChanged(cardSupports); break; default: rv = NS_ERROR_UNEXPECTED; break; } NS_ENSURE_SUCCESS(rv, rv); return rv; } NS_IMETHODIMP nsAbMDBDirectory::OnListEntryChange (uint32_t abCode, nsIAbDirectory *list) { nsresult rv = NS_OK; if (abCode == AB_NotifyPropertyChanged && list) { bool bIsMailList = false; rv = list->GetIsMailList(&bIsMailList); NS_ENSURE_SUCCESS(rv,rv); nsCOMPtr dblist(do_QueryInterface(list, &rv)); NS_ENSURE_SUCCESS(rv,rv); if (bIsMailList) { nsString listName; rv = list->GetDirName(listName); NS_ENSURE_SUCCESS(rv,rv); rv = NotifyPropertyChanged(list, "DirName", nullptr, listName.get()); NS_ENSURE_SUCCESS(rv,rv); } } return rv; } NS_IMETHODIMP nsAbMDBDirectory::OnAnnouncerGoingAway() { if (mDatabase) mDatabase->RemoveListener(this); return NS_OK; } // nsIAbDirectorySearch methods NS_IMETHODIMP nsAbMDBDirectory::StartSearch() { if (!mIsQueryURI) return NS_ERROR_FAILURE; nsresult rv; mPerformingQuery = true; mSearchCache.Clear(); nsCOMPtr arguments = do_CreateInstance(NS_ABDIRECTORYQUERYARGUMENTS_CONTRACTID,&rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr expression; rv = nsAbQueryStringToExpression::Convert(mQueryString, getter_AddRefs(expression)); NS_ENSURE_SUCCESS(rv, rv); rv = arguments->SetExpression(expression); NS_ENSURE_SUCCESS(rv, rv); // don't search the subdirectories // if the current directory is a mailing list, it won't have any subdirectories // if the current directory is a addressbook, searching both it // and the subdirectories (the mailing lists), will yield duplicate results // because every entry in a mailing list will be an entry in the parent addressbook rv = arguments->SetQuerySubDirectories(false); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); // Get the directory without the query nsCOMPtr directory; rv = abManager->GetDirectory(mURINoQuery, getter_AddRefs(directory)); NS_ENSURE_SUCCESS(rv, rv); // Bug 280232 - something was causing continuous loops in searching. Add a // check here for the directory to search not being a query uri as well in // the hopes that will at least break us out of the continuous loop even if // we don't know how we got into it. bool isQuery; rv = directory->GetIsQuery(&isQuery); NS_ENSURE_SUCCESS(rv, rv); if (isQuery) { NS_ERROR("Attempting to search a directory within a search"); return NS_ERROR_FAILURE; } // Initiate the proxy query with the no query directory nsCOMPtr queryProxy = do_CreateInstance(NS_ABDIRECTORYQUERYPROXY_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = queryProxy->Initiate(); NS_ENSURE_SUCCESS(rv, rv); rv = queryProxy->DoQuery(directory, arguments, this, -1, 0, &mContext); return NS_OK; } NS_IMETHODIMP nsAbMDBDirectory::StopSearch() { if (!mIsQueryURI) return NS_ERROR_FAILURE; return NS_OK; } // nsAbDirSearchListenerContext methods NS_IMETHODIMP nsAbMDBDirectory::OnSearchFinished(int32_t aResult, const nsAString &aErrorMsg) { mPerformingQuery = false; return NS_OK; } NS_IMETHODIMP nsAbMDBDirectory::OnSearchFoundCard(nsIAbCard* card) { mSearchCache.Put(card, card); // TODO // Search is synchronous so asserting on the // datasource will not work since the getChildCards // method will not have returned with results. // NotifyItemAdded (card); return NS_OK; } nsresult nsAbMDBDirectory::GetAbDatabase() { if (mURI.IsEmpty()) return NS_ERROR_NOT_INITIALIZED; if (mDatabase) return NS_OK; nsresult rv; if (m_IsMailList) { // Get the database of the parent directory. nsAutoCString parentURI(mURINoQuery); int32_t pos = parentURI.RFindChar('/'); // If we didn't find a / something really bad has happened if (pos == -1) return NS_ERROR_FAILURE; parentURI = StringHead(parentURI, pos); nsCOMPtr abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr directory; rv = abManager->GetDirectory(parentURI, getter_AddRefs(directory)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr mdbDir(do_QueryInterface(directory, &rv)); NS_ENSURE_SUCCESS(rv, rv); rv = mdbDir->GetDatabase(getter_AddRefs(mDatabase)); } else rv = GetDatabase(getter_AddRefs(mDatabase)); if (NS_SUCCEEDED(rv)) rv = mDatabase->AddListener(this); return rv; } NS_IMETHODIMP nsAbMDBDirectory::CardForEmailAddress(const nsACString &aEmailAddress, nsIAbCard ** aAbCard) { NS_ENSURE_ARG_POINTER(aAbCard); *aAbCard = nullptr; // Ensure that if we've not been given an email address we never match // so that we don't fail out unnecessarily and we don't match a blank email // address against random cards that the user hasn't supplied an email for. if (aEmailAddress.IsEmpty()) return NS_OK; nsresult rv = NS_OK; if (!mDatabase) rv = GetAbDatabase(); if (rv == NS_ERROR_FILE_NOT_FOUND) { // If file wasn't found, the card cannot exist. return NS_OK; } NS_ENSURE_SUCCESS(rv, rv); // Convert Email to lower case in UTF-16 format. This correctly lower-cases // it and doing this change means that we can use a hash lookup in the // database rather than searching and comparing each line individually. NS_ConvertUTF8toUTF16 lowerEmail(aEmailAddress); ToLowerCase(lowerEmail); // If lower email is empty, something went wrong somewhere, e.g. the conversion. // Hence, don't go looking for a card with no email address. Something is wrong. if (lowerEmail.IsEmpty()) return NS_ERROR_FAILURE; mDatabase->GetCardFromAttribute(this, kLowerPriEmailColumn, NS_ConvertUTF16toUTF8(lowerEmail), false, aAbCard); if (!*aAbCard) { mDatabase->GetCardFromAttribute(this, kLower2ndEmailColumn, NS_ConvertUTF16toUTF8(lowerEmail), false, aAbCard); } return NS_OK; } NS_IMETHODIMP nsAbMDBDirectory::GetCardFromProperty(const char *aProperty, const nsACString &aValue, bool caseSensitive, nsIAbCard **result) { NS_ENSURE_ARG(aProperty); NS_ENSURE_ARG_POINTER(result); *result = nullptr; // If the value is empty, don't match. if (aValue.IsEmpty()) return NS_OK; nsresult rv; if (!mDatabase) { rv = GetAbDatabase(); // We can't find the database file, so we can't find the card at all. if (rv == NS_ERROR_FILE_NOT_FOUND) return NS_OK; NS_ENSURE_SUCCESS(rv, rv); } // nsIAddrDatabase has aCaseInsensitive as its parameter return mDatabase->GetCardFromAttribute(this, aProperty, aValue, !caseSensitive, result); } NS_IMETHODIMP nsAbMDBDirectory::GetCardsFromProperty(const char *aProperty, const nsACString &aValue, bool caseSensitive, nsISimpleEnumerator **result) { NS_ENSURE_ARG(aProperty); NS_ENSURE_ARG_POINTER(result); *result = nullptr; if (aValue.IsEmpty()) return NS_OK; if (!mDatabase) { nsresult rv = GetAbDatabase(); if (rv == NS_ERROR_FILE_NOT_FOUND) return NS_OK; NS_ENSURE_SUCCESS(rv, rv); } return mDatabase->GetCardsFromAttribute(this, aProperty, aValue, !caseSensitive, result); }