1
0
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:
mguessan 2010-07-28 17:11:18 +00:00
parent b2496a60e6
commit 35d7596b09
10 changed files with 379 additions and 122 deletions

View File

@ -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);
@ -1037,7 +1055,7 @@ public abstract class ExchangeSession {
*
* @param folderName logical folder name
* @param folderClass folder class
* @param properties folder properties
* @param properties folder properties
* @return status
* @throws IOException on error
*/
@ -2526,7 +2544,7 @@ public abstract class ExchangeSession {
* @param folderPath Exchange folder path
* @param attributes requested attributes
* @param condition Exchange search query
* @param maxCount maximum item count
* @param maxCount maximum item count
* @return list of contacts
* @throws IOException on error
*/
@ -2809,7 +2827,7 @@ public abstract class ExchangeSession {
convertContactProperties(properties, VCARD_ADR_HOME_PROPERTIES, property.getValues());
} else if (property.hasParam("TYPE", "work")) {
convertContactProperties(properties, VCARD_ADR_WORK_PROPERTIES, property.getValues());
// any other type goes to other address
// any other type goes to other address
} else {
convertContactProperties(properties, VCARD_ADR_OTHER_PROPERTIES, property.getValues());
}
@ -3268,11 +3286,11 @@ public abstract class ExchangeSession {
CONTACT_ATTRIBUTES.add("haspicture");
CONTACT_ATTRIBUTES.add("keywords");
CONTACT_ATTRIBUTES.add("othermobile");
CONTACT_ATTRIBUTES.add("otherTelephone");
CONTACT_ATTRIBUTES.add("otherTelephone");
CONTACT_ATTRIBUTES.add("gender");
CONTACT_ATTRIBUTES.add("private");
CONTACT_ATTRIBUTES.add("sensitivity");
CONTACT_ATTRIBUTES.add("fburl");
CONTACT_ATTRIBUTES.add("fburl");
}
/**
@ -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,27 +3368,14 @@ 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>");
if (fbdata != null) {
freeBusy = new FreeBusy(icalDateFormat, startDate, fbdata);
}
} finally {
getMethod.releaseConnection();
String fbdata = getFreeBusyData(attendee, exchangeZuluDateFormat.format(startDate), exchangeZuluDateFormat.format(endDate), FREE_BUSY_INTERVAL);
if (fbdata != null) {
freeBusy = new FreeBusy(icalDateFormat, startDate, fbdata);
}
if (freeBusy != null && freeBusy.knownAttendee) {

View File

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

View File

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

View File

@ -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();

View File

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

View File

@ -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);
}
writer.write("\"/>");
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('>');
}
}
}

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

View File

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

View File

@ -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();
@ -90,5 +91,34 @@ public class TestExchangeSessionCalendar extends AbstractDavMailTestCase {
System.out.println(event.getBody());
}
}
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);
}
}

View File

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