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
This commit is contained in:
parent
3d0f0d74b0
commit
1b65e834c3
|
@ -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 @@
|
|||
|
||||
<!-- Hotmail and variants. NOTE: These are handled by exchange if available, else POP3. -->
|
||||
<!-- EXCHANGE-REMOVE-SECTION-START -->
|
||||
<provider id="live" label="Windows Live Hotmail Plus" domain="live.com">
|
||||
<provider id="live1" label="Windows Live Hotmail Plus" domain="live.*">
|
||||
<incoming uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
<outgoing uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
</provider>
|
||||
<provider id="hotmail" label="Windows Live Hotmail Plus" domain="hotmail.com">
|
||||
<provider id="live2" label="Windows Live Hotmail Plus" domain="live.*.*">
|
||||
<incoming uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
<outgoing uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
</provider>
|
||||
<provider id="msn" label="Windows Live Hotmail Plus" domain="msn.com">
|
||||
<provider id="live3" label="Windows Live Hotmail Plus" domain="*.live.*">
|
||||
<incoming uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
<outgoing uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
</provider>
|
||||
<provider id="hotmail1" label="Windows Live Hotmail Plus" domain="hotmail.*">
|
||||
<incoming uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
<outgoing uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
</provider>
|
||||
<provider id="hotmail2" label="Windows Live Hotmail Plus" domain="hotmail.*.*">
|
||||
<incoming uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
<outgoing uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
</provider>
|
||||
<provider id="hotmail3" label="Windows Live Hotmail Plus" domain="livemail.*">
|
||||
<incoming uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
<outgoing uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
</provider>
|
||||
<provider id="hotmail4" label="Windows Live Hotmail Plus" domain="livemail.*.*">
|
||||
<incoming uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
<outgoing uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
</provider>
|
||||
<provider id="msn" label="Windows Live Hotmail Plus" domain="msn.*">
|
||||
<incoming uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
<outgoing uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
</provider>
|
||||
<provider id="msnhotmail" label="Windows Live Hotmail Plus" domain="msnhotmail.com">
|
||||
<incoming uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
<outgoing uri="eas+ssl+://m.hotmail.com" username="$email" />
|
||||
</provider>
|
||||
|
|
|
@ -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 <code>s1</code> matches the string <code>s2</code>. The string
|
||||
* <code>s2</code> 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 <code>s2</code> has
|
||||
* multiple globals.
|
||||
* Returns true if the string <code>s1</code> matches the string <code>s2</code>. The string
|
||||
* <code>s2</code> 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 <code>s1</code> equals the string <code>s2</code>. The string
|
||||
* <code>s2</code> 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 <code>s1</code> starts with the string <code>s2</code>. The string
|
||||
* <code>s2</code> 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 <code>s1</code> ends with the string <code>s2</code>. The string
|
||||
* <code>s2</code> 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.
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue