blob: 69d5fcdaab0324106b31d9ea32adc058f8cbba32 [file] [log] [blame]
// Copyright (C) 2009 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.mail;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.base.MoreObjects;
import java.io.IOException;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
public abstract class EmailHeader {
public abstract boolean isEmpty();
public abstract void write(Writer w) throws IOException;
public static class String extends EmailHeader {
private final java.lang.String value;
public String(java.lang.String v) {
value = v;
}
public java.lang.String getString() {
return value;
}
@Override
public boolean isEmpty() {
return value == null || value.length() == 0;
}
@Override
public void write(Writer w) throws IOException {
if (needsQuotedPrintable(value)) {
w.write(quotedPrintable(value));
} else {
w.write(value);
}
}
@Override
public int hashCode() {
return Objects.hashCode(value);
}
@Override
public boolean equals(Object o) {
return (o instanceof String) && Objects.equals(value, ((String) o).value);
}
@Override
public java.lang.String toString() {
return MoreObjects.toStringHelper(this).addValue(value).toString();
}
}
public static boolean needsQuotedPrintable(java.lang.String value) {
for (int i = 0; i < value.length(); i++) {
if (value.charAt(i) < ' ' || '~' < value.charAt(i)) {
return true;
}
}
return false;
}
static boolean needsQuotedPrintableWithinPhrase(int cp) {
switch (cp) {
case '!':
case '*':
case '+':
case '-':
case '/':
case '=':
case '_':
return false;
default:
if (('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z') || ('0' <= cp && cp <= '9')) {
return false;
}
return true;
}
}
public static java.lang.String quotedPrintable(java.lang.String value) {
final StringBuilder r = new StringBuilder();
r.append("=?UTF-8?Q?");
for (int i = 0; i < value.length(); i++) {
final int cp = value.codePointAt(i);
if (cp == ' ') {
r.append('_');
} else if (needsQuotedPrintableWithinPhrase(cp)) {
byte[] buf = new java.lang.String(Character.toChars(cp)).getBytes(UTF_8);
for (byte b : buf) {
r.append('=');
r.append(Integer.toHexString((b >>> 4) & 0x0f).toUpperCase());
r.append(Integer.toHexString(b & 0x0f).toUpperCase());
}
} else {
r.append(Character.toChars(cp));
}
}
r.append("?=");
return r.toString();
}
public static class Date extends EmailHeader {
private final java.util.Date value;
public Date(java.util.Date v) {
value = v;
}
public java.util.Date getDate() {
return value;
}
@Override
public boolean isEmpty() {
return value == null;
}
@Override
public void write(Writer w) throws IOException {
final SimpleDateFormat fmt;
// Mon, 1 Jun 2009 10:49:44 -0700
fmt = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.US);
w.write(fmt.format(value));
}
@Override
public int hashCode() {
return Objects.hashCode(value);
}
@Override
public boolean equals(Object o) {
return (o instanceof Date) && Objects.equals(value, ((Date) o).value);
}
@Override
public java.lang.String toString() {
return MoreObjects.toStringHelper(this).addValue(value).toString();
}
}
public static class AddressList extends EmailHeader {
private final List<Address> list = new ArrayList<>();
public AddressList() {}
public AddressList(Address addr) {
add(addr);
}
public List<Address> getAddressList() {
return Collections.unmodifiableList(list);
}
public void add(Address addr) {
list.add(addr);
}
public void remove(java.lang.String email) {
list.removeIf(address -> address.getEmail().equals(email));
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public void write(Writer w) throws IOException {
int len = 8;
boolean firstAddress = true;
boolean needComma = false;
for (Address addr : list) {
java.lang.String s = addr.toHeaderString();
if (firstAddress) {
firstAddress = false;
} else if (72 < len + s.length()) {
w.write(",\r\n\t");
len = 8;
needComma = false;
}
if (needComma) {
w.write(", ");
}
w.write(s);
len += s.length();
needComma = true;
}
}
@Override
public int hashCode() {
return Objects.hashCode(list);
}
@Override
public boolean equals(Object o) {
return (o instanceof AddressList) && Objects.equals(list, ((AddressList) o).list);
}
@Override
public java.lang.String toString() {
return MoreObjects.toStringHelper(this).addValue(list).toString();
}
}
}