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.
|
|
|
|
*/
|
2008-10-31 13:12:30 -04:00
|
|
|
package davmail.exchange;
|
|
|
|
|
2009-04-27 19:03:58 -04:00
|
|
|
import davmail.BundleMessage;
|
2009-05-10 19:10:48 -04:00
|
|
|
import davmail.Settings;
|
2009-09-10 04:09:29 -04:00
|
|
|
import davmail.exception.DavMailAuthenticationException;
|
2010-02-01 17:52:36 -05:00
|
|
|
import davmail.exception.DavMailException;
|
2008-11-03 20:47:10 -05:00
|
|
|
import davmail.http.DavGatewayHttpClientFacade;
|
2008-10-31 13:12:30 -04:00
|
|
|
import org.apache.commons.httpclient.HttpClient;
|
|
|
|
import org.apache.commons.httpclient.HttpStatus;
|
|
|
|
import org.apache.commons.httpclient.methods.GetMethod;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
2010-02-01 17:52:36 -05:00
|
|
|
import java.net.NetworkInterface;
|
|
|
|
import java.net.SocketException;
|
2009-05-10 19:10:48 -04:00
|
|
|
import java.util.Enumeration;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.Map;
|
2008-10-31 13:12:30 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Create ExchangeSession instances.
|
|
|
|
*/
|
2008-12-17 10:31:08 -05:00
|
|
|
public final class ExchangeSessionFactory {
|
2008-12-04 06:50:31 -05:00
|
|
|
private static final Object LOCK = new Object();
|
2009-09-21 17:34:13 -04:00
|
|
|
private static final Map<PoolKey, ExchangeSession> POOL_MAP = new HashMap<PoolKey, ExchangeSession>();
|
2009-05-10 19:10:48 -04:00
|
|
|
private static boolean configChecked;
|
2009-09-02 20:06:03 -04:00
|
|
|
private static boolean errorSent;
|
2008-12-04 06:50:31 -05:00
|
|
|
|
|
|
|
static class PoolKey {
|
2009-09-21 17:34:13 -04:00
|
|
|
final String url;
|
|
|
|
final String userName;
|
|
|
|
final String password;
|
2008-12-04 06:50:31 -05:00
|
|
|
|
2009-04-16 17:52:17 -04:00
|
|
|
PoolKey(String url, String userName, String password) {
|
2008-12-04 06:50:31 -05:00
|
|
|
this.url = url;
|
|
|
|
this.userName = userName;
|
|
|
|
this.password = password;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean equals(Object object) {
|
|
|
|
return object == this ||
|
|
|
|
object instanceof PoolKey &&
|
|
|
|
((PoolKey) object).url.equals(this.url) &&
|
|
|
|
((PoolKey) object).userName.equals(this.userName) &&
|
|
|
|
((PoolKey) object).password.equals(this.password);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int hashCode() {
|
|
|
|
return url.hashCode() + userName.hashCode() + password.hashCode();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-05 09:53:38 -05:00
|
|
|
private ExchangeSessionFactory() {
|
|
|
|
}
|
|
|
|
|
2008-10-31 13:12:30 -04:00
|
|
|
/**
|
|
|
|
* Create authenticated Exchange session
|
|
|
|
*
|
|
|
|
* @param userName user login
|
|
|
|
* @param password user password
|
|
|
|
* @return authenticated session
|
2009-04-16 18:20:30 -04:00
|
|
|
* @throws IOException on error
|
2008-10-31 13:12:30 -04:00
|
|
|
*/
|
|
|
|
public static ExchangeSession getInstance(String userName, String password) throws IOException {
|
2009-05-10 19:10:48 -04:00
|
|
|
ExchangeSession session = null;
|
2008-10-31 13:12:30 -04:00
|
|
|
try {
|
2008-12-04 06:50:31 -05:00
|
|
|
String baseUrl = Settings.getProperty("davmail.url");
|
2010-01-20 16:20:05 -05:00
|
|
|
|
|
|
|
// prepend default windows domain prefix
|
|
|
|
String defaultDomain = Settings.getProperty("davmail.defaultDomain");
|
2010-03-21 16:45:09 -04:00
|
|
|
if (userName.indexOf('\\') < 0 && defaultDomain != null) {
|
2010-01-20 16:20:05 -05:00
|
|
|
userName = defaultDomain + '\\' + userName;
|
|
|
|
}
|
2008-12-04 06:50:31 -05:00
|
|
|
PoolKey poolKey = new PoolKey(baseUrl, userName, password);
|
|
|
|
|
|
|
|
synchronized (LOCK) {
|
2009-09-21 17:34:13 -04:00
|
|
|
session = POOL_MAP.get(poolKey);
|
2009-03-19 04:58:55 -04:00
|
|
|
}
|
|
|
|
if (session != null) {
|
|
|
|
ExchangeSession.LOGGER.debug("Got session " + session + " from cache");
|
2008-12-04 06:50:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (session != null && session.isExpired()) {
|
|
|
|
ExchangeSession.LOGGER.debug("Session " + session + " expired");
|
|
|
|
session = null;
|
2009-03-19 04:58:55 -04:00
|
|
|
// expired session, remove from cache
|
|
|
|
synchronized (LOCK) {
|
2009-09-21 17:34:13 -04:00
|
|
|
POOL_MAP.remove(poolKey);
|
2009-03-19 04:58:55 -04:00
|
|
|
}
|
2008-12-04 06:50:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (session == null) {
|
2009-09-30 17:54:53 -04:00
|
|
|
session = new ExchangeSession(poolKey.url, poolKey.userName, poolKey.password);
|
2008-12-04 06:50:31 -05:00
|
|
|
ExchangeSession.LOGGER.debug("Created new session: " + session);
|
|
|
|
}
|
2009-12-20 05:51:02 -05:00
|
|
|
// successful login, put session in cache
|
2009-03-19 04:58:55 -04:00
|
|
|
synchronized (LOCK) {
|
2009-09-21 17:34:13 -04:00
|
|
|
POOL_MAP.put(poolKey, session);
|
2009-03-19 04:58:55 -04:00
|
|
|
}
|
2009-05-10 19:10:48 -04:00
|
|
|
// session opened, future failure will mean network down
|
|
|
|
configChecked = true;
|
2009-09-02 20:06:03 -04:00
|
|
|
// Reset so next time an problem occurs message will be sent once
|
|
|
|
errorSent = false;
|
2009-09-10 04:09:29 -04:00
|
|
|
} catch (DavMailAuthenticationException exc) {
|
|
|
|
throw exc;
|
2009-09-17 09:16:52 -04:00
|
|
|
} catch (DavMailException exc) {
|
|
|
|
throw exc;
|
2010-02-01 17:52:36 -05:00
|
|
|
} catch (IllegalStateException exc) {
|
|
|
|
throw exc;
|
2009-09-07 04:15:31 -04:00
|
|
|
} catch (Exception exc) {
|
2009-09-02 20:06:03 -04:00
|
|
|
handleNetworkDown(exc);
|
2008-10-31 13:12:30 -04:00
|
|
|
}
|
2009-05-10 19:10:48 -04:00
|
|
|
return session;
|
2008-10-31 13:12:30 -04:00
|
|
|
}
|
|
|
|
|
2009-09-22 11:55:31 -04:00
|
|
|
/**
|
|
|
|
* Get a non expired session.
|
|
|
|
* If the current session is not expired, return current session, else try to create a new session
|
|
|
|
*
|
|
|
|
* @param currentSession current session
|
|
|
|
* @param userName user login
|
|
|
|
* @param password user password
|
|
|
|
* @return authenticated session
|
|
|
|
* @throws IOException on error
|
|
|
|
*/
|
|
|
|
public static ExchangeSession getInstance(ExchangeSession currentSession, String userName, String password)
|
|
|
|
throws IOException {
|
|
|
|
ExchangeSession session = currentSession;
|
|
|
|
try {
|
|
|
|
if (session.isExpired()) {
|
2010-02-02 17:48:40 -05:00
|
|
|
ExchangeSession.LOGGER.debug("Session " + session + " expired, trying to open a new one");
|
2009-09-22 11:55:31 -04:00
|
|
|
session = null;
|
|
|
|
String baseUrl = Settings.getProperty("davmail.url");
|
|
|
|
PoolKey poolKey = new PoolKey(baseUrl, userName, password);
|
|
|
|
// expired session, remove from cache
|
|
|
|
synchronized (LOCK) {
|
|
|
|
POOL_MAP.remove(poolKey);
|
|
|
|
}
|
|
|
|
session = getInstance(userName, password);
|
|
|
|
}
|
|
|
|
} catch (DavMailAuthenticationException exc) {
|
2010-02-02 17:48:40 -05:00
|
|
|
ExchangeSession.LOGGER.debug("Unable to reopen session", exc);
|
2009-09-22 11:55:31 -04:00
|
|
|
throw exc;
|
|
|
|
} catch (Exception exc) {
|
2010-02-02 17:48:40 -05:00
|
|
|
ExchangeSession.LOGGER.debug("Unable to reopen session", exc);
|
2009-09-22 11:55:31 -04:00
|
|
|
handleNetworkDown(exc);
|
|
|
|
}
|
|
|
|
return session;
|
|
|
|
}
|
|
|
|
|
2009-08-13 17:04:46 -04:00
|
|
|
/**
|
|
|
|
* Send a request to Exchange server to check current settings.
|
2009-09-02 20:06:03 -04:00
|
|
|
*
|
2009-08-13 17:04:46 -04:00
|
|
|
* @throws IOException if unable to access Exchange server
|
|
|
|
*/
|
2008-10-31 13:12:30 -04:00
|
|
|
public static void checkConfig() throws IOException {
|
2008-11-03 20:47:10 -05:00
|
|
|
String url = Settings.getProperty("davmail.url");
|
2010-03-24 06:23:26 -04:00
|
|
|
HttpClient httpClient = DavGatewayHttpClientFacade.getInstance(url);
|
2010-02-01 17:52:36 -05:00
|
|
|
GetMethod testMethod = new GetMethod(url);
|
2008-10-31 13:12:30 -04:00
|
|
|
try {
|
2009-12-20 05:51:02 -05:00
|
|
|
// get webMail root url (will not follow redirects)
|
2010-02-12 05:23:07 -05:00
|
|
|
int status = DavGatewayHttpClientFacade.executeTestMethod(httpClient, testMethod);
|
2008-10-31 13:12:30 -04:00
|
|
|
ExchangeSession.LOGGER.debug("Test configuration status: " + status);
|
|
|
|
if (status != HttpStatus.SC_OK && status != HttpStatus.SC_UNAUTHORIZED
|
2010-02-12 05:23:07 -05:00
|
|
|
&& !DavGatewayHttpClientFacade.isRedirect(status)) {
|
2009-04-27 19:03:58 -04:00
|
|
|
throw new DavMailException("EXCEPTION_CONNECTION_FAILED", url, status);
|
2008-10-31 13:12:30 -04:00
|
|
|
}
|
2009-05-10 19:10:48 -04:00
|
|
|
// session opened, future failure will mean network down
|
|
|
|
configChecked = true;
|
2009-09-02 20:06:03 -04:00
|
|
|
// Reset so next time an problem occurs message will be sent once
|
|
|
|
errorSent = false;
|
2008-10-31 13:12:30 -04:00
|
|
|
} catch (Exception exc) {
|
2009-09-02 20:06:03 -04:00
|
|
|
handleNetworkDown(exc);
|
2008-11-03 20:47:10 -05:00
|
|
|
} finally {
|
|
|
|
testMethod.releaseConnection();
|
2008-10-31 13:12:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-05-10 19:10:48 -04:00
|
|
|
private static void handleNetworkDown(Exception exc) throws DavMailException {
|
|
|
|
if (!checkNetwork() || configChecked) {
|
2009-07-15 18:47:31 -04:00
|
|
|
ExchangeSession.LOGGER.warn(BundleMessage.formatLog("EXCEPTION_NETWORK_DOWN"));
|
2009-05-10 19:10:48 -04:00
|
|
|
throw new NetworkDownException("EXCEPTION_NETWORK_DOWN");
|
|
|
|
} else {
|
2009-07-15 18:47:31 -04:00
|
|
|
BundleMessage message = new BundleMessage("EXCEPTION_CONNECT", exc.getClass().getName(), exc.getMessage());
|
2009-09-02 20:06:03 -04:00
|
|
|
if (errorSent) {
|
|
|
|
ExchangeSession.LOGGER.warn(message);
|
2009-09-22 05:03:32 -04:00
|
|
|
throw new NetworkDownException("EXCEPTION_DAVMAIL_CONFIGURATION", message);
|
2009-09-02 20:06:03 -04:00
|
|
|
} else {
|
|
|
|
// Mark that an error has been sent so you only get one
|
|
|
|
// error in a row (not a repeating string of errors).
|
|
|
|
errorSent = true;
|
|
|
|
ExchangeSession.LOGGER.error(message);
|
|
|
|
throw new DavMailException("EXCEPTION_DAVMAIL_CONFIGURATION", message);
|
|
|
|
}
|
2009-05-10 19:10:48 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-31 13:12:30 -04:00
|
|
|
/**
|
|
|
|
* Check if at least one network interface is up and active (i.e. has an address)
|
2008-11-03 05:56:57 -05:00
|
|
|
*
|
2008-10-31 13:12:30 -04:00
|
|
|
* @return true if network available
|
|
|
|
*/
|
2009-04-24 17:34:33 -04:00
|
|
|
static boolean checkNetwork() {
|
2008-10-31 13:12:30 -04:00
|
|
|
boolean up = false;
|
|
|
|
Enumeration<NetworkInterface> enumeration;
|
|
|
|
try {
|
|
|
|
enumeration = NetworkInterface.getNetworkInterfaces();
|
|
|
|
while (!up && enumeration.hasMoreElements()) {
|
|
|
|
NetworkInterface networkInterface = enumeration.nextElement();
|
|
|
|
up = networkInterface.isUp() && !networkInterface.isLoopback()
|
|
|
|
&& networkInterface.getInetAddresses().hasMoreElements();
|
|
|
|
}
|
2008-11-03 05:56:57 -05:00
|
|
|
} catch (NoSuchMethodError error) {
|
|
|
|
ExchangeSession.LOGGER.debug("Unable to test network interfaces (not available under Java 1.5)");
|
|
|
|
up = true;
|
2008-10-31 13:12:30 -04:00
|
|
|
} catch (SocketException exc) {
|
|
|
|
ExchangeSession.LOGGER.error("DavMail configuration exception: \n Error listing network interfaces " + exc.getMessage(), exc);
|
|
|
|
}
|
|
|
|
return up;
|
|
|
|
}
|
2008-12-08 08:49:21 -05:00
|
|
|
|
2009-08-13 17:04:46 -04:00
|
|
|
/**
|
|
|
|
* Reset config check status and clear session pool.
|
|
|
|
*/
|
2008-12-08 08:49:21 -05:00
|
|
|
public static void reset() {
|
2009-07-15 18:47:31 -04:00
|
|
|
configChecked = false;
|
2009-09-02 20:06:03 -04:00
|
|
|
errorSent = false;
|
2009-09-21 17:34:13 -04:00
|
|
|
POOL_MAP.clear();
|
2008-12-08 08:49:21 -05:00
|
|
|
}
|
2008-10-31 13:12:30 -04:00
|
|
|
}
|