package davmail.smtp; import davmail.AbstractConnection; import davmail.DavGatewayTray; import davmail.exchange.ExchangeSession; import sun.misc.BASE64Decoder; import java.io.IOException; import java.net.Socket; import java.util.Date; import java.util.StringTokenizer; /** * Dav Gateway smtp connection implementation */ public class SmtpConnection extends AbstractConnection { protected static final int INITIAL = 0; protected static final int AUTHENTICATED = 1; protected static final int STARTMAIL = 2; protected static final int RECIPIENT = 3; protected static final int MAILDATA = 4; // Initialize the streams and start the thread public SmtpConnection(Socket clientSocket) { super(clientSocket); } public void run() { String line; StringTokenizer tokens; try { sendClient("220 DavMail SMTP ready at " + new Date()); for (; ;) { line = readClient(); // unable to read line, connection closed ? if (line == null) { break; } tokens = new StringTokenizer(line); if (tokens.hasMoreTokens()) { String command = tokens.nextToken(); if ("QUIT".equalsIgnoreCase(command)) { sendClient("221 Closing connection"); break; } else if ("EHLO".equals(command)) { // inform server that AUTH is supported // actually it is mandatory (only way to get credentials) sendClient("250-AUTH LOGIN PLAIN"); sendClient("250 Hello"); } else if ("HELO".equals(command)) { sendClient("250 Hello"); } else if ("AUTH".equals(command)) { if (tokens.hasMoreElements()) { String authType = tokens.nextToken(); if ("PLAIN".equals(authType) && tokens.hasMoreElements()) { decodeCredentials(tokens.nextToken()); session = new ExchangeSession(); try { session.login(userName, password); sendClient("235 OK Authenticated"); state = AUTHENTICATED; } catch (Exception e) { DavGatewayTray.warn("Authentication failed",e); sendClient("554 Authenticated failed"); state = INITIAL; } } else { sendClient("451 Error : unknown authentication type"); } } else { sendClient("451 Error : authentication type not specified"); } } else if ("MAIL".equals(command)) { if (state == AUTHENTICATED) { state = STARTMAIL; sendClient("250 Sender OK"); } else { state = INITIAL; sendClient("503 Bad sequence of commands"); } } else if ("RCPT".equals(command)) { if (state == STARTMAIL || state == RECIPIENT) { state = RECIPIENT; sendClient("250 Recipient OK"); } else { state = AUTHENTICATED; sendClient("503 Bad sequence of commands"); } } else if ("DATA".equals(command)) { if (state == RECIPIENT) { state = MAILDATA; sendClient("354 Start mail input; end with ."); try { session.sendMessage(in); state = AUTHENTICATED; sendClient("250 Queued mail for delivery"); } catch (Exception e) { DavGatewayTray.error("Authentication failed",e); state = AUTHENTICATED; sendClient("451 Error : " + e.getMessage()); } } else { state = AUTHENTICATED; sendClient("503 Bad sequence of commands"); } } } else { sendClient("500 Unrecognized command"); } os.flush(); } } catch (IOException e) { DavGatewayTray.error("Exception handling client",e); } finally { try { client.close(); } catch (IOException e2) { DavGatewayTray.debug("Exception closing client",e2); } try { if (session != null) { session.close(); } } catch (IOException e3) { DavGatewayTray.debug("Exception closing gateway",e3); } } DavGatewayTray.resetIcon(); } /** * Decode SMTP credentials * * @param encodedCredentials smtp encoded credentials * @throws java.io.IOException */ protected void decodeCredentials(String encodedCredentials) throws IOException { BASE64Decoder decoder = new BASE64Decoder(); String decodedCredentials = new String(decoder.decodeBuffer(encodedCredentials)); int index = decodedCredentials.indexOf((char) 0, 1); if (index > 0) { userName = decodedCredentials.substring(1, index); password = decodedCredentials.substring(index + 1); } else { throw new IOException("Invalid credentials"); } } }