LCOV - code coverage report
Current view: top level - mail - MailHeaderParser.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 52 56 92.9 %
Date: 2022-11-19 15:00:39 Functions: 4 5 80.0 %

          Line data    Source code
       1             : // Copyright (C) 2016 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.mail;
      16             : 
      17             : import com.google.common.base.Splitter;
      18             : import com.google.common.base.Strings;
      19             : import com.google.common.flogger.FluentLogger;
      20             : import com.google.common.primitives.Ints;
      21             : import java.sql.Timestamp;
      22             : import java.time.Instant;
      23             : import java.time.format.DateTimeParseException;
      24             : 
      25             : /** Parse metadata from inbound email */
      26           0 : public class MailHeaderParser {
      27           4 :   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
      28             : 
      29             :   public static MailMetadata parse(MailMessage m) {
      30           4 :     MailMetadata metadata = new MailMetadata();
      31             :     // Find author
      32           4 :     metadata.author = m.from().email();
      33             : 
      34             :     // Check email headers for X-Gerrit-<Name>
      35           4 :     for (String header : m.additionalHeaders()) {
      36           2 :       if (header.startsWith(MailHeader.CHANGE_NUMBER.fieldWithDelimiter())) {
      37           1 :         String num = header.substring(MailHeader.CHANGE_NUMBER.fieldWithDelimiter().length());
      38           1 :         metadata.changeNumber = Ints.tryParse(num);
      39           2 :       } else if (header.startsWith(MailHeader.PATCH_SET.fieldWithDelimiter())) {
      40           1 :         String ps = header.substring(MailHeader.PATCH_SET.fieldWithDelimiter().length());
      41           1 :         metadata.patchSet = Ints.tryParse(ps);
      42           2 :       } else if (header.startsWith(MailHeader.COMMENT_DATE.fieldWithDelimiter())) {
      43           1 :         String ts = header.substring(MailHeader.COMMENT_DATE.fieldWithDelimiter().length()).trim();
      44             :         try {
      45           1 :           metadata.timestamp =
      46           1 :               Timestamp.from(MailProcessingUtil.rfcDateformatter.parse(ts, Instant::from));
      47           0 :         } catch (DateTimeParseException e) {
      48           0 :           logger.atSevere().withCause(e).log(
      49           0 :               "Mail: Error while parsing timestamp from header of message %s", m.id());
      50           1 :         }
      51           2 :       } else if (header.startsWith(MailHeader.MESSAGE_TYPE.fieldWithDelimiter())) {
      52           1 :         metadata.messageType =
      53           1 :             header.substring(MailHeader.MESSAGE_TYPE.fieldWithDelimiter().length());
      54             :       }
      55           2 :     }
      56           4 :     if (metadata.hasRequiredFields()) {
      57           1 :       return metadata;
      58             :     }
      59             : 
      60             :     // If the required fields were not yet found, continue to parse the text
      61           4 :     if (!Strings.isNullOrEmpty(m.textContent())) {
      62           4 :       Iterable<String> lines = Splitter.on('\n').split(m.textContent().replace("\r\n", "\n"));
      63           4 :       extractFooters(lines, metadata, m);
      64           4 :       if (metadata.hasRequiredFields()) {
      65           3 :         return metadata;
      66             :       }
      67             :     }
      68             : 
      69             :     // If the required fields were not yet found, continue to parse the HTML
      70             :     // HTML footer are contained inside a <div> tag
      71           3 :     if (!Strings.isNullOrEmpty(m.htmlContent())) {
      72           1 :       Iterable<String> lines = Splitter.on("</div>").split(m.htmlContent().replace("\r\n", "\n"));
      73           1 :       extractFooters(lines, metadata, m);
      74           1 :       if (metadata.hasRequiredFields()) {
      75           1 :         return metadata;
      76             :       }
      77             :     }
      78             : 
      79           2 :     return metadata;
      80             :   }
      81             : 
      82             :   private static void extractFooters(Iterable<String> lines, MailMetadata metadata, MailMessage m) {
      83           4 :     for (String line : lines) {
      84           4 :       if (metadata.changeNumber == null && line.contains(MailHeader.CHANGE_NUMBER.getName())) {
      85           3 :         metadata.changeNumber =
      86           3 :             Ints.tryParse(extractFooter(MailHeader.CHANGE_NUMBER.withDelimiter(), line));
      87           4 :       } else if (metadata.patchSet == null && line.contains(MailHeader.PATCH_SET.getName())) {
      88           3 :         metadata.patchSet =
      89           3 :             Ints.tryParse(extractFooter(MailHeader.PATCH_SET.withDelimiter(), line));
      90           4 :       } else if (metadata.timestamp == null && line.contains(MailHeader.COMMENT_DATE.getName())) {
      91           3 :         String ts = extractFooter(MailHeader.COMMENT_DATE.withDelimiter(), line);
      92             :         try {
      93           3 :           metadata.timestamp =
      94           3 :               Timestamp.from(MailProcessingUtil.rfcDateformatter.parse(ts, Instant::from));
      95           1 :         } catch (DateTimeParseException e) {
      96           1 :           logger.atSevere().withCause(e).log(
      97           1 :               "Mail: Error while parsing timestamp from footer of message %s", m.id());
      98           3 :         }
      99           4 :       } else if (metadata.messageType == null && line.contains(MailHeader.MESSAGE_TYPE.getName())) {
     100           3 :         metadata.messageType = extractFooter(MailHeader.MESSAGE_TYPE.withDelimiter(), line);
     101             :       }
     102           4 :     }
     103           4 :   }
     104             : 
     105             :   private static String extractFooter(String key, String line) {
     106           3 :     return line.substring(line.indexOf(key) + key.length()).trim();
     107             :   }
     108             : }

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