1 package org.seasar.cubby.validator.validators; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.regex.Matcher; 6 import java.util.regex.Pattern; 7 8 import org.seasar.cubby.validator.BaseValidator; 9 import org.seasar.cubby.validator.ValidationContext; 10 import org.seasar.framework.util.StringUtil; 11 12 public class EmailValidator extends BaseValidator { 13 14 private static final String SPECIAL_CHARS = "\\(\\)<>@,;:\\\\\\\"\\.\\[\\]"; 15 private static final String VALID_CHARS = "[^\\s" + SPECIAL_CHARS + "]"; 16 private static final String QUOTED_USER = "(\"[^\"]*\")"; 17 private static final String ATOM = VALID_CHARS + '+'; 18 private static final String WORD = "(" + ATOM + "|" + QUOTED_USER + ")"; 19 20 private static final String LEGAL_ASCII_PATTERN = "^[\\x00-\\x7F]+$"; 21 private static final String EMAIL_PATTERN = "^(.+)@(.+)$"; 22 private static final String IP_DOMAIN_PATTERN = 23 "^(\\d{1,3})[.](\\d{1,3})[.](\\d{1,3})[.](\\d{1,3})$"; 24 25 private static final String USER_PATTERN = "^" + WORD + "(\\." + WORD + ")*$"; 26 private static final String DOMAIN_PATTERN = "^" + ATOM + "(\\." + ATOM + ")*$"; 27 private static final String ATOM_PATTERN = "(" + ATOM + ")"; 28 29 public EmailValidator() { 30 this("valid.email"); 31 } 32 33 public EmailValidator(final String messageKey) { 34 this.setMessageKey(messageKey); 35 } 36 37 public String validate(final ValidationContext ctx) { 38 final Object value = ctx.getValue(); 39 if (value == null) { 40 return null; 41 } 42 if (value instanceof String) { 43 final String email = (String) value; 44 if (StringUtil.isEmpty(email)) { 45 return null; 46 } 47 48 boolean match = !email.endsWith("."); 49 if(match){ 50 Pattern pattern = Pattern.compile(LEGAL_ASCII_PATTERN); 51 Matcher matchAsciiPat = pattern.matcher(email); 52 match = matchAsciiPat.matches(); 53 } 54 55 if(match){ 56 Pattern pattern = Pattern.compile(EMAIL_PATTERN); 57 Matcher matcher = pattern.matcher(email); 58 match = matcher.find(); 59 if(match){ 60 if (isValidUser(matcher.group(1)) && 61 isValidDomain(matcher.group(2))) { 62 return null; 63 } 64 } 65 } 66 } 67 return getMessage(getPropertyMessage(ctx.getName())); 68 } 69 70 private boolean isValidDomain(String domain) { 71 Pattern pattern = Pattern.compile(IP_DOMAIN_PATTERN); 72 Matcher ipAddressMatcher = pattern.matcher(domain); 73 74 if (ipAddressMatcher.find()) { 75 if (isValidIpAddress(ipAddressMatcher)) { 76 return true; 77 } 78 } else { 79 pattern = Pattern.compile(DOMAIN_PATTERN); 80 Matcher domainMatcher = pattern.matcher(domain); 81 if (domainMatcher.matches()) { 82 if (isValidSymbolicDomain(domain)) { 83 return true; 84 } 85 } 86 } 87 return false; 88 } 89 90 private boolean isValidUser(String user) { 91 Pattern pattern = Pattern.compile(USER_PATTERN); 92 Matcher userMatcher = pattern.matcher(user); 93 return userMatcher.matches(); 94 } 95 96 private boolean isValidIpAddress(Matcher ipAddressMatcher) { 97 for (int i = 1; i <= 4; i++) { 98 String ipSegment = ipAddressMatcher.group(i); 99 if (ipSegment == null || ipSegment.length() <= 0) { 100 return false; 101 } 102 103 int iIpSegment = 0; 104 105 try { 106 iIpSegment = Integer.parseInt(ipSegment); 107 } catch(NumberFormatException e) { 108 return false; 109 } 110 111 if (iIpSegment > 255) { 112 return false; 113 } 114 115 } 116 return true; 117 } 118 119 private boolean isValidSymbolicDomain(String domain) { 120 List<String> domainSegments = new ArrayList<String>(); 121 boolean match = true; 122 int i = 0; 123 124 Pattern pattern = Pattern.compile(ATOM_PATTERN); 125 Matcher atomMatcher; 126 String ds; 127 while (match) { 128 atomMatcher = pattern.matcher(domain); 129 match = atomMatcher.find(); 130 if (match) { 131 ds = atomMatcher.group(1); 132 domainSegments.add(ds); 133 int l = ds.length() + 1; 134 domain = 135 (l >= domain.length()) 136 ? "" 137 : domain.substring(l); 138 139 i++; 140 } 141 } 142 143 int size = domainSegments.size(); 144 if( size > 0){ 145 String end = domainSegments.get(size-1); 146 if (end.length() < 2 || end.length() > 4) { 147 return false; 148 } 149 } 150 151 if (domainSegments.size() < 2) { 152 return false; 153 } 154 155 return true; 156 } 157 }