001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.validator; 018 019import org.apache.commons.validator.routines.InetAddressValidator; 020 021import java.util.regex.Matcher; 022import java.util.regex.Pattern; 023 024/** 025 * <p>Perform email validations.</p> 026 * <p> 027 * This class is a Singleton; you can retrieve the instance via the getInstance() method. 028 * </p> 029 * <p> 030 * Based on a script by <a href="mailto:stamhankar@hotmail.com">Sandeep V. Tamhankar</a> 031 * http://javascript.internet.com 032 * </p> 033 * <p> 034 * This implementation is not guaranteed to catch all possible errors in an email address. 035 * For example, an address like nobody@noplace.somedog will pass validator, even though there 036 * is no TLD "somedog" 037 * </p>. 038 * 039 * @version $Revision$ 040 * @since Validator 1.1 041 * @deprecated Use the new EmailValidator in the routines package. This class 042 * will be removed in a future release. 043 */ 044@Deprecated 045public class EmailValidator { 046 047 private static final String SPECIAL_CHARS = "\\p{Cntrl}\\(\\)<>@,;:'\\\\\\\"\\.\\[\\]"; 048 private static final String VALID_CHARS = "[^\\s" + SPECIAL_CHARS + "]"; 049 private static final String QUOTED_USER = "(\"[^\"]*\")"; 050 private static final String ATOM = VALID_CHARS + '+'; 051 private static final String WORD = "((" + VALID_CHARS + "|')+|" + QUOTED_USER + ")"; 052 053// NOT USED private static final Pattern LEGAL_ASCII_PATTERN = Pattern.compile("^\\p{ASCII}+$"); 054// NOT USED private static final Pattern EMAIL_PATTERN = Pattern.compile("^(.+)@(.+)$"); 055 private static final Pattern IP_DOMAIN_PATTERN = Pattern.compile("^\\[(.*)\\]$"); 056 private static final Pattern TLD_PATTERN = Pattern.compile("^([a-zA-Z]+)$"); 057 058 private static final Pattern USER_PATTERN = Pattern.compile("^\\s*" + WORD + "(\\." + WORD + ")*$"); 059 private static final Pattern DOMAIN_PATTERN = Pattern.compile("^" + ATOM + "(\\." + ATOM + ")*\\s*$"); 060 private static final Pattern ATOM_PATTERN = Pattern.compile("(" + ATOM + ")"); 061 062 /** 063 * Singleton instance of this class. 064 */ 065 private static final EmailValidator EMAIL_VALIDATOR = new EmailValidator(); 066 067 /** 068 * Returns the Singleton instance of this validator. 069 * @return singleton instance of this validator. 070 */ 071 public static EmailValidator getInstance() { 072 return EMAIL_VALIDATOR; 073 } 074 075 /** 076 * Protected constructor for subclasses to use. 077 */ 078 protected EmailValidator() { 079 super(); 080 } 081 082 /** 083 * <p>Checks if a field has a valid e-mail address.</p> 084 * 085 * @param email The value validation is being performed on. A <code>null</code> 086 * value is considered invalid. 087 * @return true if the email address is valid. 088 */ 089 public boolean isValid(String email) { 090 return org.apache.commons.validator.routines.EmailValidator.getInstance().isValid(email); 091 } 092 093 /** 094 * Returns true if the domain component of an email address is valid. 095 * @param domain being validated. 096 * @return true if the email address's domain is valid. 097 */ 098 protected boolean isValidDomain(String domain) { 099 boolean symbolic = false; 100 101 // see if domain is an IP address in brackets 102 Matcher ipDomainMatcher = IP_DOMAIN_PATTERN.matcher(domain); 103 104 if (ipDomainMatcher.matches()) { 105 InetAddressValidator inetAddressValidator = 106 InetAddressValidator.getInstance(); 107 if (inetAddressValidator.isValid(ipDomainMatcher.group(1))) { 108 return true; 109 } 110 } else { 111 // Domain is symbolic name 112 symbolic = DOMAIN_PATTERN.matcher(domain).matches(); 113 } 114 115 if (symbolic) { 116 if (!isValidSymbolicDomain(domain)) { 117 return false; 118 } 119 } else { 120 return false; 121 } 122 123 return true; 124 } 125 126 /** 127 * Returns true if the user component of an email address is valid. 128 * @param user being validated 129 * @return true if the user name is valid. 130 */ 131 protected boolean isValidUser(String user) { 132 return USER_PATTERN.matcher(user).matches(); 133 } 134 135 /** 136 * Validates an IP address. Returns true if valid. 137 * @param ipAddress IP address 138 * @return true if the ip address is valid. 139 */ 140 protected boolean isValidIpAddress(String ipAddress) { 141 Matcher ipAddressMatcher = IP_DOMAIN_PATTERN.matcher(ipAddress); 142 for (int i = 1; i <= 4; i++) { // CHECKSTYLE IGNORE MagicNumber 143 String ipSegment = ipAddressMatcher.group(i); 144 if (ipSegment == null || ipSegment.length() <= 0) { 145 return false; 146 } 147 148 int iIpSegment = 0; 149 150 try { 151 iIpSegment = Integer.parseInt(ipSegment); 152 } catch(NumberFormatException e) { 153 return false; 154 } 155 156 if (iIpSegment > 255) { // CHECKSTYLE IGNORE MagicNumber 157 return false; 158 } 159 160 } 161 return true; 162 } 163 164 /** 165 * Validates a symbolic domain name. Returns true if it's valid. 166 * @param domain symbolic domain name 167 * @return true if the symbolic domain name is valid. 168 */ 169 protected boolean isValidSymbolicDomain(String domain) { 170 String[] domainSegment = new String[10]; // CHECKSTYLE IGNORE MagicNumber 171 boolean match = true; 172 int i = 0; 173 Matcher atomMatcher = ATOM_PATTERN.matcher(domain); 174 while (match) { 175 match = atomMatcher.matches(); 176 if (match) { 177 domainSegment[i] = atomMatcher.group(1); 178 int l = domainSegment[i].length() + 1; 179 domain = 180 (l >= domain.length()) 181 ? "" 182 : domain.substring(l); 183 184 i++; 185 } 186 } 187 188 int len = i; 189 190 // Make sure there's a host name preceding the domain. 191 if (len < 2) { 192 return false; 193 } 194 195 String tld = domainSegment[len - 1]; 196 if (tld.length() > 1) { 197 if (! TLD_PATTERN.matcher(tld).matches()) { 198 return false; 199 } 200 } else { 201 return false; 202 } 203 204 return true; 205 } 206 /** 207 * Recursively remove comments, and replace with a single space. The simpler 208 * regexps in the Email Addressing FAQ are imperfect - they will miss escaped 209 * chars in atoms, for example. 210 * Derived From Mail::RFC822::Address 211 * @param emailStr The email address 212 * @return address with comments removed. 213 */ 214 protected String stripComments(String emailStr) { 215 String result = emailStr; 216 String commentPat = "^((?:[^\"\\\\]|\\\\.)*(?:\"(?:[^\"\\\\]|\\\\.)*\"(?:[^\"\\\\]|\111111\\\\.)*)*)\\((?:[^()\\\\]|\\\\.)*\\)/"; 217 Pattern commentMatcher = Pattern.compile(commentPat); 218 219 while (commentMatcher.matcher(result).matches()) { 220 result = result.replaceFirst(commentPat, "\1 "); 221 } 222 return result; 223 } 224}