001// Generated by delombok at Sat Feb 25 17:58:34 UTC 2023
002package io.cui.tools.net;
003
004import java.net.IDN;
005import java.util.function.UnaryOperator;
006import java.util.regex.Pattern;
007import lombok.NonNull;
008
009/**
010 * <p>
011 * Utility class to handle IDN email addresses.
012 * </p>
013 * See
014 * <ul>
015 * <li>
016 * <a href="https://docs.oracle.com/javase/tutorial/i18n/network/idn.html">https://docs.oracle.com/
017 * javase/tutorial/i18n/network/idn.html</a></li>
018 * <li>
019 * <a href="https://de.wikipedia.org/wiki/Internationalisierter_Domainname">https://de.wikipedia.org
020 * /wiki/Internationalisierter_Domainname</a></li>
021 * <li>
022 * <a href="https://en.wikipedia.org/wiki/Internationalized_domain_name">https://en.wikipedia.org/
023 * wiki/Internationalized_domain_name</a></li>
024 * </ul>
025 *
026 * @author Matthias Walliczek
027 */
028public final class IDNInternetAddress {
029    private static final Pattern addressPatternWithDisplayName = Pattern.compile("(.{0,64})<(.{1,64})@(.{1,64})>(.{0,64})");
030    private static final Pattern addressPattern = Pattern.compile("(.{1,64})@(.{1,64})");
031
032    /**
033     * Encode the domain part of an email address
034     *
035     * @param completeAddress the address to encode in RFC822 format
036     * @return the encoded address in RFC822 format
037     */
038    public static String encode(@NonNull final String completeAddress) {
039        if (completeAddress == null) {
040            throw new java.lang.NullPointerException("completeAddress is marked non-null but is null");
041        }
042        return encode(completeAddress, untrustedHtml -> untrustedHtml);
043    }
044
045    /**
046     * Encodes the given address and sanitizes the elements with the provided sanitizer. It takes
047     * care on the special elements like {@code <>} by not trying to sanitize them.
048     *
049     * @param completeAddress
050     * @param sanitizer to be passed as UnaryOperator
051     * @return the sanitized and encoded address.
052     */
053    public static String encode(@NonNull final String completeAddress, UnaryOperator<String> sanitizer) {
054        if (completeAddress == null) {
055            throw new java.lang.NullPointerException("completeAddress is marked non-null but is null");
056        }
057        var matcher = addressPatternWithDisplayName.matcher(completeAddress);
058        if (matcher.matches() && matcher.groupCount() == 4) {
059            return sanitizer.apply(matcher.group(1)) + "<" + sanitizer.apply(matcher.group(2)) + "@" + sanitizer.apply(IDN.toASCII(matcher.group(3))) + ">" + sanitizer.apply(matcher.group(4));
060        }
061        matcher = addressPattern.matcher(completeAddress);
062        if (matcher.matches() && matcher.groupCount() == 2) {
063            return sanitizer.apply(matcher.group(1)) + "@" + sanitizer.apply(IDN.toASCII(matcher.group(2)));
064        }
065        return sanitizer.apply(completeAddress);
066    }
067
068    /**
069     * Decode the domain part of an email address
070     *
071     * @param completeAddress the address to decode in RFC822 format
072     * @return the decoded address in RFC822 format
073     */
074    public static String decode(@NonNull final String completeAddress) {
075        if (completeAddress == null) {
076            throw new java.lang.NullPointerException("completeAddress is marked non-null but is null");
077        }
078        return decode(completeAddress, untrustedHtml -> untrustedHtml);
079    }
080
081    /**
082     * Decodes the given address and sanitizes the elements with the provided sanitizer. It takes
083     * care on the special elements like <> by not trying to sanitize them.
084     *
085     * @param completeAddress
086     * @param sanitizer to be passed as UnaryOperator
087     * @return the sanitized and decoded address.
088     */
089    public static String decode(@NonNull final String completeAddress, UnaryOperator<String> sanitizer) {
090        if (completeAddress == null) {
091            throw new java.lang.NullPointerException("completeAddress is marked non-null but is null");
092        }
093        var matcher = addressPatternWithDisplayName.matcher(completeAddress);
094        if (matcher.matches() && matcher.groupCount() == 4) {
095            return sanitizer.apply(matcher.group(1)) + "<" + sanitizer.apply(matcher.group(2)) + "@" + sanitizer.apply(IDN.toUnicode(matcher.group(3))) + ">" + sanitizer.apply(matcher.group(4));
096        }
097        matcher = addressPattern.matcher(completeAddress);
098        if (matcher.matches() && matcher.groupCount() == 2) {
099            return sanitizer.apply(matcher.group(1)) + "@" + sanitizer.apply(IDN.toUnicode(matcher.group(2)));
100        }
101        return sanitizer.apply(completeAddress);
102    }
103
104    @java.lang.SuppressWarnings("all")
105    @lombok.Generated
106    private IDNInternetAddress() {
107        throw new java.lang.UnsupportedOperationException("This is a utility class and cannot be instantiated");
108    }
109}