Search in sources :

Example 1 with MailMessage

use of com.google.gerrit.mail.MailMessage in project gerrit by GerritCodeReview.

the class MessageIdGeneratorIT method fromMailMessage.

@Test
public void fromMailMessage() throws Exception {
    String id = "unique-id";
    MailMessage mailMessage = MailMessage.builder().id(id).from(Address.create("email@email.com")).dateReceived(Instant.EPOCH).subject("subject").build();
    assertThat(messageIdGenerator.fromMailMessage(mailMessage).id()).isEqualTo(id + "-REJECTION");
}
Also used : MailMessage(com.google.gerrit.mail.MailMessage) Test(org.junit.Test) AbstractDaemonTest(com.google.gerrit.acceptance.AbstractDaemonTest)

Example 2 with MailMessage

use of com.google.gerrit.mail.MailMessage in project gerrit by GerritCodeReview.

the class ImapMailReceiver method handleEmails.

/**
 * Opens a connection to the mail server, removes emails where deletion is pending, reads new
 * email and closes the connection.
 *
 * @param async determines if processing messages should happen asynchronously
 * @throws MailTransferException in case of a known transport failure
 * @throws IOException in case of a low-level transport failure
 */
@Override
public synchronized void handleEmails(boolean async) throws MailTransferException, IOException {
    IMAPClient imap;
    if (mailSettings.encryption != Encryption.NONE) {
        imap = new IMAPSClient(mailSettings.encryption.name(), true);
    } else {
        imap = new IMAPClient();
    }
    if (mailSettings.port > 0) {
        imap.setDefaultPort(mailSettings.port);
    }
    // Set a 30s timeout for each operation
    imap.setDefaultTimeout(30 * 1000);
    imap.connect(mailSettings.host);
    try {
        if (!imap.login(mailSettings.username, mailSettings.password)) {
            throw new MailTransferException("Could not login to IMAP server");
        }
        try {
            if (!imap.select(INBOX_FOLDER)) {
                throw new MailTransferException("Could not select IMAP folder " + INBOX_FOLDER);
            }
            // should fetch.
            if (!imap.fetch("1:*", "(INTERNALDATE)")) {
                // false indicates that there are no messages to fetch
                logger.atInfo().log("Fetched 0 messages via IMAP");
                return;
            }
            // Format of reply is one line per email and one line to indicate
            // that the fetch was successful.
            // Example:
            // * 1 FETCH (INTERNALDATE "Mon, 24 Oct 2016 16:53:22 +0200 (CEST)")
            // * 2 FETCH (INTERNALDATE "Mon, 24 Oct 2016 16:53:22 +0200 (CEST)")
            // AAAC OK FETCH completed.
            int numMessages = imap.getReplyStrings().length - 1;
            logger.atInfo().log("Fetched %d messages via IMAP", numMessages);
            // Fetch the full version of all emails
            List<MailMessage> mailMessages = new ArrayList<>(numMessages);
            for (int i = 1; i <= numMessages; i++) {
                if (imap.fetch(i + ":" + i, "(BODY.PEEK[])")) {
                    // Obtain full reply
                    String[] rawMessage = imap.getReplyStrings();
                    if (rawMessage.length < 2) {
                        continue;
                    }
                    // First and last line are IMAP status codes. We have already
                    // checked, that the fetch returned true (OK), so we safely ignore
                    // those two lines.
                    StringBuilder b = new StringBuilder(2 * (rawMessage.length - 2));
                    for (int j = 1; j < rawMessage.length - 1; j++) {
                        if (j > 1) {
                            b.append("\n");
                        }
                        b.append(rawMessage[j]);
                    }
                    try {
                        MailMessage mailMessage = RawMailParser.parse(b.toString());
                        if (pendingDeletion.contains(mailMessage.id())) {
                            // Mark message as deleted
                            if (imap.store(i + ":" + i, "+FLAGS", "(\\Deleted)")) {
                                pendingDeletion.remove(mailMessage.id());
                            } else {
                                logger.atSevere().log("Could not mark mail message as deleted: %s", mailMessage.id());
                            }
                        } else {
                            mailMessages.add(mailMessage);
                        }
                    } catch (MailParsingException e) {
                        logger.atSevere().withCause(e).log("Exception while parsing email after IMAP fetch");
                    }
                } else {
                    logger.atSevere().log("IMAP fetch failed. Will retry in next fetch cycle.");
                }
            }
            // Permanently delete emails marked for deletion
            if (!imap.expunge()) {
                logger.atSevere().log("Could not expunge IMAP emails");
            }
            dispatchMailProcessor(mailMessages, async);
        } finally {
            imap.logout();
        }
    } finally {
        imap.disconnect();
    }
}
Also used : MailMessage(com.google.gerrit.mail.MailMessage) IMAPSClient(org.apache.commons.net.imap.IMAPSClient) MailParsingException(com.google.gerrit.mail.MailParsingException) IMAPClient(org.apache.commons.net.imap.IMAPClient) ArrayList(java.util.ArrayList)

Example 3 with MailMessage

use of com.google.gerrit.mail.MailMessage in project gerrit by GerritCodeReview.

the class MailProcessorIT method limitNumberOfComments.

@Test
@GerritConfig(name = "change.maxComments", value = "9")
public void limitNumberOfComments() throws Exception {
    // This change has 2 change messages and 2 comments.
    String changeId = createChangeWithReview();
    String ts = MailProcessingUtil.rfcDateformatter.format(ZonedDateTime.ofInstant(gApi.changes().id(changeId).get().updated.toInstant(), ZoneId.of("UTC")));
    CommentInput commentInput = new CommentInput();
    commentInput.line = 1;
    commentInput.message = "foo";
    commentInput.path = FILE_NAME;
    RobotCommentInput robotCommentInput = TestCommentHelper.createRobotCommentInputWithMandatoryFields(FILE_NAME);
    ReviewInput reviewInput = new ReviewInput();
    reviewInput.comments = ImmutableMap.of(FILE_NAME, ImmutableList.of(commentInput));
    reviewInput.robotComments = ImmutableMap.of(FILE_NAME, ImmutableList.of(robotCommentInput));
    // Add 1 change message and another 2 comments. Total count is now 7, which is still OK.
    gApi.changes().id(changeId).current().review(reviewInput);
    ChangeInfo changeInfo = gApi.changes().id(changeId).get();
    MailMessage.Builder mailMessage = messageBuilderWithDefaultFields();
    String txt = newPlaintextBody(getChangeUrl(changeInfo) + "/1", "1) change message", "2) reply to comment", "3) file comment");
    mailMessage.textContent(txt + textFooterForChange(changeInfo._number, ts));
    ImmutableSet<CommentInfo> commentsBefore = getCommentsAndRobotComments(changeId);
    // Should have 4 comments (and 3 change messages).
    assertThat(commentsBefore).hasSize(4);
    // The email adds 3 new comments (of which 1 is the change message).
    mailProcessor.process(mailMessage.build());
    ImmutableSet<CommentInfo> commentsAfter = getCommentsAndRobotComments(changeId);
    assertThat(commentsAfter).isEqualTo(commentsBefore);
    assertNotifyTo(user);
    Message message = sender.nextMessage();
    assertThat(message.body()).contains("rejected one or more comments");
}
Also used : MailMessage(com.google.gerrit.mail.MailMessage) ChangeInfo(com.google.gerrit.extensions.common.ChangeInfo) MailMessage(com.google.gerrit.mail.MailMessage) Message(com.google.gerrit.testing.FakeEmailSender.Message) CommentInput(com.google.gerrit.extensions.api.changes.ReviewInput.CommentInput) RobotCommentInput(com.google.gerrit.extensions.api.changes.ReviewInput.RobotCommentInput) RobotCommentInput(com.google.gerrit.extensions.api.changes.ReviewInput.RobotCommentInput) CommentInfo(com.google.gerrit.extensions.common.CommentInfo) ReviewInput(com.google.gerrit.extensions.api.changes.ReviewInput) GerritConfig(com.google.gerrit.acceptance.config.GerritConfig) Test(org.junit.Test)

Example 4 with MailMessage

use of com.google.gerrit.mail.MailMessage in project gerrit by GerritCodeReview.

the class MailProcessorIT method limitCumulativeCommentSize.

@Test
@GerritConfig(name = "change.cumulativeCommentSizeLimit", value = "7k")
public void limitCumulativeCommentSize() throws Exception {
    // Use large sizes because autogenerated messages already have O(100) bytes.
    String commentText2000Bytes = new String(new char[2000]).replace("\0", "x");
    String changeId = createChangeWithReview();
    CommentInput commentInput = new CommentInput();
    commentInput.line = 1;
    commentInput.message = commentText2000Bytes;
    commentInput.path = FILE_NAME;
    ReviewInput reviewInput = new ReviewInput().message(commentText2000Bytes);
    reviewInput.comments = ImmutableMap.of(FILE_NAME, ImmutableList.of(commentInput));
    // Use up ~4000 bytes.
    gApi.changes().id(changeId).current().review(reviewInput);
    ChangeInfo changeInfo = gApi.changes().id(changeId).get();
    String ts = MailProcessingUtil.rfcDateformatter.format(ZonedDateTime.ofInstant(gApi.changes().id(changeId).get().updated.toInstant(), ZoneId.of("UTC")));
    // Hit the limit when trying that again.
    MailMessage.Builder mailMessage = messageBuilderWithDefaultFields();
    String txt = newPlaintextBody(getChangeUrl(changeInfo) + "/1", "change message: " + commentText2000Bytes, "reply to comment: " + commentText2000Bytes, null);
    mailMessage.textContent(txt + textFooterForChange(changeInfo._number, ts));
    List<CommentInfo> commentsBefore = testCommentHelper.getPublishedComments(changeId);
    mailProcessor.process(mailMessage.build());
    assertThat(testCommentHelper.getPublishedComments(changeId)).isEqualTo(commentsBefore);
    assertNotifyTo(user);
    Message message = sender.nextMessage();
    assertThat(message.body()).contains("rejected one or more comments");
}
Also used : MailMessage(com.google.gerrit.mail.MailMessage) ChangeInfo(com.google.gerrit.extensions.common.ChangeInfo) MailMessage(com.google.gerrit.mail.MailMessage) Message(com.google.gerrit.testing.FakeEmailSender.Message) CommentInput(com.google.gerrit.extensions.api.changes.ReviewInput.CommentInput) RobotCommentInput(com.google.gerrit.extensions.api.changes.ReviewInput.RobotCommentInput) CommentInfo(com.google.gerrit.extensions.common.CommentInfo) ReviewInput(com.google.gerrit.extensions.api.changes.ReviewInput) GerritConfig(com.google.gerrit.acceptance.config.GerritConfig) Test(org.junit.Test)

Example 5 with MailMessage

use of com.google.gerrit.mail.MailMessage in project gerrit by GerritCodeReview.

the class MailReceiver method dispatchMailProcessor.

protected void dispatchMailProcessor(List<MailMessage> messages, boolean async) {
    for (MailMessage m : messages) {
        if (async) {
            @SuppressWarnings("unused") Future<?> possiblyIgnoredError = workQueue.getDefaultQueue().submit(() -> {
                try {
                    mailProcessor.process(m);
                    requestDeletion(m.id());
                } catch (RestApiException | UpdateException e) {
                    logger.atSevere().withCause(e).log("Mail: Can't process message %s . Won't delete.", m.id());
                }
            });
        } else {
            // Synchronous processing is used only in tests.
            try {
                mailProcessor.process(m);
                requestDeletion(m.id());
            } catch (RestApiException | UpdateException e) {
                logger.atSevere().withCause(e).log("Mail: Can't process messages. Won't delete.");
            }
        }
    }
}
Also used : MailMessage(com.google.gerrit.mail.MailMessage) UpdateException(com.google.gerrit.server.update.UpdateException) RestApiException(com.google.gerrit.extensions.restapi.RestApiException)

Aggregations

MailMessage (com.google.gerrit.mail.MailMessage)7 ArrayList (java.util.ArrayList)3 Test (org.junit.Test)3 GerritConfig (com.google.gerrit.acceptance.config.GerritConfig)2 ReviewInput (com.google.gerrit.extensions.api.changes.ReviewInput)2 CommentInput (com.google.gerrit.extensions.api.changes.ReviewInput.CommentInput)2 RobotCommentInput (com.google.gerrit.extensions.api.changes.ReviewInput.RobotCommentInput)2 ChangeInfo (com.google.gerrit.extensions.common.ChangeInfo)2 CommentInfo (com.google.gerrit.extensions.common.CommentInfo)2 RestApiException (com.google.gerrit.extensions.restapi.RestApiException)2 MailParsingException (com.google.gerrit.mail.MailParsingException)2 UpdateException (com.google.gerrit.server.update.UpdateException)2 Message (com.google.gerrit.testing.FakeEmailSender.Message)2 Strings (com.google.common.base.Strings)1 ImmutableList (com.google.common.collect.ImmutableList)1 ImmutableMap (com.google.common.collect.ImmutableMap)1 Iterables (com.google.common.collect.Iterables)1 FluentLogger (com.google.common.flogger.FluentLogger)1 AbstractDaemonTest (com.google.gerrit.acceptance.AbstractDaemonTest)1 Account (com.google.gerrit.entities.Account)1