📄 smtphandler.java
字号:
StringBuffer exceptionBuffer = new StringBuffer(256) .append("Cannot open connection from ") .append(remoteHost) .append(" (") .append(remoteIP) .append("): ") .append(e.getMessage()); String exceptionString = exceptionBuffer.toString(); getLogger().error(exceptionString, e ); throw new RuntimeException(exceptionString); } if (getLogger().isInfoEnabled()) { StringBuffer infoBuffer = new StringBuffer(128) .append("Connection from ") .append(remoteHost) .append(" (") .append(remoteIP) .append(")"); getLogger().info(infoBuffer.toString()); } try { out = new InternetPrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()), 1024), false); // Initially greet the connector // Format is: Sat, 24 Jan 1998 13:16:09 -0500 responseBuffer.append("220 ") .append(theConfigData.getHelloName()) .append(" SMTP Server (") .append(SOFTWARE_TYPE) .append(") ready ") .append(rfc822DateFormat.format(new Date())); String responseString = clearResponseBuffer(); writeLoggedFlushedResponse(responseString); theWatchdog.start(); while (parseCommand(readCommandLine())) { theWatchdog.reset(); } theWatchdog.stop(); getLogger().debug("Closing socket."); } catch (SocketException se) { if (getLogger().isErrorEnabled()) { StringBuffer errorBuffer = new StringBuffer(64) .append("Socket to ") .append(remoteHost) .append(" (") .append(remoteIP) .append(") closed remotely."); getLogger().error(errorBuffer.toString(), se ); } } catch ( InterruptedIOException iioe ) { if (getLogger().isErrorEnabled()) { StringBuffer errorBuffer = new StringBuffer(64) .append("Socket to ") .append(remoteHost) .append(" (") .append(remoteIP) .append(") timeout."); getLogger().error( errorBuffer.toString(), iioe ); } } catch ( IOException ioe ) { if (getLogger().isErrorEnabled()) { StringBuffer errorBuffer = new StringBuffer(256) .append("Exception handling socket to ") .append(remoteHost) .append(" (") .append(remoteIP) .append(") : ") .append(ioe.getMessage()); getLogger().error( errorBuffer.toString(), ioe ); } } catch (Exception e) { if (getLogger().isErrorEnabled()) { getLogger().error( "Exception opening socket: " + e.getMessage(), e ); } } finally { resetHandler(); } } /** * Resets the handler data to a basic state. */ private void resetHandler() { resetState(); clearResponseBuffer(); in = null; inReader = null; out = null; remoteHost = null; remoteIP = null; authenticatedUser = null; smtpID = null; if (theWatchdog != null) { if (theWatchdog instanceof Disposable) { ((Disposable)theWatchdog).dispose(); } theWatchdog = null; } try { if (socket != null) { socket.close(); } } catch (IOException e) { if (getLogger().isErrorEnabled()) { getLogger().error("Exception closing socket: " + e.getMessage()); } } finally { socket = null; } synchronized (this) { handlerThread = null; } } /** * Clears the response buffer, returning the String of characters in the buffer. * * @return the data in the response buffer */ private String clearResponseBuffer() { String responseString = responseBuffer.toString(); responseBuffer.delete(0,responseBuffer.length()); return responseString; } /** * This method logs at a "DEBUG" level the response string that * was sent to the SMTP client. The method is provided largely * as syntactic sugar to neaten up the code base. It is declared * private and final to encourage compiler inlining. * * @param responseString the response string sent to the client */ private final void logResponseString(String responseString) { if (getLogger().isDebugEnabled()) { getLogger().debug("Sent: " + responseString); } } /** * Write and flush a response string. The response is also logged. * Should be used for the last line of a multi-line response or * for a single line response. * * @param responseString the response string sent to the client */ final void writeLoggedFlushedResponse(String responseString) { out.println(responseString); out.flush(); logResponseString(responseString); } /** * Write a response string. The response is also logged. * Used for multi-line responses. * * @param responseString the response string sent to the client */ final void writeLoggedResponse(String responseString) { out.println(responseString); logResponseString(responseString); } /** * Reads a line of characters off the command line. * * @return the trimmed input line * @throws IOException if an exception is generated reading in the input characters */ final String readCommandLine() throws IOException { for (;;) try { String commandLine = inReader.readLine(); if (commandLine != null) { commandLine = commandLine.trim(); } return commandLine; } catch (CRLFTerminatedReader.TerminationException te) { writeLoggedFlushedResponse("501 Syntax error at character position " + te.position() + ". CR and LF must be CRLF paired. See RFC 2821 #2.7.1."); } } /** * Sets the user name associated with this SMTP interaction. * * @param userID the user name */ private void setUser(String userID) { authenticatedUser = userID; } /** * Returns the user name associated with this SMTP interaction. * * @return the user name */ private String getUser() { return authenticatedUser; } /** * Resets message-specific, but not authenticated user, state. * */ private void resetState() { ArrayList recipients = (ArrayList)state.get(RCPT_LIST); if (recipients != null) { recipients.clear(); } state.clear(); } /** * This method parses SMTP commands read off the wire in handleConnection. * Actual processing of the command (possibly including additional back and * forth communication with the client) is delegated to one of a number of * command specific handler methods. The primary purpose of this method is * to parse the raw command string to determine exactly which handler should * be called. It returns true if expecting additional commands, false otherwise. * * @param rawCommand the raw command string passed in over the socket * * @return whether additional commands are expected. */ private boolean parseCommand(String command) throws Exception { String argument = null; boolean returnValue = true; if (command == null) { return false; } if ((state.get(MESG_FAILED) == null) && (getLogger().isDebugEnabled())) { getLogger().debug("Command received: " + command); } int spaceIndex = command.indexOf(" "); if (spaceIndex > 0) { argument = command.substring(spaceIndex + 1); command = command.substring(0, spaceIndex); } command = command.toUpperCase(Locale.US); if (command.equals(COMMAND_HELO)) { doHELO(argument); } else if (command.equals(COMMAND_EHLO)) { doEHLO(argument); } else if (command.equals(COMMAND_AUTH)) { doAUTH(argument); } else if (command.equals(COMMAND_MAIL)) { doMAIL(argument); } else if (command.equals(COMMAND_RCPT)) { doRCPT(argument); } else if (command.equals(COMMAND_NOOP)) { doNOOP(argument); } else if (command.equals(COMMAND_RSET)) { doRSET(argument); } else if (command.equals(COMMAND_DATA)) { doDATA(argument); } else if (command.equals(COMMAND_QUIT)) { doQUIT(argument); returnValue = false; } else if (command.equals(COMMAND_VRFY)) { doVRFY(argument); } else if (command.equals(COMMAND_EXPN)) { doEXPN(argument); } else if (command.equals(COMMAND_HELP)) { doHELP(argument); } else { if (state.get(MESG_FAILED) == null) { doUnknownCmd(command, argument); } } return returnValue; } /** * Handler method called upon receipt of a HELO command. * Responds with a greeting and informs the client whether * client authentication is required. * * @param argument the argument passed in with the command by the SMTP client */ private void doHELO(String argument) { String responseString = null; if (argument == null) { responseString = "501 Domain address required: " + COMMAND_HELO; writeLoggedFlushedResponse(responseString); } else { resetState(); state.put(CURRENT_HELO_MODE, COMMAND_HELO); if (authRequired) { //This is necessary because we're going to do a multiline response responseBuffer.append("250-"); } else { responseBuffer.append("250 "); } responseBuffer.append(theConfigData.getHelloName()) .append(" Hello ") .append(argument) .append(" (") .append(remoteHost)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -