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 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