mirror of
https://github.com/moparisthebest/davmail
synced 2024-12-13 03:02:22 -05:00
EWS: implement user availability (freebusy) and shared folder access
git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@1312 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
parent
b2496a60e6
commit
35d7596b09
@ -111,6 +111,11 @@ public abstract class ExchangeSession {
|
||||
protected String rootPath;
|
||||
protected String email;
|
||||
protected String alias;
|
||||
/**
|
||||
* Lower case Caldav path to current user mailbox.
|
||||
* /users/<i>email</i>
|
||||
*/
|
||||
protected String currentMailboxPath;
|
||||
protected final HttpClient httpClient;
|
||||
|
||||
private final String userName;
|
||||
@ -238,7 +243,20 @@ public abstract class ExchangeSession {
|
||||
* @throws NoRouteToHostException on error
|
||||
* @throws UnknownHostException on error
|
||||
*/
|
||||
public abstract boolean isExpired() throws NoRouteToHostException, UnknownHostException;
|
||||
public boolean isExpired() throws NoRouteToHostException, UnknownHostException {
|
||||
boolean isExpired = false;
|
||||
try {
|
||||
getFolder("");
|
||||
} catch (UnknownHostException exc) {
|
||||
throw exc;
|
||||
} catch (NoRouteToHostException exc) {
|
||||
throw exc;
|
||||
} catch (IOException e) {
|
||||
isExpired = true;
|
||||
}
|
||||
|
||||
return isExpired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test authentication mode : form based or basic.
|
||||
@ -1001,8 +1019,8 @@ public abstract class ExchangeSession {
|
||||
* Create Exchange message folder.
|
||||
*
|
||||
* @param folderName logical folder name
|
||||
* @throws IOException on error
|
||||
* @return status
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public int createMessageFolder(String folderName) throws IOException {
|
||||
return createFolder(folderName, "IPF.Note", null);
|
||||
@ -1013,8 +1031,8 @@ public abstract class ExchangeSession {
|
||||
*
|
||||
* @param folderName logical folder name
|
||||
* @param properties folder properties
|
||||
* @throws IOException on error
|
||||
* @return status
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public int createCalendarFolder(String folderName, Map<String, String> properties) throws IOException {
|
||||
return createFolder(folderName, "IPF.Appointment", properties);
|
||||
@ -1025,8 +1043,8 @@ public abstract class ExchangeSession {
|
||||
*
|
||||
* @param folderName logical folder name
|
||||
* @param properties folder properties
|
||||
* @throws IOException on error
|
||||
* @return status
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public int createContactFolder(String folderName, Map<String, String> properties) throws IOException {
|
||||
return createFolder(folderName, "IPF.Contact", properties);
|
||||
@ -3308,6 +3326,17 @@ public abstract class ExchangeSession {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get freebusy data string from Exchange.
|
||||
*
|
||||
* @param attendee attendee email address
|
||||
* @param start start date in Exchange zulu format
|
||||
* @param end end date in Exchange zulu format
|
||||
* @param interval freebusy interval in minutes
|
||||
* @return freebusy data or null
|
||||
*/
|
||||
protected abstract String getFreeBusyData(String attendee, String start, String end, int interval) throws IOException;
|
||||
|
||||
/**
|
||||
* Get freebusy info for attendee between start and end date.
|
||||
*
|
||||
@ -3326,7 +3355,6 @@ public abstract class ExchangeSession {
|
||||
SimpleDateFormat exchangeZuluDateFormat = getExchangeZuluDateFormat();
|
||||
SimpleDateFormat icalDateFormat = getZuluDateFormat();
|
||||
|
||||
String freebusyUrl;
|
||||
Date startDate;
|
||||
Date endDate;
|
||||
try {
|
||||
@ -3340,28 +3368,15 @@ public abstract class ExchangeSession {
|
||||
} else {
|
||||
endDate = icalDateFormat.parse(endDateValue);
|
||||
}
|
||||
freebusyUrl = publicFolderUrl + "/?cmd=freebusy" +
|
||||
"&start=" + exchangeZuluDateFormat.format(startDate) +
|
||||
"&end=" + exchangeZuluDateFormat.format(endDate) +
|
||||
"&interval=" + FREE_BUSY_INTERVAL +
|
||||
"&u=SMTP:" + attendee;
|
||||
} catch (ParseException e) {
|
||||
throw new DavMailException("EXCEPTION_INVALID_DATES", e.getMessage());
|
||||
}
|
||||
|
||||
FreeBusy freeBusy = null;
|
||||
GetMethod getMethod = new GetMethod(freebusyUrl);
|
||||
getMethod.setRequestHeader("Content-Type", "text/xml");
|
||||
|
||||
try {
|
||||
DavGatewayHttpClientFacade.executeGetMethod(httpClient, getMethod, true);
|
||||
String fbdata = StringUtil.getLastToken(getMethod.getResponseBodyAsString(), "<a:fbdata>", "</a:fbdata>");
|
||||
String fbdata = getFreeBusyData(attendee, exchangeZuluDateFormat.format(startDate), exchangeZuluDateFormat.format(endDate), FREE_BUSY_INTERVAL);
|
||||
if (fbdata != null) {
|
||||
freeBusy = new FreeBusy(icalDateFormat, startDate, fbdata);
|
||||
}
|
||||
} finally {
|
||||
getMethod.releaseConnection();
|
||||
}
|
||||
|
||||
if (freeBusy != null && freeBusy.knownAttendee) {
|
||||
return freeBusy;
|
||||
|
@ -47,9 +47,7 @@ import org.w3c.dom.Node;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import java.io.*;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
@ -174,6 +172,25 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
return !getFolderPath(folderPath).toLowerCase().startsWith(mailPath.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFreeBusyData(String attendee, String start, String end, int interval) throws IOException {
|
||||
String freebusyUrl = publicFolderUrl + "/?cmd=freebusy" +
|
||||
"&start=" + start +
|
||||
"&end=" + end +
|
||||
"&interval=" + interval +
|
||||
"&u=SMTP:" + attendee;
|
||||
GetMethod getMethod = new GetMethod(freebusyUrl);
|
||||
getMethod.setRequestHeader("Content-Type", "text/xml");
|
||||
String fbdata = null;
|
||||
try {
|
||||
DavGatewayHttpClientFacade.executeGetMethod(httpClient, getMethod, true);
|
||||
fbdata = StringUtil.getLastToken(getMethod.getResponseBodyAsString(), "<a:fbdata>", "</a:fbdata>");
|
||||
} finally {
|
||||
getMethod.releaseConnection();
|
||||
}
|
||||
return fbdata;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@ -335,25 +352,6 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public boolean isExpired() throws NoRouteToHostException, UnknownHostException {
|
||||
boolean isExpired = false;
|
||||
try {
|
||||
getFolder("");
|
||||
} 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 MultiCondition(Operator operator, Condition... condition) {
|
||||
super(operator, condition);
|
||||
|
@ -18,6 +18,9 @@
|
||||
*/
|
||||
package davmail.exchange.ews;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Distinguished Folder Id.
|
||||
*/
|
||||
@ -27,21 +30,40 @@ public class DistinguishedFolderId extends FolderId {
|
||||
super("t:DistinguishedFolderId", value, null);
|
||||
}
|
||||
|
||||
public static final DistinguishedFolderId CALENDAR = new DistinguishedFolderId("calendar");
|
||||
public static final DistinguishedFolderId CONTACTS = new DistinguishedFolderId("contacts");
|
||||
public static final DistinguishedFolderId DELETEDITEMS = new DistinguishedFolderId("deleteditems");
|
||||
public static final DistinguishedFolderId DRAFTS = new DistinguishedFolderId("drafts");
|
||||
public static final DistinguishedFolderId INBOX = new DistinguishedFolderId("inbox");
|
||||
public static final DistinguishedFolderId JOURNAL = new DistinguishedFolderId("journal");
|
||||
public static final DistinguishedFolderId NOTES = new DistinguishedFolderId("notes");
|
||||
public static final DistinguishedFolderId OUTBOX = new DistinguishedFolderId("outbox");
|
||||
public static final DistinguishedFolderId SENTITEMS = new DistinguishedFolderId("sentitems");
|
||||
public static final DistinguishedFolderId TASKS = new DistinguishedFolderId("tasks");
|
||||
public static final DistinguishedFolderId MSGFOLDERROOT = new DistinguishedFolderId("msgfolderroot");
|
||||
public static final DistinguishedFolderId PUBLICFOLDERSROOT = new DistinguishedFolderId("publicfoldersroot");
|
||||
public static final DistinguishedFolderId ROOT = new DistinguishedFolderId("root");
|
||||
public static final DistinguishedFolderId JUNKEMAIL = new DistinguishedFolderId("junkemail");
|
||||
public static final DistinguishedFolderId SEARCHFOLDERS = new DistinguishedFolderId("searchfolders");
|
||||
public static final DistinguishedFolderId VOICEMAIL = new DistinguishedFolderId("voicemail");
|
||||
private DistinguishedFolderId(String value, String mailbox) {
|
||||
super("t:DistinguishedFolderId", value, null, mailbox);
|
||||
}
|
||||
|
||||
/**
|
||||
* DistinguishedFolderId names
|
||||
*/
|
||||
@SuppressWarnings({"UnusedDeclaration", "JavaDoc"})
|
||||
public static enum Name {
|
||||
calendar, contacts, deleteditems, drafts, inbox, journal, notes, outbox, sentitems, tasks, msgfolderroot,
|
||||
publicfoldersroot, root, junkemail, searchfolders, voicemail
|
||||
}
|
||||
|
||||
protected static final Map<Name, DistinguishedFolderId> folderIdMap = new HashMap<Name, DistinguishedFolderId>();
|
||||
|
||||
static {
|
||||
for (Name name : Name.values()) {
|
||||
folderIdMap.put(name, new DistinguishedFolderId(name.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DistinguishedFolderId object for mailbox and name.
|
||||
*
|
||||
* @param mailbox mailbox name
|
||||
* @param name folder id name
|
||||
* @return DistinguishedFolderId object
|
||||
*/
|
||||
public static DistinguishedFolderId getInstance(String mailbox, Name name) {
|
||||
if (mailbox == null) {
|
||||
return folderIdMap.get(name);
|
||||
} else {
|
||||
return new DistinguishedFolderId(name.toString(), mailbox);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -360,6 +360,7 @@ public abstract class EWSMethod extends PostMethod {
|
||||
endChanges(writer);
|
||||
}
|
||||
|
||||
|
||||
protected void writeIndexedPageItemView(Writer writer) throws IOException {
|
||||
if (maxCount > 0) {
|
||||
writer.write("<m:IndexedPageItemView MaxEntriesReturned=\"");
|
||||
@ -540,7 +541,9 @@ public abstract class EWSMethod extends PostMethod {
|
||||
*/
|
||||
public void checkSuccess() throws EWSException {
|
||||
if (errorDetail != null) {
|
||||
if (!"ErrorAccessDenied".equals(errorDetail)) {
|
||||
if (!"ErrorAccessDenied".equals(errorDetail)
|
||||
&& !"ErrorNameResolutionMultipleResults".equals(errorDetail)
|
||||
&& !"ErrorMailRecipientNotFound".equals(errorDetail)) {
|
||||
try {
|
||||
throw new EWSException(errorDetail + "\n request: " + new String(generateSoapEnvelope(), "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
@ -794,6 +797,8 @@ public abstract class EWSMethod extends PostMethod {
|
||||
}
|
||||
} else if (isStartTag(reader, responseCollectionName)) {
|
||||
handleItems(reader);
|
||||
} else {
|
||||
handleCustom(reader);
|
||||
}
|
||||
}
|
||||
|
||||
@ -808,6 +813,11 @@ public abstract class EWSMethod extends PostMethod {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"NoopMethodInAbstractClass"})
|
||||
protected void handleCustom(XMLStreamReader reader) throws XMLStreamException {
|
||||
// override to handle custom content
|
||||
}
|
||||
|
||||
private void handleItems(XMLStreamReader reader) throws XMLStreamException {
|
||||
while (reader.hasNext() && !isEndTag(reader, responseCollectionName)) {
|
||||
reader.next();
|
||||
|
@ -33,8 +33,6 @@ import org.apache.commons.httpclient.methods.GetMethod;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
@ -75,20 +73,15 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
super(url, userName, password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExpired() throws NoRouteToHostException, UnknownHostException {
|
||||
// TODO: implement
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildSessionInfo(HttpMethod method) throws DavMailException {
|
||||
// nothing to do, mailPath not used in EWS mode
|
||||
// check EWS access
|
||||
HttpMethod getMethod = new GetMethod("/ews/exchange.asmx");
|
||||
getMethod.setFollowRedirects(false);
|
||||
try {
|
||||
getMethod = DavGatewayHttpClientFacade.executeFollowRedirects(httpClient, getMethod);
|
||||
if (getMethod.getStatusCode() != HttpStatus.SC_OK) {
|
||||
int status = DavGatewayHttpClientFacade.executeNoRedirect(httpClient, getMethod);
|
||||
if (status != HttpStatus.SC_MOVED_TEMPORARILY) {
|
||||
throw DavGatewayHttpClientFacade.buildHttpException(getMethod);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
@ -98,6 +91,14 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
getMethod.releaseConnection();
|
||||
}
|
||||
|
||||
// also need to retrieve email and alias
|
||||
alias = getAliasFromOptions();
|
||||
email = getEmailFromOptions();
|
||||
if (email == null || alias == null) {
|
||||
throw new DavMailAuthenticationException("EXCEPTION_EWS_NOT_AVAILABLE");
|
||||
}
|
||||
currentMailboxPath = "/users/" + email.toLowerCase();
|
||||
|
||||
try {
|
||||
folderIdMap = new HashMap<String, String>();
|
||||
// load actual well known folder ids
|
||||
@ -114,9 +115,6 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
throw new DavMailAuthenticationException("EXCEPTION_EWS_NOT_AVAILABLE");
|
||||
}
|
||||
|
||||
// also need to retrieve email and alias
|
||||
alias = getAliasFromOptions();
|
||||
email = getEmailFromOptions();
|
||||
}
|
||||
|
||||
class Message extends ExchangeSession.Message {
|
||||
@ -502,9 +500,9 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
FOLDER_PROPERTIES.add(Field.get("highestUid"));
|
||||
}
|
||||
|
||||
protected Folder buildFolder(EWSMethod.Item item) {
|
||||
protected Folder buildFolder(String mailbox, EWSMethod.Item item) {
|
||||
Folder folder = new Folder();
|
||||
folder.folderId = new FolderId(item);
|
||||
folder.folderId = new FolderId(mailbox, item);
|
||||
folder.displayName = item.get(Field.get("folderDisplayName").getResponseName());
|
||||
folder.folderClass = item.get(Field.get("folderclass").getResponseName());
|
||||
folder.etag = item.get(Field.get("lastmodified").getResponseName());
|
||||
@ -540,7 +538,7 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
BaseShape.ID_ONLY, parentFolderId, FOLDER_PROPERTIES, (SearchExpression) condition);
|
||||
executeMethod(findFolderMethod);
|
||||
for (EWSMethod.Item item : findFolderMethod.getResponseItems()) {
|
||||
Folder folder = buildFolder(item);
|
||||
Folder folder = buildFolder(parentFolderId.mailbox, item);
|
||||
if (parentFolderPath.length() > 0) {
|
||||
folder.folderPath = parentFolderPath + '/' + item.get(Field.get("urlcompname").getResponseName());
|
||||
} else if (folderIdMap.get(folder.folderId.value) != null) {
|
||||
@ -571,12 +569,13 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
* @throws IOException on error
|
||||
*/
|
||||
protected EwsExchangeSession.Folder internalGetFolder(String folderPath) throws IOException {
|
||||
GetFolderMethod getFolderMethod = new GetFolderMethod(BaseShape.ID_ONLY, getFolderId(folderPath), FOLDER_PROPERTIES);
|
||||
FolderId folderId = getFolderId(folderPath);
|
||||
GetFolderMethod getFolderMethod = new GetFolderMethod(BaseShape.ID_ONLY, folderId, FOLDER_PROPERTIES);
|
||||
executeMethod(getFolderMethod);
|
||||
EWSMethod.Item item = getFolderMethod.getResponseItem();
|
||||
Folder folder = null;
|
||||
if (item != null) {
|
||||
folder = buildFolder(item);
|
||||
folder = buildFolder(folderId.mailbox, item);
|
||||
folder.folderPath = folderPath;
|
||||
}
|
||||
return folder;
|
||||
@ -1085,8 +1084,14 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
|
||||
@Override
|
||||
public boolean isSharedFolder(String folderPath) {
|
||||
// TODO
|
||||
return false;
|
||||
return folderPath.startsWith("/") && !folderPath.toLowerCase().startsWith(currentMailboxPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFreeBusyData(String attendee, String start, String end, int interval) throws IOException {
|
||||
GetUserAvailabilityMethod getUserAvailabilityMethod = new GetUserAvailabilityMethod(attendee, start, end, interval);
|
||||
executeMethod(getUserAvailabilityMethod);
|
||||
return getUserAvailabilityMethod.getMergedFreeBusy();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1103,47 +1108,64 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
return folderId;
|
||||
}
|
||||
|
||||
private FolderId getFolderIdIfExists(String folderPath) throws IOException {
|
||||
protected static final String USERS_ROOT = "/users/";
|
||||
|
||||
protected FolderId getFolderIdIfExists(String folderPath) throws IOException {
|
||||
String lowerCaseFolderPath = folderPath.toLowerCase();
|
||||
if (currentMailboxPath.equals(lowerCaseFolderPath)) {
|
||||
return getSubFolderIdIfExists(null, "");
|
||||
} else if (lowerCaseFolderPath.startsWith(currentMailboxPath + '/')) {
|
||||
return getSubFolderIdIfExists(null, folderPath.substring(currentMailboxPath.length() + 1));
|
||||
} else if (folderPath.startsWith("/users/")) {
|
||||
int slashIndex = folderPath.indexOf('/', USERS_ROOT.length());
|
||||
String mailbox;
|
||||
String subFolderPath;
|
||||
if (slashIndex >= 0) {
|
||||
mailbox = folderPath.substring(USERS_ROOT.length(), slashIndex);
|
||||
subFolderPath = folderPath.substring(slashIndex+1);
|
||||
} else {
|
||||
mailbox = folderPath.substring(USERS_ROOT.length());
|
||||
subFolderPath = "";
|
||||
}
|
||||
return getSubFolderIdIfExists(mailbox, subFolderPath);
|
||||
} else {
|
||||
return getSubFolderIdIfExists(null, folderPath);
|
||||
}
|
||||
}
|
||||
|
||||
protected FolderId getSubFolderIdIfExists(String mailbox, String folderPath) throws IOException {
|
||||
String[] folderNames;
|
||||
FolderId currentFolderId;
|
||||
String lowerCaseFolderPath = folderPath.toLowerCase();
|
||||
if (email != null) {
|
||||
String currentMailboxPath = "/users/" + email.toLowerCase();
|
||||
if (currentMailboxPath.equals(lowerCaseFolderPath)) {
|
||||
return DistinguishedFolderId.MSGFOLDERROOT;
|
||||
} else if (lowerCaseFolderPath.startsWith(currentMailboxPath + '/')) {
|
||||
return getFolderIdIfExists(folderPath.substring(currentMailboxPath.length() + 1));
|
||||
}
|
||||
}
|
||||
|
||||
if (folderPath.startsWith(PUBLIC_ROOT)) {
|
||||
currentFolderId = DistinguishedFolderId.PUBLICFOLDERSROOT;
|
||||
currentFolderId = DistinguishedFolderId.getInstance(mailbox, DistinguishedFolderId.Name.publicfoldersroot);
|
||||
folderNames = folderPath.substring(PUBLIC_ROOT.length()).split("/");
|
||||
} else if (folderPath.startsWith(INBOX) || folderPath.startsWith(LOWER_CASE_INBOX)) {
|
||||
currentFolderId = DistinguishedFolderId.INBOX;
|
||||
currentFolderId = DistinguishedFolderId.getInstance(mailbox, DistinguishedFolderId.Name.inbox);
|
||||
folderNames = folderPath.substring(INBOX.length()).split("/");
|
||||
} else if (folderPath.startsWith(CALENDAR)) {
|
||||
currentFolderId = DistinguishedFolderId.CALENDAR;
|
||||
currentFolderId = DistinguishedFolderId.getInstance(mailbox, DistinguishedFolderId.Name.calendar);
|
||||
folderNames = folderPath.substring(CALENDAR.length()).split("/");
|
||||
} else if (folderPath.startsWith(CONTACTS)) {
|
||||
currentFolderId = DistinguishedFolderId.CONTACTS;
|
||||
currentFolderId = DistinguishedFolderId.getInstance(mailbox, DistinguishedFolderId.Name.contacts);
|
||||
folderNames = folderPath.substring(CONTACTS.length()).split("/");
|
||||
} else if (folderPath.startsWith(SENT)) {
|
||||
currentFolderId = DistinguishedFolderId.SENTITEMS;
|
||||
currentFolderId = DistinguishedFolderId.getInstance(mailbox, DistinguishedFolderId.Name.sentitems);
|
||||
folderNames = folderPath.substring(SENT.length()).split("/");
|
||||
} else if (folderPath.startsWith(DRAFTS)) {
|
||||
currentFolderId = DistinguishedFolderId.DRAFTS;
|
||||
currentFolderId = DistinguishedFolderId.getInstance(mailbox, DistinguishedFolderId.Name.drafts);
|
||||
folderNames = folderPath.substring(DRAFTS.length()).split("/");
|
||||
} else if (folderPath.startsWith(TRASH)) {
|
||||
currentFolderId = DistinguishedFolderId.DELETEDITEMS;
|
||||
currentFolderId = DistinguishedFolderId.getInstance(mailbox, DistinguishedFolderId.Name.deleteditems);
|
||||
folderNames = folderPath.substring(TRASH.length()).split("/");
|
||||
} else if (folderPath.startsWith(JUNK)) {
|
||||
currentFolderId = DistinguishedFolderId.JUNKEMAIL;
|
||||
currentFolderId = DistinguishedFolderId.getInstance(mailbox, DistinguishedFolderId.Name.junkemail);
|
||||
folderNames = folderPath.substring(JUNK.length()).split("/");
|
||||
} else if (folderPath.startsWith(UNSENT)) {
|
||||
currentFolderId = DistinguishedFolderId.OUTBOX;
|
||||
currentFolderId = DistinguishedFolderId.getInstance(mailbox, DistinguishedFolderId.Name.outbox);
|
||||
folderNames = folderPath.substring(UNSENT.length()).split("/");
|
||||
} else {
|
||||
currentFolderId = DistinguishedFolderId.MSGFOLDERROOT;
|
||||
currentFolderId = DistinguishedFolderId.getInstance(mailbox, DistinguishedFolderId.Name.msgfolderroot);
|
||||
folderNames = folderPath.split("/");
|
||||
}
|
||||
for (String folderName : folderNames) {
|
||||
@ -1170,7 +1192,7 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
executeMethod(findFolderMethod);
|
||||
EWSMethod.Item item = findFolderMethod.getResponseItem();
|
||||
if (item != null) {
|
||||
folderId = new FolderId(item);
|
||||
folderId = new FolderId(parentFolderId.mailbox, item);
|
||||
}
|
||||
return folderId;
|
||||
}
|
||||
|
@ -26,6 +26,20 @@ import java.io.Writer;
|
||||
*/
|
||||
public class FolderId extends Option {
|
||||
protected String changeKey;
|
||||
protected String mailbox;
|
||||
|
||||
/**
|
||||
* Create FolderId with specified tag name.
|
||||
*
|
||||
* @param name field tag name
|
||||
* @param value id value
|
||||
* @param changeKey folder change key
|
||||
* @param mailbox shared mailbox name
|
||||
*/
|
||||
protected FolderId(String name, String value, String changeKey, String mailbox) {
|
||||
this(name, value, changeKey);
|
||||
this.mailbox = mailbox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create FolderId with specified tag name.
|
||||
@ -39,24 +53,14 @@ public class FolderId extends Option {
|
||||
this.changeKey = changeKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create FolderId
|
||||
*
|
||||
* @param value id value
|
||||
* @param changeKey folder change key
|
||||
*/
|
||||
public FolderId(String value, String changeKey) {
|
||||
super("t:FolderId", value);
|
||||
this.changeKey = changeKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Folder id from response item.
|
||||
*
|
||||
* @param mailbox mailbox name
|
||||
* @param item response item
|
||||
*/
|
||||
public FolderId(EWSMethod.Item item) {
|
||||
this(item.get("FolderId"), item.get("ChangeKey"));
|
||||
public FolderId(String mailbox, EWSMethod.Item item) {
|
||||
this("t:FolderId", item.get("FolderId"), item.get("ChangeKey"), mailbox);
|
||||
}
|
||||
|
||||
|
||||
@ -73,7 +77,15 @@ public class FolderId extends Option {
|
||||
writer.write("\" ChangeKey=\"");
|
||||
writer.write(changeKey);
|
||||
}
|
||||
if (mailbox == null) {
|
||||
writer.write("\"/>");
|
||||
} else {
|
||||
writer.write("\"><t:Mailbox><t:EmailAddress>");
|
||||
writer.write(mailbox);
|
||||
writer.write("</t:EmailAddress></t:Mailbox></");
|
||||
writer.write(name);
|
||||
writer.write('>');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
108
src/java/davmail/exchange/ews/GetUserAvailabilityMethod.java
Normal file
108
src/java/davmail/exchange/ews/GetUserAvailabilityMethod.java
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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 javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* GetUserAvailability method.
|
||||
*/
|
||||
public class GetUserAvailabilityMethod extends EWSMethod {
|
||||
protected String attendee;
|
||||
protected String start;
|
||||
protected String end;
|
||||
protected String mergedFreeBusy;
|
||||
protected int interval;
|
||||
|
||||
/**
|
||||
* Build EWS method
|
||||
*
|
||||
* @param attendee attendee email address
|
||||
* @param start start date in Exchange zulu format
|
||||
* @param end end date in Exchange zulu format
|
||||
* @param interval freebusy interval in minutes
|
||||
*/
|
||||
public GetUserAvailabilityMethod(String attendee, String start, String end, int interval) {
|
||||
super("FreeBusy", "GetUserAvailabilityRequest");
|
||||
this.attendee = attendee;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeSoapBody(Writer writer) throws IOException {
|
||||
// write UTC timezone
|
||||
writer.write("<t:TimeZone>" +
|
||||
"<t:Bias>0</t:Bias>" +
|
||||
"<t:StandardTime>" +
|
||||
"<t:Bias>0</t:Bias>" +
|
||||
"<t:Time>00:00:00</t:Time>" +
|
||||
"<t:DayOrder>1</t:DayOrder>" +
|
||||
"<t:Month>1</t:Month>" +
|
||||
"<t:DayOfWeek>Sunday</t:DayOfWeek>" +
|
||||
"</t:StandardTime>" +
|
||||
"<t:DaylightTime>" +
|
||||
"<t:Bias>0</t:Bias>" +
|
||||
"<t:Time>00:00:00</t:Time>" +
|
||||
"<t:DayOrder>1</t:DayOrder>" +
|
||||
"<t:Month>1</t:Month>" +
|
||||
"<t:DayOfWeek>Sunday</t:DayOfWeek>" +
|
||||
"</t:DaylightTime>" +
|
||||
"</t:TimeZone>");
|
||||
// write attendee address
|
||||
writer.write("<m:MailboxDataArray>" +
|
||||
"<t:MailboxData>" +
|
||||
"<t:Email>" +
|
||||
"<t:Address>");
|
||||
writer.write(attendee);
|
||||
writer.write("</t:Address>" +
|
||||
"</t:Email>" +
|
||||
"<t:AttendeeType>Required</t:AttendeeType>" +
|
||||
"</t:MailboxData>" +
|
||||
"</m:MailboxDataArray>");
|
||||
// freebusy range
|
||||
writer.write("<t:FreeBusyViewOptions>" +
|
||||
"<t:TimeWindow>" +
|
||||
"<t:StartTime>");
|
||||
writer.write(start);
|
||||
writer.write("</t:StartTime>" +
|
||||
"<t:EndTime>");
|
||||
writer.write(end);
|
||||
writer.write("</t:EndTime>" +
|
||||
"</t:TimeWindow>" +
|
||||
"<t:MergedFreeBusyIntervalInMinutes>60</t:MergedFreeBusyIntervalInMinutes>" +
|
||||
"<t:RequestedView>MergedOnly</t:RequestedView>" +
|
||||
"</t:FreeBusyViewOptions>");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleCustom(XMLStreamReader reader) throws XMLStreamException {
|
||||
if (isStartTag(reader, "MergedFreeBusy")) {
|
||||
this.mergedFreeBusy = reader.getElementText();
|
||||
}
|
||||
}
|
||||
|
||||
public String getMergedFreeBusy() {
|
||||
return mergedFreeBusy;
|
||||
}
|
||||
}
|
@ -285,6 +285,35 @@ public final class DavGatewayHttpClientFacade {
|
||||
return currentMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute method with httpClient, do not follow 30x redirects.
|
||||
*
|
||||
* @param httpClient Http client instance
|
||||
* @param method Http method
|
||||
* @return status
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public static int executeNoRedirect(HttpClient httpClient, HttpMethod method) throws IOException {
|
||||
int status;
|
||||
try {
|
||||
status = httpClient.executeMethod(method);
|
||||
// check NTLM
|
||||
if ((status == HttpStatus.SC_UNAUTHORIZED || status == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED)
|
||||
&& acceptsNTLMOnly(method) && !hasNTLM(httpClient)) {
|
||||
LOGGER.debug("Received " + status + " unauthorized at " + method.getURI() + ", retrying with NTLM");
|
||||
resetMethod(method);
|
||||
addNTLM(httpClient);
|
||||
status = httpClient.executeMethod(method);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} finally {
|
||||
method.releaseConnection();
|
||||
}
|
||||
// caller will need to release connection
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute webdav search method.
|
||||
*
|
||||
|
@ -18,18 +18,19 @@
|
||||
*/
|
||||
package davmail.exchange;
|
||||
|
||||
import davmail.AbstractDavMailTestCase;
|
||||
import davmail.Settings;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Test Exchange session calendar features .
|
||||
*/
|
||||
@SuppressWarnings({"UseOfSystemOutOrSystemErr"})
|
||||
public class TestExchangeSessionCalendar extends AbstractDavMailTestCase {
|
||||
public class TestExchangeSessionCalendar extends AbstractExchangeSessionTestCase {
|
||||
|
||||
public void testGetVtimezone() {
|
||||
ExchangeSession.VTimezone timezone = session.getVTimezone();
|
||||
@ -91,4 +92,33 @@ public class TestExchangeSessionCalendar extends AbstractDavMailTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetFreeBusyData() throws IOException, MessagingException {
|
||||
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
cal.set(Calendar.MONTH, 7);
|
||||
cal.set(Calendar.DAY_OF_MONTH, 1);
|
||||
cal.set(Calendar.HOUR_OF_DAY, 0);
|
||||
cal.set(Calendar.MINUTE, 0);
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
Date startDate = cal.getTime();
|
||||
cal.set(Calendar.HOUR_OF_DAY, 23);
|
||||
cal.set(Calendar.MINUTE, 59);
|
||||
cal.set(Calendar.SECOND, 59);
|
||||
Date endDate = cal.getTime();
|
||||
SimpleDateFormat formatter = ExchangeSession.getExchangeZuluDateFormat();
|
||||
// personal fbdata
|
||||
String fbdata = session.getFreeBusyData(session.getEmail(), formatter.format(startDate),
|
||||
formatter.format(endDate), 60);
|
||||
assertNotNull(fbdata);
|
||||
// other user data
|
||||
fbdata = session.getFreeBusyData(Settings.getProperty("davmail.to"), formatter.format(startDate),
|
||||
formatter.format(endDate), 60);
|
||||
assertNotNull(fbdata);
|
||||
// unknown user data
|
||||
fbdata = session.getFreeBusyData("unknown@company.org", formatter.format(startDate),
|
||||
formatter.format(endDate), 60);
|
||||
assertNull(fbdata);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,9 @@
|
||||
*/
|
||||
package davmail.exchange;
|
||||
|
||||
import davmail.Settings;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
@ -121,5 +124,13 @@ public class TestExchangeSessionFolder extends AbstractExchangeSessionTestCase {
|
||||
session.deleteFolder(folderName);
|
||||
}
|
||||
|
||||
public void testGetSharedFolder() throws IOException, MessagingException {
|
||||
ExchangeSession.Folder folder = session.getFolder("/users/"+ Settings.getProperty("davmail.to")+"/inbox");
|
||||
ExchangeSession.MessageList messages = session.searchMessages("/users/"+ Settings.getProperty("davmail.to")+"/inbox");
|
||||
for (ExchangeSession.Message message:messages) {
|
||||
System.out.println(message.getMimeMessage());
|
||||
}
|
||||
assertNotNull(folder);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user