Home | History | Annotate | Download | only in common
      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 @Deprecated
     40 public class Rfc822Validator implements AutoCompleteTextView.Validator {
     41     /*
     42      * Regex.EMAIL_ADDRESS_PATTERN hardcodes the TLD that we accept, but we
     43      * want to make sure we will keep accepting email addresses with TLD's
     44      * that don't exist at the time of this writing, so this regexp relaxes
     45      * that constraint by accepting any kind of top level domain, not just
     46      * ".com", ".fr", etc...
     47      */
     48     private static final Pattern EMAIL_ADDRESS_PATTERN =
     49             Pattern.compile("[^\\s@]+@([^\\s@\\.]+\\.)+[a-zA-z][a-zA-Z][a-zA-Z]*");
     50 
     51     private String mDomain;
     52     private boolean mRemoveInvalid = false;
     53 
     54     /**
     55      * Constructs a new validator that uses the specified domain name as
     56      * the default when none is specified.
     57      */
     58     public Rfc822Validator(String domain) {
     59         mDomain = domain;
     60     }
     61 
     62     /**
     63      * {@inheritDoc}
     64      */
     65     public boolean isValid(CharSequence text) {
     66         Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(text);
     67 
     68         return tokens.length == 1 &&
     69                EMAIL_ADDRESS_PATTERN.
     70                    matcher(tokens[0].getAddress()).matches();
     71     }
     72 
     73     /**
     74      * Specify if the validator should remove invalid tokens instead of trying
     75      * to fix them. This can be used to strip results of incorrectly formatted
     76      * tokens.
     77      *
     78      * @param remove true to remove tokens with the wrong format, false to
     79      *            attempt to fix them
     80      */
     81     public void setRemoveInvalid(boolean remove) {
     82         mRemoveInvalid = remove;
     83     }
     84 
     85     /**
     86      * @return a string in which all the characters that are illegal for the username
     87      * or the domain name part of the email address have been removed.
     88      */
     89     private String removeIllegalCharacters(String s) {
     90         StringBuilder result = new StringBuilder();
     91         int length = s.length();
     92         for (int i = 0; i < length; i++) {
     93             char c = s.charAt(i);
     94 
     95             /*
     96              * An RFC822 atom can contain any ASCII printing character
     97              * except for periods and any of the following punctuation.
     98              * A local-part can contain multiple atoms, concatenated by
     99              * periods, so do allow periods here.
    100              */
    101 
    102             if (c <= ' ' || c > '~') {
    103                 continue;
    104             }
    105 
    106             if (c == '(' || c == ')' || c == '<' || c == '>' ||
    107                 c == '@' || c == ',' || c == ';' || c == ':' ||
    108                 c == '\\' || c == '"' || c == '[' || c == ']') {
    109                 continue;
    110             }
    111 
    112             result.append(c);
    113         }
    114         return result.toString();
    115     }
    116 
    117     /**
    118      * {@inheritDoc}
    119      */
    120     public CharSequence fixText(CharSequence cs) {
    121         // Return an empty string if the email address only contains spaces, \n or \t
    122         if (TextUtils.getTrimmedLength(cs) == 0) return "";
    123 
    124         Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(cs);
    125         StringBuilder sb = new StringBuilder();
    126 
    127         for (int i = 0; i < tokens.length; i++) {
    128             String text = tokens[i].getAddress();
    129 
    130             if (mRemoveInvalid && !isValid(text)) {
    131                 continue;
    132             }
    133             int index = text.indexOf('@');
    134             if (index < 0) {
    135                 // append the domain of the account if it exists
    136                 if (mDomain != null) {
    137                     tokens[i].setAddress(removeIllegalCharacters(text) + "@" + mDomain);
    138                 }
    139             } else {
    140                 // Otherwise, remove the illegal characters on both sides of the '@'
    141                 String fix = removeIllegalCharacters(text.substring(0, index));
    142                 if (TextUtils.isEmpty(fix)) {
    143                     // if the address is empty after removing invalid chars
    144                     // don't use it
    145                     continue;
    146                 }
    147                 String domain = removeIllegalCharacters(text.substring(index + 1));
    148                 boolean emptyDomain = domain.length() == 0;
    149                 if (!emptyDomain || mDomain != null) {
    150                     tokens[i].setAddress(fix + "@" + (!emptyDomain ? domain : mDomain));
    151                 }
    152             }
    153 
    154             sb.append(tokens[i].toString());
    155             if (i + 1 < tokens.length) {
    156                 sb.append(", ");
    157             }
    158         }
    159 
    160         return sb;
    161     }
    162 }
    163