From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../addrbook/src/nsAbQueryStringToExpression.cpp | 293 +++++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 comm/mailnews/addrbook/src/nsAbQueryStringToExpression.cpp (limited to 'comm/mailnews/addrbook/src/nsAbQueryStringToExpression.cpp') diff --git a/comm/mailnews/addrbook/src/nsAbQueryStringToExpression.cpp b/comm/mailnews/addrbook/src/nsAbQueryStringToExpression.cpp new file mode 100644 index 0000000000..bf5e158de3 --- /dev/null +++ b/comm/mailnews/addrbook/src/nsAbQueryStringToExpression.cpp @@ -0,0 +1,293 @@ +/* -*- 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 "nsAbQueryStringToExpression.h" + +#include "nsComponentManagerUtils.h" +#include "nsServiceManagerUtils.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsITextToSubURI.h" +#include "nsAbBooleanExpression.h" +#include "plstr.h" + +/** + * This code parses the query expression passed in as an addressbook URI. + * The expression takes the form: + * (BOOL1(FIELD1,OP1,VALUE1)..(FIELDn,OPn,VALUEn)(BOOL2(FIELD1,OP1,VALUE1)...)...) + * + * BOOLn A boolean operator joining subsequent terms delimited by (). + * For possible values see CreateBooleanExpression(). + * FIELDn An addressbook card data field. + * OPn An operator for the search term. + * For possible values see CreateBooleanConditionString(). + * VALUEn The value to be matched in the FIELDn via the OPn operator. + * The value must be URL encoded by the caller, if it contains any + * special characters including '(' and ')'. + */ +nsresult nsAbQueryStringToExpression::Convert( + const nsACString& aQueryString, nsIAbBooleanExpression** expression) { + nsresult rv; + + nsAutoCString q(aQueryString); + q.StripWhitespace(); + const char* queryChars = q.get(); + + nsCOMPtr s; + rv = ParseExpression(&queryChars, getter_AddRefs(s)); + NS_ENSURE_SUCCESS(rv, rv); + + // Case: Not end of string + if (*queryChars != 0) return NS_ERROR_FAILURE; + + nsCOMPtr e(do_QueryInterface(s, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + e.forget(expression); + return rv; +} + +nsresult nsAbQueryStringToExpression::ParseExpression( + const char** index, nsISupports** expression) { + nsresult rv; + + if (**index == '?') { + (*index)++; + } + + if (**index != '(') return NS_ERROR_FAILURE; + + const char* indexBracket = *index + 1; + while (*indexBracket && *indexBracket != '(' && *indexBracket != ')') + indexBracket++; + + // Case: End of string + if (*indexBracket == 0) return NS_ERROR_FAILURE; + + // Case: "((" or "()" + if (indexBracket == *index + 1) { + return NS_ERROR_FAILURE; + } + // Case: "(*(" + else if (*indexBracket == '(') { + // printf ("Case: (*(: %s\n", *index); + + nsCString operation; + rv = ParseOperationEntry(*index, indexBracket, getter_Copies(operation)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr e; + rv = CreateBooleanExpression(operation.get(), getter_AddRefs(e)); + NS_ENSURE_SUCCESS(rv, rv); + + // Case: "(*)(*)....(*))" + *index = indexBracket; + rv = ParseExpressions(index, e); + NS_ENSURE_SUCCESS(rv, rv); + + e.forget(expression); + } + // Case" "(*)" + else if (*indexBracket == ')') { + // printf ("Case: (*): %s\n", *index); + + nsCOMPtr conditionString; + rv = ParseCondition(index, indexBracket, getter_AddRefs(conditionString)); + NS_ENSURE_SUCCESS(rv, rv); + + conditionString.forget(expression); + } + + if (**index != ')') return NS_ERROR_FAILURE; + + (*index)++; + + return NS_OK; +} + +nsresult nsAbQueryStringToExpression::ParseExpressions( + const char** index, nsIAbBooleanExpression* expression) { + nsresult rv; + nsTArray> expressions; + + // Case: ")(*)(*)....(*))" + // printf ("Case: )(*)(*)....(*)): %s\n", *index); + while (**index == '(') { + nsCOMPtr childExpression; + rv = ParseExpression(index, getter_AddRefs(childExpression)); + NS_ENSURE_SUCCESS(rv, rv); + + expressions.AppendElement(childExpression); + } + + if (**index == 0) return NS_ERROR_FAILURE; + + // Case: "))" + // printf ("Case: )): %s\n", *index); + + if (**index != ')') return NS_ERROR_FAILURE; + + expression->SetExpressions(expressions); + + return NS_OK; +} + +nsresult nsAbQueryStringToExpression::ParseCondition( + const char** index, const char* indexBracketClose, + nsIAbBooleanConditionString** conditionString) { + nsresult rv; + + (*index)++; + + nsCString entries[3]; + for (int i = 0; i < 3; i++) { + rv = ParseConditionEntry(index, indexBracketClose, + getter_Copies(entries[i])); + NS_ENSURE_SUCCESS(rv, rv); + + if (*index == indexBracketClose) break; + } + + if (*index != indexBracketClose) return NS_ERROR_FAILURE; + + nsCOMPtr c; + rv = CreateBooleanConditionString(entries[0].get(), entries[1].get(), + entries[2].get(), getter_AddRefs(c)); + NS_ENSURE_SUCCESS(rv, rv); + + c.forget(conditionString); + return NS_OK; +} + +nsresult nsAbQueryStringToExpression::ParseConditionEntry( + const char** index, const char* indexBracketClose, char** entry) { + const char* indexDeliminator = *index; + while (indexDeliminator != indexBracketClose && *indexDeliminator != ',') + indexDeliminator++; + + int entryLength = indexDeliminator - *index; + if (entryLength) + *entry = PL_strndup(*index, entryLength); + else + *entry = 0; + + if (indexDeliminator != indexBracketClose) + *index = indexDeliminator + 1; + else + *index = indexDeliminator; + + return NS_OK; +} + +nsresult nsAbQueryStringToExpression::ParseOperationEntry( + const char* indexBracketOpen1, const char* indexBracketOpen2, + char** operation) { + int operationLength = indexBracketOpen2 - indexBracketOpen1 - 1; + if (operationLength) + *operation = PL_strndup(indexBracketOpen1 + 1, operationLength); + else + *operation = 0; + + return NS_OK; +} + +nsresult nsAbQueryStringToExpression::CreateBooleanExpression( + const char* operation, nsIAbBooleanExpression** expression) { + nsAbBooleanOperationType op; + if (PL_strcasecmp(operation, "and") == 0) + op = nsIAbBooleanOperationTypes::AND; + else if (PL_strcasecmp(operation, "or") == 0) + op = nsIAbBooleanOperationTypes::OR; + else if (PL_strcasecmp(operation, "not") == 0) + op = nsIAbBooleanOperationTypes::NOT; + else + return NS_ERROR_FAILURE; + + nsresult rv; + + nsCOMPtr expr = + do_CreateInstance("@mozilla.org/boolean-expression/n-peer;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = expr->SetOperation(op); + expr.forget(expression); + return rv; +} + +nsresult nsAbQueryStringToExpression::CreateBooleanConditionString( + const char* attribute, const char* condition, const char* value, + nsIAbBooleanConditionString** conditionString) { + if (attribute == 0 || condition == 0 || value == 0) return NS_ERROR_FAILURE; + + nsAbBooleanConditionType c; + + if (PL_strcasecmp(condition, "=") == 0) + c = nsIAbBooleanConditionTypes::Is; + else if (PL_strcasecmp(condition, "!=") == 0) + c = nsIAbBooleanConditionTypes::IsNot; + else if (PL_strcasecmp(condition, "lt") == 0) + c = nsIAbBooleanConditionTypes::LessThan; + else if (PL_strcasecmp(condition, "gt") == 0) + c = nsIAbBooleanConditionTypes::GreaterThan; + else if (PL_strcasecmp(condition, "bw") == 0) + c = nsIAbBooleanConditionTypes::BeginsWith; + else if (PL_strcasecmp(condition, "ew") == 0) + c = nsIAbBooleanConditionTypes::EndsWith; + else if (PL_strcasecmp(condition, "c") == 0) + c = nsIAbBooleanConditionTypes::Contains; + else if (PL_strcasecmp(condition, "!c") == 0) + c = nsIAbBooleanConditionTypes::DoesNotContain; + else if (PL_strcasecmp(condition, "~=") == 0) + c = nsIAbBooleanConditionTypes::SoundsLike; + else if (PL_strcasecmp(condition, "regex") == 0) + c = nsIAbBooleanConditionTypes::RegExp; + else if (PL_strcasecmp(condition, "ex") == 0) + c = nsIAbBooleanConditionTypes::Exists; + else if (PL_strcasecmp(condition, "!ex") == 0) + c = nsIAbBooleanConditionTypes::DoesNotExist; + else + return NS_ERROR_FAILURE; + + nsresult rv; + + nsCOMPtr cs = do_CreateInstance( + "@mozilla.org/boolean-expression/condition-string;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = cs->SetCondition(c); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr textToSubURI = + do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) { + nsString attributeUCS2; + nsString valueUCS2; + + rv = textToSubURI->UnEscapeAndConvert( + "UTF-8"_ns, nsDependentCString(attribute), attributeUCS2); + NS_ENSURE_SUCCESS(rv, rv); + + rv = textToSubURI->UnEscapeAndConvert("UTF-8"_ns, nsDependentCString(value), + valueUCS2); + NS_ENSURE_SUCCESS(rv, rv); + + NS_ConvertUTF16toUTF8 attributeUTF8(attributeUCS2); + + rv = cs->SetName(attributeUTF8.get()); + NS_ENSURE_SUCCESS(rv, rv); + rv = cs->SetValue(valueUCS2.get()); + NS_ENSURE_SUCCESS(rv, rv); + } else { + NS_ConvertUTF8toUTF16 valueUCS2(value); + + rv = cs->SetName(attribute); + NS_ENSURE_SUCCESS(rv, rv); + rv = cs->SetValue(valueUCS2.get()); + NS_ENSURE_SUCCESS(rv, rv); + } + + cs.forget(conditionString); + return NS_OK; +} -- cgit v1.2.3