Subversion Repositories javautils

Rev

Rev 17 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. package de.viathinksoft.utils.mail.syntaxchecker;
  2.  
  3. import java.util.Arrays;
  4. import java.util.HashSet;
  5. import java.util.regex.Pattern;
  6.  
  7. import de.viathinksoft.utils.mail.address.EMailAddress;
  8.  
  9. /**
  10.  * This class is not stable. For a good syntax check, please use the classes of
  11.  * Dominic Sayers or Cal Henderson.
  12.  *
  13.  * @author Daniel Marschall
  14.  * @version 0.1
  15.  *
  16.  */
  17. @Deprecated
  18. public class MailSyntaxChecker {
  19.  
  20.         private static final String REGEX_IP = "\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b";
  21.  
  22.         // Führt eine Prüfung der E-Mail-Adresse gemäß SMTP-Spezifikation RFC 5321
  23.         // aus
  24.         private static final boolean CHECK_SMTP_SIZE_LIMITS = false;
  25.  
  26.         // Führt eine Prüfung der TLD gemäß IANA-Daten aus
  27.         private static final boolean CHECK_TLD_RECOGNIZED = true;
  28.  
  29.         // Führt eine DNS-Prüfung durch
  30.         private static final boolean CHECK_DNS = true;
  31.  
  32.         // http://data.iana.org/TLD/tlds-alpha-by-domain.txt
  33.         // Version 2010052500, Last Updated Tue May 25 14:07:02 2010 UTC
  34.         private static final HashSet<String> RECOGNIZED_TLDS_PUNYCODE = hmaker(new String[] {
  35.                         "AC", "AD", "AE", "AERO", "AF", "AG", "AI", "AL", "AM", "AN", "AO",
  36.                         "AQ", "AR", "ARPA", "AS", "ASIA", "AT", "AU", "AW", "AX", "AZ",
  37.                         "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BIZ", "BJ", "BM",
  38.                         "BN", "BO", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", "CAT",
  39.                         "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO",
  40.                         "COM", "COOP", "CR", "CU", "CV", "CX", "CY", "CZ", "DE", "DJ",
  41.                         "DK", "DM", "DO", "DZ", "EC", "EDU", "EE", "EG", "ER", "ES", "ET",
  42.                         "EU", "FI", "FJ", "FK", "FM", "FO", "FR", "GA", "GB", "GD", "GE",
  43.                         "GF", "GG", "GH", "GI", "GL", "GM", "GN", "GOV", "GP", "GQ", "GR",
  44.                         "GS", "GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU",
  45.                         "ID", "IE", "IL", "IM", "IN", "INFO", "INT", "IO", "IQ", "IR",
  46.                         "IS", "IT", "JE", "JM", "JO", "JOBS", "JP", "KE", "KG", "KH", "KI",
  47.                         "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", "LI",
  48.                         "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME",
  49.                         "MG", "MH", "MIL", "MK", "ML", "MM", "MN", "MO", "MOBI", "MP",
  50.                         "MQ", "MR", "MS", "MT", "MU", "MUSEUM", "MV", "MW", "MX", "MY",
  51.                         "MZ", "NA", "NAME", "NC", "NE", "NET", "NF", "NG", "NI", "NL",
  52.                         "NO", "NP", "NR", "NU", "NZ", "OM", "ORG", "PA", "PE", "PF", "PG",
  53.                         "PH", "PK", "PL", "PM", "PN", "PR", "PRO", "PS", "PT", "PW", "PY",
  54.                         "QA", "RE", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SD", "SE",
  55.                         "SG", "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "ST",
  56.                         "SU", "SV", "SY", "SZ", "TC", "TD", "TEL", "TF", "TG", "TH", "TJ",
  57.                         "TK", "TL", "TM", "TN", "TO", "TP", "TR", "TRAVEL", "TT", "TV",
  58.                         "TW", "TZ", "UA", "UG", "UK", "US", "UY", "UZ", "VA", "VC", "VE",
  59.                         "VG", "VI", "VN", "VU", "WF", "WS", "XN--0ZWM56D",
  60.                         "XN--11B5BS3A9AJ6G", "XN--80AKHBYKNJ4F", "XN--9T4B11YI5A",
  61.                         "XN--DEBA0AD", "XN--G6W251D", "XN--HGBK6AJ7F53BBA",
  62.                         "XN--HLCJ6AYA9ESC7A", "XN--JXALPDLP", "XN--KGBECHTV",
  63.                         "XN--MGBAAM7A8H", "XN--MGBERP4A5D4AR", "XN--P1AI", "XN--WGBH1C",
  64.                         "XN--ZCKZAH", "YE", "YT", "ZA", "ZM", "ZW", });
  65.  
  66.         private static boolean checkSmtpSizeLimits(EMailAddress email) {
  67.                 // RFC 5321: 4.5.3.1.1. Local-part Längenbegrenzung bei SMTP: 64
  68.                 // Byte
  69.                 // QUE: Soll das auch als Punicode-Variante geprüft werden?
  70.                 if ((email.getLocalPart().length() > 64)
  71.                                 || (email.getLocalPart().length() < 1)) {
  72.                         return false;
  73.                 }
  74.  
  75.                 // RFC 5321: 4.5.3.1.2. Domain-part Längenbegrenzung bei SMTP: 255
  76.                 // Byte
  77.                 if ((email.getDomainPartPunycode().length() > 255)
  78.                                 || (email.getDomainPartPunycode().length() < 1)) {
  79.                         return false;
  80.                 }
  81.  
  82.                 // RFC 5321: 4.5.3.1.5. Reply-Line Längenbegrenzung bei SMTP: 512
  83.                 // Byte. Laut
  84.                 // http://de.wikipedia.org/wiki/E-Mail-Adresse#L.C3.A4nge_der_E-Mail-Adresse
  85.                 // folgt daraus: Länge der MailAddresse ist 254 Bytes.
  86.                 if (email.getMailAddressPunycodedDomain().length() > 254) {
  87.                         return false;
  88.                 }
  89.  
  90.                 return true;
  91.         }
  92.  
  93.         private static boolean checkTldRecognized(EMailAddress email) {
  94.                 // TODO: Mailadressen sind aber auch als ...@[IP] gültig. Dann keine
  95.                 // TLD!
  96.                 return RECOGNIZED_TLDS_PUNYCODE.contains(email.getTldPunycode()
  97.                                 .toUpperCase());
  98.         }
  99.  
  100.         private static boolean preg_match(String regex, String data) {
  101.                 return Pattern.compile(regex).matcher(data).matches();
  102.         }
  103.  
  104.         private static boolean checkDns(String domainOrIP) {
  105.                 // TODO
  106.  
  107.                 return true;
  108.         }
  109.  
  110.         public static boolean isMailValid(String email) {
  111.                 return isMailValid(new EMailAddress(email));
  112.         }
  113.  
  114.         /**
  115.          * Checks if an E-Mail-Address is valid
  116.          *
  117.          * @param email
  118.          * @return
  119.          */
  120.         public static boolean isMailValid(EMailAddress email) {
  121.                 if (CHECK_SMTP_SIZE_LIMITS) {
  122.                         if (!checkSmtpSizeLimits(email))
  123.                                 return false;
  124.                 }
  125.  
  126.                 // Begin RFC-Checks
  127.  
  128.                 final String address = email.getMailAddressUnicode();
  129.                 final String localPart = email.getLocalPart();
  130.                 final String domainPart = email.getDomainPartPunycode();
  131.  
  132.                 // Weder localPart noch domainPart dürfen zwei aufeinanderfolgende
  133.                 // Punkte besitzen.
  134.  
  135.                 if (address.contains("..")) {
  136.                         return false;
  137.                 }
  138.  
  139.                 // localPart darf keine Punkte am Anfang oder Ende besitzen
  140.                
  141.                 if (localPart.length() == 0) {
  142.                         return false;
  143.                 }
  144.                 if (localPart.startsWith(".") || localPart.endsWith(".")) {
  145.                         return false;
  146.                 }
  147.  
  148.                 // domainPart darf keine Punkte am Anfang oder Ende besitzen
  149.  
  150.                 if (domainPart.startsWith(".") || domainPart.endsWith(".")) {
  151.                         return false;
  152.                 }
  153.  
  154.                 // domainPart prüfen
  155.  
  156.                 if (preg_match("^" + REGEX_IP + "$", domainPart)) {
  157.                         // domainPart is <IP>
  158.                         // QUE: Ist das überhaupt gemäß RFC gültig?
  159.  
  160.                         String ip = ""; // TODO
  161.  
  162.                         if (CHECK_DNS) {
  163.                                 if (!checkDns(ip))
  164.                                         return false;
  165.                         }
  166.                 } else if (preg_match("^\\[" + REGEX_IP + "\\]$", domainPart)) {
  167.                         // domainPart is [<IP>]
  168.  
  169.                         String ip = ""; // TODO
  170.  
  171.                         if (CHECK_DNS) {
  172.                                 if (!checkDns(ip))
  173.                                         return false;
  174.                         }
  175.                 } else {
  176.                         if (!preg_match("^[A-Za-z0-9\\-\\.]+$", domainPart)) {
  177.                                 return false;
  178.                         }
  179.  
  180.                         if (CHECK_TLD_RECOGNIZED) {
  181.                                 if (!checkTldRecognized(email))
  182.                                         return false;
  183.                         }
  184.  
  185.                         if (CHECK_DNS) {
  186.                                 if (!checkDns(domainPart))
  187.                                         return false;
  188.                         }
  189.                 }
  190.  
  191.                 // localPart prüfen
  192.  
  193.                 if (!preg_match("^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$",
  194.                                 localPart.replaceAll("\\\\", "").replaceAll("@", ""))) {
  195.                         // character not valid in local part unless
  196.                         // local part is quoted
  197.                         if (!preg_match("^\"(\\\\\"|[^\"])+\"$", localPart.replaceAll(
  198.                                         "\\\\", "").replaceAll("@", ""))) {
  199.                                 return false;
  200.                         }
  201.                 }
  202.  
  203.                 // TODO: Weitere Tests gemäß RFC?
  204.  
  205.                 return true;
  206.         }
  207.  
  208.         /**
  209.          * build a HashSet from a array of String literals.
  210.          *
  211.          * @param list
  212.          *            array of strings
  213.          *
  214.          * @return HashSet you can use to test if a string is in the set.
  215.          */
  216.         private static HashSet<String> hmaker(String[] list) {
  217.                 HashSet<String> map = new HashSet<String>(Math.max(
  218.                                 (int) (list.length / .75f) + 1, 16));
  219.                 map.addAll(Arrays.asList(list));
  220.                 return map;
  221.         }
  222. }
  223.