1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.validator;
18
19 import org.apache.commons.validator.routines.InetAddressValidator;
20
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
23
24 /**
25 * <p>Perform email validations.</p>
26 * <p>
27 * This class is a Singleton; you can retrieve the instance via the getInstance() method.
28 * </p>
29 * <p>
30 * Based on a script by <a href="mailto:stamhankar@hotmail.com">Sandeep V. Tamhankar</a>
31 * http://javascript.internet.com
32 * </p>
33 * <p>
34 * This implementation is not guaranteed to catch all possible errors in an email address.
35 * For example, an address like nobody@noplace.somedog will pass validator, even though there
36 * is no TLD "somedog"
37 * </p>.
38 *
39 * @version $Revision: 1441674 $ $Date: 2013-02-01 20:02:24 -0500 (Fri, 01 Feb 2013) $
40 * @since Validator 1.1
41 * @deprecated Use the new EmailValidator in the routines package. This class
42 * will be removed in a future release.
43 */
44 public class EmailValidator {
45
46 private static final String SPECIAL_CHARS = "\\p{Cntrl}\\(\\)<>@,;:'\\\\\\\"\\.\\[\\]";
47 private static final String VALID_CHARS = "[^\\s" + SPECIAL_CHARS + "]";
48 private static final String QUOTED_USER = "(\"[^\"]*\")";
49 private static final String ATOM = VALID_CHARS + '+';
50 private static final String WORD = "((" + VALID_CHARS + "|')+|" + QUOTED_USER + ")";
51
52 // NOT USED private static final Pattern LEGAL_ASCII_PATTERN = Pattern.compile("^\\p{ASCII}+$");
53 // NOT USED private static final Pattern EMAIL_PATTERN = Pattern.compile("^(.+)@(.+)$");
54 private static final Pattern IP_DOMAIN_PATTERN = Pattern.compile("^\\[(.*)\\]$");
55 private static final Pattern TLD_PATTERN = Pattern.compile("^([a-zA-Z]+)$");
56
57 private static final Pattern USER_PATTERN = Pattern.compile("^\\s*" + WORD + "(\\." + WORD + ")*$");
58 private static final Pattern DOMAIN_PATTERN = Pattern.compile("^" + ATOM + "(\\." + ATOM + ")*\\s*$");
59 private static final Pattern ATOM_PATTERN = Pattern.compile("(" + ATOM + ")");
60
61 /**
62 * Singleton instance of this class.
63 */
64 private static final EmailValidator EMAIL_VALIDATOR = new EmailValidator();
65
66 /**
67 * Returns the Singleton instance of this validator.
68 * @return singleton instance of this validator.
69 */
70 public static EmailValidator getInstance() {
71 return EMAIL_VALIDATOR;
72 }
73
74 /**
75 * Protected constructor for subclasses to use.
76 */
77 protected EmailValidator() {
78 super();
79 }
80
81 /**
82 * <p>Checks if a field has a valid e-mail address.</p>
83 *
84 * @param email The value validation is being performed on. A <code>null</code>
85 * value is considered invalid.
86 * @return true if the email address is valid.
87 */
88 public boolean isValid(String email) {
89 return org.apache.commons.validator.routines.EmailValidator.getInstance().isValid(email);
90 }
91
92 /**
93 * Returns true if the domain component of an email address is valid.
94 * @param domain being validated.
95 * @return true if the email address's domain is valid.
96 */
97 protected boolean isValidDomain(String domain) {
98 boolean symbolic = false;
99
100 // see if domain is an IP address in brackets
101 Matcher ipDomainMatcher = IP_DOMAIN_PATTERN.matcher(domain);
102
103 if (ipDomainMatcher.matches()) {
104 InetAddressValidator inetAddressValidator =
105 InetAddressValidator.getInstance();
106 if (inetAddressValidator.isValid(ipDomainMatcher.group(1))) {
107 return true;
108 }
109 } else {
110 // Domain is symbolic name
111 symbolic = DOMAIN_PATTERN.matcher(domain).matches();
112 }
113
114 if (symbolic) {
115 if (!isValidSymbolicDomain(domain)) {
116 return false;
117 }
118 } else {
119 return false;
120 }
121
122 return true;
123 }
124
125 /**
126 * Returns true if the user component of an email address is valid.
127 * @param user being validated
128 * @return true if the user name is valid.
129 */
130 protected boolean isValidUser(String user) {
131 return USER_PATTERN.matcher(user).matches();
132 }
133
134 /**
135 * Validates an IP address. Returns true if valid.
136 * @param ipAddress IP address
137 * @return true if the ip address is valid.
138 */
139 protected boolean isValidIpAddress(String ipAddress) {
140 Matcher ipAddressMatcher = IP_DOMAIN_PATTERN.matcher(ipAddress);
141 for (int i = 1; i <= 4; i++) {
142 String ipSegment = ipAddressMatcher.group(i);
143 if (ipSegment == null || ipSegment.length() <= 0) {
144 return false;
145 }
146
147 int iIpSegment = 0;
148
149 try {
150 iIpSegment = Integer.parseInt(ipSegment);
151 } catch(NumberFormatException e) {
152 return false;
153 }
154
155 if (iIpSegment > 255) {
156 return false;
157 }
158
159 }
160 return true;
161 }
162
163 /**
164 * Validates a symbolic domain name. Returns true if it's valid.
165 * @param domain symbolic domain name
166 * @return true if the symbolic domain name is valid.
167 */
168 protected boolean isValidSymbolicDomain(String domain) {
169 String[] domainSegment = new String[10];
170 boolean match = true;
171 int i = 0;
172 Matcher atomMatcher = ATOM_PATTERN.matcher(domain);
173 while (match) {
174 match = atomMatcher.matches();
175 if (match) {
176 domainSegment[i] = atomMatcher.group(1);
177 int l = domainSegment[i].length() + 1;
178 domain =
179 (l >= domain.length())
180 ? ""
181 : domain.substring(l);
182
183 i++;
184 }
185 }
186
187 int len = i;
188
189 // Make sure there's a host name preceding the domain.
190 if (len < 2) {
191 return false;
192 }
193
194 // TODO: the tld should be checked against some sort of configurable
195 // list
196 String tld = domainSegment[len - 1];
197 if (tld.length() > 1) {
198 if (! TLD_PATTERN.matcher(tld).matches()) {
199 return false;
200 }
201 } else {
202 return false;
203 }
204
205 return true;
206 }
207 /**
208 * Recursively remove comments, and replace with a single space. The simpler
209 * regexps in the Email Addressing FAQ are imperfect - they will miss escaped
210 * chars in atoms, for example.
211 * Derived From Mail::RFC822::Address
212 * @param emailStr The email address
213 * @return address with comments removed.
214 */
215 protected String stripComments(String emailStr) {
216 String result = emailStr;
217 String commentPat = "^((?:[^\"\\\\]|\\\\.)*(?:\"(?:[^\"\\\\]|\\\\.)*\"(?:[^\"\\\\]|\111111\\\\.)*)*)\\((?:[^()\\\\]|\\\\.)*\\)/";
218 Pattern commentMatcher = Pattern.compile(commentPat);
219
220 while (commentMatcher.matcher(result).matches()) {
221 result = result.replaceFirst(commentPat, "\1 ");
222 }
223 return result;
224 }
225 }