Subversion Repositories javautils

Rev

Blame | Last modification | View Log | RSS feed

  1. package de.viathinksoft.utils.mail;
  2.  
  3. import java.net.IDN;
  4.  
  5. import de.viathinksoft.utils.mail.syntaxchecker.MailSyntaxChecker;
  6.  
  7. /**
  8.  *
  9.  * This class parses an email address (trims whitespaces from it) and stores it
  10.  * in its original form as well as store a RFC-compatible punycoded domainpart.
  11.  * So, if you enter a Unicode-Mail-Address you can easily access the trimmed and
  12.  * punycoded domain-part mail-address. Warning! This class does NOT check if the
  13.  * email address is fully valid. Please use the syntax checker class for this.
  14.  *
  15.  * @author Daniel Marschall
  16.  *
  17.  */
  18. public class EMailAddress {
  19.  
  20.         // Constants
  21.  
  22.         /**
  23.          * This constant is used by toString() and tells if whether
  24.          * getMailAddressUnicode() or getMailAddressPunycodedDomain() should be
  25.          * returned.
  26.          */
  27.         static boolean USE_UNICODE_AS_STANDARD = false;
  28.        
  29.         // Attributes
  30.  
  31.         /**
  32.          * The local part of our parsed mail address. (Part before "@") It is
  33.          * allways Unicode, since the mail servers have to take care about it. Even
  34.          * if Unicode mail addresses will become popular in future, the local part
  35.          * will probably not punycoded.
  36.          */
  37.         private String localPart;
  38.         /**
  39.          * The domain part of our parsed mail address (part after "@") inclusive our
  40.          * top level domain (TLD). It is in its Unicode form.
  41.          */
  42.         private String domainPartUnicode;
  43.  
  44.         /**
  45.          * The domain part of our parsed mail address (part after "@") inclusive our
  46.          * top level domain (TLD). It is in its Punycode (ASCII) form.
  47.          */
  48.         private String domainPartPunycode;
  49.  
  50.         /**
  51.          * The top level domain (COM, ORG, BIZ...) of our parsed mail address. The
  52.          * dot is not included. It is in its Unicode form.
  53.          */
  54.         private String tldUnicode;
  55.  
  56.         /**
  57.          * The top level domain (COM, ORG, BIZ...) of our parsed mail address. The
  58.          * dot is not included. It is in its Punycode form.
  59.          */
  60.         private String tldPunycode;
  61.  
  62.         // Getter and Setter
  63.  
  64.         /**
  65.          * The local part of our parsed mail address. (Part before "@") It is
  66.          * allways Unicode, since the mail servers have to take care about it. Even
  67.          * if Unicode mail addresses will become popular in future, the local part
  68.          * will probably not punycoded.
  69.          *
  70.          * @return The local part
  71.          */
  72.         public String getLocalPart() {
  73.                 return localPart;
  74.         }
  75.  
  76.         /**
  77.          * The domain part of our parsed mail address (part after "@") inclusive our
  78.          * top level domain (TLD). It is in its Unicode form.
  79.          *
  80.          * @return The domain part in Unicode.
  81.          */
  82.         public String getDomainPartUnicode() {
  83.                 return domainPartUnicode;
  84.         }
  85.  
  86.         /**
  87.          * The domain part of our parsed mail address (part after "@") inclusive our
  88.          * top level domain (TLD). It is in its Punycode (ASCII) form.
  89.          *
  90.          * @return The domain part in Punycode.
  91.          */
  92.         public String getDomainPartPunycode() {
  93.                 return domainPartPunycode;
  94.         }
  95.  
  96.         /**
  97.          * The top level domain (COM, ORG, BIZ...) of our parsed mail address. The
  98.          * dot is not included. It is in its Unicode form.
  99.          *
  100.          * @return The TLD in Unicode.
  101.          */
  102.         public String getTldUnicode() {
  103.                 return tldUnicode;
  104.         }
  105.  
  106.         /**
  107.          * The top level domain (COM, ORG, BIZ...) of our parsed mail address. The
  108.          * dot is not included. It is in its Punycode form.
  109.          *
  110.          * @return The TLD in Punycode.
  111.          */
  112.         public String getTldPunycode() {
  113.                 return tldPunycode;
  114.         }
  115.  
  116.         // Constructors
  117.  
  118.         /**
  119.          * Creates an email address object out of an email address string.
  120.          *
  121.          * @param eMailAddress
  122.          *            bare computer email address. e.g. roedyg@mindprod.com No
  123.          *            "Roedy Green" <roedyg@mindprod.com> style addresses. No local
  124.          *            addresses, e.g. roedy.
  125.          * @throws InvalidMailAddressException
  126.          */
  127.         public EMailAddress(String eMailAddress) throws InvalidMailAddressException {
  128.                 super();
  129.  
  130.                 if (eMailAddress == null) {
  131.                         throw new InvalidMailAddressException();
  132.                 }
  133.  
  134.                 // Zuerst trimmen (z.B. für Formulardaten) Wir splitten dann beim
  135.                 // At-Zeichen (@) und berücksichtigen ein escaped-At
  136.                 // (\@)
  137.                 String[] res = eMailAddress.trim().split("(?<!\\\\)@");
  138.  
  139.                 // @-sign was not used once
  140.                 if (res.length != 2) {
  141.                         throw new InvalidMailAddressException();
  142.                 }
  143.  
  144.                 // Temporary we store the values here.
  145.  
  146.                 String localPart = res[0];
  147.                 String domainPart = res[1];
  148.  
  149.                 // We parse the local part.
  150.  
  151.                 if (localPart == null)
  152.                         localPart = "";
  153.                 this.localPart = localPart;
  154.  
  155.                 // We parse the domainPart and allocate punycode and unicode fields.
  156.  
  157.                 if (domainPart == null)
  158.                         domainPart = "";
  159.                 if (isUnicode(domainPart)) {
  160.                         this.domainPartUnicode = domainPart;
  161.                         this.domainPartPunycode = IDN.toASCII(domainPart);
  162.                 } else /* if (isPunycode(domainPart)) */{
  163.                         this.domainPartUnicode = IDN.toUnicode(domainPart);
  164.                         this.domainPartPunycode = domainPart;
  165.                 }
  166.  
  167.                 // We additionally parse the TLD and also determinate if it is punycode
  168.                 // or not.
  169.  
  170.                 int dotIdx;
  171.  
  172.                 dotIdx = this.domainPartUnicode.lastIndexOf('.');
  173.                 if (dotIdx >= 0) {
  174.                         this.tldUnicode = this.domainPartUnicode.substring(dotIdx + 1);
  175.                 } else {
  176.                         // We do not throw an exception here because it could be an email to
  177.                         // a network computer or an IP address.
  178.                         this.tldUnicode = "";
  179.                 }
  180.  
  181.                 dotIdx = this.domainPartPunycode.lastIndexOf('.');
  182.                 if (dotIdx >= 0) {
  183.                         this.tldPunycode = this.domainPartPunycode.substring(dotIdx + 1);
  184.                 } else {
  185.                         // We do not throw an exception here because it could be an email to
  186.                         // a network computer or an IP address.
  187.                         this.tldPunycode = "";
  188.                 }
  189.         }
  190.  
  191.         // Methods
  192.  
  193.         /**
  194.          * Returns the email address with punycoded domain name and TLD. You should use
  195.          * this method to send emails.
  196.          *
  197.          * @return The email address with punycoded domain name and TLD.
  198.          */
  199.         public String getMailAddressPunycodedDomain() {
  200.                 return this.localPart + "@" + this.domainPartPunycode;
  201.         }
  202.  
  203.         /**
  204.          * Returns the email address with internationalized domain names and TLD.
  205.          *
  206.          * @return The email address with internationalized domain name and TLD.
  207.          */
  208.         public String getMailAddressUnicode() {
  209.                 return this.localPart + "@" + this.domainPartUnicode;
  210.         }
  211.  
  212.         /**
  213.          * Returns a string which represents the mail address. If the constant
  214.          * USE_UNICODE_AS_STANDARD is true, the internationalized domain names will
  215.          * not translated into the corresponding Punycode. If false, then not.
  216.          *
  217.          * @return The string which represents the mail address. Warning! Since this
  218.          *         method is rather designed to show a formatted mail address, it
  219.          *         should NOT be used to send emails. Please only use this function
  220.          *         if you want to output.
  221.          */
  222.         @Override
  223.         public String toString() {
  224.                 if (USE_UNICODE_AS_STANDARD) {
  225.                         return this.getMailAddressUnicode();
  226.                 } else {
  227.                         return this.getMailAddressPunycodedDomain();
  228.                 }
  229.         }
  230.  
  231.         /**
  232.          * Checks if an object is equal to our email address object.
  233.          *
  234.          * @return Boolean which describes if it is equal or not.
  235.          */
  236.         @Override
  237.         public boolean equals(Object obj) {
  238.                 // Initial checks
  239.  
  240.                 if (this == obj)
  241.                         return true;
  242.                 if (obj == null)
  243.                         return false;
  244.                 if (obj.getClass() != getClass())
  245.                         return false;
  246.  
  247.                 // Compare the fields
  248.  
  249.                 if (!this.domainPartPunycode
  250.                                 .equals(((EMailAddress) obj).domainPartPunycode)) {
  251.                         return false;
  252.                 }
  253.                 if (!this.domainPartUnicode
  254.                                 .equals(((EMailAddress) obj).domainPartUnicode)) {
  255.                         return false;
  256.                 }
  257.                 if (!this.localPart.equals(((EMailAddress) obj).localPart)) {
  258.                         return false;
  259.                 }
  260.                 if (!this.tldUnicode.equals(((EMailAddress) obj).tldUnicode)) {
  261.                         return false;
  262.                 }
  263.                 if (!this.tldPunycode.equals(((EMailAddress) obj).tldPunycode)) {
  264.                         return false;
  265.                 }
  266.  
  267.                 // Everything's fine ^^
  268.  
  269.                 return true;
  270.  
  271.                 // return this.toString().equals(obj.toString());
  272.         }
  273.  
  274.         /**
  275.          * Creates a deep copy of the email address object.
  276.          *
  277.          * @return A new instance of the email address object with the same
  278.          *         properties.
  279.          */
  280.         @Override
  281.         protected EMailAddress clone() throws CloneNotSupportedException {
  282.                 try {
  283.                         return new EMailAddress(this.toString());
  284.                 } catch (InvalidMailAddressException e) {
  285.                         return null;
  286.                 }
  287.         }
  288.  
  289.         /**
  290.          * Asks the mail syntax checker if the current mail address is valid or not.
  291.          * Warning! This check is NOT performed automatically. There is no guarantee
  292.          * that the syntax check is 100% correct. There might be mail address which
  293.          * are valid but marked as invalid (because server disobeyed RFC rules etc)
  294.          * and mail addresses which are invalid but marked valid (e.g. simply if
  295.          * they were not assigned).
  296.          *
  297.          * @return Boolean which represents if the mail address is valid or not.
  298.          */
  299.         public boolean isSyntaxValid() {
  300.                 return MailSyntaxChecker.isMailValid(this);
  301.         }
  302.  
  303.         // ---------- STATIC FUNCTIONS ----------
  304.  
  305.         /**
  306.          * Determinates if a given string can be converted into Punycode.
  307.          *
  308.          * @param str
  309.          *            The string which should be checked
  310.          * @return Boolean which shows if the string is not yet punicoded.
  311.          */
  312.         protected static boolean isUnicode(String str) {
  313.                 if (str == null)
  314.                         return false;
  315.                 return (!IDN.toASCII(str).equals(str));
  316.         }
  317.  
  318.         /**
  319.          * Determinates if a given string is in Punycode format.
  320.          *
  321.          * @param str
  322.          *            The string which should be checked
  323.          * @return Boolean which shows if the string is punycoded or not.
  324.          */
  325.         protected static boolean isPunycode(String str) {
  326.                 if (str == null)
  327.                         return false;
  328.                 return (!IDN.toUnicode(str).equals(str));
  329.         }
  330. }
  331.