davmail/src/java/davmail/AbstractConnection.java

270 lines
9.1 KiB
Java

/*
* DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway
* Copyright (C) 2009 Mickael Guessant
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package davmail;
import davmail.exception.DavMailException;
import davmail.exchange.ExchangeSession;
import davmail.ui.tray.DavGatewayTray;
import java.io.*;
import java.net.Socket;
/**
* Generic connection common to pop3 and smtp implementations
*/
public class AbstractConnection extends Thread {
protected enum State {
INITIAL, LOGIN, USER, PASSWORD, AUTHENTICATED, STARTMAIL, RECIPIENT, MAILDATA
}
protected static class LineReaderInputStream extends PushbackInputStream {
final String encoding;
/**
* @inheritDoc
*/
protected LineReaderInputStream(InputStream in, String encoding) {
super(in);
if (encoding == null) {
this.encoding = "ASCII";
} else {
this.encoding = encoding;
}
}
public String readLine() throws IOException {
ByteArrayOutputStream baos = null;
int b;
while ((b = read()) > -1) {
if (b == '\r') {
int next = read();
if (next != '\n') {
unread(next);
}
break;
} else if (b == '\n') {
break;
}
if (baos == null) {
baos = new ByteArrayOutputStream();
}
baos.write(b);
}
if (baos != null) {
return new String(baos.toByteArray(), encoding);
} else {
return null;
}
}
/**
* Read byteSize bytes from inputStream, return content as String.
*
* @param byteSize content size
* @return content
* @throws IOException on error
*/
public String readContentAsString(int byteSize) throws IOException {
return new String(readContent(byteSize), encoding);
}
/**
* Read byteSize bytes from inputStream, return content as byte array.
*
* @param byteSize content size
* @return content
* @throws IOException on error
*/
public byte[] readContent(int byteSize) throws IOException {
byte[] buffer = new byte[byteSize];
int startIndex = 0;
int count = 0;
while (count >= 0 && startIndex < byteSize) {
count = read(buffer, startIndex, byteSize - startIndex);
startIndex += count;
}
if (startIndex < byteSize) {
throw new DavMailException("EXCEPTION_END_OF_STREAM");
}
return buffer;
}
}
protected final Socket client;
protected LineReaderInputStream in;
protected OutputStream os;
// user name and password initialized through connection
protected String userName;
protected String password;
// connection state
protected State state = State.INITIAL;
// Exchange session proxy
protected ExchangeSession session;
/**
* Only set the thread name and socket
*
* @param name thread type name
* @param clientSocket client socket
*/
public AbstractConnection(String name, Socket clientSocket) {
super(name + '-' + clientSocket.getPort());
this.client = clientSocket;
setDaemon(true);
}
/**
* Initialize the streams and set thread name.
*
* @param name thread type name
* @param clientSocket client socket
* @param encoding socket stream encoding
*/
public AbstractConnection(String name, Socket clientSocket, String encoding) {
super(name + '-' + clientSocket.getPort());
this.client = clientSocket;
try {
in = new LineReaderInputStream(client.getInputStream(), encoding);
os = new BufferedOutputStream(client.getOutputStream());
} catch (IOException e) {
close();
DavGatewayTray.error(new BundleMessage("LOG_EXCEPTION_GETTING_SOCKET_STREAMS"), e);
}
}
/**
* Send message to client followed by CRLF.
*
* @param message message
* @throws IOException on error
*/
public void sendClient(String message) throws IOException {
sendClient(null, message);
}
/**
* Send prefix and message to client followed by CRLF.
*
* @param prefix prefix
* @param message message
* @throws IOException on error
*/
public void sendClient(String prefix, String message) throws IOException {
if (prefix != null) {
os.write(prefix.getBytes("UTF-8"));
DavGatewayTray.debug(new BundleMessage("LOG_SEND_CLIENT_PREFIX_MESSAGE", prefix, message));
} else {
DavGatewayTray.debug(new BundleMessage("LOG_SEND_CLIENT_MESSAGE", message));
}
os.write(message.getBytes("UTF-8"));
os.write((char) 13);
os.write((char) 10);
os.flush();
}
/**
* Send only bytes to client.
*
* @param messageBytes content
* @throws IOException on error
*/
public void sendClient(byte[] messageBytes) throws IOException {
sendClient(messageBytes, 0, messageBytes.length);
}
/**
* Send only bytes to client.
*
* @param messageBytes content
* @param offset the start offset in the data.
* @param length the number of bytes to write.
* @throws IOException on error
*/
public void sendClient(byte[] messageBytes, int offset, int length) throws IOException {
//StringBuffer logBuffer = new StringBuffer("> ");
//logBuffer.append(new String(messageBytes, offset, length));
//DavGatewayTray.debug(logBuffer.toString());
os.write(messageBytes, offset, length);
os.flush();
}
/**
* Read a line from the client connection.
* Log message to logger
*
* @return command line or null
* @throws IOException when unable to read line
*/
public String readClient() throws IOException {
String line = in.readLine();
if (line != null) {
if (line.startsWith("PASS")) {
DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_PASS"));
// SMTP LOGIN
} else if (line.startsWith("AUTH LOGIN ")) {
DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_AUTH_LOGIN"));
// IMAP LOGIN
} else if (state == State.INITIAL && line.indexOf(' ') >= 0 &&
line.substring(line.indexOf(' ') + 1).toUpperCase().startsWith("LOGIN")) {
DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_LOGIN"));
} else if (state == State.PASSWORD) {
DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_PASSWORD"));
// HTTP Basic Authentication
} else if (line.startsWith("Authorization:")) {
DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_AUTHORIZATION"));
} else if (line.startsWith("AUTH PLAIN")) {
DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_AUTH_PLAIN"));
} else {
DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_LINE", line));
}
}
DavGatewayTray.switchIcon();
return line;
}
/**
* Close client connection, streams and Exchange session .
*/
public void close() {
if (in != null) {
try {
in.close();
} catch (IOException e2) {
DavGatewayTray.warn(new BundleMessage("LOG_EXCEPTION_CLOSING_CLIENT_INPUT_STREAM"), e2);
}
}
if (os != null) {
try {
os.close();
} catch (IOException e2) {
DavGatewayTray.warn(new BundleMessage("LOG_EXCEPTION_CLOSING_CLIENT_OUTPUT_STREAM"), e2);
}
}
try {
client.close();
} catch (IOException e2) {
DavGatewayTray.warn(new BundleMessage("LOG_EXCEPTION_CLOSING_CLIENT_SOCKET"), e2);
}
}
}