2009-07-21 04:39:18 -04:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2006-12-12 18:57:24 -05:00
|
|
|
package davmail;
|
|
|
|
|
2010-07-12 12:35:46 -04:00
|
|
|
import davmail.exception.DavMailException;
|
2006-12-12 18:57:24 -05:00
|
|
|
import davmail.exchange.ExchangeSession;
|
2009-04-03 03:38:31 -04:00
|
|
|
import davmail.ui.tray.DavGatewayTray;
|
2009-04-01 11:51:12 -04:00
|
|
|
import org.apache.commons.codec.binary.Base64;
|
2006-12-12 18:57:24 -05:00
|
|
|
|
2008-12-03 06:38:35 -05:00
|
|
|
import java.io.*;
|
2006-12-12 18:57:24 -05:00
|
|
|
import java.net.Socket;
|
|
|
|
|
2009-01-29 17:18:53 -05:00
|
|
|
|
2006-12-12 18:57:24 -05:00
|
|
|
/**
|
|
|
|
* Generic connection common to pop3 and smtp implementations
|
|
|
|
*/
|
|
|
|
public class AbstractConnection extends Thread {
|
2009-01-29 17:18:53 -05:00
|
|
|
|
2009-04-17 05:20:11 -04:00
|
|
|
protected enum State {
|
|
|
|
INITIAL, LOGIN, USER, PASSWORD, AUTHENTICATED, STARTMAIL, RECIPIENT, MAILDATA
|
|
|
|
}
|
2009-01-29 17:18:53 -05:00
|
|
|
|
2010-07-12 12:35:46 -04:00
|
|
|
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 {
|
2010-07-13 03:07:29 -04:00
|
|
|
ByteArrayOutputStream baos = null;
|
2010-07-12 12:35:46 -04:00
|
|
|
int b;
|
|
|
|
while ((b = read()) > -1) {
|
|
|
|
if (b == '\r') {
|
|
|
|
int next = read();
|
|
|
|
if (next != '\n') {
|
|
|
|
unread(next);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
} else if (b == '\n') {
|
|
|
|
break;
|
|
|
|
}
|
2010-07-13 03:07:29 -04:00
|
|
|
if (baos == null) {
|
|
|
|
baos = new ByteArrayOutputStream();
|
|
|
|
}
|
2010-07-12 12:35:46 -04:00
|
|
|
baos.write(b);
|
|
|
|
}
|
2010-07-13 03:07:29 -04:00
|
|
|
if (baos != null) {
|
|
|
|
return new String(baos.toByteArray(), encoding);
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
2010-07-12 12:35:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Read byteSize bytes from inputStream, return content as String.
|
2010-07-13 03:07:29 -04:00
|
|
|
*
|
2010-07-12 12:35:46 -04:00
|
|
|
* @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.
|
2010-07-13 03:07:29 -04:00
|
|
|
*
|
2010-07-12 12:35:46 -04:00
|
|
|
* @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 = in.read(buffer, startIndex, byteSize - startIndex);
|
|
|
|
startIndex += count;
|
|
|
|
}
|
|
|
|
if (startIndex < byteSize) {
|
|
|
|
throw new DavMailException("EXCEPTION_END_OF_STREAM");
|
|
|
|
}
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-15 05:37:55 -04:00
|
|
|
protected final Socket client;
|
|
|
|
|
2010-07-12 12:35:46 -04:00
|
|
|
protected LineReaderInputStream in;
|
2006-12-12 18:57:24 -05:00
|
|
|
protected OutputStream os;
|
|
|
|
// user name and password initialized through connection
|
2009-04-16 18:20:30 -04:00
|
|
|
protected String userName;
|
|
|
|
protected String password;
|
2006-12-12 18:57:24 -05:00
|
|
|
// connection state
|
2009-01-29 17:18:53 -05:00
|
|
|
protected State state = State.INITIAL;
|
2006-12-12 18:57:24 -05:00
|
|
|
// Exchange session proxy
|
|
|
|
protected ExchangeSession session;
|
|
|
|
|
2009-09-08 18:40:05 -04:00
|
|
|
/**
|
|
|
|
* Only set the thread name and socket
|
|
|
|
*
|
|
|
|
* @param name thread type name
|
|
|
|
* @param clientSocket client socket
|
|
|
|
*/
|
2008-12-03 06:38:35 -05:00
|
|
|
public AbstractConnection(String name, Socket clientSocket) {
|
2009-09-08 18:40:05 -04:00
|
|
|
super(name + '-' + clientSocket.getPort());
|
2008-12-03 06:38:35 -05:00
|
|
|
this.client = clientSocket;
|
2009-05-17 18:24:43 -04:00
|
|
|
setDaemon(true);
|
2008-12-03 06:38:35 -05:00
|
|
|
}
|
|
|
|
|
2009-09-08 18:40:05 -04:00
|
|
|
/**
|
|
|
|
* Initialize the streams and set thread name.
|
|
|
|
*
|
|
|
|
* @param name thread type name
|
|
|
|
* @param clientSocket client socket
|
|
|
|
* @param encoding socket stream encoding
|
|
|
|
*/
|
2008-11-29 09:24:12 -05:00
|
|
|
public AbstractConnection(String name, Socket clientSocket, String encoding) {
|
2009-04-17 05:20:11 -04:00
|
|
|
super(name + '-' + clientSocket.getPort());
|
2007-05-09 19:37:24 -04:00
|
|
|
this.client = clientSocket;
|
2006-12-12 18:57:24 -05:00
|
|
|
try {
|
2010-07-12 12:35:46 -04:00
|
|
|
in = new LineReaderInputStream(client.getInputStream(), encoding);
|
2008-12-03 06:38:35 -05:00
|
|
|
os = new BufferedOutputStream(client.getOutputStream());
|
2006-12-12 18:57:24 -05:00
|
|
|
} catch (IOException e) {
|
2007-05-15 05:37:55 -04:00
|
|
|
close();
|
2009-04-17 05:20:11 -04:00
|
|
|
DavGatewayTray.error(new BundleMessage("LOG_EXCEPTION_GETTING_SOCKET_STREAMS"), e);
|
2006-12-12 18:57:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-26 19:56:28 -05:00
|
|
|
/**
|
|
|
|
* Send message to client followed by CRLF.
|
2008-11-29 09:24:12 -05:00
|
|
|
*
|
2008-11-26 19:56:28 -05:00
|
|
|
* @param message message
|
|
|
|
* @throws IOException on error
|
|
|
|
*/
|
2006-12-12 18:57:24 -05:00
|
|
|
public void sendClient(String message) throws IOException {
|
|
|
|
sendClient(null, message);
|
|
|
|
}
|
|
|
|
|
2008-11-26 19:56:28 -05:00
|
|
|
/**
|
|
|
|
* Send prefix and message to client followed by CRLF.
|
2008-11-29 09:24:12 -05:00
|
|
|
*
|
|
|
|
* @param prefix prefix
|
2008-11-26 19:56:28 -05:00
|
|
|
* @param message message
|
|
|
|
* @throws IOException on error
|
|
|
|
*/
|
2006-12-12 18:57:24 -05:00
|
|
|
public void sendClient(String prefix, String message) throws IOException {
|
|
|
|
if (prefix != null) {
|
|
|
|
os.write(prefix.getBytes());
|
2009-04-23 10:54:06 -04:00
|
|
|
DavGatewayTray.debug(new BundleMessage("LOG_SEND_CLIENT_PREFIX_MESSAGE", prefix, message));
|
|
|
|
} else {
|
|
|
|
DavGatewayTray.debug(new BundleMessage("LOG_SEND_CLIENT_MESSAGE", message));
|
2006-12-12 18:57:24 -05:00
|
|
|
}
|
|
|
|
os.write(message.getBytes());
|
2008-11-29 09:24:12 -05:00
|
|
|
os.write((char) 13);
|
|
|
|
os.write((char) 10);
|
2006-12-12 18:57:24 -05:00
|
|
|
os.flush();
|
|
|
|
}
|
|
|
|
|
2008-11-26 19:56:28 -05:00
|
|
|
/**
|
|
|
|
* Send only bytes to client.
|
2008-11-29 09:24:12 -05:00
|
|
|
*
|
2008-11-26 19:56:28 -05:00
|
|
|
* @param messageBytes content
|
|
|
|
* @throws IOException on error
|
|
|
|
*/
|
|
|
|
public void sendClient(byte[] messageBytes) throws IOException {
|
2009-03-19 03:42:37 -04:00
|
|
|
sendClient(messageBytes, 0, messageBytes.length);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send only bytes to client.
|
|
|
|
*
|
|
|
|
* @param messageBytes content
|
2009-04-17 05:20:11 -04:00
|
|
|
* @param offset the start offset in the data.
|
|
|
|
* @param length the number of bytes to write.
|
2009-03-19 03:42:37 -04:00
|
|
|
* @throws IOException on error
|
|
|
|
*/
|
|
|
|
public void sendClient(byte[] messageBytes, int offset, int length) throws IOException {
|
|
|
|
//StringBuffer logBuffer = new StringBuffer("> ");
|
2009-03-20 12:07:29 -04:00
|
|
|
//logBuffer.append(new String(messageBytes, offset, length));
|
2009-03-19 03:42:37 -04:00
|
|
|
//DavGatewayTray.debug(logBuffer.toString());
|
|
|
|
os.write(messageBytes, offset, length);
|
2008-11-26 19:56:28 -05:00
|
|
|
os.flush();
|
|
|
|
}
|
|
|
|
|
2006-12-12 18:57:24 -05:00
|
|
|
/**
|
|
|
|
* Read a line from the client connection.
|
2009-12-20 05:51:02 -05:00
|
|
|
* Log message to logger
|
2007-03-14 07:55:37 -04:00
|
|
|
*
|
2006-12-12 18:57:24 -05:00
|
|
|
* @return command line or null
|
2007-03-14 07:55:37 -04:00
|
|
|
* @throws IOException when unable to read line
|
2006-12-12 18:57:24 -05:00
|
|
|
*/
|
|
|
|
public String readClient() throws IOException {
|
|
|
|
String line = in.readLine();
|
2008-11-26 19:56:28 -05:00
|
|
|
if (line != null) {
|
|
|
|
if (line.startsWith("PASS")) {
|
2009-04-23 10:54:06 -04:00
|
|
|
DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_PASS"));
|
2010-04-07 18:02:58 -04:00
|
|
|
// SMTP LOGIN
|
|
|
|
} else if (line.startsWith("AUTH LOGIN ")) {
|
|
|
|
DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_AUTH_LOGIN"));
|
2009-01-29 17:18:53 -05:00
|
|
|
// IMAP LOGIN
|
2009-04-17 05:20:11 -04:00
|
|
|
} else if (state == State.INITIAL && line.indexOf(' ') >= 0 &&
|
|
|
|
line.substring(line.indexOf(' ') + 1).startsWith("LOGIN")) {
|
2009-04-23 10:54:06 -04:00
|
|
|
DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_LOGIN"));
|
2009-01-29 17:18:53 -05:00
|
|
|
} else if (state == State.PASSWORD) {
|
2009-04-23 10:54:06 -04:00
|
|
|
DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_PASSWORD"));
|
2009-01-29 17:18:53 -05:00
|
|
|
// HTTP Basic Authentication
|
2008-11-29 09:24:12 -05:00
|
|
|
} else if (line.startsWith("Authorization:")) {
|
2009-04-23 10:54:06 -04:00
|
|
|
DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_AUTHORIZATION"));
|
2009-02-11 08:22:38 -05:00
|
|
|
} else if (line.startsWith("AUTH PLAIN")) {
|
2009-04-23 10:54:06 -04:00
|
|
|
DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_AUTH_PLAIN"));
|
2008-11-26 19:56:28 -05:00
|
|
|
} else {
|
2009-04-23 10:54:06 -04:00
|
|
|
DavGatewayTray.debug(new BundleMessage("LOG_READ_CLIENT_LINE", line));
|
2008-11-26 19:56:28 -05:00
|
|
|
}
|
2006-12-14 10:14:18 -05:00
|
|
|
}
|
2006-12-12 18:57:24 -05:00
|
|
|
DavGatewayTray.switchIcon();
|
|
|
|
return line;
|
|
|
|
}
|
|
|
|
|
2007-05-15 05:37:55 -04:00
|
|
|
/**
|
|
|
|
* Close client connection, streams and Exchange session .
|
|
|
|
*/
|
|
|
|
public void close() {
|
|
|
|
if (in != null) {
|
|
|
|
try {
|
|
|
|
in.close();
|
|
|
|
} catch (IOException e2) {
|
2009-04-17 05:20:11 -04:00
|
|
|
DavGatewayTray.warn(new BundleMessage("LOG_EXCEPTION_CLOSING_CLIENT_INPUT_STREAM"), e2);
|
2007-05-15 05:37:55 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (os != null) {
|
|
|
|
try {
|
|
|
|
os.close();
|
|
|
|
} catch (IOException e2) {
|
2009-04-17 05:20:11 -04:00
|
|
|
DavGatewayTray.warn(new BundleMessage("LOG_EXCEPTION_CLOSING_CLIENT_OUTPUT_STREAM"), e2);
|
2007-05-15 05:37:55 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
client.close();
|
|
|
|
} catch (IOException e2) {
|
2009-04-17 05:20:11 -04:00
|
|
|
DavGatewayTray.warn(new BundleMessage("LOG_EXCEPTION_CLOSING_CLIENT_SOCKET"), e2);
|
2007-05-15 05:37:55 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-26 19:56:28 -05:00
|
|
|
protected String base64Encode(String value) {
|
2009-04-01 11:51:12 -04:00
|
|
|
return new String(new Base64().encode(value.getBytes()));
|
2008-11-26 19:56:28 -05:00
|
|
|
}
|
|
|
|
|
2008-12-17 10:31:08 -05:00
|
|
|
protected String base64Decode(String value) {
|
2009-04-01 11:51:12 -04:00
|
|
|
return new String(new Base64().decode(value.getBytes()));
|
2008-11-26 19:56:28 -05:00
|
|
|
}
|
2006-12-12 18:57:24 -05:00
|
|
|
}
|