📄 pop3handler.java
字号:
/**************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * * or more contributor license agreements. See the NOTICE file * * distributed with this work for additional information * * regarding copyright ownership. The ASF licenses this file * * to you 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 org.apache.james.pop3server;import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;import org.apache.avalon.excalibur.pool.Poolable;import org.apache.avalon.framework.container.ContainerUtil;import org.apache.avalon.framework.logger.AbstractLogEnabled;import org.apache.commons.collections.ListUtils;import org.apache.james.Constants;import org.apache.james.core.MailImpl;import org.apache.james.services.MailRepository;import org.apache.james.util.CRLFTerminatedReader;import org.apache.james.util.ExtraDotOutputStream;import org.apache.james.util.InternetPrintWriter;import org.apache.james.util.watchdog.BytesWrittenResetOutputStream;import org.apache.james.util.watchdog.Watchdog;import org.apache.james.util.watchdog.WatchdogTarget;import org.apache.mailet.Mail;import javax.mail.MessagingException;import javax.mail.internet.MimeMessage;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.PrintWriter;import java.net.Socket;import java.util.ArrayList;import java.util.Enumeration;import java.util.Iterator;import java.util.List;import java.util.Locale;import java.util.StringTokenizer;/** * The handler class for POP3 connections. * */public class POP3Handler extends AbstractLogEnabled implements ConnectionHandler, Poolable { // POP3 Server identification string used in POP3 headers private static final String softwaretype = "JAMES POP3 Server " + Constants.SOFTWARE_VERSION; // POP3 response prefixes private final static String OK_RESPONSE = "+OK"; // OK response. Requested content // will follow private final static String ERR_RESPONSE = "-ERR"; // Error response. Requested content // will not be provided. This prefix // is followed by a more detailed // error message // Authentication states for the POP3 interaction private final static int AUTHENTICATION_READY = 0; // Waiting for user id private final static int AUTHENTICATION_USERSET = 1; // User id provided, waiting for // password private final static int TRANSACTION = 2; // A valid user id/password combination // has been provided. In this state // the client can access the mailbox // of the specified user private static final Mail DELETED = new MailImpl(); // A placeholder for emails deleted // during the course of the POP3 // transaction. This Mail instance // is used to enable fast checks as // to whether an email has been // deleted from the inbox. /** * The per-service configuration data that applies to all handlers */ private POP3HandlerConfigurationData theConfigData; /** * The mail server's copy of the user's inbox */ private MailRepository userInbox; /** * The thread executing this handler */ private Thread handlerThread; /** * The TCP/IP socket over which the POP3 interaction * is occurring */ private Socket socket; /** * The reader associated with incoming characters. */ private CRLFTerminatedReader in; /** * The writer to which outgoing messages are written. */ private PrintWriter out; /** * The socket's output stream */ private OutputStream outs; /** * The current transaction state of the handler */ private int state; /** * The user id associated with the POP3 dialogue */ private String user; /** * A dynamic list representing the set of * emails in the user's inbox at any given time * during the POP3 transaction. */ private ArrayList userMailbox = new ArrayList(); private ArrayList backupUserMailbox; // A snapshot list representing the set of // emails in the user's inbox at the beginning // of the transaction /** * The watchdog being used by this handler to deal with idle timeouts. */ private Watchdog theWatchdog; /** * The watchdog target that idles out this handler. */ private WatchdogTarget theWatchdogTarget = new POP3WatchdogTarget(); /** * Set the configuration data for the handler. * * @param theData the configuration data */ void setConfigurationData(POP3HandlerConfigurationData theData) { theConfigData = theData; } /** * Set the Watchdog for use by this handler. * * @param theWatchdog the watchdog */ void setWatchdog(Watchdog theWatchdog) { this.theWatchdog = theWatchdog; } /** * Gets the Watchdog Target that should be used by Watchdogs managing * this connection. * * @return the WatchdogTarget */ WatchdogTarget getWatchdogTarget() { return theWatchdogTarget; } /** * Idle out this connection */ void idleClose() { if (getLogger() != null) { getLogger().error("POP3 Connection has idled out."); } try { if (socket != null) { socket.close(); } } catch (Exception e) { // ignored } finally { socket = null; } synchronized (this) { // Interrupt the thread to recover from internal hangs if (handlerThread != null) { handlerThread.interrupt(); handlerThread = null; } } } /** * @see org.apache.avalon.cornerstone.services.connection.ConnectionHandler#handleConnection(Socket) */ public void handleConnection( Socket connection ) throws IOException { String remoteHost = ""; String remoteIP = ""; try { this.socket = connection; synchronized (this) { handlerThread = Thread.currentThread(); } // in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "ASCII"), 512); in = new CRLFTerminatedReader(new BufferedInputStream(socket.getInputStream(), 512), "ASCII"); remoteIP = socket.getInetAddress().getHostAddress (); remoteHost = socket.getInetAddress().getHostName (); } catch (Exception e) { if (getLogger().isErrorEnabled()) { StringBuffer exceptionBuffer = new StringBuffer(256) .append("Cannot open connection from ") .append(remoteHost) .append(" (") .append(remoteIP) .append("): ") .append(e.getMessage()); getLogger().error( exceptionBuffer.toString(), e ); } } if (getLogger().isInfoEnabled()) { StringBuffer logBuffer = new StringBuffer(128) .append("Connection from ") .append(remoteHost) .append(" (") .append(remoteIP) .append(") "); getLogger().info(logBuffer.toString()); } try { outs = new BufferedOutputStream(socket.getOutputStream(), 1024); out = new InternetPrintWriter(outs, true); state = AUTHENTICATION_READY; user = "unknown"; StringBuffer responseBuffer = new StringBuffer(256) .append(OK_RESPONSE) .append(" ") .append(theConfigData.getHelloName()) .append(" POP3 server (") .append(POP3Handler.softwaretype) .append(") ready "); out.println(responseBuffer.toString()); theWatchdog.start(); while (parseCommand(readCommandLine())) { theWatchdog.reset(); } theWatchdog.stop(); if (getLogger().isInfoEnabled()) { StringBuffer logBuffer = new StringBuffer(128) .append("Connection for ") .append(user) .append(" from ") .append(remoteHost) .append(" (") .append(remoteIP) .append(") closed."); getLogger().info(logBuffer.toString()); } } catch (Exception e) { out.println(ERR_RESPONSE + " Error closing connection."); out.flush(); StringBuffer exceptionBuffer = new StringBuffer(128) .append("Exception during connection from ") .append(remoteHost) .append(" (") .append(remoteIP) .append(") : ") .append(e.getMessage()); getLogger().error(exceptionBuffer.toString(), e ); } finally { resetHandler(); } } /** * Resets the handler data to a basic state. */ private void resetHandler() { if (theWatchdog != null) { ContainerUtil.dispose(theWatchdog); theWatchdog = null; } // Close and clear streams, sockets try { if (socket != null) { socket.close(); socket = null; } } catch (IOException ioe) { // Ignoring exception on close } finally { socket = null; } try { if (in != null) { in.close(); } } catch (Exception e) { // Ignored } finally { in = null; } try { if (out != null) { out.close(); } } catch (Exception e) { // Ignored } finally { out = null; } try { if (outs != null) { outs.close(); } } catch (Exception e) { // Ignored } finally { outs = null; } synchronized (this) { handlerThread = null; } // Clear user data user = null; userInbox = null; if (userMailbox != null) { userMailbox.clear(); userMailbox = null; } if (backupUserMailbox != null) { backupUserMailbox.clear(); backupUserMailbox = null; } // Clear config data theConfigData = null; } /** * Implements a "stat". If the handler is currently in * a transaction state, this amounts to a rollback of the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -