/* -*- 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 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); 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 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 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 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 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 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 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 cs = do_CreateInstance(NS_BOOLEANCONDITIONSTRING_CONTRACTID, &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", 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; }