diff options
Diffstat (limited to 'java/com/google/gerrit/server/mail/receive/Pop3MailReceiver.java')
-rw-r--r-- | java/com/google/gerrit/server/mail/receive/Pop3MailReceiver.java | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/java/com/google/gerrit/server/mail/receive/Pop3MailReceiver.java b/java/com/google/gerrit/server/mail/receive/Pop3MailReceiver.java new file mode 100644 index 0000000000..54971c407c --- /dev/null +++ b/java/com/google/gerrit/server/mail/receive/Pop3MailReceiver.java @@ -0,0 +1,125 @@ +// Copyright (C) 2016 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.server.mail.receive; + +import com.google.common.flogger.FluentLogger; +import com.google.common.primitives.Ints; +import com.google.gerrit.mail.MailMessage; +import com.google.gerrit.mail.MailParsingException; +import com.google.gerrit.mail.RawMailParser; +import com.google.gerrit.server.git.WorkQueue; +import com.google.gerrit.server.mail.EmailSettings; +import com.google.gerrit.server.mail.Encryption; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import java.io.BufferedReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.apache.commons.net.pop3.POP3Client; +import org.apache.commons.net.pop3.POP3MessageInfo; +import org.apache.commons.net.pop3.POP3SClient; + +/** An implementation of {@link MailReceiver} for POP3. */ +@Singleton +public class Pop3MailReceiver extends MailReceiver { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); + + @Inject + Pop3MailReceiver(EmailSettings mailSettings, MailProcessor mailProcessor, WorkQueue workQueue) { + super(mailSettings, mailProcessor, workQueue); + } + + /** + * 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 { + POP3Client pop3; + if (mailSettings.encryption != Encryption.NONE) { + pop3 = new POP3SClient(mailSettings.encryption.name(), true); + } else { + pop3 = new POP3Client(); + } + if (mailSettings.port > 0) { + pop3.setDefaultPort(mailSettings.port); + } + pop3.connect(mailSettings.host); + try { + if (!pop3.login(mailSettings.username, mailSettings.password)) { + throw new MailTransferException( + "Could not login to POP3 email server. Check username and password"); + } + try { + POP3MessageInfo[] messages = pop3.listMessages(); + if (messages == null) { + throw new MailTransferException("Could not retrieve message list via POP3"); + } + logger.atInfo().log("Received %d messages via POP3", messages.length); + // Fetch messages + List<MailMessage> mailMessages = new ArrayList<>(); + for (POP3MessageInfo msginfo : messages) { + if (msginfo == null) { + // Message was deleted + continue; + } + try (BufferedReader reader = (BufferedReader) pop3.retrieveMessage(msginfo.number)) { + if (reader == null) { + throw new MailTransferException( + "Could not retrieve POP3 message header for message " + msginfo.identifier); + } + int[] message = fetchMessage(reader); + MailMessage mailMessage = RawMailParser.parse(message); + // Delete messages where deletion is pending. This requires + // knowing the integer message ID of the email. We therefore parse + // the message first and extract the Message-ID specified in RFC + // 822 and delete the message if deletion is pending. + if (pendingDeletion.contains(mailMessage.id())) { + if (pop3.deleteMessage(msginfo.number)) { + pendingDeletion.remove(mailMessage.id()); + } else { + logger.atSevere().log("Could not delete message %d", msginfo.number); + } + } else { + // Process message further + mailMessages.add(mailMessage); + } + } catch (MailParsingException e) { + logger.atSevere().log("Could not parse message %d", msginfo.number); + } + } + dispatchMailProcessor(mailMessages, async); + } finally { + pop3.logout(); + } + } finally { + pop3.disconnect(); + } + } + + public final int[] fetchMessage(BufferedReader reader) throws IOException { + List<Integer> character = new ArrayList<>(); + int ch; + while ((ch = reader.read()) != -1) { + character.add(ch); + } + return Ints.toArray(character); + } +} |