1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.common; 18 19 import android.text.TextUtils; 20 import android.text.util.Rfc822Token; 21 import android.text.util.Rfc822Tokenizer; 22 import android.widget.AutoCompleteTextView; 23 24 import java.util.regex.Pattern; 25 26 /** 27 * This class works as a Validator for AutoCompleteTextView for 28 * email addresses. If a token does not appear to be a valid address, 29 * it is trimmed of characters that cannot legitimately appear in one 30 * and has the specified domain name added. It is meant for use with 31 * {@link Rfc822Token} and {@link Rfc822Tokenizer}. 32 * 33 * @deprecated In the future make sure we don't quietly alter the user's 34 * text in ways they did not intend. Meanwhile, hide this 35 * class from the public API because it does not even have 36 * a full understanding of the syntax it claims to correct. 37 * @hide 38 */ 39 public class Rfc822Validator implements AutoCompleteTextView.Validator { 40 /* 41 * Regex.EMAIL_ADDRESS_PATTERN hardcodes the TLD that we accept, but we 42 * want to make sure we will keep accepting email addresses with TLD's 43 * that don't exist at the time of this writing, so this regexp relaxes 44 * that constraint by accepting any kind of top level domain, not just 45 * ".com", ".fr", etc... 46 */ 47 private static final Pattern EMAIL_ADDRESS_PATTERN = 48 Pattern.compile("[^\\s@]+@[^\\s@]+\\.[a-zA-z][a-zA-Z][a-zA-Z]*"); 49 50 private String mDomain; 51 52 /** 53 * Constructs a new validator that uses the specified domain name as 54 * the default when none is specified. 55 */ 56 public Rfc822Validator(String domain) { 57 mDomain = domain; 58 } 59 60 /** 61 * {@inheritDoc} 62 */ 63 public boolean isValid(CharSequence text) { 64 Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(text); 65 66 return tokens.length == 1 && 67 EMAIL_ADDRESS_PATTERN. 68 matcher(tokens[0].getAddress()).matches(); 69 } 70 71 /** 72 * @return a string in which all the characters that are illegal for the username 73 * or the domain name part of the email address have been removed. 74 */ 75 private String removeIllegalCharacters(String s) { 76 StringBuilder result = new StringBuilder(); 77 int length = s.length(); 78 for (int i = 0; i < length; i++) { 79 char c = s.charAt(i); 80 81 /* 82 * An RFC822 atom can contain any ASCII printing character 83 * except for periods and any of the following punctuation. 84 * A local-part can contain multiple atoms, concatenated by 85 * periods, so do allow periods here. 86 */ 87 88 if (c <= ' ' || c > '~') { 89 continue; 90 } 91 92 if (c == '(' || c == ')' || c == '<' || c == '>' || 93 c == '@' || c == ',' || c == ';' || c == ':' || 94 c == '\\' || c == '"' || c == '[' || c == ']') { 95 continue; 96 } 97 98 result.append(c); 99 } 100 return result.toString(); 101 } 102 103 /** 104 * {@inheritDoc} 105 */ 106 public CharSequence fixText(CharSequence cs) { 107 // Return an empty string if the email address only contains spaces, \n or \t 108 if (TextUtils.getTrimmedLength(cs) == 0) return ""; 109 110 Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(cs); 111 StringBuilder sb = new StringBuilder(); 112 113 for (int i = 0; i < tokens.length; i++) { 114 String text = tokens[i].getAddress(); 115 int index = text.indexOf('@'); 116 if (index < 0) { 117 // If there is no @, just append the domain of the account 118 tokens[i].setAddress(removeIllegalCharacters(text) + "@" + mDomain); 119 } else { 120 // Otherwise, remove the illegal characters on both sides of the '@' 121 String fix = removeIllegalCharacters(text.substring(0, index)); 122 String domain = removeIllegalCharacters(text.substring(index + 1)); 123 tokens[i].setAddress(fix + "@" + (domain.length() != 0 ? domain : mDomain)); 124 } 125 126 sb.append(tokens[i].toString()); 127 if (i + 1 < tokens.length) { 128 sb.append(", "); 129 } 130 } 131 132 return sb; 133 } 134 } 135