From 1b65e834c3d3281de9e0eb74e04def6ded8baa14 Mon Sep 17 00:00:00 2001 From: Marc Blank Date: Wed, 14 Sep 2011 16:24:32 -0700 Subject: [PATCH] Allow multiple wildcards in providers.xml; add hotmail domains * Change handling of the providers.xml file to allow asterisk as a placeholder for an individual domain name part (the previous behavior was a very greedy wildcard) * Add hotmail aliases using the new scheme * Update unit tests Bug: 5318329 Change-Id: I73a0dfcb956830b18c5460a1b3ddfc58459d08c9 --- res/xml/providers.xml | 39 +++++- .../activity/setup/AccountSettingsUtils.java | 130 +++++------------- .../setup/AccountSettingsUtilsTests.java | 111 +++++---------- 3 files changed, 102 insertions(+), 178 deletions(-) diff --git a/res/xml/providers.xml b/res/xml/providers.xml index a223d2fa3..2541fe0da 100644 --- a/res/xml/providers.xml +++ b/res/xml/providers.xml @@ -91,9 +91,12 @@ contain pattern matching characters that can be used to match user entered domains without knowing the exact domain. - The domain attribute may specify a most one global character - a '*'. The - global character matches zero or more characters. This is a very greedy wild - card and may lead to unexpected matches. + An asterisk (*) is used to match that part of a domain name that is demarcated + by a period (dot); no other characters may appear on either side of an asterisk. + Therefore, foo.*.com and *.mail.com are valid, whereas a*.com and foo.c* are not. + An asterisk is also not greedy; it only matches a single part of a domain name; + therefore, foo.bar.bletch is NOT matched by foo.*; it does, however, match + foo.*.* or foo.bar.*. The alternate is the wild card character - a '?'. The wild card character matches any single character. This is very useful when the number of characters @@ -168,15 +171,39 @@ - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/android/email/activity/setup/AccountSettingsUtils.java b/src/com/android/email/activity/setup/AccountSettingsUtils.java index 45e912f64..9ff519b6c 100644 --- a/src/com/android/email/activity/setup/AccountSettingsUtils.java +++ b/src/com/android/email/activity/setup/AccountSettingsUtils.java @@ -16,13 +16,6 @@ package com.android.email.activity.setup; -import com.android.email.R; -import com.android.email.VendorPolicyLoader; -import com.android.email.provider.AccountBackupRestore; -import com.android.emailcommon.Logging; -import com.android.emailcommon.provider.Account; -import com.android.emailcommon.provider.EmailContent.AccountColumns; - import android.content.ContentValues; import android.content.Context; import android.content.res.XmlResourceParser; @@ -30,15 +23,23 @@ import android.text.Editable; import android.util.Log; import android.widget.EditText; +import com.android.email.R; +import com.android.email.VendorPolicyLoader; +import com.android.email.provider.AccountBackupRestore; +import com.android.emailcommon.Logging; +import com.android.emailcommon.provider.Account; +import com.android.emailcommon.provider.EmailContent.AccountColumns; +import com.google.common.annotations.VisibleForTesting; + import java.io.Serializable; -import java.util.regex.Pattern; public class AccountSettingsUtils { - /** Pattern to match globals in the domain */ - private final static Pattern DOMAIN_GLOB_PATTERN = Pattern.compile("\\*"); + /** Pattern to match any part of a domain */ + private final static String WILD_STRING = "*"; /** Will match any, single character */ private final static char WILD_CHARACTER = '?'; + private final static String DOMAIN_SEPARATOR = "\\."; /** * Commits the UI-related settings of an account to the provider. This is static so that it @@ -116,7 +117,7 @@ public class AccountSettingsUtils { && "provider".equals(xml.getName())) { String providerDomain = getXmlAttribute(context, xml, "domain"); try { - if (globMatchIgnoreCase(domain, providerDomain)) { + if (matchProvider(domain, providerDomain)) { provider = new Provider(); provider.id = getXmlAttribute(context, xml, "id"); provider.label = getXmlAttribute(context, xml, "label"); @@ -154,99 +155,44 @@ public class AccountSettingsUtils { } /** - * Returns if the string s1 matches the string s2. The string - * s2 may contain any number of wildcards -- a '?' character -- and/or a - * single global character -- a '*' character. Wildcards match any, single character - * while a global character matches zero or more characters. - * @throws IllegalArgumentException if either string is null or s2 has - * multiple globals. + * Returns true if the string s1 matches the string s2. The string + * s2 may contain any number of wildcards -- a '?' character -- and/or asterisk + * characters -- '*'. Wildcards match any single character, while the asterisk matches a domain + * part (i.e. substring demarcated by a period, '.') */ - /*package*/ static boolean globMatchIgnoreCase(String s1, String s2) - throws IllegalArgumentException { - if (s1 == null || s2 == null) { - throw new IllegalArgumentException("one or both strings are null"); + @VisibleForTesting + static boolean matchProvider(String testDomain, String providerDomain) { + String[] testParts = testDomain.split(DOMAIN_SEPARATOR); + String[] providerParts = providerDomain.split(DOMAIN_SEPARATOR); + if (testParts.length != providerParts.length) { + return false; } - - // Handle the possible global in the domain name - String[] globParts = DOMAIN_GLOB_PATTERN.split(s2); - switch (globParts.length) { - case 1: - // No globals; test for simple equality - if (!wildEqualsIgnoreCase(s1, globParts[0])) { - return false; - } - break; - case 2: - // Global; test the front & end parts of the domain - String d1 = globParts[0]; - String d2 = globParts[1]; - if (!wildStartsWithIgnoreCase(s1, d1) || - !wildEndsWithIgnoreCase(s1.substring(d1.length()), d2)) { - return false; - } - break; - default: - throw new IllegalArgumentException("Multiple globals"); + for (int i = 0; i < testParts.length; i++) { + String testPart = testParts[i].toLowerCase(); + String providerPart = providerParts[i].toLowerCase(); + if (!providerPart.equals(WILD_STRING) && + !matchWithWildcards(testPart, providerPart)) { + return false; + } } return true; } - /** - * Returns if the string s1 equals the string s2. The string - * s2 may contain zero or more wildcards -- a '?' character. - * @throws IllegalArgumentException if the strings are null. - */ - /*package*/ static boolean wildEqualsIgnoreCase(String s1, String s2) - throws IllegalArgumentException { - if (s1 == null || s2 == null) { - throw new IllegalArgumentException("one or both strings are null"); - } - if (s1.length() != s2.length()) { + private static boolean matchWithWildcards(String testPart, String providerPart) { + int providerLength = providerPart.length(); + if (testPart.length() != providerLength){ return false; } - char[] charArray1 = s1.toLowerCase().toCharArray(); - char[] charArray2 = s2.toLowerCase().toCharArray(); - for (int i = 0; i < charArray2.length; i++) { - if (charArray2[i] == WILD_CHARACTER || charArray1[i] == charArray2[i]) continue; - return false; + for (int i = 0; i < providerLength; i++) { + char testChar = testPart.charAt(i); + char providerChar = providerPart.charAt(i); + if (testChar != providerChar && providerChar != WILD_CHARACTER) { + return false; + } } return true; } - /** - * Returns if the string s1 starts with the string s2. The string - * s2 may contain zero or more wildcards -- a '?' character. - * @throws IllegalArgumentException if the strings are null. - */ - /*package*/ static boolean wildStartsWithIgnoreCase(String s1, String s2) - throws IllegalArgumentException { - if (s1 == null || s2 == null) { - throw new IllegalArgumentException("one or both strings are null"); - } - if (s1.length() < s2.length()) { - return false; - } - s1 = s1.substring(0, s2.length()); - return wildEqualsIgnoreCase(s1, s2); - } - - /** - * Returns if the string s1 ends with the string s2. The string - * s2 may contain zero or more wildcards -- a '?' character. - * @throws IllegalArgumentException if the strings are null. - */ - /*package*/ static boolean wildEndsWithIgnoreCase(String s1, String s2) - throws IllegalArgumentException { - if (s1 == null || s2 == null) { - throw new IllegalArgumentException("one or both strings are null"); - } - if (s1.length() < s2.length()) { - return false; - } - s1 = s1.substring(s1.length() - s2.length(), s1.length()); - return wildEqualsIgnoreCase(s1, s2); - } - /** * Attempts to get the given attribute as a String resource first, and if it fails * returns the attribute as a simple String value. diff --git a/tests/src/com/android/email/activity/setup/AccountSettingsUtilsTests.java b/tests/src/com/android/email/activity/setup/AccountSettingsUtilsTests.java index b4f04abec..ebe59458d 100644 --- a/tests/src/com/android/email/activity/setup/AccountSettingsUtilsTests.java +++ b/tests/src/com/android/email/activity/setup/AccountSettingsUtilsTests.java @@ -16,14 +16,13 @@ package com.android.email.activity.setup; -import com.android.email.tests.R; -import com.android.email.activity.setup.AccountSettingsUtils.Provider; - import android.content.Context; -import android.test.AndroidTestCase; import android.test.InstrumentationTestCase; import android.test.suitebuilder.annotation.SmallTest; +import com.android.email.activity.setup.AccountSettingsUtils.Provider; +import com.android.email.tests.R; + /** * This is a series of unit tests for the AccountSettingsUtils class. * @@ -100,86 +99,38 @@ public class AccountSettingsUtilsTests extends InstrumentationTestCase { assertNull(testProvider); } - public void testGlobEndsWithIgnoreCase() { - assertTrue(AccountSettingsUtils.wildEndsWithIgnoreCase( - "yahoo.com.tw", ".??")); - assertTrue(AccountSettingsUtils.wildEndsWithIgnoreCase( - "abcd", "a??d")); - assertFalse(AccountSettingsUtils.wildEndsWithIgnoreCase( - "yahoo.com.tw.foo.com", ".??")); - assertFalse(AccountSettingsUtils.wildEndsWithIgnoreCase( - "abc", "a??d")); - } + public void testMatchProvider() { + assertTrue(AccountSettingsUtils.matchProvider("foo.com", "foo.com")); + assertFalse(AccountSettingsUtils.matchProvider("foo.co", "foo.com")); + assertFalse(AccountSettingsUtils.matchProvider("", "foo.com")); - public void testGlobStartsWithIgnoreCase() { - assertTrue(AccountSettingsUtils.wildStartsWithIgnoreCase( - "tw.yahoo.com", "??.")); - assertTrue(AccountSettingsUtils.wildStartsWithIgnoreCase( - "abcdxyz", "a??d")); - assertFalse(AccountSettingsUtils.wildStartsWithIgnoreCase( - "abc", "a??d")); - } + assertTrue(AccountSettingsUtils.matchProvider("foo.com", "fo?.com")); + assertTrue(AccountSettingsUtils.matchProvider("foo.com", "f??.com")); + assertTrue(AccountSettingsUtils.matchProvider("fzz.com", "f??.com")); + assertTrue(AccountSettingsUtils.matchProvider("foo.com", "???.???")); + assertFalse(AccountSettingsUtils.matchProvider("foo.com", "???.????")); - public void testGlobEqualsIgnoreCase() { - assertTrue(AccountSettingsUtils.wildEqualsIgnoreCase( - "tw.yahoo.com", "??.yahoo.com")); - assertTrue(AccountSettingsUtils.wildEqualsIgnoreCase( - "yahoo.com.tw", "yahoo.com.??")); - assertTrue(AccountSettingsUtils.wildEqualsIgnoreCase( - "abcdxyz", "a??dxyz")); - assertFalse(AccountSettingsUtils.wildEqualsIgnoreCase( - "abc", "a??d")); - assertFalse(AccountSettingsUtils.wildEqualsIgnoreCase( - "abccxyz", "a??d")); - } + assertTrue(AccountSettingsUtils.matchProvider("foo.com", "*.com")); + assertTrue(AccountSettingsUtils.matchProvider("foo.com", "foo.*")); + assertTrue(AccountSettingsUtils.matchProvider("foo.com", "*.*")); + assertFalse(AccountSettingsUtils.matchProvider("foo.com", "fox.*")); + assertTrue(AccountSettingsUtils.matchProvider("foo.com", "*.???")); + assertFalse(AccountSettingsUtils.matchProvider("foo.com", "*.?")); - public void testGlobMatchIgnoreCase() { - assertTrue(AccountSettingsUtils.globMatchIgnoreCase( - "mail.yahoo.com", "mail*yahoo.com")); - assertTrue(AccountSettingsUtils.globMatchIgnoreCase( - "mail.foo.bar.yahoo.com", "mail*yahoo.com")); - assertTrue(AccountSettingsUtils.globMatchIgnoreCase( - "mail.notwhatyouwant.myyahoo.com", "mail*yahoo.com")); + assertFalse(AccountSettingsUtils.matchProvider("foo.bar.com", "food.barge.comb")); + assertTrue(AccountSettingsUtils.matchProvider("foo.bar.com", "foo.bar.com")); + assertFalse(AccountSettingsUtils.matchProvider("foo.bar.com", "foo.bar.gag.com")); + assertTrue(AccountSettingsUtils.matchProvider("foo.bar.com", "foo.*.com")); + assertTrue(AccountSettingsUtils.matchProvider("foo.bar.com", "foo.*.*")); + assertFalse(AccountSettingsUtils.matchProvider("foo.bar.com", "foo.bar.*.*")); + assertFalse(AccountSettingsUtils.matchProvider("foo.bar.com", "foo.bar.*com")); + assertTrue(AccountSettingsUtils.matchProvider("foo.bar.com", "*.bar.com")); + assertTrue(AccountSettingsUtils.matchProvider("foo.bar.com", "*.*.com")); + assertTrue(AccountSettingsUtils.matchProvider("foo.bar.com", "*.*.*")); + assertTrue(AccountSettingsUtils.matchProvider("foo.bar.com", "foo.bar.*")); - // Test other combinations - assertTrue(AccountSettingsUtils.globMatchIgnoreCase( - "yahoo.com", "yahoo.com")); - assertFalse(AccountSettingsUtils.globMatchIgnoreCase( - "yahoo.com.au", "yahoo.com")); - assertFalse(AccountSettingsUtils.globMatchIgnoreCase( - "yahoo.com", "yahoo.com.au")); - - // Try mixed case in the domain name - assertTrue(AccountSettingsUtils.globMatchIgnoreCase( - "GmAiL.cOm", "gMaIl.CoM")); - - assertFalse(AccountSettingsUtils.globMatchIgnoreCase( - "nonexist.frr.com", "*.rr.com")); - assertFalse(AccountSettingsUtils.globMatchIgnoreCase( - "rr.com", "*.rr.com")); - assertTrue(AccountSettingsUtils.globMatchIgnoreCase( - "abbc.com", "ab*bc.com")); - assertFalse(AccountSettingsUtils.globMatchIgnoreCase( - "abc.com", "ab*bc.com")); - - try { - AccountSettingsUtils.globMatchIgnoreCase( - "abc.com", "ab*bc*.com"); - fail("Should have thrown an IllegalArgumentException"); - } catch (IllegalArgumentException e) { - } - try { - AccountSettingsUtils.globMatchIgnoreCase( - null, "ab*bc*.com"); - fail("Should have thrown an IllegalArgumentException"); - } catch (IllegalArgumentException e) { - } - try { - AccountSettingsUtils.globMatchIgnoreCase( - "abc.com", null); - fail("Should have thrown an IllegalArgumentException"); - } catch (IllegalArgumentException e) { - } + assertTrue(AccountSettingsUtils.matchProvider("foo.bar.com", "foo.???.*")); + assertFalse(AccountSettingsUtils.matchProvider("foo.bar.com", "foo.*??.*")); } public void testExpandTemplates() {