📄 smtpconnection.java
字号:
send(command); List list = new ArrayList(); do { switch (getResponse()) { case OK: case AMBIGUOUS: response = response.trim(); if (response.indexOf('@') != -1) { list.add(response); } else if (response.indexOf('<') != -1) { list.add(response); } else if (response.indexOf(' ') == -1) { list.add(response); } break; default: return null; } } while (continuation); return Collections.unmodifiableList(list); } /** * Returns a list of valid possibilities for the specified mailing list, * or null on failure. * @param address a mailing list name */ public List expn(String address) throws IOException { String command = EXPN + ' ' + address; send(command); List list = new ArrayList(); do { switch (getResponse()) { case OK: response = response.trim(); list.add(response); break; default: return null; } } while (continuation); return Collections.unmodifiableList(list); } /** * Returns some useful information about the specified parameter. * Typically this is a command. * @param arg the context of the query, or null for general information * @return a list of possibly useful information, or null if the command * failed. */ public List help(String arg) throws IOException { String command = (arg == null) ? HELP : HELP + ' ' + arg; send(command); List list = new ArrayList(); do { switch (getResponse()) { case INFO: list.add(response); break; default: return null; } } while (continuation); return Collections.unmodifiableList(list); } /** * Issues a NOOP command. * This does nothing, but can be used to keep the connection alive. */ public void noop() throws IOException { send(NOOP); getAllResponses(); } /** * Close the connection to the server. */ public void quit() throws IOException { try { send(QUIT); getAllResponses(); /* RFC 2821 states that the server MUST send an OK reply here, but * many don't: postfix, for instance, sends 221. * In any case we have done our best. */ } catch (IOException e) { } finally { // Close the socket anyway. socket.close(); } } /** * Issues a HELO command. * @param hostname the local host name */ public boolean helo(String hostname) throws IOException { String command = HELO + ' ' + hostname; send(command); return (getAllResponses() == OK); } /** * Issues an EHLO command. * If successful, returns a list of the SMTP extensions supported by the * server. * Otherwise returns null, and HELO should be called. * @param hostname the local host name */ public List ehlo(String hostname) throws IOException { String command = EHLO + ' ' + hostname; send(command); List extensions = new ArrayList(); do { switch (getResponse()) { case OK: extensions.add(response); break; default: return null; } } while (continuation); return Collections.unmodifiableList(extensions); } /** * Returns a configured SSLSocketFactory to use in creating new SSL * sockets. * @param tm an optional trust manager to use */ protected SSLSocketFactory getSSLSocketFactory(TrustManager tm) throws GeneralSecurityException { if (tm == null) { tm = new EmptyX509TrustManager(); } SSLContext context = SSLContext.getInstance("TLS"); TrustManager[] trust = new TrustManager[] { tm }; context.init(null, trust, null); return context.getSocketFactory(); } /** * Negotiate TLS over the current connection. * This depends on many features, such as the JSSE classes being in the * classpath. Returns true if successful, false otherwise. */ public boolean starttls() throws IOException { return starttls(new EmptyX509TrustManager()); } /** * Negotiate TLS over the current connection. * This depends on many features, such as the JSSE classes being in the * classpath. Returns true if successful, false otherwise. * @param tm the custom trust manager to use */ public boolean starttls(TrustManager tm) throws IOException { try { SSLSocketFactory factory = getSSLSocketFactory(tm); send(STARTTLS); if (getAllResponses() != READY) { return false; } String hostname = socket.getInetAddress().getHostName(); int port = socket.getPort(); SSLSocket ss = (SSLSocket) factory.createSocket(socket, hostname, port, true); String[] protocols = { "TLSv1", "SSLv3" }; ss.setEnabledProtocols(protocols); ss.setUseClientMode(true); ss.startHandshake(); // Set up streams InputStream in = ss.getInputStream(); in = new BufferedInputStream(in); in = new CRLFInputStream(in); this.in = new LineInputStream(in); OutputStream out = ss.getOutputStream(); out = new BufferedOutputStream(out); this.out = new CRLFOutputStream(out); return true; } catch (GeneralSecurityException e) { return false; } } // -- Authentication -- /** * Authenticates the connection using the specified SASL mechanism, * username, and password. * @param mechanism a SASL authentication mechanism, e.g. LOGIN, PLAIN, * CRAM-MD5, GSSAPI * @param username the authentication principal * @param password the authentication credentials * @return true if authentication was successful, false otherwise */ public boolean authenticate(String mechanism, String username, String password) throws IOException { try { String[] m = new String[] { mechanism }; CallbackHandler ch = new SaslCallbackHandler(username, password); // Avoid lengthy callback procedure for GNU Crypto HashMap p = new HashMap(); p.put("gnu.crypto.sasl.username", username); p.put("gnu.crypto.sasl.password", password); SaslClient sasl = Sasl.createSaslClient(m, null, "smtp", socket.getInetAddress().getHostName(), p, ch); if (sasl == null) { // Fall back to home-grown SASL clients if ("LOGIN".equalsIgnoreCase(mechanism)) { sasl = new SaslLogin(username, password); } else if ("PLAIN".equalsIgnoreCase(mechanism)) { sasl = new SaslPlain(username, password); } else if ("CRAM-MD5".equalsIgnoreCase(mechanism)) { sasl = new SaslCramMD5(username, password); } else { return false; } } StringBuffer cmd = new StringBuffer(AUTH); cmd.append(' '); cmd.append(mechanism); if (sasl.hasInitialResponse()) { cmd.append(' '); byte[] init = sasl.evaluateChallenge(new byte[0]); if (init.length == 0) { cmd.append('='); } else { cmd.append(new String(BASE64.encode(init), "US-ASCII")); } } send(cmd.toString()); while (true) { switch (getAllResponses()) { case 334: try { byte[] c0 = response.getBytes("US-ASCII"); byte[] c1 = BASE64.decode(c0); // challenge byte[] r0 = sasl.evaluateChallenge(c1); byte[] r1 = BASE64.encode(r0); // response out.write(r1); out.write(0x0d); out.flush(); logger.log(SMTP_TRACE, "> " + new String(r1, "US-ASCII")); } catch (SaslException e) { // Error in SASL challenge evaluation - cancel exchange out.write(0x2a); out.write(0x0d); out.flush(); logger.log(SMTP_TRACE, "> *"); } break; case 235: String qop = (String) sasl.getNegotiatedProperty(Sasl.QOP); if ("auth-int".equalsIgnoreCase(qop) || "auth-conf".equalsIgnoreCase(qop)) { InputStream in = socket.getInputStream(); in = new BufferedInputStream(in); in = new SaslInputStream(sasl, in); in = new CRLFInputStream(in); this.in = new LineInputStream(in); OutputStream out = socket.getOutputStream(); out = new BufferedOutputStream(out); out = new SaslOutputStream(sasl, out); this.out = new CRLFOutputStream(out); } return true; default: return false; } } } catch (SaslException e) { logger.log(SMTP_TRACE, e.getMessage(), e); return false; // No provider for mechanism } catch (RuntimeException e) { logger.log(SMTP_TRACE, e.getMessage(), e); return false; // No javax.security.sasl classes } } // -- Utility methods -- /** * Send the specified command string to the server. * @param command the command to send */ protected void send(String command) throws IOException { logger.log(SMTP_TRACE, "> " + command); out.write(command.getBytes("US-ASCII")); out.write(0x0d); out.flush(); } /** * Returns the next response from the server. */ protected int getResponse() throws IOException { String line = null; try { line = in.readLine(); // Handle special case eg 334 where CRLF occurs after code. if (line.length() < 4) { line = line + '\n' + in.readLine(); } logger.log(SMTP_TRACE, "< " + line); int code = Integer.parseInt(line.substring(0, 3)); continuation = (line.charAt(3) == '-'); response = line.substring(4); return code; } catch (NumberFormatException e) { throw new ProtocolException("Unexpected response: " + line); } } /** * Returns the next response from the server. * If the response is a continuation, continues to read responses until * continuation ceases. If a different response code from the first is * encountered, this causes a protocol exception. */ protected int getAllResponses() throws IOException { int code1, code; boolean err = false; code1 = code = getResponse(); while (continuation) { code = getResponse(); if (code != code1) { err = true; } } if (err) { throw new ProtocolException("Conflicting response codes"); } return code; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -