diff options
Diffstat (limited to 'mailnews/addrbook/src/nsAbDirectoryQuery.cpp')
-rw-r--r-- | mailnews/addrbook/src/nsAbDirectoryQuery.cpp | 528 |
1 files changed, 528 insertions, 0 deletions
diff --git a/mailnews/addrbook/src/nsAbDirectoryQuery.cpp b/mailnews/addrbook/src/nsAbDirectoryQuery.cpp new file mode 100644 index 000000000..9c9826ac8 --- /dev/null +++ b/mailnews/addrbook/src/nsAbDirectoryQuery.cpp @@ -0,0 +1,528 @@ +/* -*- 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 "nsAbDirectoryQuery.h" +#include "nsAbDirectoryQueryProxy.h" +#include "nsAbUtils.h" +#include "nsAbBooleanExpression.h" +#include "nsArrayUtils.h" +#include "nsComponentManagerUtils.h" +#include "nsStringGlue.h" +#include "nsUnicharUtils.h" +#include "nsIAbDirSearchListener.h" +#include "nsISimpleEnumerator.h" +#include "nsMsgUtils.h" + +NS_IMPL_ISUPPORTS(nsAbDirectoryQuerySimpleBooleanExpression, nsIAbBooleanExpression) + +nsAbDirectoryQuerySimpleBooleanExpression::nsAbDirectoryQuerySimpleBooleanExpression() : + mOperation (nsIAbBooleanOperationTypes::AND) +{ +} + +nsAbDirectoryQuerySimpleBooleanExpression::~nsAbDirectoryQuerySimpleBooleanExpression() +{ +} + +/* attribute nsAbBooleanOperationType operation; */ +NS_IMETHODIMP nsAbDirectoryQuerySimpleBooleanExpression::GetOperation(nsAbBooleanOperationType *aOperation) +{ + if (!aOperation) + return NS_ERROR_NULL_POINTER; + + *aOperation = mOperation; + + return NS_OK; +} +NS_IMETHODIMP nsAbDirectoryQuerySimpleBooleanExpression::SetOperation(nsAbBooleanOperationType aOperation) +{ + if (aOperation != nsIAbBooleanOperationTypes::AND && + aOperation != nsIAbBooleanOperationTypes::OR) + return NS_ERROR_FAILURE; + + mOperation = aOperation; + + return NS_OK; +} + +/* attribute nsIArray expressions; */ +NS_IMETHODIMP nsAbDirectoryQuerySimpleBooleanExpression::GetExpressions(nsIArray **aExpressions) +{ + if (!aExpressions) + return NS_ERROR_NULL_POINTER; + + if (!mExpressions) + { + mExpressions = do_CreateInstance(NS_ARRAY_CONTRACTID); + if (!mExpressions) + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(*aExpressions = mExpressions); + return NS_OK; +} + +NS_IMETHODIMP nsAbDirectoryQuerySimpleBooleanExpression::SetExpressions(nsIArray *aExpressions) +{ + if (!aExpressions) + return NS_ERROR_NULL_POINTER; + + // Ensure all the items are of the right type. + nsresult rv; + uint32_t count; + rv = aExpressions->GetLength(&count); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIAbBooleanConditionString> queryExpression; + + for (uint32_t i = 0; i < count; ++i) + { + queryExpression = do_QueryElementAt(aExpressions, i, &rv); + if (NS_FAILED(rv)) + return NS_ERROR_ILLEGAL_VALUE; + } + + // Values ok, so we can just save and return. + mExpressions = aExpressions; + + return NS_OK; +} + +NS_IMPL_ISUPPORTS(nsAbDirectoryQueryArguments, nsIAbDirectoryQueryArguments) + +nsAbDirectoryQueryArguments::nsAbDirectoryQueryArguments() : + mQuerySubDirectories(true) +{ +} + +nsAbDirectoryQueryArguments::~nsAbDirectoryQueryArguments() +{ +} + +/* attribute nsISupports matchItems; */ +NS_IMETHODIMP nsAbDirectoryQueryArguments::GetExpression(nsISupports** aExpression) +{ + if (!aExpression) + return NS_ERROR_NULL_POINTER; + + NS_IF_ADDREF(*aExpression = mExpression); + return NS_OK; +} + +NS_IMETHODIMP nsAbDirectoryQueryArguments::SetExpression(nsISupports* aExpression) +{ + mExpression = aExpression; + return NS_OK; +} + +/* attribute boolean querySubDirectories; */ +NS_IMETHODIMP nsAbDirectoryQueryArguments::GetQuerySubDirectories(bool* aQuerySubDirectories) +{ + NS_ENSURE_ARG_POINTER(aQuerySubDirectories); + *aQuerySubDirectories = mQuerySubDirectories; + return NS_OK; +} + +NS_IMETHODIMP nsAbDirectoryQueryArguments::SetQuerySubDirectories(bool aQuerySubDirectories) +{ + mQuerySubDirectories = aQuerySubDirectories; + return NS_OK; +} + +NS_IMETHODIMP nsAbDirectoryQueryArguments::GetTypeSpecificArg(nsISupports** aArg) +{ + NS_ENSURE_ARG_POINTER(aArg); + + NS_IF_ADDREF(*aArg = mTypeSpecificArg); + return NS_OK; +} + +NS_IMETHODIMP nsAbDirectoryQueryArguments::SetTypeSpecificArg(nsISupports* aArg) +{ + mTypeSpecificArg = aArg; + return NS_OK; +} + +NS_IMETHODIMP nsAbDirectoryQueryArguments::GetFilter(nsACString & aFilter) +{ + aFilter.Assign(mFilter); + return NS_OK; +} + +NS_IMETHODIMP nsAbDirectoryQueryArguments::SetFilter(const nsACString & aFilter) +{ + mFilter.Assign(aFilter); + return NS_OK; +} + +NS_IMPL_ISUPPORTS(nsAbDirectoryQueryPropertyValue, nsIAbDirectoryQueryPropertyValue) + +nsAbDirectoryQueryPropertyValue::nsAbDirectoryQueryPropertyValue() +{ +} + +nsAbDirectoryQueryPropertyValue::nsAbDirectoryQueryPropertyValue(const char* aName, + const char16_t* aValue) +{ + mName = aName; + mValue = aValue; +} + +nsAbDirectoryQueryPropertyValue::nsAbDirectoryQueryPropertyValue(const char* aName, + nsISupports* aValueISupports) +{ + mName = aName; + mValueISupports = aValueISupports; +} + +nsAbDirectoryQueryPropertyValue::~nsAbDirectoryQueryPropertyValue() +{ +} + +/* read only attribute string name; */ +NS_IMETHODIMP nsAbDirectoryQueryPropertyValue::GetName(char* *aName) +{ + *aName = mName.IsEmpty() ? 0 : ToNewCString(mName); + + return NS_OK; +} + +/* read only attribute wstring value; */ +NS_IMETHODIMP nsAbDirectoryQueryPropertyValue::GetValue(char16_t* *aValue) +{ + *aValue = ToNewUnicode(mValue); + if (!(*aValue)) + return NS_ERROR_OUT_OF_MEMORY; + else + return NS_OK; +} + +/* readonly attribute nsISupports valueISupports; */ +NS_IMETHODIMP nsAbDirectoryQueryPropertyValue::GetValueISupports(nsISupports* *aValueISupports) +{ + if (!mValueISupports) + return NS_ERROR_NULL_POINTER; + + NS_IF_ADDREF(*aValueISupports = mValueISupports); + return NS_OK; +} + +/* Implementation file */ +NS_IMPL_ISUPPORTS(nsAbDirectoryQuery, nsIAbDirectoryQuery) + +nsAbDirectoryQuery::nsAbDirectoryQuery() +{ +} + +nsAbDirectoryQuery::~nsAbDirectoryQuery() +{ +} + +NS_IMETHODIMP nsAbDirectoryQuery::DoQuery(nsIAbDirectory *aDirectory, + nsIAbDirectoryQueryArguments* arguments, + nsIAbDirSearchListener* listener, + int32_t resultLimit, int32_t timeOut, + int32_t* _retval) +{ + NS_ENSURE_ARG_POINTER(aDirectory); + + nsCOMPtr<nsISupports> supportsExpression; + nsresult rv = arguments->GetExpression(getter_AddRefs(supportsExpression)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIAbBooleanExpression> expression(do_QueryInterface(supportsExpression, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + bool doSubDirectories; + rv = arguments->GetQuerySubDirectories(&doSubDirectories); + NS_ENSURE_SUCCESS(rv, rv); + + rv = query(aDirectory, expression, listener, doSubDirectories, &resultLimit); + + rv = NS_FAILED(rv) ? queryError(listener) : queryFinished(listener); + + *_retval = 0; + return rv; +} + +/* void stopQuery (in long contextID); */ +NS_IMETHODIMP nsAbDirectoryQuery::StopQuery(int32_t contextID) +{ + return NS_OK; +} + + +nsresult nsAbDirectoryQuery::query(nsIAbDirectory* directory, + nsIAbBooleanExpression* expression, + nsIAbDirSearchListener* listener, + bool doSubDirectories, + int32_t* resultLimit) +{ + if (*resultLimit == 0) + return NS_OK; + + nsresult rv = queryCards(directory, expression, listener, resultLimit); + NS_ENSURE_SUCCESS(rv, rv); + + if (doSubDirectories && resultLimit != 0) + { + rv = queryChildren(directory, expression, listener, doSubDirectories, + resultLimit); + NS_ENSURE_SUCCESS(rv, rv); + } + + return rv; +} + +nsresult nsAbDirectoryQuery::queryChildren(nsIAbDirectory* directory, + nsIAbBooleanExpression* expression, + nsIAbDirSearchListener* listener, + bool doSubDirectories, + int32_t* resultLimit) +{ + nsresult rv = NS_OK; + + nsCOMPtr<nsISimpleEnumerator> subDirectories; + rv = directory->GetChildNodes(getter_AddRefs(subDirectories)); + NS_ENSURE_SUCCESS(rv, rv); + + bool hasMore; + while (NS_SUCCEEDED(rv = subDirectories->HasMoreElements(&hasMore)) && hasMore) + { + nsCOMPtr<nsISupports> item; + rv = subDirectories->GetNext (getter_AddRefs (item)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIAbDirectory> subDirectory(do_QueryInterface(item, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = query(subDirectory, expression, listener, doSubDirectories, resultLimit); + NS_ENSURE_SUCCESS(rv, rv); + + } + return NS_OK; +} + +nsresult nsAbDirectoryQuery::queryCards(nsIAbDirectory* directory, + nsIAbBooleanExpression* expression, + nsIAbDirSearchListener* listener, + int32_t* resultLimit) +{ + nsresult rv = NS_OK; + + nsCOMPtr<nsISimpleEnumerator> cards; + rv = directory->GetChildCards(getter_AddRefs(cards)); + if (NS_FAILED(rv)) + { + if (rv != NS_ERROR_NOT_IMPLEMENTED) + NS_ENSURE_SUCCESS(rv, rv); + else + return NS_OK; + } + + if (!cards) + return NS_OK; + + bool more; + while (NS_SUCCEEDED(cards->HasMoreElements(&more)) && more) + { + nsCOMPtr<nsISupports> item; + rv = cards->GetNext(getter_AddRefs(item)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIAbCard> card(do_QueryInterface(item, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = matchCard (card, expression, listener, resultLimit); + NS_ENSURE_SUCCESS(rv, rv); + + if (*resultLimit == 0) + return NS_OK; + } + + return NS_OK; +} + +nsresult nsAbDirectoryQuery::matchCard(nsIAbCard* card, + nsIAbBooleanExpression* expression, + nsIAbDirSearchListener* listener, + int32_t* resultLimit) +{ + bool matchFound = false; + nsresult rv = matchCardExpression(card, expression, &matchFound); + NS_ENSURE_SUCCESS(rv, rv); + + if (matchFound) + { + (*resultLimit)--; + rv = queryMatch(card, listener); + NS_ENSURE_SUCCESS(rv, rv); + } + + return rv; +} + +nsresult nsAbDirectoryQuery::matchCardExpression(nsIAbCard* card, + nsIAbBooleanExpression* expression, + bool* result) +{ + nsAbBooleanOperationType operation; + nsresult rv = expression->GetOperation (&operation); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIArray> childExpressions; + rv = expression->GetExpressions (getter_AddRefs (childExpressions)); + NS_ENSURE_SUCCESS(rv, rv); + + uint32_t count; + rv = childExpressions->GetLength(&count); + NS_ENSURE_SUCCESS(rv, rv); + + if (operation == nsIAbBooleanOperationTypes::NOT && + count > 1) + return NS_ERROR_FAILURE; + + bool value = *result = false; + nsCOMPtr<nsIAbBooleanConditionString> childCondition; + nsCOMPtr<nsIAbBooleanExpression> childExpression; + + for (uint32_t i = 0; i < count; i++) + { + childCondition = do_QueryElementAt(childExpressions, i, &rv); + if (NS_SUCCEEDED(rv)) + { + rv = matchCardCondition (card, childCondition, &value); + NS_ENSURE_SUCCESS(rv, rv); + } + else + { + childExpression = do_QueryElementAt(childExpressions, i, &rv); + if (NS_SUCCEEDED(rv)) + { + rv = matchCardExpression (card, childExpression, &value); + NS_ENSURE_SUCCESS(rv, rv); + } + else + return NS_ERROR_FAILURE; + } + if (operation == nsIAbBooleanOperationTypes::OR && value) + break; + else if (operation == nsIAbBooleanOperationTypes::AND && !value) + break; + else if (operation == nsIAbBooleanOperationTypes::NOT) + value = !value; + } + *result = value; + + return NS_OK; +} + +nsresult nsAbDirectoryQuery::matchCardCondition(nsIAbCard* card, + nsIAbBooleanConditionString* condition, + bool* matchFound) +{ + nsAbBooleanConditionType conditionType; + nsresult rv = condition->GetCondition (&conditionType); + NS_ENSURE_SUCCESS(rv, rv); + + nsCString name; + rv = condition->GetName (getter_Copies (name)); + NS_ENSURE_SUCCESS(rv, rv); + + if (name.Equals ("card:nsIAbCard")) + { + *matchFound = (conditionType == nsIAbBooleanConditionTypes::Exists); + return NS_OK; + } + + nsString matchValue; + rv = condition->GetValue (getter_Copies (matchValue)); + NS_ENSURE_SUCCESS(rv, rv); + + if (name.EqualsLiteral("IsMailList")) + { + bool isMailList; + rv = card->GetIsMailList(&isMailList); + NS_ENSURE_SUCCESS(rv, rv); + + // Only equals is supported. + if (conditionType != nsIAbBooleanConditionTypes::Is) + return NS_ERROR_FAILURE; + + *matchFound = isMailList ? matchValue.EqualsLiteral("TRUE") : + matchValue.EqualsLiteral("FALSE"); + return NS_OK; + } + + nsString value; + (void)card->GetPropertyAsAString(name.get(), value); + + if (value.IsEmpty()) + { + *matchFound = (conditionType == nsIAbBooleanConditionTypes::DoesNotExist) ? + true : false; + return NS_OK; + } + + /* TODO + * What about allowing choice between case insensitive + * and case sensitive comparisons? + * + */ + switch (conditionType) + { + case nsIAbBooleanConditionTypes::Exists: + *matchFound = true; + break; + case nsIAbBooleanConditionTypes::Contains: + *matchFound = CaseInsensitiveFindInReadable(matchValue, value); + break; + case nsIAbBooleanConditionTypes::DoesNotContain: + *matchFound = !CaseInsensitiveFindInReadable(matchValue, value); + break; + case nsIAbBooleanConditionTypes::Is: + *matchFound = value.Equals(matchValue, nsCaseInsensitiveStringComparator()); + break; + case nsIAbBooleanConditionTypes::IsNot: + *matchFound = !value.Equals(matchValue, nsCaseInsensitiveStringComparator()); + break; + case nsIAbBooleanConditionTypes::BeginsWith: + *matchFound = StringBeginsWith(value, matchValue, nsCaseInsensitiveStringComparator()); + break; + case nsIAbBooleanConditionTypes::LessThan: + *matchFound = Compare(value, matchValue, nsCaseInsensitiveStringComparator()) < 0; + break; + case nsIAbBooleanConditionTypes::GreaterThan: + *matchFound = Compare(value, matchValue, nsCaseInsensitiveStringComparator()) > 0; + break; + case nsIAbBooleanConditionTypes::EndsWith: + *matchFound = StringEndsWith(value, matchValue, nsCaseInsensitiveStringComparator()); + break; + case nsIAbBooleanConditionTypes::SoundsLike: + case nsIAbBooleanConditionTypes::RegExp: + *matchFound = false; + break; + default: + *matchFound = false; + } + + return rv; +} + +nsresult nsAbDirectoryQuery::queryMatch(nsIAbCard* card, + nsIAbDirSearchListener* listener) +{ + return listener->OnSearchFoundCard(card); +} + +nsresult nsAbDirectoryQuery::queryFinished(nsIAbDirSearchListener* listener) +{ + return listener->OnSearchFinished(nsIAbDirectoryQueryResultListener::queryResultComplete, EmptyString()); +} + +nsresult nsAbDirectoryQuery::queryError(nsIAbDirSearchListener* listener) +{ + return listener->OnSearchFinished(nsIAbDirectoryQueryResultListener::queryResultError, EmptyString()); +} |