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 */ 39490556a764a879cd0eaff358e90705cc1335c92eErik@Deprecated 40823b6f3516076b92f78c3fc27037d24bb514e653Ying Wangpublic class Rfc822Validator implements AutoCompleteTextView.Validator { 41823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang /* 42823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * Regex.EMAIL_ADDRESS_PATTERN hardcodes the TLD that we accept, but we 43823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * want to make sure we will keep accepting email addresses with TLD's 44823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * that don't exist at the time of this writing, so this regexp relaxes 45823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * that constraint by accepting any kind of top level domain, not just 46823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * ".com", ".fr", etc... 47823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang */ 48823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang private static final Pattern EMAIL_ADDRESS_PATTERN = 49b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook Pattern.compile("[^\\s@]+@([^\\s@\\.]+\\.)+[a-zA-z][a-zA-Z][a-zA-Z]*"); 50823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 51823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang private String mDomain; 52490556a764a879cd0eaff358e90705cc1335c92eErik private boolean mRemoveInvalid = false; 53823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 54823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang /** 55823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * Constructs a new validator that uses the specified domain name as 56823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * the default when none is specified. 57823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang */ 58823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang public Rfc822Validator(String domain) { 59823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang mDomain = domain; 60823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 61823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 62823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang /** 63823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * {@inheritDoc} 64823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang */ 65823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang public boolean isValid(CharSequence text) { 66823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(text); 67823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 68823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang return tokens.length == 1 && 69823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang EMAIL_ADDRESS_PATTERN. 70823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang matcher(tokens[0].getAddress()).matches(); 71823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 72823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 73823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang /** 74490556a764a879cd0eaff358e90705cc1335c92eErik * Specify if the validator should remove invalid tokens instead of trying 75490556a764a879cd0eaff358e90705cc1335c92eErik * to fix them. This can be used to strip results of incorrectly formatted 76490556a764a879cd0eaff358e90705cc1335c92eErik * tokens. 77490556a764a879cd0eaff358e90705cc1335c92eErik * 78490556a764a879cd0eaff358e90705cc1335c92eErik * @param remove true to remove tokens with the wrong format, false to 79490556a764a879cd0eaff358e90705cc1335c92eErik * attempt to fix them 80490556a764a879cd0eaff358e90705cc1335c92eErik */ 81490556a764a879cd0eaff358e90705cc1335c92eErik public void setRemoveInvalid(boolean remove) { 82490556a764a879cd0eaff358e90705cc1335c92eErik mRemoveInvalid = remove; 83490556a764a879cd0eaff358e90705cc1335c92eErik } 84490556a764a879cd0eaff358e90705cc1335c92eErik 85490556a764a879cd0eaff358e90705cc1335c92eErik /** 86823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * @return a string in which all the characters that are illegal for the username 87823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * or the domain name part of the email address have been removed. 88823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang */ 89823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang private String removeIllegalCharacters(String s) { 90823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang StringBuilder result = new StringBuilder(); 91823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang int length = s.length(); 92823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang for (int i = 0; i < length; i++) { 93823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang char c = s.charAt(i); 94823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 95823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang /* 96823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * An RFC822 atom can contain any ASCII printing character 97823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * except for periods and any of the following punctuation. 98823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * A local-part can contain multiple atoms, concatenated by 99823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * periods, so do allow periods here. 100823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang */ 101823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 102823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang if (c <= ' ' || c > '~') { 103823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang continue; 104823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 105823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 106823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang if (c == '(' || c == ')' || c == '<' || c == '>' || 107823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang c == '@' || c == ',' || c == ';' || c == ':' || 108823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang c == '\\' || c == '"' || c == '[' || c == ']') { 109823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang continue; 110823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 111823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 112823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang result.append(c); 113823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 114823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang return result.toString(); 115823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 116823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 117823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang /** 118823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * {@inheritDoc} 119823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang */ 120823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang public CharSequence fixText(CharSequence cs) { 121823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // Return an empty string if the email address only contains spaces, \n or \t 122823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang if (TextUtils.getTrimmedLength(cs) == 0) return ""; 123823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 124823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(cs); 125823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang StringBuilder sb = new StringBuilder(); 126823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 127823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang for (int i = 0; i < tokens.length; i++) { 128823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang String text = tokens[i].getAddress(); 129490556a764a879cd0eaff358e90705cc1335c92eErik 130490556a764a879cd0eaff358e90705cc1335c92eErik if (mRemoveInvalid && !isValid(text)) { 131490556a764a879cd0eaff358e90705cc1335c92eErik continue; 132490556a764a879cd0eaff358e90705cc1335c92eErik } 133823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang int index = text.indexOf('@'); 134823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang if (index < 0) { 135490556a764a879cd0eaff358e90705cc1335c92eErik // append the domain of the account if it exists 136490556a764a879cd0eaff358e90705cc1335c92eErik if (mDomain != null) { 137490556a764a879cd0eaff358e90705cc1335c92eErik tokens[i].setAddress(removeIllegalCharacters(text) + "@" + mDomain); 138490556a764a879cd0eaff358e90705cc1335c92eErik } 139823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } else { 140823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // Otherwise, remove the illegal characters on both sides of the '@' 141823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang String fix = removeIllegalCharacters(text.substring(0, index)); 142490556a764a879cd0eaff358e90705cc1335c92eErik if (TextUtils.isEmpty(fix)) { 143490556a764a879cd0eaff358e90705cc1335c92eErik // if the address is empty after removing invalid chars 144490556a764a879cd0eaff358e90705cc1335c92eErik // don't use it 145490556a764a879cd0eaff358e90705cc1335c92eErik continue; 146490556a764a879cd0eaff358e90705cc1335c92eErik } 147823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang String domain = removeIllegalCharacters(text.substring(index + 1)); 148490556a764a879cd0eaff358e90705cc1335c92eErik boolean emptyDomain = domain.length() == 0; 149490556a764a879cd0eaff358e90705cc1335c92eErik if (!emptyDomain || mDomain != null) { 150490556a764a879cd0eaff358e90705cc1335c92eErik tokens[i].setAddress(fix + "@" + (!emptyDomain ? domain : mDomain)); 151490556a764a879cd0eaff358e90705cc1335c92eErik } 152823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 153823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 154823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang sb.append(tokens[i].toString()); 155823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang if (i + 1 < tokens.length) { 156823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang sb.append(", "); 157823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 158823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 159823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 160823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang return sb; 161823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 162823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang} 163