summaryrefslogtreecommitdiffstats
path: root/mailnews/addrbook/src/nsAbMDBDirectory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/addrbook/src/nsAbMDBDirectory.cpp')
-rw-r--r--mailnews/addrbook/src/nsAbMDBDirectory.cpp1125
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);
+}