summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/addrbook/src/nsAbQueryStringToExpression.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/addrbook/src/nsAbQueryStringToExpression.cpp')
-rw-r--r--comm/mailnews/addrbook/src/nsAbQueryStringToExpression.cpp293
1 files changed, 293 insertions, 0 deletions
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<nsISupports> 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<nsIAbBooleanExpression> 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<nsIAbBooleanExpression> 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<nsIAbBooleanConditionString> 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<RefPtr<nsISupports>> expressions;
+
+ // Case: ")(*)(*)....(*))"
+ // printf ("Case: )(*)(*)....(*)): %s\n", *index);
+ while (**index == '(') {
+ nsCOMPtr<nsISupports> 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<nsIAbBooleanConditionString> 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<nsIAbBooleanExpression> 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<nsIAbBooleanConditionString> 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<nsITextToSubURI> 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;
+}