mirror of
https://github.com/moparisthebest/davmail
synced 2024-12-13 11:12:22 -05:00
EWS: map folder path to and from IMAP
git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@1081 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
parent
1fed7df8c3
commit
0569d15e97
@ -98,6 +98,17 @@ public abstract class ExchangeSession {
|
||||
|
||||
protected static final int FREE_BUSY_INTERVAL = 15;
|
||||
|
||||
protected static final String PUBLIC_ROOT = "/public";
|
||||
protected static final String CALENDAR = "calendar";
|
||||
protected static final String CONTACTS = "contacts";
|
||||
protected static final String INBOX = "INBOX";
|
||||
protected static final String SENT = "Sent";
|
||||
protected static final String DRAFTS = "Drafts";
|
||||
protected static final String TRASH = "Trash";
|
||||
protected static final String JUNK = "Junk";
|
||||
protected static final String UNSENT = "Unsent Messages";
|
||||
|
||||
|
||||
protected static final Namespace DAV = Namespace.getNamespace("DAV:");
|
||||
protected static final Namespace URN_SCHEMAS_HTTPMAIL = Namespace.getNamespace("urn:schemas:httpmail:");
|
||||
protected static final Namespace SCHEMAS_EXCHANGE = Namespace.getNamespace("http://schemas.microsoft.com/exchange/");
|
||||
@ -123,6 +134,7 @@ public abstract class ExchangeSession {
|
||||
WELL_KNOWN_FOLDERS.add(DavPropertyName.create("drafts", URN_SCHEMAS_HTTPMAIL));
|
||||
WELL_KNOWN_FOLDERS.add(DavPropertyName.create("calendar", URN_SCHEMAS_HTTPMAIL));
|
||||
WELL_KNOWN_FOLDERS.add(DavPropertyName.create("contacts", URN_SCHEMAS_HTTPMAIL));
|
||||
WELL_KNOWN_FOLDERS.add(DavPropertyName.create("outbox", URN_SCHEMAS_HTTPMAIL));
|
||||
}
|
||||
|
||||
protected static final DavPropertyNameSet DISPLAY_NAME = new DavPropertyNameSet();
|
||||
@ -168,6 +180,7 @@ public abstract class ExchangeSession {
|
||||
protected String draftsUrl;
|
||||
protected String calendarUrl;
|
||||
protected String contactsUrl;
|
||||
protected String outboxUrl;
|
||||
protected String publicFolderUrl;
|
||||
|
||||
/**
|
||||
@ -851,13 +864,23 @@ public abstract class ExchangeSession {
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Condition and(Condition... condition);
|
||||
protected abstract static class IsNullCondition extends Condition {
|
||||
protected String attributeName;
|
||||
|
||||
protected abstract Condition or(Condition... condition);
|
||||
protected IsNullCondition(String attributeName) {
|
||||
this.attributeName = attributeName;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Condition not(Condition condition);
|
||||
public abstract Condition and(Condition... condition);
|
||||
|
||||
protected abstract AttributeCondition equals(String attributeName, String value);
|
||||
public abstract Condition or(Condition... condition);
|
||||
|
||||
public abstract Condition not(Condition condition);
|
||||
|
||||
public abstract Condition equals(String attributeName, String value);
|
||||
|
||||
public abstract Condition isNull(String attributeName);
|
||||
|
||||
/**
|
||||
* Search mail and generic folders under given folder.
|
||||
@ -869,7 +892,9 @@ public abstract class ExchangeSession {
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public List<Folder> getSubFolders(String folderName, boolean recursive) throws IOException {
|
||||
return getSubFolders(folderName, or(equals("folderclass", "IPF.Note"), equals("folderclass", "IPF")), recursive);
|
||||
return getSubFolders(folderName,
|
||||
or(equals("folderclass", "IPF.Note"), isNull("folderclass")),
|
||||
recursive);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1017,18 +1042,18 @@ public abstract class ExchangeSession {
|
||||
*/
|
||||
public String getFolderPath(String folderName) {
|
||||
String folderPath;
|
||||
if (folderName.startsWith("INBOX")) {
|
||||
folderPath = folderName.replaceFirst("INBOX", inboxUrl);
|
||||
} else if (folderName.startsWith("Trash")) {
|
||||
folderPath = folderName.replaceFirst("Trash", deleteditemsUrl);
|
||||
} else if (folderName.startsWith("Drafts")) {
|
||||
folderPath = folderName.replaceFirst("Drafts", draftsUrl);
|
||||
} else if (folderName.startsWith("Sent")) {
|
||||
folderPath = folderName.replaceFirst("Sent", sentitemsUrl);
|
||||
} else if (folderName.startsWith("calendar")) {
|
||||
folderPath = folderName.replaceFirst("calendar", calendarUrl);
|
||||
} else if (folderName.startsWith("contacts")) {
|
||||
folderPath = folderName.replaceFirst("contacts", contactsUrl);
|
||||
if (folderName.startsWith(INBOX)) {
|
||||
folderPath = folderName.replaceFirst(INBOX, inboxUrl);
|
||||
} else if (folderName.startsWith(TRASH)) {
|
||||
folderPath = folderName.replaceFirst(TRASH, deleteditemsUrl);
|
||||
} else if (folderName.startsWith(DRAFTS)) {
|
||||
folderPath = folderName.replaceFirst(DRAFTS, draftsUrl);
|
||||
} else if (folderName.startsWith(SENT)) {
|
||||
folderPath = folderName.replaceFirst(SENT, sentitemsUrl);
|
||||
} else if (folderName.startsWith(CALENDAR)) {
|
||||
folderPath = folderName.replaceFirst(CALENDAR, calendarUrl);
|
||||
} else if (folderName.startsWith(CONTACTS)) {
|
||||
folderPath = folderName.replaceFirst(CONTACTS, contactsUrl);
|
||||
} else if (folderName.startsWith("public")) {
|
||||
folderPath = publicFolderUrl + folderName.substring("public".length());
|
||||
// absolute folder path
|
||||
|
@ -126,16 +126,18 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
draftsUrl = getURIPropertyIfExists(properties, "drafts", URN_SCHEMAS_HTTPMAIL);
|
||||
calendarUrl = getURIPropertyIfExists(properties, "calendar", URN_SCHEMAS_HTTPMAIL);
|
||||
contactsUrl = getURIPropertyIfExists(properties, "contacts", URN_SCHEMAS_HTTPMAIL);
|
||||
outboxUrl = getURIPropertyIfExists(properties, "outbox", URN_SCHEMAS_HTTPMAIL);
|
||||
// junk folder not available over webdav
|
||||
|
||||
// default public folder path
|
||||
publicFolderUrl = "/public";
|
||||
publicFolderUrl = PUBLIC_ROOT;
|
||||
|
||||
// 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");
|
||||
publicUri.setPath(PUBLIC_ROOT);
|
||||
publicFolderUrl = publicUri.getURI();
|
||||
}
|
||||
PropFindMethod propFindMethod = new PropFindMethod(publicFolderUrl, CONTENT_TAG, 0);
|
||||
@ -155,14 +157,15 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
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
|
||||
LOGGER.debug("Inbox URL: " + inboxUrl +
|
||||
" Trash URL: " + deleteditemsUrl +
|
||||
" Sent URL: " + sentitemsUrl +
|
||||
" Send URL: " + sendmsgUrl +
|
||||
" Drafts URL: " + draftsUrl +
|
||||
" Calendar URL: " + calendarUrl +
|
||||
" Contacts URL: " + contactsUrl +
|
||||
" Outbox URL: " + outboxUrl +
|
||||
" Public folder URL: " + publicFolderUrl
|
||||
);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error(e.getMessage());
|
||||
@ -231,26 +234,43 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
}
|
||||
}
|
||||
|
||||
protected static class IsNullCondition extends ExchangeSession.IsNullCondition {
|
||||
protected IsNullCondition(String attributeName) {
|
||||
super(attributeName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(StringBuilder buffer) {
|
||||
buffer.append('"').append(attributeMap.get(attributeName)).append('"');
|
||||
buffer.append(" is null");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Condition and(Condition... condition) {
|
||||
public Condition and(Condition... condition) {
|
||||
return new MultiCondition(Operator.And, condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Condition or(Condition... condition) {
|
||||
public Condition or(Condition... condition) {
|
||||
return new MultiCondition(Operator.Or, condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Condition not(Condition condition) {
|
||||
public Condition not(Condition condition) {
|
||||
return new NotCondition(condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AttributeCondition equals(String attributeName, String value) {
|
||||
public Condition equals(String attributeName, String value) {
|
||||
return new AttributeCondition(attributeName, Operator.IsEqualTo, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Condition isNull(String attributeName) {
|
||||
return new IsNullCondition(attributeName);
|
||||
}
|
||||
|
||||
|
||||
protected Folder buildFolder(MultiStatusResponse entity) throws IOException {
|
||||
String href = URIUtil.decode(entity.getHref());
|
||||
@ -265,13 +285,17 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
|
||||
// replace well known folder names
|
||||
if (href.startsWith(inboxUrl)) {
|
||||
folder.folderPath = href.replaceFirst(inboxUrl, "INBOX");
|
||||
folder.folderPath = href.replaceFirst(inboxUrl, INBOX);
|
||||
} else if (href.startsWith(sentitemsUrl)) {
|
||||
folder.folderPath = href.replaceFirst(sentitemsUrl, "Sent");
|
||||
folder.folderPath = href.replaceFirst(sentitemsUrl, SENT);
|
||||
} else if (href.startsWith(draftsUrl)) {
|
||||
folder.folderPath = href.replaceFirst(draftsUrl, "Drafts");
|
||||
folder.folderPath = href.replaceFirst(draftsUrl, DRAFTS);
|
||||
} else if (href.startsWith(deleteditemsUrl)) {
|
||||
folder.folderPath = href.replaceFirst(deleteditemsUrl, "Trash");
|
||||
folder.folderPath = href.replaceFirst(deleteditemsUrl, TRASH);
|
||||
} else if (href.startsWith(calendarUrl)) {
|
||||
folder.folderPath = href.replaceFirst(calendarUrl, CALENDAR);
|
||||
} else if (href.startsWith(contactsUrl)) {
|
||||
folder.folderPath = href.replaceFirst(contactsUrl, CONTACTS);
|
||||
} else {
|
||||
int index = href.indexOf(mailPath.substring(0, mailPath.length() - 1));
|
||||
if (index >= 0) {
|
||||
@ -315,7 +339,8 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
*/
|
||||
@Override
|
||||
public List<Folder> getSubFolders(String folderName, Condition condition, boolean recursive) throws IOException {
|
||||
String mode = recursive ? "DEEP" : "SHALLOW";
|
||||
boolean isPublic = folderName.startsWith("/public");
|
||||
String mode = (!isPublic && recursive) ? "DEEP" : "SHALLOW";
|
||||
List<Folder> folders = new ArrayList<Folder>();
|
||||
StringBuilder searchRequest = new StringBuilder();
|
||||
searchRequest.append("Select \"DAV:nosubs\", \"DAV:hassubs\", \"http://schemas.microsoft.com/exchange/outlookfolderclass\", " +
|
||||
@ -330,7 +355,11 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
httpClient, URIUtil.encodePath(getFolderPath(folderName)), searchRequest.toString());
|
||||
|
||||
for (MultiStatusResponse response : responses) {
|
||||
Folder folder = buildFolder(response);
|
||||
folders.add(buildFolder(response));
|
||||
if (isPublic && recursive) {
|
||||
getSubFolders(folder.folderPath, condition, recursive);
|
||||
}
|
||||
}
|
||||
return folders;
|
||||
}
|
||||
|
@ -39,6 +39,8 @@ import java.util.Map;
|
||||
*/
|
||||
public class EwsExchangeSession extends ExchangeSession {
|
||||
|
||||
protected Map<String, String> folderIdMap;
|
||||
|
||||
protected class Folder extends ExchangeSession.Folder {
|
||||
public FolderId folderId;
|
||||
}
|
||||
@ -66,6 +68,22 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
} finally {
|
||||
headMethod.releaseConnection();
|
||||
}
|
||||
|
||||
try {
|
||||
folderIdMap = new HashMap<String, String>();
|
||||
// load actual well known folder ids
|
||||
folderIdMap.put(getFolder(INBOX).folderId.value, INBOX);
|
||||
folderIdMap.put(getFolder(CALENDAR).folderId.value, CALENDAR);
|
||||
folderIdMap.put(getFolder(CONTACTS).folderId.value, CONTACTS);
|
||||
folderIdMap.put(getFolder(SENT).folderId.value, SENT);
|
||||
folderIdMap.put(getFolder(DRAFTS).folderId.value, DRAFTS);
|
||||
folderIdMap.put(getFolder(TRASH).folderId.value, TRASH);
|
||||
folderIdMap.put(getFolder(JUNK).folderId.value, JUNK);
|
||||
folderIdMap.put(getFolder(UNSENT).folderId.value, UNSENT);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error(e.getMessage(), e);
|
||||
throw new DavMailAuthenticationException("EXCEPTION_EWS_NOT_AVAILABLE");
|
||||
}
|
||||
}
|
||||
|
||||
protected static class MultiCondition extends ExchangeSession.MultiCondition implements SearchExpression {
|
||||
@ -124,26 +142,44 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
}
|
||||
}
|
||||
|
||||
protected static class IsNullCondition extends ExchangeSession.IsNullCondition implements SearchExpression {
|
||||
protected IsNullCondition(String attributeName) {
|
||||
super(attributeName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(StringBuilder buffer) {
|
||||
buffer.append("<t:Not><t:Exists>");
|
||||
attributeMap.get(attributeName).appendTo(buffer);
|
||||
buffer.append("</t:Exists></t:Not>");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Condition and(Condition... condition) {
|
||||
public Condition and(Condition... condition) {
|
||||
return new MultiCondition(Operator.And, condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Condition or(Condition... condition) {
|
||||
public Condition or(Condition... condition) {
|
||||
return new MultiCondition(Operator.Or, condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Condition not(Condition condition) {
|
||||
public Condition not(Condition condition) {
|
||||
return new NotCondition(condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AttributeCondition equals(String attributeName, String value) {
|
||||
public Condition equals(String attributeName, String value) {
|
||||
return new AttributeCondition(attributeName, Operator.IsEqualTo, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Condition isNull(String attributeName) {
|
||||
return new IsNullCondition(attributeName);
|
||||
}
|
||||
|
||||
protected Folder buildFolder(EWSMethod.Item item) {
|
||||
Folder folder = new Folder();
|
||||
folder.folderId = new FolderId(item.get("FolderId"));
|
||||
@ -151,7 +187,6 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
folder.etag = item.get(ExtendedFieldURI.PR_LAST_MODIFICATION_TIME.getPropertyTag());
|
||||
// TODO: implement ctag
|
||||
folder.ctag = String.valueOf(System.currentTimeMillis());
|
||||
// TODO: implement contentClass, noInferiors
|
||||
folder.unreadCount = item.getInt("UnreadCount");
|
||||
folder.hasChildren = item.getInt("ChildFolderCount") != 0;
|
||||
// noInferiors not implemented
|
||||
@ -185,6 +220,8 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
Folder folder = buildFolder(item);
|
||||
if (parentFolderPath.length() > 0) {
|
||||
folder.folderPath = parentFolderPath + '/' + item.get(ExtendedFieldURI.PR_URL_COMP_NAME.getPropertyTag());
|
||||
} else if (folderIdMap.get(folder.folderId.value) != null) {
|
||||
folder.folderPath = folderIdMap.get(folder.folderId.value);
|
||||
} else {
|
||||
folder.folderPath = item.get(ExtendedFieldURI.PR_URL_COMP_NAME.getPropertyTag());
|
||||
}
|
||||
@ -199,7 +236,7 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public ExchangeSession.Folder getFolder(String folderPath) throws IOException {
|
||||
public EwsExchangeSession.Folder getFolder(String folderPath) throws IOException {
|
||||
GetFolderMethod getFolderMethod = new GetFolderMethod(BaseShape.ALL_PROPERTIES, getFolderId(folderPath));
|
||||
getFolderMethod.addAdditionalProperty(ExtendedFieldURI.PR_URL_COMP_NAME);
|
||||
getFolderMethod.addAdditionalProperty(ExtendedFieldURI.PR_LAST_MODIFICATION_TIME);
|
||||
@ -219,28 +256,43 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
return folder;
|
||||
}
|
||||
|
||||
protected static final String PUBLIC_ROOT = "/public";
|
||||
|
||||
private FolderId getFolderId(String folderPath) throws IOException {
|
||||
String[] folderNames;
|
||||
FolderId currentFolderId;
|
||||
if (folderPath.startsWith("/public")) {
|
||||
currentFolderId = DistinguishedFolderId.PUBLICFOLDERSROOT;
|
||||
if (folderPath.startsWith(PUBLIC_ROOT)) {
|
||||
currentFolderId = DistinguishedFolderId.PUBLICFOLDERSROOT;
|
||||
folderNames = folderPath.substring(PUBLIC_ROOT.length()).split("/");
|
||||
} else if (folderPath.startsWith(INBOX)) {
|
||||
currentFolderId = DistinguishedFolderId.INBOX;
|
||||
folderNames = folderPath.substring(INBOX.length()).split("/");
|
||||
} else if (folderPath.startsWith(CALENDAR)) {
|
||||
currentFolderId = DistinguishedFolderId.CALENDAR;
|
||||
folderNames = folderPath.substring(CALENDAR.length()).split("/");
|
||||
} else if (folderPath.startsWith(CONTACTS)) {
|
||||
currentFolderId = DistinguishedFolderId.CONTACTS;
|
||||
folderNames = folderPath.substring(CONTACTS.length()).split("/");
|
||||
} else if (folderPath.startsWith(SENT)) {
|
||||
currentFolderId = DistinguishedFolderId.SENTITEMS;
|
||||
folderNames = folderPath.substring(SENT.length()).split("/");
|
||||
} else if (folderPath.startsWith(DRAFTS)) {
|
||||
currentFolderId = DistinguishedFolderId.DRAFTS;
|
||||
folderNames = folderPath.substring(DRAFTS.length()).split("/");
|
||||
} else if (folderPath.startsWith(TRASH)) {
|
||||
currentFolderId = DistinguishedFolderId.DELETEDITEMS;
|
||||
folderNames = folderPath.substring(TRASH.length()).split("/");
|
||||
} else if (folderPath.startsWith(JUNK)) {
|
||||
currentFolderId = DistinguishedFolderId.JUNKEMAIL;
|
||||
folderNames = folderPath.substring(JUNK.length()).split("/");
|
||||
} else if (folderPath.startsWith(UNSENT)) {
|
||||
currentFolderId = DistinguishedFolderId.OUTBOX;
|
||||
folderNames = folderPath.substring(UNSENT.length()).split("/");
|
||||
} else {
|
||||
currentFolderId = DistinguishedFolderId.MSGFOLDERROOT;
|
||||
folderNames = folderPath.split("/");
|
||||
currentFolderId = DistinguishedFolderId.MSGFOLDERROOT;
|
||||
folderNames = folderPath.split("/");
|
||||
}
|
||||
for (String folderName : folderNames) {
|
||||
if ("INBOX".equals(folderName)) {
|
||||
currentFolderId = DistinguishedFolderId.INBOX;
|
||||
} else if ("Sent".equals(folderName)) {
|
||||
currentFolderId = DistinguishedFolderId.SENTITEMS;
|
||||
} else if ("Drafts".equals(folderName)) {
|
||||
currentFolderId = DistinguishedFolderId.DRAFTS;
|
||||
} else if ("Trash".equals(folderName)) {
|
||||
currentFolderId = DistinguishedFolderId.DELETEDITEMS;
|
||||
} else if (folderName.length() > 0) {
|
||||
if (folderName.length() > 0) {
|
||||
currentFolderId = getSubFolderByName(currentFolderId, folderName);
|
||||
}
|
||||
}
|
||||
@ -261,7 +313,9 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
findFolderMethod.releaseConnection();
|
||||
}
|
||||
EWSMethod.Item item = findFolderMethod.getResponseItem();
|
||||
// TODO: handle not found error
|
||||
if (item == null) {
|
||||
throw new DavMailException("EXCEPTION_FOLDER_NOT_FOUND", folderName);
|
||||
}
|
||||
return new FolderId(item.get("FolderId"));
|
||||
}
|
||||
|
||||
|
@ -258,3 +258,4 @@ UI_IMAP_AUTO_EXPUNGE_HELP=Delete messages immediately on the server over IMAP
|
||||
UI_IMAP_IDLE_DELAY=IDLE folder monitor delay (IMAP):
|
||||
UI_IMAP_IDLE_DELAY_HELP=IMAP folder idle monitor delay in minutes, leave empty to disable IDLE support
|
||||
EXCEPTION_EWS_NOT_AVAILABLE=EWS end point not available
|
||||
EXCEPTION_FOLDER_NOT_FOUND=Folder {0} not found
|
||||
|
@ -257,3 +257,4 @@ UI_IMAP_IDLE_DELAY_HELP=D
|
||||
UI_IMAP_AUTO_EXPUNGE=IMAP suppression immédiate :
|
||||
UI_IMAP_AUTO_EXPUNGE_HELP=Supprimer immédiatement les messages du serveur via IMAP
|
||||
EXCEPTION_EWS_NOT_AVAILABLE=Point d''accès EWS non disponible
|
||||
EXCEPTION_FOLDER_NOT_FOUND=Dossier {0} non trouvé
|
||||
|
Loading…
Reference in New Issue
Block a user