Line data Source code
1 : // Copyright (C) 2009 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.entities; 16 : 17 : import com.google.auto.value.AutoValue; 18 : import com.google.auto.value.extension.memoized.Memoized; 19 : import com.google.gerrit.common.Nullable; 20 : 21 : /** Represents an address (name + email) in an email message. */ 22 : @AutoValue 23 148 : public abstract class Address { 24 : public static Address parse(String in) { 25 16 : final int lt = in.indexOf('<'); 26 16 : final int gt = in.indexOf('>'); 27 16 : final int at = in.indexOf("@"); 28 16 : if (0 <= lt && lt < gt && lt + 1 < at && at + 1 < gt) { 29 9 : final String email = in.substring(lt + 1, gt).trim(); 30 9 : final String name = in.substring(0, lt).trim(); 31 9 : int nameStart = 0; 32 9 : int nameEnd = name.length(); 33 9 : if (name.startsWith("\"")) { 34 0 : nameStart++; 35 : } 36 9 : if (name.endsWith("\"")) { 37 0 : nameEnd--; 38 : } 39 9 : return Address.create(name.length() > 0 ? name.substring(nameStart, nameEnd) : null, email); 40 : } 41 : 42 16 : if (lt < 0 && gt < 0 && 0 < at && at < in.length() - 1) { 43 14 : return Address.create(in); 44 : } 45 : 46 13 : throw new IllegalArgumentException("Invalid email address: " + in); 47 : } 48 : 49 : @Nullable 50 : public static Address tryParse(String in) { 51 : try { 52 13 : return parse(in); 53 12 : } catch (IllegalArgumentException e) { 54 12 : return null; 55 : } 56 : } 57 : 58 : public static Address create(String email) { 59 17 : return create(null, email); 60 : } 61 : 62 : public static Address create(String name, String email) { 63 148 : return new AutoValue_Address(name, email); 64 : } 65 : 66 : @Nullable 67 : public abstract String name(); 68 : 69 : public abstract String email(); 70 : 71 : @Memoized 72 : @Override 73 : public int hashCode() { 74 106 : return email().hashCode(); 75 : } 76 : 77 : @Override 78 : public final boolean equals(Object other) { 79 20 : if (other instanceof Address) { 80 20 : return email().equals(((Address) other).email()); 81 : } 82 0 : return false; 83 : } 84 : 85 : @Override 86 : public final String toString() { 87 18 : return toHeaderString(); 88 : } 89 : 90 : public String toHeaderString() { 91 19 : if (name() != null) { 92 17 : return quotedPhrase(name()) + " <" + email() + ">"; 93 13 : } else if (isSimple()) { 94 13 : return email(); 95 : } 96 1 : return "<" + email() + ">"; 97 : } 98 : 99 : private static final String MUST_QUOTE_EMAIL = "()<>,;:\\\"[]"; 100 : private static final String MUST_QUOTE_NAME = MUST_QUOTE_EMAIL + "@."; 101 : 102 : private boolean isSimple() { 103 13 : for (int i = 0; i < email().length(); i++) { 104 13 : final char c = email().charAt(i); 105 13 : if (c <= ' ' || 0x7F <= c || MUST_QUOTE_EMAIL.indexOf(c) != -1) { 106 1 : return false; 107 : } 108 : } 109 13 : return true; 110 : } 111 : 112 : private static String quotedPhrase(String name) { 113 17 : if (EmailHeader.needsQuotedPrintable(name)) { 114 1 : return EmailHeader.quotedPrintable(name); 115 : } 116 17 : for (int i = 0; i < name.length(); i++) { 117 17 : final char c = name.charAt(i); 118 17 : if (MUST_QUOTE_NAME.indexOf(c) != -1) { 119 5 : return wrapInQuotes(name); 120 : } 121 : } 122 17 : return name; 123 : } 124 : 125 : private static String wrapInQuotes(String name) { 126 5 : final StringBuilder r = new StringBuilder(2 + name.length()); 127 5 : r.append('"'); 128 5 : for (int i = 0; i < name.length(); i++) { 129 5 : char c = name.charAt(i); 130 5 : if (c == '"' || c == '\\') { 131 1 : r.append('\\'); 132 : } 133 5 : r.append(c); 134 : } 135 5 : r.append('"'); 136 5 : return r.toString(); 137 : } 138 : }