📄 smtphandler.java
字号:
/*********************************************************************** * Copyright (c) 2000-2004 The Apache Software Foundation. * * All rights reserved. * * ------------------------------------------------------------------- * * 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 org.apache.james.smtpserver;import java.io.*;import java.net.*;import java.util.*;import javax.mail.*;import javax.mail.internet.*;import org.apache.avalon.framework.activity.Initializable;import org.apache.avalon.framework.component.ComponentException;import org.apache.avalon.framework.component.ComponentManager;import org.apache.avalon.framework.component.Composable;import org.apache.avalon.framework.configuration.Configurable;import org.apache.avalon.framework.configuration.Configuration;import org.apache.avalon.framework.configuration.ConfigurationException;import org.apache.avalon.framework.context.Context;import org.apache.avalon.framework.context.ContextException;import org.apache.avalon.framework.context.Contextualizable;import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;import org.apache.avalon.cornerstone.services.scheduler.PeriodicTimeTrigger;import org.apache.avalon.cornerstone.services.scheduler.Target;import org.apache.avalon.cornerstone.services.scheduler.TimeScheduler;import org.apache.james.*;import org.apache.james.core.*;import org.apache.james.services.MailServer;import org.apache.james.services.UsersRepository;import org.apache.james.services.UsersStore;import org.apache.james.util.*;import org.apache.mailet.*;import javax.security.sasl.*;/** * This handles an individual incoming message. It handles regular SMTP * commands, and when it receives a message, adds it to the spool. * * This is $Revision: 1.1.2.3 $ * Committed on $Date: 2004/03/15 03:54:14 $ by: $Author: noel $ */public class SMTPHandler extends BaseConnectionHandler implements ConnectionHandler, Composable, Configurable, Target { public final static String SERVER_NAME = "SERVER_NAME"; public final static String SERVER_TYPE = "SERVER_TYPE"; public final static String REMOTE_NAME = "REMOTE_NAME"; public final static String REMOTE_IP = "REMOTE_IP"; public final static String NAME_GIVEN = "NAME_GIVEN"; public final static String CURRENT_HELO_MODE = "CURRENT_HELO_MODE"; public final static String SENDER = "SENDER_ADDRESS"; public final static String MESG_FAILED = "MESG_FAILED"; public final static String RCPT_VECTOR = "RCPT_VECTOR"; public final static String SMTP_ID = "SMTP_ID"; public final static String AUTH = "AUTHENTICATED"; public final static char[] SMTPTerminator = {'\r','\n','.','\r','\n'}; private final static boolean DEEP_DEBUG = true; private Socket socket; private DataInputStream in; private PrintWriter out; private String remoteHost; private String remoteHostGiven; private String remoteIP; private String messageID; private String smtpID; private boolean authRequired = false; private boolean verifyIdentity = false; private TimeScheduler scheduler; private UsersRepository users; private MailServer mailServer; private String softwaretype = "JAMES SMTP Server " + Constants.SOFTWARE_VERSION; private static long count; private HashMap state = new HashMap(); private Random random = new Random(); private long maxmessagesize = 0; private static SaslServerFactory serverFactory = new cryptix.sasl.ServerFactory(); public void configure ( Configuration configuration ) throws ConfigurationException { super.configure(configuration); authRequired = configuration.getChild("authRequired").getValueAsBoolean(true); verifyIdentity = configuration.getChild("verifyIdentity").getValueAsBoolean(false); // get the message size limit from the conf file and multiply // by 1024, to put it in bytes maxmessagesize = configuration.getChild( "maxmessagesize" ).getValueAsLong( 0 ) * 1024; if (DEEP_DEBUG) { getLogger().debug("Max message size is: " + maxmessagesize); } Sasl.setSaslServerFactory(serverFactory); } public void compose( final ComponentManager componentManager ) throws ComponentException { mailServer = (MailServer)componentManager.lookup( "org.apache.james.services.MailServer"); scheduler = (TimeScheduler)componentManager.lookup( "org.apache.avalon.cornerstone.services.scheduler.TimeScheduler"); UsersStore usersStore = (UsersStore)componentManager.lookup( "org.apache.james.services.UsersStore" ); users = usersStore.getRepository("LocalUsers"); } /** * Handle a connection. * This handler is responsible for processing connections as they occur. * * @param connection the connection * @exception IOException if an error reading from socket occurs * @exception ProtocolException if an error handling connection occurs */ public void handleConnection( Socket connection ) throws IOException { try { this.socket = connection; final InputStream bufferedInput = new BufferedInputStream( socket.getInputStream(), 1024 ); in = new DataInputStream( bufferedInput ); out = new InternetPrintWriter(socket.getOutputStream(), true); remoteHost = socket.getInetAddress ().getHostName (); remoteIP = socket.getInetAddress ().getHostAddress (); smtpID = Math.abs(random.nextInt() % 1024) + ""; resetState(); } catch (Exception e) { getLogger().error("Cannot open connection from " + remoteHost + " (" + remoteIP + "): " + e.getMessage(), e ); throw new RuntimeException("Cannot open connection from " + remoteHost + " (" + remoteIP + "): " + e.getMessage()); } getLogger().info("Connection from " + remoteHost + " (" + remoteIP + ")"); try { // Initially greet the connector // Format is: Sat, 24 Jan 1998 13:16:09 -0500 final PeriodicTimeTrigger trigger = new PeriodicTimeTrigger( timeout, -1 ); scheduler.addTrigger( this.toString(), trigger, this ); out.println("220 " + this.helloName + " SMTP Server (" + softwaretype + ") ready " + RFC822DateFormat.toString(new Date())); while (parseCommand(in.readLine())) { scheduler.resetTrigger(this.toString()); } socket.close(); scheduler.removeTrigger(this.toString()); } catch (SocketException se) { getLogger().debug("Socket to " + remoteHost + " closed remotely.", se ); } catch ( InterruptedIOException iioe ) { getLogger().debug( "Socket to " + remoteHost + " timeout.", iioe ); } catch ( IOException ioe ) { getLogger().debug( "Exception handling socket to " + remoteHost + ":" + ioe.getMessage(), ioe ); } catch (Exception e) { getLogger().debug( "Exception opening socket: " + e.getMessage(), e ); } finally { try { socket.close(); } catch (IOException e) { getLogger().error("Exception closing socket: " + e.getMessage()); } } } public void targetTriggered( final String triggerName ) { getLogger().error("Connection timeout on socket"); try { out.println("Connection timeout. Closing connection"); socket.close(); } catch (IOException e) { } } private void resetState() { state.clear(); state.put(SERVER_NAME, this.helloName ); state.put(SERVER_TYPE, this.softwaretype ); state.put(REMOTE_NAME, remoteHost); state.put(REMOTE_IP, remoteIP); state.put(SMTP_ID, smtpID); } private boolean parseCommand(String command) throws Exception { if (command == null) return false; if (state.get(MESG_FAILED) == null) { getLogger().info("Command received: " + command); } StringTokenizer commandLine = new StringTokenizer(command.trim(), " :"); int arguments = commandLine.countTokens(); if (arguments == 0) { return true; } else if(arguments > 0) { command = commandLine.nextToken(); } String argument = (String) null; if(arguments > 1) { argument = commandLine.nextToken(); } String argument1 = (String) null; if(arguments > 2) { argument1 = commandLine.nextToken(); } if (command.equalsIgnoreCase("HELO")) doHELO(command,argument,argument1); else if (command.equalsIgnoreCase("EHLO")) doEHLO(command,argument,argument1); else if (command.equalsIgnoreCase("AUTH")) doAUTH(command,argument,argument1); else if (command.equalsIgnoreCase("MAIL")) doMAIL(command,argument,argument1); else if (command.equalsIgnoreCase("RCPT")) doRCPT(command,argument,argument1); else if (command.equalsIgnoreCase("NOOP")) doNOOP(command,argument,argument1); else if (command.equalsIgnoreCase("RSET")) doRSET(command,argument,argument1); else if (command.equalsIgnoreCase("DATA")) doDATA(command,argument,argument1); else if (command.equalsIgnoreCase("QUIT")) doQUIT(command,argument,argument1); else doUnknownCmd(command,argument,argument1); return (command.equalsIgnoreCase("QUIT") == false); } private void doHELO(String command,String argument,String argument1) { if (state.containsKey(CURRENT_HELO_MODE)) { out.println("250 " + state.get(SERVER_NAME) + " Duplicate HELO"); } else if (argument == null) { out.println("501 domain address required: " + command); } else { state.put(CURRENT_HELO_MODE, command); state.put(NAME_GIVEN, argument); out.println( "250 " + state.get(SERVER_NAME) + " Hello " + argument + " (" + state.get(REMOTE_NAME) + " [" + state.get(REMOTE_IP) + "])"); } } private void doEHLO(String command,String argument,String argument1) { if (state.containsKey(CURRENT_HELO_MODE)) { out.println("250 " + state.get(SERVER_NAME) + " Duplicate EHLO"); } else if (argument == null) { out.println("501 domain address required: " + command); } else { state.put(CURRENT_HELO_MODE, command); state.put(NAME_GIVEN, argument); if (authRequired) { out.println("250-AUTH "+getAuthString()); } if (maxmessagesize > 0) { out.println("250-SIZE " + maxmessagesize); } out.println( "250 " + state.get(SERVER_NAME) + " Hello " + argument + " (" + state.get(REMOTE_NAME) + " [" + state.get(REMOTE_IP) + "])"); } } private String getAuthString() { StringBuffer authString = new StringBuffer("LOGIN "); String[] mechanisms = serverFactory.getMechanismNames(null); if (mechanisms.length > 0) { authString.append(mechanisms[0]); for (int i=1;i<mechanisms.length;i++) { authString.append(" "+mechanisms[i]); } } return authString.toString(); } private void doAUTH(String command,String argument,String argument1) throws Exception { String[] mechanisms = serverFactory.getMechanismNames(null); if (state.containsKey(AUTH)) { out.println("503 User has previously authenticated." + " Further authentication is not required!"); return; } else if (argument == null) { out.println("501 Usage: AUTH <"+getAuthString()+ "> [<initial response>]"); return;// } else if (argument.equalsIgnoreCase("PLAIN")) {// String userpass, user, pass;// StringTokenizer authTokenizer;// if (argument1 == null) {// out.println("334 OK. Continue authentication");// userpass = in.readLine().trim();// } else// userpass = argument1.trim();// authTokenizer = new StringTokenizer(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -