Rfc822Validator.java revision b4f5e0e5755938f2be9a2f1a1a6609b018c530ad
1823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang/* 2823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * Copyright (C) 2008 The Android Open Source Project 3823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * 4823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * Licensed under the Apache License, Version 2.0 (the "License"); 5823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * you may not use this file except in compliance with the License. 6823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * You may obtain a copy of the License at 7823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * 8823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * http://www.apache.org/licenses/LICENSE-2.0 9823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * 10823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * Unless required by applicable law or agreed to in writing, software 11823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * distributed under the License is distributed on an "AS IS" BASIS, 12823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * See the License for the specific language governing permissions and 14823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * limitations under the License. 15823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang */ 16823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 17823b6f3516076b92f78c3fc27037d24bb514e653Ying Wangpackage com.android.common; 18823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 19823b6f3516076b92f78c3fc27037d24bb514e653Ying Wangimport android.text.TextUtils; 20823b6f3516076b92f78c3fc27037d24bb514e653Ying Wangimport android.text.util.Rfc822Token; 21823b6f3516076b92f78c3fc27037d24bb514e653Ying Wangimport android.text.util.Rfc822Tokenizer; 22823b6f3516076b92f78c3fc27037d24bb514e653Ying Wangimport android.widget.AutoCompleteTextView; 23823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 24823b6f3516076b92f78c3fc27037d24bb514e653Ying Wangimport java.util.regex.Pattern; 25823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 26823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang/** 27823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * This class works as a Validator for AutoCompleteTextView for 28823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * email addresses. If a token does not appear to be a valid address, 29823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * it is trimmed of characters that cannot legitimately appear in one 30823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * and has the specified domain name added. It is meant for use with 31823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * {@link Rfc822Token} and {@link Rfc822Tokenizer}. 32823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * 33823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * @deprecated In the future make sure we don't quietly alter the user's 34823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * text in ways they did not intend. Meanwhile, hide this 35823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * class from the public API because it does not even have 36823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * a full understanding of the syntax it claims to correct. 37823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * @hide 38823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang */ 39823b6f3516076b92f78c3fc27037d24bb514e653Ying Wangpublic class Rfc822Validator implements AutoCompleteTextView.Validator { 40823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang /* 41823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * Regex.EMAIL_ADDRESS_PATTERN hardcodes the TLD that we accept, but we 42823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * want to make sure we will keep accepting email addresses with TLD's 43823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * that don't exist at the time of this writing, so this regexp relaxes 44823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * that constraint by accepting any kind of top level domain, not just 45823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * ".com", ".fr", etc... 46823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang */ 47823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang private static final Pattern EMAIL_ADDRESS_PATTERN = 48b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook Pattern.compile("[^\\s@]+@([^\\s@\\.]+\\.)+[a-zA-z][a-zA-Z][a-zA-Z]*"); 49823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 50823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang private String mDomain; 51823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 52823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang /** 53823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * Constructs a new validator that uses the specified domain name as 54823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * the default when none is specified. 55823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang */ 56823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang public Rfc822Validator(String domain) { 57823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang mDomain = domain; 58823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 59823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 60823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang /** 61823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * {@inheritDoc} 62823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang */ 63823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang public boolean isValid(CharSequence text) { 64823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(text); 65823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 66823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang return tokens.length == 1 && 67823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang EMAIL_ADDRESS_PATTERN. 68823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang matcher(tokens[0].getAddress()).matches(); 69823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 70823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 71823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang /** 72823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * @return a string in which all the characters that are illegal for the username 73823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * or the domain name part of the email address have been removed. 74823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang */ 75823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang private String removeIllegalCharacters(String s) { 76823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang StringBuilder result = new StringBuilder(); 77823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang int length = s.length(); 78823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang for (int i = 0; i < length; i++) { 79823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang char c = s.charAt(i); 80823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 81823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang /* 82823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * An RFC822 atom can contain any ASCII printing character 83823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * except for periods and any of the following punctuation. 84823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * A local-part can contain multiple atoms, concatenated by 85823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * periods, so do allow periods here. 86823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang */ 87823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 88823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang if (c <= ' ' || c > '~') { 89823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang continue; 90823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 91823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 92823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang if (c == '(' || c == ')' || c == '<' || c == '>' || 93823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang c == '@' || c == ',' || c == ';' || c == ':' || 94823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang c == '\\' || c == '"' || c == '[' || c == ']') { 95823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang continue; 96823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 97823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 98823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang result.append(c); 99823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 100823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang return result.toString(); 101823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 102823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 103823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang /** 104823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * {@inheritDoc} 105823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang */ 106823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang public CharSequence fixText(CharSequence cs) { 107823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // Return an empty string if the email address only contains spaces, \n or \t 108823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang if (TextUtils.getTrimmedLength(cs) == 0) return ""; 109823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 110823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(cs); 111823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang StringBuilder sb = new StringBuilder(); 112823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 113823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang for (int i = 0; i < tokens.length; i++) { 114823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang String text = tokens[i].getAddress(); 115823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang int index = text.indexOf('@'); 116823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang if (index < 0) { 117823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // If there is no @, just append the domain of the account 118823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang tokens[i].setAddress(removeIllegalCharacters(text) + "@" + mDomain); 119823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } else { 120823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // Otherwise, remove the illegal characters on both sides of the '@' 121823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang String fix = removeIllegalCharacters(text.substring(0, index)); 122823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang String domain = removeIllegalCharacters(text.substring(index + 1)); 123823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang tokens[i].setAddress(fix + "@" + (domain.length() != 0 ? domain : mDomain)); 124823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 125823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 126823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang sb.append(tokens[i].toString()); 127823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang if (i + 1 < tokens.length) { 128823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang sb.append(", "); 129823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 130823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 131823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 132823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang return sb; 133823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 134823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang} 135