summaryrefslogtreecommitdiffstats
path: root/mailnews/addrbook/src/nsAbQueryStringToExpression.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/addrbook/src/nsAbQueryStringToExpression.cpp')
-rw-r--r--mailnews/addrbook/src/nsAbQueryStringToExpression.cpp337
1 files changed, 337 insertions, 0 deletions
diff --git a/mailnews/addrbook/src/nsAbQueryStringToExpression.cpp b/mailnews/addrbook/src/nsAbQueryStringToExpression.cpp
new file mode 100644
index 000000000..fe1f22e00
--- /dev/null
+++ b/mailnews/addrbook/src/nsAbQueryStringToExpression.cpp
@@ -0,0 +1,337 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 "nsStringGlue.h"
+#include "nsITextToSubURI.h"
+#include "nsAbBooleanExpression.h"
+#include "nsAbBaseCID.h"
+#include "plstr.h"
+#include "nsIMutableArray.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);
+
+ NS_IF_ADDREF(*expression = e);
+ return rv;
+}
+
+nsresult nsAbQueryStringToExpression::ParseExpression (
+ const char** index,
+ nsISupports** expression)
+{
+ nsresult rv;
+
+ 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);
+
+ NS_IF_ADDREF(*expression = e);
+ }
+ // Case" "(*)"
+ else if (*indexBracket == ')')
+ {
+ // printf ("Case: (*): %s\n", *index);
+
+ nsCOMPtr<nsIAbBooleanConditionString> conditionString;
+ rv = ParseCondition (index, indexBracket,
+ getter_AddRefs(conditionString));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ NS_IF_ADDREF(*expression = conditionString);
+ }
+
+ if (**index != ')')
+ return NS_ERROR_FAILURE;
+
+ (*index)++;
+
+ return NS_OK;
+}
+
+
+nsresult nsAbQueryStringToExpression::ParseExpressions (
+ const char** index,
+ nsIAbBooleanExpression* expression)
+{
+ nsresult rv;
+ nsCOMPtr<nsIMutableArray> expressions(do_CreateInstance(NS_ARRAY_CONTRACTID,
+ &rv));
+ if (NS_FAILED(rv))
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ // 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, false);
+ }
+
+ 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);
+
+ NS_IF_ADDREF(*conditionString = c);
+ 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(NS_BOOLEANEXPRESSION_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ NS_IF_ADDREF(*expression = expr);
+
+ rv = expr->SetOperation (op);
+ 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
+ return NS_ERROR_FAILURE;
+
+ nsresult rv;
+
+ nsCOMPtr<nsIAbBooleanConditionString> cs = do_CreateInstance(NS_BOOLEANCONDITIONSTRING_CONTRACTID, &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",
+ attribute, getter_Copies(attributeUCS2));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = textToSubURI->UnEscapeAndConvert("UTF-8",
+ value, getter_Copies(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);
+ }
+
+
+ NS_IF_ADDREF(*conditionString = cs);
+ return NS_OK;
+}
+
+