mirror of
https://github.com/moparisthebest/davmail
synced 2025-03-05 11:49:46 -05:00
EWS: move WebDav code to DavExchangeSession
git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@1084 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
parent
51936619e3
commit
38f74f5c75
@ -291,21 +291,7 @@ public abstract class ExchangeSession {
|
|||||||
* @throws NoRouteToHostException on error
|
* @throws NoRouteToHostException on error
|
||||||
* @throws UnknownHostException on error
|
* @throws UnknownHostException on error
|
||||||
*/
|
*/
|
||||||
public boolean isExpired() throws NoRouteToHostException, UnknownHostException {
|
public abstract boolean isExpired() throws NoRouteToHostException, UnknownHostException;
|
||||||
boolean isExpired = false;
|
|
||||||
try {
|
|
||||||
DavGatewayHttpClientFacade.executePropFindMethod(
|
|
||||||
httpClient, URIUtil.encodePath(inboxUrl), 0, DISPLAY_NAME);
|
|
||||||
} catch (UnknownHostException exc) {
|
|
||||||
throw exc;
|
|
||||||
} catch (NoRouteToHostException exc) {
|
|
||||||
throw exc;
|
|
||||||
} catch (IOException e) {
|
|
||||||
isExpired = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isExpired;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test authentication mode : form based or basic.
|
* Test authentication mode : form based or basic.
|
||||||
@ -604,85 +590,7 @@ public abstract class ExchangeSession {
|
|||||||
* @param messageBody mail body
|
* @param messageBody mail body
|
||||||
* @throws IOException when unable to create message
|
* @throws IOException when unable to create message
|
||||||
*/
|
*/
|
||||||
public void createMessage(String folderPath, String messageName, HashMap<String, String> properties, String messageBody) throws IOException {
|
public abstract void createMessage(String folderPath, String messageName, HashMap<String, String> properties, String messageBody) throws IOException;
|
||||||
String messageUrl = URIUtil.encodePathQuery(getFolderPath(folderPath) + '/' + messageName + ".EML");
|
|
||||||
PropPatchMethod patchMethod;
|
|
||||||
// create the message first as draft
|
|
||||||
if (properties.containsKey("draft")) {
|
|
||||||
patchMethod = new PropPatchMethod(messageUrl, buildProperties(properties));
|
|
||||||
try {
|
|
||||||
// update message with blind carbon copy and other flags
|
|
||||||
int statusCode = httpClient.executeMethod(patchMethod);
|
|
||||||
if (statusCode != HttpStatus.SC_MULTI_STATUS) {
|
|
||||||
throw new DavMailException("EXCEPTION_UNABLE_TO_CREATE_MESSAGE", messageUrl, statusCode, ' ', patchMethod.getStatusLine());
|
|
||||||
}
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
patchMethod.releaseConnection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PutMethod putmethod = new PutMethod(messageUrl);
|
|
||||||
putmethod.setRequestHeader("Translate", "f");
|
|
||||||
try {
|
|
||||||
// use same encoding as client socket reader
|
|
||||||
putmethod.setRequestEntity(new ByteArrayRequestEntity(messageBody.getBytes()));
|
|
||||||
int code = httpClient.executeMethod(putmethod);
|
|
||||||
|
|
||||||
if (code != HttpStatus.SC_OK && code != HttpStatus.SC_CREATED) {
|
|
||||||
throw new DavMailException("EXCEPTION_UNABLE_TO_CREATE_MESSAGE", messageUrl, code, ' ', putmethod.getStatusLine());
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
putmethod.releaseConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
// add bcc and other properties
|
|
||||||
if (!properties.isEmpty()) {
|
|
||||||
patchMethod = new PropPatchMethod(messageUrl, buildProperties(properties));
|
|
||||||
try {
|
|
||||||
// update message with blind carbon copy and other flags
|
|
||||||
int statusCode = httpClient.executeMethod(patchMethod);
|
|
||||||
if (statusCode != HttpStatus.SC_MULTI_STATUS) {
|
|
||||||
throw new DavMailException("EXCEPTION_UNABLE_TO_PATCH_MESSAGE", messageUrl, statusCode, ' ', patchMethod.getStatusLine());
|
|
||||||
}
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
patchMethod.releaseConnection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected List<DavProperty> buildProperties(Map<String, String> properties) {
|
|
||||||
ArrayList<DavProperty> list = new ArrayList<DavProperty>();
|
|
||||||
for (Map.Entry<String, String> entry : properties.entrySet()) {
|
|
||||||
if ("read".equals(entry.getKey())) {
|
|
||||||
list.add(new DefaultDavProperty(DavPropertyName.create("read", URN_SCHEMAS_HTTPMAIL), entry.getValue()));
|
|
||||||
} else if ("junk".equals(entry.getKey())) {
|
|
||||||
list.add(new DefaultDavProperty(DavPropertyName.create("x10830003", SCHEMAS_MAPI_PROPTAG), entry.getValue()));
|
|
||||||
} else if ("flagged".equals(entry.getKey())) {
|
|
||||||
list.add(new DefaultDavProperty(DavPropertyName.create("x10900003", SCHEMAS_MAPI_PROPTAG), entry.getValue()));
|
|
||||||
} else if ("answered".equals(entry.getKey())) {
|
|
||||||
list.add(new DefaultDavProperty(DavPropertyName.create("x10810003", SCHEMAS_MAPI_PROPTAG), entry.getValue()));
|
|
||||||
if ("102".equals(entry.getValue())) {
|
|
||||||
list.add(new DefaultDavProperty(DavPropertyName.create("x10800003", SCHEMAS_MAPI_PROPTAG), "261"));
|
|
||||||
}
|
|
||||||
} else if ("forwarded".equals(entry.getKey())) {
|
|
||||||
list.add(new DefaultDavProperty(DavPropertyName.create("x10810003", SCHEMAS_MAPI_PROPTAG), entry.getValue()));
|
|
||||||
if ("104".equals(entry.getValue())) {
|
|
||||||
list.add(new DefaultDavProperty(DavPropertyName.create("x10800003", SCHEMAS_MAPI_PROPTAG), "262"));
|
|
||||||
}
|
|
||||||
} else if ("bcc".equals(entry.getKey())) {
|
|
||||||
list.add(new DefaultDavProperty(DavPropertyName.create("bcc", Namespace.getNamespace("urn:schemas:mailheader:")), entry.getValue()));
|
|
||||||
} else if ("draft".equals(entry.getKey())) {
|
|
||||||
list.add(new DefaultDavProperty(DavPropertyName.create("x0E070003", SCHEMAS_MAPI_PROPTAG), entry.getValue()));
|
|
||||||
} else if ("deleted".equals(entry.getKey())) {
|
|
||||||
list.add(new DefaultDavProperty(DavPropertyName.create("_x0030_x8570", Namespace.getNamespace("http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-C000-000000000046}/")), entry.getValue()));
|
|
||||||
} else if ("datereceived".equals(entry.getKey())) {
|
|
||||||
list.add(new DefaultDavProperty(DavPropertyName.create("datereceived", URN_SCHEMAS_HTTPMAIL), entry.getValue()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update given properties on message.
|
* Update given properties on message.
|
||||||
@ -691,23 +599,15 @@ public abstract class ExchangeSession {
|
|||||||
* @param properties Webdav properties map
|
* @param properties Webdav properties map
|
||||||
* @throws IOException on error
|
* @throws IOException on error
|
||||||
*/
|
*/
|
||||||
public void updateMessage(Message message, Map<String, String> properties) throws IOException {
|
public abstract void updateMessage(Message message, Map<String, String> properties) throws IOException;
|
||||||
PropPatchMethod patchMethod = new PropPatchMethod(message.permanentUrl, buildProperties(properties)) {
|
|
||||||
@Override
|
|
||||||
protected void processResponseBody(HttpState httpState, HttpConnection httpConnection) {
|
|
||||||
// ignore response body, sometimes invalid with exchange mapi properties
|
|
||||||
}
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
int statusCode = httpClient.executeMethod(patchMethod);
|
|
||||||
if (statusCode != HttpStatus.SC_MULTI_STATUS) {
|
|
||||||
throw new DavMailException("EXCEPTION_UNABLE_TO_UPDATE_MESSAGE");
|
|
||||||
}
|
|
||||||
|
|
||||||
} finally {
|
/**
|
||||||
patchMethod.releaseConnection();
|
* Send message to recipients, properties contains bcc recipients and other non MIME flags.
|
||||||
}
|
* @param properties additional message properties
|
||||||
}
|
* @param messageBody MIME message body
|
||||||
|
* @throws IOException on error
|
||||||
|
*/
|
||||||
|
public abstract void sendMessage(HashMap<String, String> properties, String messageBody) throws IOException;
|
||||||
|
|
||||||
protected static final List<String> POP_MESSAGE_ATTRIBUTES = new ArrayList<String>();
|
protected static final List<String> POP_MESSAGE_ATTRIBUTES = new ArrayList<String>();
|
||||||
|
|
||||||
@ -742,6 +642,12 @@ public abstract class ExchangeSession {
|
|||||||
IMAP_MESSAGE_ATTRIBUTES.add("date");
|
IMAP_MESSAGE_ATTRIBUTES.add("date");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static final List<String> UID_MESSAGE_ATTRIBUTES = new ArrayList<String>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
UID_MESSAGE_ATTRIBUTES.add("uid");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all folder messages.
|
* Get all folder messages.
|
||||||
*
|
*
|
||||||
@ -865,8 +771,7 @@ public abstract class ExchangeSession {
|
|||||||
* @throws IOException on error
|
* @throws IOException on error
|
||||||
*/
|
*/
|
||||||
public List<Folder> getSubFolders(String folderName, boolean recursive) throws IOException {
|
public List<Folder> getSubFolders(String folderName, boolean recursive) throws IOException {
|
||||||
return getSubFolders(folderName,
|
return getSubFolders(folderName, or(equals("folderclass", "IPF.Note"), isNull("folderclass")),
|
||||||
or(equals("folderclass", "IPF.Note"), isNull("folderclass")),
|
|
||||||
recursive);
|
recursive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -902,32 +807,25 @@ public abstract class ExchangeSession {
|
|||||||
public void purgeOldestTrashAndSentMessages() throws IOException {
|
public void purgeOldestTrashAndSentMessages() throws IOException {
|
||||||
int keepDelay = Settings.getIntProperty("davmail.keepDelay");
|
int keepDelay = Settings.getIntProperty("davmail.keepDelay");
|
||||||
if (keepDelay != 0) {
|
if (keepDelay != 0) {
|
||||||
purgeOldestFolderMessages(deleteditemsUrl, keepDelay);
|
purgeOldestFolderMessages(TRASH, keepDelay);
|
||||||
}
|
}
|
||||||
// this is a new feature, default is : do nothing
|
// this is a new feature, default is : do nothing
|
||||||
int sentKeepDelay = Settings.getIntProperty("davmail.sentKeepDelay");
|
int sentKeepDelay = Settings.getIntProperty("davmail.sentKeepDelay");
|
||||||
if (sentKeepDelay != 0) {
|
if (sentKeepDelay != 0) {
|
||||||
purgeOldestFolderMessages(sentitemsUrl, sentKeepDelay);
|
purgeOldestFolderMessages(SENT, sentKeepDelay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void purgeOldestFolderMessages(String folderUrl, int keepDelay) throws IOException {
|
protected void purgeOldestFolderMessages(String folderPath, int keepDelay) throws IOException {
|
||||||
Calendar cal = Calendar.getInstance();
|
Calendar cal = Calendar.getInstance();
|
||||||
cal.add(Calendar.DAY_OF_MONTH, -keepDelay);
|
cal.add(Calendar.DAY_OF_MONTH, -keepDelay);
|
||||||
LOGGER.debug("Delete messages in " + folderUrl + " since " + cal.getTime());
|
LOGGER.debug("Delete messages in " + folderPath + " not modified since " + cal.getTime());
|
||||||
|
|
||||||
String searchRequest = "Select \"DAV:uid\"" +
|
MessageList messages = searchMessages(folderPath, UID_MESSAGE_ATTRIBUTES,
|
||||||
" FROM Scope('SHALLOW TRAVERSAL OF \"" + folderUrl + "\"')\n" +
|
lt("lastmodified", formatSearchDate(cal.getTime())));
|
||||||
" WHERE \"DAV:isfolder\" = False\n" +
|
|
||||||
" AND \"DAV:getlastmodified\" < '" + formatSearchDate(cal.getTime()) + "'\n";
|
|
||||||
MultiStatusResponse[] responses = DavGatewayHttpClientFacade.executeSearchMethod(
|
|
||||||
httpClient, URIUtil.encodePath(folderUrl), searchRequest);
|
|
||||||
|
|
||||||
for (MultiStatusResponse response : responses) {
|
for (Message message : messages) {
|
||||||
String messageUrl = URIUtil.decode(response.getHref());
|
message.delete();
|
||||||
|
|
||||||
LOGGER.debug("Delete " + messageUrl);
|
|
||||||
DavGatewayHttpClientFacade.executeDeleteMethod(httpClient, URIUtil.encodePath(messageUrl));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -995,16 +893,7 @@ public abstract class ExchangeSession {
|
|||||||
properties.put("bcc", bcc);
|
properties.put("bcc", bcc);
|
||||||
}
|
}
|
||||||
|
|
||||||
String messageName = UUID.randomUUID().toString();
|
sendMessage(properties, mailBuffer.toString());
|
||||||
|
|
||||||
createMessage("Drafts", messageName, properties, mailBuffer.toString());
|
|
||||||
|
|
||||||
String tempUrl = draftsUrl + '/' + messageName + ".EML";
|
|
||||||
MoveMethod method = new MoveMethod(URIUtil.encodePath(tempUrl), URIUtil.encodePath(sendmsgUrl), true);
|
|
||||||
int status = DavGatewayHttpClientFacade.executeHttpMethod(httpClient, method);
|
|
||||||
if (status != HttpStatus.SC_OK) {
|
|
||||||
throw DavGatewayHttpClientFacade.buildHttpException(method);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1101,23 +990,7 @@ public abstract class ExchangeSession {
|
|||||||
* @param folderClass folder class
|
* @param folderClass folder class
|
||||||
* @throws IOException on error
|
* @throws IOException on error
|
||||||
*/
|
*/
|
||||||
public void createFolder(String folderName, String folderClass) throws IOException {
|
public abstract void createFolder(String folderName, String folderClass) throws IOException;
|
||||||
String folderPath = getFolderPath(folderName);
|
|
||||||
ArrayList<DavProperty> list = new ArrayList<DavProperty>();
|
|
||||||
list.add(new DefaultDavProperty(DavPropertyName.create("outlookfolderclass", Namespace.getNamespace("http://schemas.microsoft.com/exchange/")), folderClass));
|
|
||||||
// standard MkColMethod does not take properties, override PropPatchMethod instead
|
|
||||||
PropPatchMethod method = new PropPatchMethod(URIUtil.encodePath(folderPath), list) {
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "MKCOL";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int status = DavGatewayHttpClientFacade.executeHttpMethod(httpClient, method);
|
|
||||||
// ok or already exists
|
|
||||||
if (status != HttpStatus.SC_MULTI_STATUS && status != HttpStatus.SC_METHOD_NOT_ALLOWED) {
|
|
||||||
throw DavGatewayHttpClientFacade.buildHttpException(method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete Exchange folder.
|
* Delete Exchange folder.
|
||||||
@ -1125,9 +998,7 @@ public abstract class ExchangeSession {
|
|||||||
* @param folderName logical folder name
|
* @param folderName logical folder name
|
||||||
* @throws IOException on error
|
* @throws IOException on error
|
||||||
*/
|
*/
|
||||||
public void deleteFolder(String folderName) throws IOException {
|
public abstract void deleteFolder(String folderName) throws IOException;
|
||||||
DavGatewayHttpClientFacade.executeDeleteMethod(httpClient, URIUtil.encodePath(getFolderPath(folderName)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy message to target folder
|
* Copy message to target folder
|
||||||
@ -1136,22 +1007,7 @@ public abstract class ExchangeSession {
|
|||||||
* @param targetFolder target folder
|
* @param targetFolder target folder
|
||||||
* @throws IOException on error
|
* @throws IOException on error
|
||||||
*/
|
*/
|
||||||
public void copyMessage(Message message, String targetFolder) throws IOException {
|
public abstract void copyMessage(Message message, String targetFolder) throws IOException;
|
||||||
String targetPath = URIUtil.encodePath(getFolderPath(targetFolder)) + '/' + UUID.randomUUID().toString();
|
|
||||||
CopyMethod method = new CopyMethod(message.permanentUrl, targetPath, false);
|
|
||||||
// allow rename if a message with the same name exists
|
|
||||||
method.addRequestHeader("Allow-Rename", "t");
|
|
||||||
try {
|
|
||||||
int statusCode = httpClient.executeMethod(method);
|
|
||||||
if (statusCode == HttpStatus.SC_PRECONDITION_FAILED) {
|
|
||||||
throw new DavMailException("EXCEPTION_UNABLE_TO_COPY_MESSAGE");
|
|
||||||
} else if (statusCode != HttpStatus.SC_CREATED) {
|
|
||||||
throw DavGatewayHttpClientFacade.buildHttpException(method);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
method.releaseConnection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move folder to target name.
|
* Move folder to target name.
|
||||||
@ -1160,39 +1016,9 @@ public abstract class ExchangeSession {
|
|||||||
* @param targetName target folder name/path
|
* @param targetName target folder name/path
|
||||||
* @throws IOException on error
|
* @throws IOException on error
|
||||||
*/
|
*/
|
||||||
public void moveFolder(String folderName, String targetName) throws IOException {
|
public abstract void moveFolder(String folderName, String targetName) throws IOException;
|
||||||
String folderPath = getFolderPath(folderName);
|
|
||||||
String targetPath = getFolderPath(targetName);
|
|
||||||
MoveMethod method = new MoveMethod(URIUtil.encodePath(folderPath), URIUtil.encodePath(targetPath), false);
|
|
||||||
try {
|
|
||||||
int statusCode = httpClient.executeMethod(method);
|
|
||||||
if (statusCode == HttpStatus.SC_PRECONDITION_FAILED) {
|
|
||||||
throw new DavMailException("EXCEPTION_UNABLE_TO_MOVE_FOLDER");
|
|
||||||
} else if (statusCode != HttpStatus.SC_CREATED) {
|
|
||||||
throw DavGatewayHttpClientFacade.buildHttpException(method);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
method.releaseConnection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void moveToTrash(String encodedMessageUrl) throws IOException {
|
protected abstract void moveToTrash(Message message) throws IOException;
|
||||||
String destination = URIUtil.encodePath(deleteditemsUrl) + '/' + UUID.randomUUID().toString();
|
|
||||||
LOGGER.debug("Deleting : " + encodedMessageUrl + " to " + destination);
|
|
||||||
MoveMethod method = new MoveMethod(encodedMessageUrl, destination, false);
|
|
||||||
method.addRequestHeader("Allow-rename", "t");
|
|
||||||
|
|
||||||
int status = DavGatewayHttpClientFacade.executeHttpMethod(httpClient, method);
|
|
||||||
// do not throw error if already deleted
|
|
||||||
if (status != HttpStatus.SC_CREATED && status != HttpStatus.SC_NOT_FOUND) {
|
|
||||||
throw DavGatewayHttpClientFacade.buildHttpException(method);
|
|
||||||
}
|
|
||||||
if (method.getResponseHeader("Location") != null) {
|
|
||||||
destination = method.getResponseHeader("Location").getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGGER.debug("Deleted to :" + destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exchange folder with IMAP properties
|
* Exchange folder with IMAP properties
|
||||||
@ -1688,6 +1514,7 @@ public abstract class ExchangeSession {
|
|||||||
* @throws IOException on error
|
* @throws IOException on error
|
||||||
*/
|
*/
|
||||||
public void delete() throws IOException {
|
public void delete() throws IOException {
|
||||||
|
LOGGER.debug("Delete " + permanentUrl + " (" + messageUrl + ")");
|
||||||
DavGatewayHttpClientFacade.executeDeleteMethod(httpClient, permanentUrl);
|
DavGatewayHttpClientFacade.executeDeleteMethod(httpClient, permanentUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1702,7 +1529,7 @@ public abstract class ExchangeSession {
|
|||||||
properties.put("read", "1");
|
properties.put("read", "1");
|
||||||
updateMessage(this, properties);
|
updateMessage(this, properties);
|
||||||
|
|
||||||
ExchangeSession.this.moveToTrash(permanentUrl);
|
ExchangeSession.this.moveToTrash(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,23 +24,24 @@ import davmail.exception.DavMailException;
|
|||||||
import davmail.exchange.ExchangeSession;
|
import davmail.exchange.ExchangeSession;
|
||||||
import davmail.http.DavGatewayHttpClientFacade;
|
import davmail.http.DavGatewayHttpClientFacade;
|
||||||
import davmail.ui.tray.DavGatewayTray;
|
import davmail.ui.tray.DavGatewayTray;
|
||||||
import org.apache.commons.httpclient.HttpMethod;
|
import org.apache.commons.httpclient.*;
|
||||||
import org.apache.commons.httpclient.HttpStatus;
|
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
|
||||||
import org.apache.commons.httpclient.URI;
|
import org.apache.commons.httpclient.methods.PutMethod;
|
||||||
import org.apache.commons.httpclient.URIException;
|
|
||||||
import org.apache.commons.httpclient.util.URIUtil;
|
import org.apache.commons.httpclient.util.URIUtil;
|
||||||
import org.apache.jackrabbit.webdav.MultiStatusResponse;
|
import org.apache.jackrabbit.webdav.MultiStatusResponse;
|
||||||
|
import org.apache.jackrabbit.webdav.client.methods.CopyMethod;
|
||||||
|
import org.apache.jackrabbit.webdav.client.methods.MoveMethod;
|
||||||
import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
|
import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
|
||||||
import org.apache.jackrabbit.webdav.property.DavProperty;
|
import org.apache.jackrabbit.webdav.client.methods.PropPatchMethod;
|
||||||
import org.apache.jackrabbit.webdav.property.DavPropertyName;
|
import org.apache.jackrabbit.webdav.property.*;
|
||||||
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
|
|
||||||
import org.apache.jackrabbit.webdav.property.DavPropertySet;
|
|
||||||
import org.apache.jackrabbit.webdav.xml.Namespace;
|
import org.apache.jackrabbit.webdav.xml.Namespace;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.NoRouteToHostException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -196,6 +197,26 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isExpired() throws NoRouteToHostException, UnknownHostException {
|
||||||
|
boolean isExpired = false;
|
||||||
|
try {
|
||||||
|
DavGatewayHttpClientFacade.executePropFindMethod(
|
||||||
|
httpClient, URIUtil.encodePath(inboxUrl), 0, DISPLAY_NAME);
|
||||||
|
} catch (UnknownHostException exc) {
|
||||||
|
throw exc;
|
||||||
|
} catch (NoRouteToHostException exc) {
|
||||||
|
throw exc;
|
||||||
|
} catch (IOException e) {
|
||||||
|
isExpired = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isExpired;
|
||||||
|
}
|
||||||
|
|
||||||
protected static class MultiCondition extends ExchangeSession.MultiCondition {
|
protected static class MultiCondition extends ExchangeSession.MultiCondition {
|
||||||
protected MultiCondition(Operator operator, Condition... condition) {
|
protected MultiCondition(Operator operator, Condition... condition) {
|
||||||
super(operator, condition);
|
super(operator, condition);
|
||||||
@ -455,6 +476,55 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
return folders;
|
return folders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public void createFolder(String folderName, String folderClass) throws IOException {
|
||||||
|
String folderPath = getFolderPath(folderName);
|
||||||
|
ArrayList<DavProperty> list = new ArrayList<DavProperty>();
|
||||||
|
list.add(Field.createDavProperty("folderclass", folderClass));
|
||||||
|
// standard MkColMethod does not take properties, override PropPatchMethod instead
|
||||||
|
PropPatchMethod method = new PropPatchMethod(URIUtil.encodePath(folderPath), list) {
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "MKCOL";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
int status = DavGatewayHttpClientFacade.executeHttpMethod(httpClient, method);
|
||||||
|
// ok or already exists
|
||||||
|
if (status != HttpStatus.SC_MULTI_STATUS && status != HttpStatus.SC_METHOD_NOT_ALLOWED) {
|
||||||
|
throw DavGatewayHttpClientFacade.buildHttpException(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void deleteFolder(String folderName) throws IOException {
|
||||||
|
DavGatewayHttpClientFacade.executeDeleteMethod(httpClient, URIUtil.encodePath(getFolderPath(folderName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void moveFolder(String folderName, String targetName) throws IOException {
|
||||||
|
String folderPath = getFolderPath(folderName);
|
||||||
|
String targetPath = getFolderPath(targetName);
|
||||||
|
MoveMethod method = new MoveMethod(URIUtil.encodePath(folderPath), URIUtil.encodePath(targetPath), false);
|
||||||
|
try {
|
||||||
|
int statusCode = httpClient.executeMethod(method);
|
||||||
|
if (statusCode == HttpStatus.SC_PRECONDITION_FAILED) {
|
||||||
|
throw new DavMailException("EXCEPTION_UNABLE_TO_MOVE_FOLDER");
|
||||||
|
} else if (statusCode != HttpStatus.SC_CREATED) {
|
||||||
|
throw DavGatewayHttpClientFacade.buildHttpException(method);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
method.releaseConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected String getPropertyIfExists(DavPropertySet properties, String name) {
|
protected String getPropertyIfExists(DavPropertySet properties, String name) {
|
||||||
DavProperty property = properties.get(name, EMPTY);
|
DavProperty property = properties.get(name, EMPTY);
|
||||||
if (property == null) {
|
if (property == null) {
|
||||||
@ -549,4 +619,174 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
Collections.sort(messages);
|
Collections.sort(messages);
|
||||||
return messages;
|
return messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected List<DavProperty> buildProperties(Map<String, String> properties) {
|
||||||
|
ArrayList<DavProperty> list = new ArrayList<DavProperty>();
|
||||||
|
for (Map.Entry<String, String> entry : properties.entrySet()) {
|
||||||
|
if ("read".equals(entry.getKey())) {
|
||||||
|
list.add(Field.createDavProperty("read", entry.getValue()));
|
||||||
|
} else if ("junk".equals(entry.getKey())) {
|
||||||
|
list.add(Field.createDavProperty("junk", entry.getValue()));
|
||||||
|
} else if ("flagged".equals(entry.getKey())) {
|
||||||
|
list.add(Field.createDavProperty("flagStatus", entry.getValue()));
|
||||||
|
} else if ("answered".equals(entry.getKey())) {
|
||||||
|
list.add(Field.createDavProperty("lastVerbExecuted", entry.getValue()));
|
||||||
|
if ("102".equals(entry.getValue())) {
|
||||||
|
list.add(Field.createDavProperty("iconIndex", "261"));
|
||||||
|
}
|
||||||
|
} else if ("forwarded".equals(entry.getKey())) {
|
||||||
|
list.add(Field.createDavProperty("lastVerbExecuted", entry.getValue()));
|
||||||
|
if ("104".equals(entry.getValue())) {
|
||||||
|
list.add(Field.createDavProperty("iconIndex", "262"));
|
||||||
|
}
|
||||||
|
} else if ("bcc".equals(entry.getKey())) {
|
||||||
|
list.add(Field.createDavProperty("bcc", entry.getValue()));
|
||||||
|
} else if ("draft".equals(entry.getKey())) {
|
||||||
|
list.add(Field.createDavProperty("messageFlags", entry.getValue()));
|
||||||
|
} else if ("deleted".equals(entry.getKey())) {
|
||||||
|
// TODO: need to test this
|
||||||
|
list.add(Field.createDavProperty("writedeleted", entry.getValue()));
|
||||||
|
} else if ("datereceived".equals(entry.getKey())) {
|
||||||
|
list.add(new DefaultDavProperty(DavPropertyName.create("datereceived", URN_SCHEMAS_HTTPMAIL), entry.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create message in specified folder.
|
||||||
|
* Will overwrite an existing message with same subject in the same folder
|
||||||
|
*
|
||||||
|
* @param folderPath Exchange folder path
|
||||||
|
* @param messageName message name
|
||||||
|
* @param properties message properties (flags)
|
||||||
|
* @param messageBody mail body
|
||||||
|
* @throws IOException when unable to create message
|
||||||
|
*/
|
||||||
|
public void createMessage(String folderPath, String messageName, HashMap<String, String> properties, String messageBody) throws IOException {
|
||||||
|
String messageUrl = URIUtil.encodePathQuery(getFolderPath(folderPath) + '/' + messageName + ".EML");
|
||||||
|
PropPatchMethod patchMethod;
|
||||||
|
// create the message first as draft
|
||||||
|
if (properties.containsKey("draft")) {
|
||||||
|
patchMethod = new PropPatchMethod(messageUrl, buildProperties(properties));
|
||||||
|
try {
|
||||||
|
// update message with blind carbon copy and other flags
|
||||||
|
int statusCode = httpClient.executeMethod(patchMethod);
|
||||||
|
if (statusCode != HttpStatus.SC_MULTI_STATUS) {
|
||||||
|
throw new DavMailException("EXCEPTION_UNABLE_TO_CREATE_MESSAGE", messageUrl, statusCode, ' ', patchMethod.getStatusLine());
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
patchMethod.releaseConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PutMethod putmethod = new PutMethod(messageUrl);
|
||||||
|
putmethod.setRequestHeader("Translate", "f");
|
||||||
|
try {
|
||||||
|
// use same encoding as client socket reader
|
||||||
|
putmethod.setRequestEntity(new ByteArrayRequestEntity(messageBody.getBytes()));
|
||||||
|
int code = httpClient.executeMethod(putmethod);
|
||||||
|
|
||||||
|
if (code != HttpStatus.SC_OK && code != HttpStatus.SC_CREATED) {
|
||||||
|
throw new DavMailException("EXCEPTION_UNABLE_TO_CREATE_MESSAGE", messageUrl, code, ' ', putmethod.getStatusLine());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
putmethod.releaseConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
// add bcc and other properties
|
||||||
|
if (!properties.isEmpty()) {
|
||||||
|
patchMethod = new PropPatchMethod(messageUrl, buildProperties(properties));
|
||||||
|
try {
|
||||||
|
// update message with blind carbon copy and other flags
|
||||||
|
int statusCode = httpClient.executeMethod(patchMethod);
|
||||||
|
if (statusCode != HttpStatus.SC_MULTI_STATUS) {
|
||||||
|
throw new DavMailException("EXCEPTION_UNABLE_TO_PATCH_MESSAGE", messageUrl, statusCode, ' ', patchMethod.getStatusLine());
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
patchMethod.releaseConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updateMessage(Message message, Map<String, String> properties) throws IOException {
|
||||||
|
PropPatchMethod patchMethod = new PropPatchMethod(message.permanentUrl, buildProperties(properties)) {
|
||||||
|
@Override
|
||||||
|
protected void processResponseBody(HttpState httpState, HttpConnection httpConnection) {
|
||||||
|
// ignore response body, sometimes invalid with exchange mapi properties
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
int statusCode = httpClient.executeMethod(patchMethod);
|
||||||
|
if (statusCode != HttpStatus.SC_MULTI_STATUS) {
|
||||||
|
throw new DavMailException("EXCEPTION_UNABLE_TO_UPDATE_MESSAGE");
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
patchMethod.releaseConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void sendMessage(HashMap<String, String> properties, String messageBody) throws IOException {
|
||||||
|
String messageName = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
createMessage("Drafts", messageName, properties, messageBody);
|
||||||
|
|
||||||
|
String tempUrl = draftsUrl + '/' + messageName + ".EML";
|
||||||
|
MoveMethod method = new MoveMethod(URIUtil.encodePath(tempUrl), URIUtil.encodePath(sendmsgUrl), true);
|
||||||
|
int status = DavGatewayHttpClientFacade.executeHttpMethod(httpClient, method);
|
||||||
|
if (status != HttpStatus.SC_OK) {
|
||||||
|
throw DavGatewayHttpClientFacade.buildHttpException(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void copyMessage(Message message, String targetFolder) throws IOException {
|
||||||
|
String targetPath = URIUtil.encodePath(getFolderPath(targetFolder)) + '/' + UUID.randomUUID().toString();
|
||||||
|
CopyMethod method = new CopyMethod(message.permanentUrl, targetPath, false);
|
||||||
|
// allow rename if a message with the same name exists
|
||||||
|
method.addRequestHeader("Allow-Rename", "t");
|
||||||
|
try {
|
||||||
|
int statusCode = httpClient.executeMethod(method);
|
||||||
|
if (statusCode == HttpStatus.SC_PRECONDITION_FAILED) {
|
||||||
|
throw new DavMailException("EXCEPTION_UNABLE_TO_COPY_MESSAGE");
|
||||||
|
} else if (statusCode != HttpStatus.SC_CREATED) {
|
||||||
|
throw DavGatewayHttpClientFacade.buildHttpException(method);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
method.releaseConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void moveToTrash(Message message) throws IOException {
|
||||||
|
String destination = URIUtil.encodePath(deleteditemsUrl) + '/' + UUID.randomUUID().toString();
|
||||||
|
LOGGER.debug("Deleting : " + message.permanentUrl + " to " + destination);
|
||||||
|
MoveMethod method = new MoveMethod(message.permanentUrl, destination, false);
|
||||||
|
method.addRequestHeader("Allow-rename", "t");
|
||||||
|
|
||||||
|
int status = DavGatewayHttpClientFacade.executeHttpMethod(httpClient, method);
|
||||||
|
// do not throw error if already deleted
|
||||||
|
if (status != HttpStatus.SC_CREATED && status != HttpStatus.SC_NOT_FOUND) {
|
||||||
|
throw DavGatewayHttpClientFacade.buildHttpException(method);
|
||||||
|
}
|
||||||
|
if (method.getResponseHeader("Location") != null) {
|
||||||
|
destination = method.getResponseHeader("Location").getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.debug("Deleted to :" + destination);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
package davmail.exchange.dav;
|
package davmail.exchange.dav;
|
||||||
|
|
||||||
import org.apache.jackrabbit.webdav.property.DavPropertyName;
|
import org.apache.jackrabbit.webdav.property.DavPropertyName;
|
||||||
|
import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
|
||||||
import org.apache.jackrabbit.webdav.xml.Namespace;
|
import org.apache.jackrabbit.webdav.xml.Namespace;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -94,11 +95,14 @@ public class Field {
|
|||||||
createField("flagStatus", 0x1090, PropertyType.Integer);//PR_FLAG_STATUS
|
createField("flagStatus", 0x1090, PropertyType.Integer);//PR_FLAG_STATUS
|
||||||
createField("messageFlags", 0x0e07, PropertyType.Integer);//PR_MESSAGE_FLAGS
|
createField("messageFlags", 0x0e07, PropertyType.Integer);//PR_MESSAGE_FLAGS
|
||||||
createField("lastVerbExecuted", 0x1081, PropertyType.Integer);//PR_LAST_VERB_EXECUTED
|
createField("lastVerbExecuted", 0x1081, PropertyType.Integer);//PR_LAST_VERB_EXECUTED
|
||||||
|
createField("iconIndex", 0x1080, PropertyType.Integer);//PR_ICON_INDEX
|
||||||
createField(URN_SCHEMAS_HTTPMAIL, "read");
|
createField(URN_SCHEMAS_HTTPMAIL, "read");
|
||||||
//createField("read", 0x0e69, PropertyType.Boolean);//PR_READ
|
//createField("read", 0x0e69, PropertyType.Boolean);//PR_READ
|
||||||
createField("deleted", DistinguishedPropertySetType.Common, 0x8570);
|
createField("deleted", DistinguishedPropertySetType.Common, 0x8570);
|
||||||
createField(URN_SCHEMAS_HTTPMAIL, "date"); //PR_CLIENT_SUBMIT_TIME, 0x0039
|
createField("writedeleted", DistinguishedPropertySetType.Common, 0x8570, PropertyType.Integer);
|
||||||
|
createField(URN_SCHEMAS_HTTPMAIL, "date");//PR_CLIENT_SUBMIT_TIME, 0x0039
|
||||||
//createField("date", 0x0e06, PropertyType.SystemTime);//PR_MESSAGE_DELIVERY_TIME
|
//createField("date", 0x0e06, PropertyType.SystemTime);//PR_MESSAGE_DELIVERY_TIME
|
||||||
|
createField(URN_SCHEMAS_MAILHEADER, "bcc");//PS_INTERNET_HEADERS/bcc
|
||||||
|
|
||||||
// IMAP search
|
// IMAP search
|
||||||
|
|
||||||
@ -129,6 +133,12 @@ public class Field {
|
|||||||
fieldMap.put(field.alias, field);
|
fieldMap.put(field.alias, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static void createField(String alias, DistinguishedPropertySetType propertySetType, int propertyTag, PropertyType propertyType) {
|
||||||
|
String name = '{' + distinguishedPropertySetMap.get(propertySetType) + "}/_x" +propertyTypeMap.get(propertyType)+"_x"+Integer.toHexString(propertyTag);
|
||||||
|
Field field = new Field(alias, SCHEMAS_MAPI_ID, name);
|
||||||
|
fieldMap.put(field.alias, field);
|
||||||
|
}
|
||||||
|
|
||||||
protected static void createField(Namespace namespace, String name) {
|
protected static void createField(Namespace namespace, String name) {
|
||||||
Field field = new Field(namespace, name);
|
Field field = new Field(namespace, name);
|
||||||
fieldMap.put(field.alias, field);
|
fieldMap.put(field.alias, field);
|
||||||
@ -185,4 +195,8 @@ public class Field {
|
|||||||
String name = '{' + distinguishedPropertySetMap.get(DistinguishedPropertySetType.InternetHeaders) + "}/" + headerName;
|
String name = '{' + distinguishedPropertySetMap.get(DistinguishedPropertySetType.InternetHeaders) + "}/" + headerName;
|
||||||
return new Field(SCHEMAS_MAPI_STRING, name);
|
return new Field(SCHEMAS_MAPI_STRING, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static DefaultDavProperty createDavProperty(String alias, String value) {
|
||||||
|
return new DefaultDavProperty(Field.get(alias).davPropertyName, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user