EWS: start ExchangeSession refactoring to extract Dav calls

git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@1068 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
mguessan 2010-06-02 08:46:46 +00:00
parent 6dffe9ce41
commit cbf4b4acf6
6 changed files with 268 additions and 130 deletions

View File

@ -55,7 +55,6 @@ import javax.mail.util.SharedByteArrayInputStream;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.NoRouteToHostException;
import java.net.URL;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@ -65,7 +64,7 @@ import java.util.zip.GZIPInputStream;
/**
* Exchange session through Outlook Web Access (DAV)
*/
public class ExchangeSession {
public abstract class ExchangeSession {
protected static final Logger LOGGER = Logger.getLogger("davmail.exchange.ExchangeSession");
/**
@ -162,22 +161,22 @@ public class ExchangeSession {
/**
* Various standard mail boxes Urls
*/
private String inboxUrl;
private String deleteditemsUrl;
private String sentitemsUrl;
private String sendmsgUrl;
private String draftsUrl;
private String calendarUrl;
private String contactsUrl;
private String publicFolderUrl;
protected String inboxUrl;
protected String deleteditemsUrl;
protected String sentitemsUrl;
protected String sendmsgUrl;
protected String draftsUrl;
protected String calendarUrl;
protected String contactsUrl;
protected String publicFolderUrl;
/**
* Base user mailboxes path (used to select folder)
*/
private String mailPath;
private String email;
protected String mailPath;
protected String email;
private String alias;
private final HttpClient httpClient;
protected final HttpClient httpClient;
private final String userName;
@ -236,10 +235,7 @@ public class ExchangeSession {
httpClient.getParams().setParameter(HttpClientParams.PREEMPTIVE_AUTHENTICATION, true);
}
buildMailPath(method);
// get base http mailbox http urls
getWellKnownFolders();
buildSessionInfo(method);
} catch (DavMailAuthenticationException exc) {
LOGGER.error(exc.getMessage());
@ -549,52 +545,7 @@ public class ExchangeSession {
}
}
static final String BASE_HREF = "<base href=\"";
protected void buildMailPath(HttpMethod method) throws DavMailAuthenticationException {
// find base url
String line;
// get user mail URL from html body (multi frame)
BufferedReader mainPageReader = null;
try {
mainPageReader = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream()));
//noinspection StatementWithEmptyBody
while ((line = mainPageReader.readLine()) != null && line.toLowerCase().indexOf(BASE_HREF) == -1) {
}
if (line != null) {
int start = line.toLowerCase().indexOf(BASE_HREF) + BASE_HREF.length();
int end = line.indexOf('\"', start);
String mailBoxBaseHref = line.substring(start, end);
URL baseURL = new URL(mailBoxBaseHref);
mailPath = baseURL.getPath();
LOGGER.debug("Base href found in body, mailPath is " + mailPath);
buildEmail(method.getURI().getHost());
LOGGER.debug("Current user email is " + email);
} else {
// failover for Exchange 2007 : build standard mailbox link with email
buildEmail(method.getURI().getHost());
mailPath = "/exchange/" + email + '/';
LOGGER.debug("Current user email is " + email + ", mailPath is " + mailPath);
}
} catch (IOException e) {
LOGGER.error("Error parsing main page at " + method.getPath(), e);
} finally {
if (mainPageReader != null) {
try {
mainPageReader.close();
} catch (IOException e) {
LOGGER.error("Error parsing main page at " + method.getPath());
}
}
method.releaseConnection();
}
if (mailPath == null || email == null) {
throw new DavMailAuthenticationException("EXCEPTION_AUTHENTICATION_FAILED_PASSWORD_EXPIRED");
}
}
protected abstract void buildSessionInfo(HttpMethod method) throws DavMailException;
protected String getPropertyIfExists(DavPropertySet properties, String name, Namespace namespace) {
DavProperty property = properties.get(name, namespace);
@ -650,67 +601,6 @@ public class ExchangeSession {
}
}
protected void getWellKnownFolders() throws DavMailException {
// Retrieve well known URLs
MultiStatusResponse[] responses;
try {
responses = DavGatewayHttpClientFacade.executePropFindMethod(
httpClient, URIUtil.encodePath(mailPath), 0, WELL_KNOWN_FOLDERS);
if (responses.length == 0) {
throw new DavMailException("EXCEPTION_UNABLE_TO_GET_MAIL_FOLDER", mailPath);
}
DavPropertySet properties = responses[0].getProperties(HttpStatus.SC_OK);
inboxUrl = getURIPropertyIfExists(properties, "inbox", URN_SCHEMAS_HTTPMAIL);
deleteditemsUrl = getURIPropertyIfExists(properties, "deleteditems", URN_SCHEMAS_HTTPMAIL);
sentitemsUrl = getURIPropertyIfExists(properties, "sentitems", URN_SCHEMAS_HTTPMAIL);
sendmsgUrl = getURIPropertyIfExists(properties, "sendmsg", URN_SCHEMAS_HTTPMAIL);
draftsUrl = getURIPropertyIfExists(properties, "drafts", URN_SCHEMAS_HTTPMAIL);
calendarUrl = getURIPropertyIfExists(properties, "calendar", URN_SCHEMAS_HTTPMAIL);
contactsUrl = getURIPropertyIfExists(properties, "contacts", URN_SCHEMAS_HTTPMAIL);
// default public folder path
publicFolderUrl = "/public";
// check public folder access
try {
if (inboxUrl != null) {
// try to build full public URI from inboxUrl
URI publicUri = new URI(inboxUrl, false);
publicUri.setPath("/public");
publicFolderUrl = publicUri.getURI();
}
PropFindMethod propFindMethod = new PropFindMethod(publicFolderUrl, CONTENT_TAG, 0);
try {
DavGatewayHttpClientFacade.executeMethod(httpClient, propFindMethod);
} catch (IOException e) {
// workaround for NTLM authentication only on /public
if (!DavGatewayHttpClientFacade.hasNTLM(httpClient)) {
DavGatewayHttpClientFacade.addNTLM(httpClient);
DavGatewayHttpClientFacade.executeMethod(httpClient, propFindMethod);
}
}
// update public folder URI
publicFolderUrl = propFindMethod.getURI().getURI();
} catch (IOException e) {
LOGGER.warn("Public folders not available: " + (e.getMessage() == null ? e : e.getMessage()));
publicFolderUrl = "/public";
}
LOGGER.debug("Inbox URL : " + inboxUrl +
" Trash URL : " + deleteditemsUrl +
" Sent URL : " + sentitemsUrl +
" Send URL : " + sendmsgUrl +
" Drafts URL : " + draftsUrl +
" Calendar URL : " + calendarUrl +
" Contacts URL : " + contactsUrl +
" Public folder URL : " + publicFolderUrl
);
} catch (IOException e) {
LOGGER.error(e.getMessage());
throw new DavMailAuthenticationException("EXCEPTION_UNABLE_TO_GET_MAIL_FOLDER", mailPath);
}
}
/**
* Create message in specified folder.
* Will overwrite an existing message with same subject in the same folder

View File

@ -22,6 +22,8 @@ import davmail.BundleMessage;
import davmail.Settings;
import davmail.exception.DavMailAuthenticationException;
import davmail.exception.DavMailException;
import davmail.exchange.dav.DavExchangeSession;
import davmail.exchange.ews.EwsExchangeSession;
import davmail.http.DavGatewayHttpClientFacade;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
@ -109,7 +111,11 @@ public final class ExchangeSessionFactory {
}
if (session == null) {
session = new ExchangeSession(poolKey.url, poolKey.userName, poolKey.password);
if (Settings.getBooleanProperty("davmail.enableEws")) {
session = new EwsExchangeSession(poolKey.url, poolKey.userName, poolKey.password);
} else {
session = new DavExchangeSession(poolKey.url, poolKey.userName, poolKey.password);
}
ExchangeSession.LOGGER.debug("Created new session: " + session);
}
// successful login, put session in cache

View File

@ -0,0 +1,167 @@
/*
* DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway
* Copyright (C) 2010 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.exchange.dav;
import davmail.exception.DavMailAuthenticationException;
import davmail.exception.DavMailException;
import davmail.exchange.ExchangeSession;
import davmail.http.DavGatewayHttpClientFacade;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.util.URIUtil;
import org.apache.jackrabbit.webdav.MultiStatusResponse;
import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
import org.apache.jackrabbit.webdav.property.DavPropertySet;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
/**
* Webdav Exchange adapter.
* Compatible with Exchange 2003 and 2007 with webdav available.
*/
public class DavExchangeSession extends ExchangeSession {
/**
* @inheritDoc
*/
public DavExchangeSession(String url, String userName, String password) throws IOException {
super(url, userName, password);
}
@Override
protected void buildSessionInfo(HttpMethod method) throws DavMailException {
buildMailPath(method);
// get base http mailbox http urls
getWellKnownFolders();
}
static final String BASE_HREF = "<base href=\"";
protected void buildMailPath(HttpMethod method) throws DavMailAuthenticationException {
// find base url
String line;
// get user mail URL from html body (multi frame)
BufferedReader mainPageReader = null;
try {
mainPageReader = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream()));
//noinspection StatementWithEmptyBody
while ((line = mainPageReader.readLine()) != null && line.toLowerCase().indexOf(BASE_HREF) == -1) {
}
if (line != null) {
int start = line.toLowerCase().indexOf(BASE_HREF) + BASE_HREF.length();
int end = line.indexOf('\"', start);
String mailBoxBaseHref = line.substring(start, end);
URL baseURL = new URL(mailBoxBaseHref);
mailPath = baseURL.getPath();
LOGGER.debug("Base href found in body, mailPath is " + mailPath);
buildEmail(method.getURI().getHost());
LOGGER.debug("Current user email is " + email);
} else {
// failover for Exchange 2007 : build standard mailbox link with email
buildEmail(method.getURI().getHost());
mailPath = "/exchange/" + email + '/';
LOGGER.debug("Current user email is " + email + ", mailPath is " + mailPath);
}
} catch (IOException e) {
LOGGER.error("Error parsing main page at " + method.getPath(), e);
} finally {
if (mainPageReader != null) {
try {
mainPageReader.close();
} catch (IOException e) {
LOGGER.error("Error parsing main page at " + method.getPath());
}
}
method.releaseConnection();
}
if (mailPath == null || email == null) {
throw new DavMailAuthenticationException("EXCEPTION_AUTHENTICATION_FAILED_PASSWORD_EXPIRED");
}
}
protected void getWellKnownFolders() throws DavMailException {
// Retrieve well known URLs
MultiStatusResponse[] responses;
try {
responses = DavGatewayHttpClientFacade.executePropFindMethod(
httpClient, URIUtil.encodePath(mailPath), 0, WELL_KNOWN_FOLDERS);
if (responses.length == 0) {
throw new DavMailException("EXCEPTION_UNABLE_TO_GET_MAIL_FOLDER", mailPath);
}
DavPropertySet properties = responses[0].getProperties(HttpStatus.SC_OK);
inboxUrl = getURIPropertyIfExists(properties, "inbox", URN_SCHEMAS_HTTPMAIL);
deleteditemsUrl = getURIPropertyIfExists(properties, "deleteditems", URN_SCHEMAS_HTTPMAIL);
sentitemsUrl = getURIPropertyIfExists(properties, "sentitems", URN_SCHEMAS_HTTPMAIL);
sendmsgUrl = getURIPropertyIfExists(properties, "sendmsg", URN_SCHEMAS_HTTPMAIL);
draftsUrl = getURIPropertyIfExists(properties, "drafts", URN_SCHEMAS_HTTPMAIL);
calendarUrl = getURIPropertyIfExists(properties, "calendar", URN_SCHEMAS_HTTPMAIL);
contactsUrl = getURIPropertyIfExists(properties, "contacts", URN_SCHEMAS_HTTPMAIL);
// default public folder path
publicFolderUrl = "/public";
// check public folder access
try {
if (inboxUrl != null) {
// try to build full public URI from inboxUrl
URI publicUri = new URI(inboxUrl, false);
publicUri.setPath("/public");
publicFolderUrl = publicUri.getURI();
}
PropFindMethod propFindMethod = new PropFindMethod(publicFolderUrl, CONTENT_TAG, 0);
try {
DavGatewayHttpClientFacade.executeMethod(httpClient, propFindMethod);
} catch (IOException e) {
// workaround for NTLM authentication only on /public
if (!DavGatewayHttpClientFacade.hasNTLM(httpClient)) {
DavGatewayHttpClientFacade.addNTLM(httpClient);
DavGatewayHttpClientFacade.executeMethod(httpClient, propFindMethod);
}
}
// update public folder URI
publicFolderUrl = propFindMethod.getURI().getURI();
} catch (IOException e) {
LOGGER.warn("Public folders not available: " + (e.getMessage() == null ? e : e.getMessage()));
publicFolderUrl = "/public";
}
LOGGER.debug("Inbox URL : " + inboxUrl +
" Trash URL : " + deleteditemsUrl +
" Sent URL : " + sentitemsUrl +
" Send URL : " + sendmsgUrl +
" Drafts URL : " + draftsUrl +
" Calendar URL : " + calendarUrl +
" Contacts URL : " + contactsUrl +
" Public folder URL : " + publicFolderUrl
);
} catch (IOException e) {
LOGGER.error(e.getMessage());
throw new DavMailAuthenticationException("EXCEPTION_UNABLE_TO_GET_MAIL_FOLDER", mailPath);
}
}
}

View File

@ -0,0 +1,45 @@
/*
* DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway
* Copyright (C) 2010 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.exchange.ews;
import davmail.exception.DavMailException;
import davmail.exchange.ExchangeSession;
import org.apache.commons.httpclient.HttpMethod;
import java.io.IOException;
/**
* EWS Exchange adapter.
* Compatible with Exchange 2007 and hopefully 2010.
*/
public class EwsExchangeSession extends ExchangeSession {
/**
* @inheritDoc
*/
public EwsExchangeSession(String url, String userName, String password) throws IOException {
super(url, userName, password);
}
@Override
protected void buildSessionInfo(HttpMethod method) throws DavMailException {
// nothing to do, mailPath not used in EWS mode
}
}

View File

@ -31,7 +31,9 @@ public class ExtendedFieldURI implements FieldURI {
ObjectArray, Short, ShortArray, SystemTime, SystemTimeArray, String, StringArray
}
protected final String propertyTag;
protected String propertyTag;
protected String propertySetId;
protected int propertyId;
protected final PropertyType propertyType;
public ExtendedFieldURI(String propertyTag, PropertyType propertyType) {
@ -39,10 +41,34 @@ public class ExtendedFieldURI implements FieldURI {
this.propertyType = propertyType;
}
public ExtendedFieldURI(String propertySetId, int propertyId, PropertyType propertyType) {
this.propertySetId = propertySetId;
this.propertyId = propertyId;
this.propertyType = propertyType;
}
public String getPropertyTag() {
return propertyTag;
}
public void write(Writer writer) throws IOException {
writer.write("<t:ExtendedFieldURI PropertyTag=\"");
writer.write(propertyTag);
writer.write("\" PropertyType=\"");
writer.write("<t:ExtendedFieldURI ");
if (propertyTag != null) {
writer.write("PropertyTag=\"");
writer.write(propertyTag);
writer.write("\" ");
}
if (propertySetId != null) {
writer.write("PropertySetId=\"");
writer.write(propertySetId);
writer.write("\" ");
}
if (propertyId != 0) {
writer.write("PropertyId=\"");
writer.write(String.valueOf(propertyId));
writer.write("\" ");
}
writer.write("PropertyType=\"");
writer.write(propertyType.toString());
writer.write("\"/>");
}
@ -56,5 +82,8 @@ public class ExtendedFieldURI implements FieldURI {
public static final ExtendedFieldURI PR_ACTION_FLAG = new ExtendedFieldURI("0x1081", PropertyType.Integer);
public static final ExtendedFieldURI PR_URL_COMP_NAME = new ExtendedFieldURI("0x10F3", PropertyType.String);
public static final ExtendedFieldURI PR_LAST_MODIFICATION_TIME = new ExtendedFieldURI("0x3008", PropertyType.SystemTime);
}

View File

@ -18,6 +18,7 @@
*/
package davmail.exchange;
import davmail.exchange.dav.DavExchangeSession;
import junit.framework.TestCase;
import java.io.IOException;
@ -59,7 +60,7 @@ public class AbstractExchangeSessionTestCase extends TestCase {
// open session, get username and password from davmail.properties
// Note: those properties should *not* exist in normal production mode,
// they are not used by DavMail, just by this test case
session = new ExchangeSession(Settings.getProperty("davmail.url"), Settings.getProperty("davmail.username"), Settings.getProperty("davmail.password"));
session = new DavExchangeSession(Settings.getProperty("davmail.url"), Settings.getProperty("davmail.username"), Settings.getProperty("davmail.password"));
}
}