1
0
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:
mguessan 2010-06-08 10:44:47 +00:00
parent 1fed7df8c3
commit 0569d15e97
5 changed files with 167 additions and 57 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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"));
}

View File

@ -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

View File

@ -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é