LCOV - code coverage report
Current view: top level - entities - EmailHeader.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 47 85 55.3 %
Date: 2022-11-19 15:00:39 Functions: 17 29 58.6 %

          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 static java.nio.charset.StandardCharsets.UTF_8;
      18             : 
      19             : import com.google.common.base.MoreObjects;
      20             : import java.io.IOException;
      21             : import java.io.Writer;
      22             : import java.time.Instant;
      23             : import java.time.ZoneId;
      24             : import java.time.format.DateTimeFormatter;
      25             : import java.util.ArrayList;
      26             : import java.util.Collections;
      27             : import java.util.List;
      28             : import java.util.Locale;
      29             : import java.util.Objects;
      30             : 
      31         106 : public abstract class EmailHeader {
      32             :   public abstract boolean isEmpty();
      33             : 
      34             :   public abstract void write(Writer w) throws IOException;
      35             : 
      36             :   public static class StringEmailHeader extends EmailHeader {
      37             :     private final String value;
      38             : 
      39         106 :     public StringEmailHeader(String v) {
      40         106 :       value = v;
      41         106 :     }
      42             : 
      43             :     public String getString() {
      44           7 :       return value;
      45             :     }
      46             : 
      47             :     @Override
      48             :     public boolean isEmpty() {
      49           0 :       return value == null || value.length() == 0;
      50             :     }
      51             : 
      52             :     @Override
      53             :     public void write(Writer w) throws IOException {
      54           0 :       if (needsQuotedPrintable(value)) {
      55           0 :         w.write(quotedPrintable(value));
      56             :       } else {
      57           0 :         w.write(value);
      58             :       }
      59           0 :     }
      60             : 
      61             :     @Override
      62             :     public int hashCode() {
      63           0 :       return Objects.hashCode(value);
      64             :     }
      65             : 
      66             :     @Override
      67             :     public boolean equals(Object o) {
      68           2 :       return (o instanceof StringEmailHeader)
      69           2 :           && Objects.equals(value, ((StringEmailHeader) o).value);
      70             :     }
      71             : 
      72             :     @Override
      73             :     public String toString() {
      74           1 :       return MoreObjects.toStringHelper(this).addValue(value).toString();
      75             :     }
      76             :   }
      77             : 
      78             :   public static boolean needsQuotedPrintable(String value) {
      79          17 :     for (int i = 0; i < value.length(); i++) {
      80          17 :       if (value.charAt(i) < ' ' || '~' < value.charAt(i)) {
      81           1 :         return true;
      82             :       }
      83             :     }
      84          17 :     return false;
      85             :   }
      86             : 
      87             :   static boolean needsQuotedPrintableWithinPhrase(int cp) {
      88           1 :     switch (cp) {
      89             :       case '!':
      90             :       case '*':
      91             :       case '+':
      92             :       case '-':
      93             :       case '/':
      94             :       case '=':
      95             :       case '_':
      96           0 :         return false;
      97             :       default:
      98           1 :         if (('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z') || ('0' <= cp && cp <= '9')) {
      99           1 :           return false;
     100             :         }
     101           1 :         return true;
     102             :     }
     103             :   }
     104             : 
     105             :   public static String quotedPrintable(String value) {
     106           1 :     final StringBuilder r = new StringBuilder();
     107             : 
     108           1 :     r.append("=?UTF-8?Q?");
     109           1 :     for (int i = 0; i < value.length(); i++) {
     110           1 :       final int cp = value.codePointAt(i);
     111           1 :       if (cp == ' ') {
     112           1 :         r.append('_');
     113             : 
     114           1 :       } else if (needsQuotedPrintableWithinPhrase(cp)) {
     115           1 :         byte[] buf = new String(Character.toChars(cp)).getBytes(UTF_8);
     116           1 :         for (byte b : buf) {
     117           1 :           r.append('=');
     118           1 :           r.append(Integer.toHexString((b >>> 4) & 0x0f).toUpperCase());
     119           1 :           r.append(Integer.toHexString(b & 0x0f).toUpperCase());
     120             :         }
     121             : 
     122           1 :       } else {
     123           1 :         r.append(Character.toChars(cp));
     124             :       }
     125             :     }
     126           1 :     r.append("?=");
     127             : 
     128           1 :     return r.toString();
     129             :   }
     130             : 
     131             :   public static class Date extends EmailHeader {
     132             :     private final Instant value;
     133             : 
     134         106 :     public Date(Instant v) {
     135         106 :       value = v;
     136         106 :     }
     137             : 
     138             :     public Instant getDate() {
     139           0 :       return value;
     140             :     }
     141             : 
     142             :     @Override
     143             :     public boolean isEmpty() {
     144           0 :       return value == null;
     145             :     }
     146             : 
     147             :     @Override
     148             :     public void write(Writer w) throws IOException {
     149             :       // Mon, 1 Jun 2009 10:49:44 +0000
     150           0 :       w.write(
     151           0 :           DateTimeFormatter.ofPattern("EEE, d MMM yyyy HH:mm:ss Z")
     152           0 :               .withLocale(Locale.US)
     153           0 :               .withZone(ZoneId.of("UTC"))
     154           0 :               .format(value));
     155           0 :     }
     156             : 
     157             :     @Override
     158             :     public int hashCode() {
     159           0 :       return Objects.hashCode(value);
     160             :     }
     161             : 
     162             :     @Override
     163             :     public boolean equals(Object o) {
     164           1 :       return (o instanceof Date) && Objects.equals(value, ((Date) o).value);
     165             :     }
     166             : 
     167             :     @Override
     168             :     public String toString() {
     169           0 :       return MoreObjects.toStringHelper(this).addValue(value).toString();
     170             :     }
     171             :   }
     172             : 
     173             :   public static class AddressList extends EmailHeader {
     174         106 :     private final List<Address> list = new ArrayList<>();
     175             : 
     176         106 :     public AddressList() {}
     177             : 
     178         106 :     public AddressList(Address addr) {
     179         106 :       add(addr);
     180         106 :     }
     181             : 
     182             :     public List<Address> getAddressList() {
     183          10 :       return Collections.unmodifiableList(list);
     184             :     }
     185             : 
     186             :     public void add(Address addr) {
     187         106 :       list.add(addr);
     188         106 :     }
     189             : 
     190             :     public void remove(String email) {
     191          47 :       list.removeIf(address -> address.email().equals(email));
     192          47 :     }
     193             : 
     194             :     @Override
     195             :     public boolean isEmpty() {
     196           7 :       return list.isEmpty();
     197             :     }
     198             : 
     199             :     @Override
     200             :     public void write(Writer w) throws IOException {
     201           0 :       int len = 8;
     202           0 :       boolean firstAddress = true;
     203           0 :       boolean needComma = false;
     204           0 :       for (Address addr : list) {
     205           0 :         String s = addr.toHeaderString();
     206           0 :         if (firstAddress) {
     207           0 :           firstAddress = false;
     208           0 :         } else if (72 < len + s.length()) {
     209           0 :           w.write(",\r\n\t");
     210           0 :           len = 8;
     211           0 :           needComma = false;
     212             :         }
     213             : 
     214           0 :         if (needComma) {
     215           0 :           w.write(", ");
     216             :         }
     217           0 :         w.write(s);
     218           0 :         len += s.length();
     219           0 :         needComma = true;
     220           0 :       }
     221           0 :     }
     222             : 
     223             :     @Override
     224             :     public int hashCode() {
     225           0 :       return Objects.hashCode(list);
     226             :     }
     227             : 
     228             :     @Override
     229             :     public boolean equals(Object o) {
     230           0 :       return (o instanceof AddressList) && Objects.equals(list, ((AddressList) o).list);
     231             :     }
     232             : 
     233             :     @Override
     234             :     public String toString() {
     235           0 :       return MoreObjects.toStringHelper(this).addValue(list).toString();
     236             :     }
     237             :   }
     238             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750