diff options
Diffstat (limited to 'mailnews/addrbook/src/nsAbMDBDirectory.cpp')
-rw-r--r-- | mailnews/addrbook/src/nsAbMDBDirectory.cpp | 1125 |
1 files changed, 1125 insertions, 0 deletions
diff --git a/mailnews/addrbook/src/nsAbMDBDirectory.cpp b/mailnews/addrbook/src/nsAbMDBDirectory.cpp new file mode 100644 index 000000000..be4799cf1 --- /dev/null +++ b/mailnews/addrbook/src/nsAbMDBDirectory.cpp @@ -0,0 +1,1125 @@ +/* -*- 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<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIPrefBranch> 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<nsIAbDirectory> 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<nsIMutableArray> pAddressLists; + listDir->GetAddressLists(getter_AddRefs(pAddressLists)); + if (pAddressLists) + { + uint32_t total; + rv = pAddressLists->GetLength(&total); + for (j = total - 1; j >= 0; j--) + { + nsCOMPtr<nsIAbCard> 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<nsIAddrDatabase> 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<nsresult>(mSubDirectories.RemoveObject(directory)); + + NotifyItemDeleted(directory); + return rv; +} + +nsresult nsAbMDBDirectory::NotifyItemChanged(nsISupports *item) +{ + nsresult rv; + nsCOMPtr<nsIAbManager> 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<nsISupports> supports = do_QueryInterface(list, &rv); + NS_ENSURE_SUCCESS(rv,rv); + + nsCOMPtr<nsIAbManager> 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<nsIAbManager> 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<nsIAbManager> 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<nsresult> 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<nsIAbManager> abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIAbDirectory> 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<nsIFile> 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<nsIFile> databaseFile; + rv = GetDatabaseFile(getter_AddRefs(databaseFile)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIAddrDatabase> 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<nsIMutableArray> 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<nsIAddrDatabase> database; + rv = GetDatabase(getter_AddRefs(database)); + NS_ENSURE_SUCCESS(rv,rv); + + rv = database->AddListener(this); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIAbManager> abManager = + do_GetService(NS_ABMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIAbDirectory> 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<nsIAbCard> 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<nsIAbCard> 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<nsIAbManager> abManager = + do_GetService(NS_ABMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIAbDirectory> 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<nsIAbMDBDirectory> dbdir(do_QueryInterface(dir, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + bool bIsMailingList = false; + dir->GetIsMailList(&bIsMailingList); + if (bIsMailingList) + { + nsCOMPtr<nsIAddrDatabase> 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<nsIAddrDatabase> 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<nsIAbMDBDirectory> dblist(do_QueryInterface(list, &rv)); + if (NS_FAILED(rv)) + { + nsCOMPtr<nsIAbDirectory> 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<nsIAbDirectory> newList; + rv = AddDirectory(listUri.get(), getter_AddRefs(newList)); + if (NS_SUCCEEDED(rv) && newList) + { + nsCOMPtr<nsIAbMDBDirectory> 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<nsIAbCard> 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 <nsIMdbRow> 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<nsIMutableArray> pAddressLists; + parent->GetAddressLists(getter_AddRefs(pAddressLists)); + if (pAddressLists) + { + uint32_t total; + rv = pAddressLists->GetLength(&total); + for (uint32_t i = 0; i < total; ++i) + { + nsCOMPtr<nsIAbDirectory> 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<nsISupports> cardSupports(do_QueryInterface(aCard)); + nsresult rv; + + // Notify when + // - any operation is done to a card belonging to this + // => if <this> is <aParent>, or + // - a card belonging to a directory which is parent of this is deleted + // => if aAbCode is AB_NotifyDeleted && <this> is child of <aParent>, or + // - a card belonging to a directory which is child of this is added/modified + // => if aAbCode is !AB_NotifyDeleted && <this> is parent of <aParent> + + 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<nsIAbMDBDirectory> 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<nsIAbDirectoryQueryArguments> arguments = do_CreateInstance(NS_ABDIRECTORYQUERYARGUMENTS_CONTRACTID,&rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIAbBooleanExpression> 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<nsIAbManager> abManager = + do_GetService(NS_ABMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // Get the directory without the query + nsCOMPtr<nsIAbDirectory> 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<nsIAbDirectoryQueryProxy> 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<nsIAbManager> abManager = + do_GetService(NS_ABMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIAbDirectory> directory; + rv = abManager->GetDirectory(parentURI, getter_AddRefs(directory)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIAbMDBDirectory> 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); +} |