1
0
mirror of https://github.com/moparisthebest/davmail synced 2024-11-11 11:55:08 -05:00

Caldav: Implement basic Carddav search requests

git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@1035 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
mguessan 2010-05-06 19:26:44 +00:00
parent 4fbb040a35
commit 0faf2497db
3 changed files with 292 additions and 90 deletions

View File

@ -273,6 +273,10 @@ public class CaldavConnection extends AbstractConnection {
if (request.path.endsWith("/")) { if (request.path.endsWith("/")) {
// GET request on a folder => build ics content of all folder events // GET request on a folder => build ics content of all folder events
String folderPath = request.getExchangeFolderPath(); String folderPath = request.getExchangeFolderPath();
ExchangeSession.Folder folder = session.getFolder(folderPath);
if (folder.isContact()) {
sendHttpResponse(HttpStatus.SC_OK, buildEtagHeader(session.getFolderResourceTag(folderPath)), "text/vcard", (byte[])null, true);
} else {
List<ExchangeSession.Event> events = session.getAllEvents(folderPath); List<ExchangeSession.Event> events = session.getAllEvents(folderPath);
ChunkedResponse response = new ChunkedResponse(HttpStatus.SC_OK, "text/calendar;charset=UTF-8"); ChunkedResponse response = new ChunkedResponse(HttpStatus.SC_OK, "text/calendar;charset=UTF-8");
response.append("BEGIN:VCALENDAR\r\n"); response.append("BEGIN:VCALENDAR\r\n");
@ -281,12 +285,12 @@ public class CaldavConnection extends AbstractConnection {
response.append("METHOD:PUBLISH\r\n"); response.append("METHOD:PUBLISH\r\n");
for (ExchangeSession.Event event : events) { for (ExchangeSession.Event event : events) {
String icsContent = StringUtil.getToken(event.getICS(), "BEGIN:VTIMEZONE", "END:VCALENDAR"); String icsContent = StringUtil.getToken(event.getBody(), "BEGIN:VTIMEZONE", "END:VCALENDAR");
if (icsContent != null) { if (icsContent != null) {
response.append("BEGIN:VTIMEZONE"); response.append("BEGIN:VTIMEZONE");
response.append(icsContent); response.append(icsContent);
} else { } else {
icsContent = StringUtil.getToken(event.getICS(), "BEGIN:VEVENT", "END:VCALENDAR"); icsContent = StringUtil.getToken(event.getBody(), "BEGIN:VEVENT", "END:VCALENDAR");
if (icsContent != null) { if (icsContent != null) {
response.append("BEGIN:VEVENT"); response.append("BEGIN:VEVENT");
response.append(icsContent); response.append(icsContent);
@ -295,14 +299,15 @@ public class CaldavConnection extends AbstractConnection {
} }
response.append("END:VCALENDAR"); response.append("END:VCALENDAR");
response.close(); response.close();
}
} else { } else {
ExchangeSession.Event event = session.getEvent(request.getExchangeFolderPath(), lastPath); ExchangeSession.Item item = session.getItem(request.getExchangeFolderPath(), lastPath);
sendHttpResponse(HttpStatus.SC_OK, buildEtagHeader(event.getEtag()), "text/calendar;charset=UTF-8", event.getICS(), true); sendHttpResponse(HttpStatus.SC_OK, buildEtagHeader(item.getEtag()), item.getContentType(), item.getBody(), true);
} }
} else if (request.isHead()) { } else if (request.isHead()) {
// test event // test event
ExchangeSession.Event event = session.getEvent(request.getExchangeFolderPath(), lastPath); ExchangeSession.Item item = session.getItem(request.getExchangeFolderPath(), lastPath);
sendHttpResponse(HttpStatus.SC_OK, buildEtagHeader(event.getEtag()), "text/calendar;charset=UTF-8", (byte[]) null, true); sendHttpResponse(HttpStatus.SC_OK, buildEtagHeader(item.getEtag()), item.getContentType(), (byte[]) null, true);
} else { } else {
sendUnsupported(request); sendUnsupported(request);
} }
@ -319,40 +324,54 @@ public class CaldavConnection extends AbstractConnection {
} }
} }
private void appendContactsResponses(CaldavResponse response, CaldavRequest request, List<ExchangeSession.Contact> contacts) throws IOException {
int size = contacts.size();
int count = 0;
for (ExchangeSession.Contact contact : contacts) {
DavGatewayTray.debug(new BundleMessage("LOG_LISTING_CONTACT", ++count, size));
DavGatewayTray.switchIcon();
appendItemResponse(response, request, contact);
}
}
protected void appendEventsResponses(CaldavResponse response, CaldavRequest request, List<ExchangeSession.Event> events) throws IOException { protected void appendEventsResponses(CaldavResponse response, CaldavRequest request, List<ExchangeSession.Event> events) throws IOException {
int size = events.size(); int size = events.size();
int count = 0; int count = 0;
for (ExchangeSession.Event event : events) { for (ExchangeSession.Event event : events) {
DavGatewayTray.debug(new BundleMessage("LOG_LISTING_EVENT", ++count, size)); DavGatewayTray.debug(new BundleMessage("LOG_LISTING_EVENT", ++count, size));
DavGatewayTray.switchIcon(); DavGatewayTray.switchIcon();
appendEventResponse(response, request, event); appendItemResponse(response, request, event);
} }
} }
protected void appendEventResponse(CaldavResponse response, CaldavRequest request, ExchangeSession.Event event) throws IOException { protected void appendItemResponse(CaldavResponse response, CaldavRequest request, ExchangeSession.Item item) throws IOException {
StringBuilder eventPath = new StringBuilder(); StringBuilder eventPath = new StringBuilder();
eventPath.append(URIUtil.encodePath(request.getPath())); eventPath.append(URIUtil.encodePath(request.getPath()));
if (!(eventPath.charAt(eventPath.length() - 1) == '/')) { if (!(eventPath.charAt(eventPath.length() - 1) == '/')) {
eventPath.append('/'); eventPath.append('/');
} }
String eventName = StringUtil.xmlEncode(event.getName()); String itemName = StringUtil.xmlEncode(item.getName());
eventPath.append(URIUtil.encodeWithinQuery(eventName)); eventPath.append(URIUtil.encodeWithinQuery(itemName));
response.startResponse(eventPath.toString()); response.startResponse(eventPath.toString());
response.startPropstat(); response.startPropstat();
if (request.hasProperty("calendar-data")) { if (request.hasProperty("calendar-data") && item instanceof ExchangeSession.Event) {
response.appendCalendarData(event.getICS()); response.appendCalendarData(item.getBody());
} }
if (request.hasProperty("getcontenttype")) { if (request.hasProperty("getcontenttype")) {
response.appendProperty("D:getcontenttype", "text/calendar; component=vevent"); if (item instanceof ExchangeSession.Event) {
response.appendProperty("D:getcontenttype", "text/calendar; component=vevent");
} else if (item instanceof ExchangeSession.Contact) {
response.appendProperty("D:getcontenttype", "text/vcard");
}
} }
if (request.hasProperty("getetag")) { if (request.hasProperty("getetag")) {
response.appendProperty("D:getetag", event.getEtag()); response.appendProperty("D:getetag", item.getEtag());
} }
if (request.hasProperty("resourcetype")) { if (request.hasProperty("resourcetype")) {
response.appendProperty("D:resourcetype"); response.appendProperty("D:resourcetype");
} }
if (request.hasProperty("displayname")) { if (request.hasProperty("displayname")) {
response.appendProperty("D:displayname", eventName); response.appendProperty("D:displayname", itemName);
} }
response.endPropStatOK(); response.endPropStatOK();
response.endResponse(); response.endResponse();
@ -365,8 +384,9 @@ public class CaldavConnection extends AbstractConnection {
* @param request Caldav request * @param request Caldav request
* @param subFolder calendar folder path relative to request path * @param subFolder calendar folder path relative to request path
* @throws IOException on error * @throws IOException on error
* @return Exchange folder object
*/ */
public void appendFolder(CaldavResponse response, CaldavRequest request, String subFolder) throws IOException { public ExchangeSession.Folder appendFolder(CaldavResponse response, CaldavRequest request, String subFolder) throws IOException {
ExchangeSession.Folder folder = session.getFolder(request.getExchangeFolderPath(subFolder)); ExchangeSession.Folder folder = session.getFolder(request.getExchangeFolderPath(subFolder));
response.startResponse(URIUtil.encodePath(request.getPath(subFolder))); response.startResponse(URIUtil.encodePath(request.getPath(subFolder)));
@ -420,6 +440,7 @@ public class CaldavConnection extends AbstractConnection {
response.endPropStatOK(); response.endPropStatOK();
response.endResponse(); response.endResponse();
return folder;
} }
/** /**
@ -560,17 +581,21 @@ public class CaldavConnection extends AbstractConnection {
String folderPath = request.getExchangeFolderPath(); String folderPath = request.getExchangeFolderPath();
CaldavResponse response = new CaldavResponse(HttpStatus.SC_MULTI_STATUS); CaldavResponse response = new CaldavResponse(HttpStatus.SC_MULTI_STATUS);
response.startMultistatus(); response.startMultistatus();
appendFolder(response, request, null); ExchangeSession.Folder folder = appendFolder(response, request, null);
if (request.getDepth() == 1) { if (request.getDepth() == 1) {
DavGatewayTray.debug(new BundleMessage("LOG_SEARCHING_CALENDAR_EVENTS", folderPath)); if (folder.isContact()) {
List<ExchangeSession.Event> events = session.getAllEvents(folderPath); appendContactsResponses(response, request, session.getAllContacts(folderPath));
DavGatewayTray.debug(new BundleMessage("LOG_FOUND_CALENDAR_EVENTS", events.size())); } else {
appendEventsResponses(response, request, events); DavGatewayTray.debug(new BundleMessage("LOG_SEARCHING_CALENDAR_EVENTS", folderPath));
// Send sub folders for multi-calendar support under iCal, except for public folders List<ExchangeSession.Event> events = session.getAllEvents(folderPath);
if (!folderPath.startsWith("/public")) { DavGatewayTray.debug(new BundleMessage("LOG_FOUND_CALENDAR_EVENTS", events.size()));
List<ExchangeSession.Folder> folderList = session.getSubCalendarFolders(folderPath, false); appendEventsResponses(response, request, events);
for (ExchangeSession.Folder folder : folderList) { // Send sub folders for multi-calendar support under iCal, except for public folders
appendFolder(response, request, folder.folderPath.substring(folder.folderPath.indexOf('/') + 1)); if (!folderPath.startsWith("/public")) {
List<ExchangeSession.Folder> folderList = session.getSubCalendarFolders(folderPath, false);
for (ExchangeSession.Folder subFolder : folderList) {
appendFolder(response, request, subFolder.folderPath.substring(subFolder.folderPath.indexOf('/') + 1));
}
} }
} }
} }
@ -630,9 +655,9 @@ public class CaldavConnection extends AbstractConnection {
// ignore cases for Sunbird // ignore cases for Sunbird
if (eventName != null && eventName.length() > 0 if (eventName != null && eventName.length() > 0
&& !"inbox".equals(eventName) && !"calendar".equals(eventName)) { && !"inbox".equals(eventName) && !"calendar".equals(eventName)) {
ExchangeSession.Event event; ExchangeSession.Item item;
event = session.getEvent(folderPath, eventName); item = session.getItem(folderPath, eventName);
appendEventResponse(response, request, event); appendItemResponse(response, request, item);
} }
} catch (HttpException e) { } catch (HttpException e) {
DavGatewayTray.warn(new BundleMessage("LOG_EVENT_NOT_AVAILABLE", eventName, href)); DavGatewayTray.warn(new BundleMessage("LOG_EVENT_NOT_AVAILABLE", eventName, href));

View File

@ -106,12 +106,15 @@ public class ExchangeSession {
protected static final Namespace URN_SCHEMAS_HTTPMAIL = Namespace.getNamespace("urn:schemas:httpmail:"); 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/"); protected static final Namespace SCHEMAS_EXCHANGE = Namespace.getNamespace("http://schemas.microsoft.com/exchange/");
protected static final Namespace SCHEMAS_MAPI_PROPTAG = Namespace.getNamespace("http://schemas.microsoft.com/mapi/proptag/"); protected static final Namespace SCHEMAS_MAPI_PROPTAG = Namespace.getNamespace("http://schemas.microsoft.com/mapi/proptag/");
protected static final Namespace URN_SCHEMAS_CONTACTS = Namespace.getNamespace("urn:schemas:contacts:");
protected static final DavPropertyNameSet EVENT_REQUEST_PROPERTIES = new DavPropertyNameSet(); protected static final DavPropertyNameSet EVENT_REQUEST_PROPERTIES = new DavPropertyNameSet();
static { static {
EVENT_REQUEST_PROPERTIES.add(DavPropertyName.create("permanenturl", SCHEMAS_EXCHANGE)); EVENT_REQUEST_PROPERTIES.add(DavPropertyName.create("permanenturl", SCHEMAS_EXCHANGE));
EVENT_REQUEST_PROPERTIES.add(DavPropertyName.GETETAG); EVENT_REQUEST_PROPERTIES.add(DavPropertyName.GETETAG);
EVENT_REQUEST_PROPERTIES.add(DavPropertyName.create("contentclass", Namespace.getNamespace("DAV:")));
} }
protected static final DavPropertyNameSet WELL_KNOWN_FOLDERS = new DavPropertyNameSet(); protected static final DavPropertyNameSet WELL_KNOWN_FOLDERS = new DavPropertyNameSet();
@ -605,6 +608,15 @@ public class ExchangeSession {
} }
} }
protected String getPropertyIfExists(DavPropertySet properties, DavPropertyName davPropertyName, String defaultValue) {
String value = getPropertyIfExists(properties, davPropertyName);
if (value == null) {
return defaultValue;
} else {
return value;
}
}
protected String getPropertyIfExists(DavPropertySet properties, DavPropertyName davPropertyName) { protected String getPropertyIfExists(DavPropertySet properties, DavPropertyName davPropertyName) {
DavProperty property = properties.get(davPropertyName); DavProperty property = properties.get(davPropertyName);
if (property == null) { if (property == null) {
@ -1876,20 +1888,181 @@ public class ExchangeSession {
} }
/** /**
* Calendar event object * Generic folder item.
*/ */
public class Event { public abstract class Item {
protected String href; protected String href;
protected String permanentUrl; protected String permanentUrl;
protected String displayName; protected String displayName;
protected String etag; protected String etag;
protected String contentClass; protected String contentClass;
protected String noneMatch; protected String noneMatch;
/**
* Create empty Item.
*/
public Item() {
}
/**
* Return item content type
* @return content type
*/
public abstract String getContentType();
/**
* Retrieve item body from Exchange
* @return item body
* @throws HttpException on error
*/
public abstract String getBody() throws HttpException;
/**
* Build Item instance from multistatusResponse info
* @param multiStatusResponse response
* @throws URIException on error
*/
public Item(MultiStatusResponse multiStatusResponse) throws URIException {
href = URIUtil.decode(multiStatusResponse.getHref());
permanentUrl = getPropertyIfExists(multiStatusResponse.getProperties(HttpStatus.SC_OK), "permanenturl", SCHEMAS_EXCHANGE);
etag = getPropertyIfExists(multiStatusResponse.getProperties(HttpStatus.SC_OK), "getetag", Namespace.getNamespace("DAV:"));
displayName = getPropertyIfExists(multiStatusResponse.getProperties(HttpStatus.SC_OK), "displayname", Namespace.getNamespace("DAV:"));
}
/**
* Get event name (file name part in URL).
*
* @return event name
*/
public String getName() {
int index = href.lastIndexOf('/');
if (index >= 0) {
return href.substring(index + 1);
} else {
return href;
}
}
/**
* Get event etag (last change tag).
*
* @return event etag
*/
public String getEtag() {
return etag;
}
protected HttpException buildHttpException(Exception e) {
String message = "Unable to get event " + getName() + " at " + permanentUrl + ": " + e.getMessage();
LOGGER.warn(message);
return new HttpException(message);
}
}
/**
* Calendar event object
*/
public class Contact extends Item {
/**
* Build Contact instance from multistatusResponse info
* @param multiStatusResponse response
* @throws URIException on error
*/
public Contact(MultiStatusResponse multiStatusResponse) throws URIException {
super(multiStatusResponse);
}
@Override
public String getContentType() {
return "text/vcard";
}
@Override
public String getBody() throws HttpException {
// first retrieve contact details
String result = null;
PropFindMethod propFindMethod = null;
try {
propFindMethod = new PropFindMethod(URIUtil.encodePath(permanentUrl));
DavGatewayHttpClientFacade.executeHttpMethod(httpClient, propFindMethod);
MultiStatus responses = propFindMethod.getResponseBodyAsMultiStatus();
if (responses.getResponses().length > 0) {
DavPropertySet properties = responses.getResponses()[0].getProperties(HttpStatus.SC_OK);
ICSBufferedWriter writer = new ICSBufferedWriter();
writer.writeLine("BEGIN:VCARD");
writer.writeLine("VERSION:3.0");
writer.write("UID:");
writer.writeLine(URIUtil.encodePath(getName()));
writer.write("FN:");
writer.writeLine(getPropertyIfExists(properties, DavPropertyName.create("cn", URN_SCHEMAS_CONTACTS), ""));
// RFC 2426: Family Name, Given Name, Additional Names, Honorific Prefixes, and Honorific Suffixes
writer.write("N:");
writer.write(getPropertyIfExists(properties, DavPropertyName.create("sn", URN_SCHEMAS_CONTACTS), ""));
writer.write(";");
writer.write(getPropertyIfExists(properties, DavPropertyName.create("givenName", URN_SCHEMAS_CONTACTS), ""));
writer.write(";");
writer.writeLine(getPropertyIfExists(properties, DavPropertyName.create("middlename", URN_SCHEMAS_CONTACTS), ""));
writer.write("TEL;TYPE=cell:");
writer.writeLine(getPropertyIfExists(properties, DavPropertyName.create("mobile", URN_SCHEMAS_CONTACTS), ""));
//writer.writeLine(getPropertyIfExists(properties, DavPropertyName.create("initials", URN_SCHEMAS_CONTACTS), ""));
// The structured type value corresponds, in sequence, to the post office box; the extended address;
// the street address; the locality (e.g., city); the region (e.g., state or province);
// the postal code; the country name
// ADR;TYPE=dom,home,postal,parcel:;;123 Main Street;Any Town;CA;91921-1234
writer.write("ADR;TYPE=home:;;");
writer.write(getPropertyIfExists(properties, DavPropertyName.create("homepostaladdress", URN_SCHEMAS_CONTACTS), ""));
writer.write(";;;");
writer.newLine();
writer.writeLine("END:VCARD");
result = writer.toString();
}
} catch (DavException e) {
throw buildHttpException(e);
} catch (IOException e) {
throw buildHttpException(e);
} finally {
if (propFindMethod != null) {
propFindMethod.releaseConnection();
}
}
return result;
}
}
/**
* Calendar event object
*/
public class Event extends Item {
/** /**
* ICS content * ICS content
*/ */
protected String icsBody; protected String icsBody;
/**
* Build Event instance from multistatusResponse info
* @param multiStatusResponse response
* @throws URIException on error
*/
public Event(MultiStatusResponse multiStatusResponse) throws URIException {
super(multiStatusResponse);
}
/**
* Create empty event.
*/
public Event() {
}
@Override
public String getContentType() {
return "text/calendar;charset=UTF-8";
}
protected boolean isCalendarContentType(String contentType) { protected boolean isCalendarContentType(String contentType) {
return contentType.startsWith("text/calendar") || contentType.startsWith("application/ics"); return contentType.startsWith("text/calendar") || contentType.startsWith("application/ics");
} }
@ -1977,7 +2150,8 @@ public class ExchangeSession {
* @return ICS (iCalendar) event * @return ICS (iCalendar) event
* @throws HttpException on error * @throws HttpException on error
*/ */
public String getICS() throws HttpException { @Override
public String getBody() throws HttpException {
String result; String result;
LOGGER.debug("Get event: " + permanentUrl); LOGGER.debug("Get event: " + permanentUrl);
// try to get PR_INTERNET_CONTENT // try to get PR_INTERNET_CONTENT
@ -2004,35 +2178,6 @@ public class ExchangeSession {
return result; return result;
} }
protected HttpException buildHttpException(Exception e) {
String message = "Unable to get event " + getName() + " at " + permanentUrl + ": " + e.getMessage();
LOGGER.warn(message);
return new HttpException(message);
}
/**
* Get event name (file name part in URL).
*
* @return event name
*/
public String getName() {
int index = href.lastIndexOf('/');
if (index >= 0) {
return href.substring(index + 1);
} else {
return href;
}
}
/**
* Get event etag (last change tag).
*
* @return event etag
*/
public String getEtag() {
return etag;
}
protected String fixTimezoneId(String line, String validTimezoneId) { protected String fixTimezoneId(String line, String validTimezoneId) {
return StringUtil.replaceToken(line, "TZID=", ":", validTimezoneId); return StringUtil.replaceToken(line, "TZID=", ":", validTimezoneId);
} }
@ -2630,8 +2775,8 @@ public class ExchangeSession {
LOGGER.warn("Unable to patch event to trigger activeSync push"); LOGGER.warn("Unable to patch event to trigger activeSync push");
} else { } else {
// need to retrieve new etag // need to retrieve new etag
Event newEvent = getEvent(href); Item newItem = getItem(href);
eventResult.etag = newEvent.etag; eventResult.etag = newItem.etag;
} }
} }
return eventResult; return eventResult;
@ -2639,6 +2784,38 @@ public class ExchangeSession {
} }
} }
/**
* Search contacts in provided folder.
*
* @param folderPath Exchange folder path
* @return list of contacts
* @throws IOException on error
*/
public List<Contact> getAllContacts(String folderPath) throws IOException {
String searchQuery = "Select \"DAV:getetag\", \"http://schemas.microsoft.com/exchange/permanenturl\", \"DAV:displayname\"" +
" FROM Scope('SHALLOW TRAVERSAL OF \"" + folderPath + "\"')\n" +
" WHERE \"DAV:contentclass\" = 'urn:content-classes:person'\n";
return getContacts(folderPath, searchQuery);
}
/**
* Search contacts in provided folder matching the search query.
*
* @param folderPath Exchange folder path
* @param searchQuery Exchange search query
* @return list of contacts
* @throws IOException on error
*/
protected List<Contact> getContacts(String folderPath, String searchQuery) throws IOException {
List<Contact> contacts = new ArrayList<Contact>();
MultiStatusResponse[] responses = DavGatewayHttpClientFacade.executeSearchMethod(httpClient, URIUtil.encodePath(folderPath), searchQuery);
for (MultiStatusResponse response : responses) {
contacts.add(new Contact(response));
}
return contacts;
}
/** /**
* Search calendar messages in provided folder. * Search calendar messages in provided folder.
* *
@ -2718,13 +2895,13 @@ public class ExchangeSession {
MultiStatusResponse[] responses = DavGatewayHttpClientFacade.executeSearchMethod(httpClient, URIUtil.encodePath(folderPath), searchQuery); MultiStatusResponse[] responses = DavGatewayHttpClientFacade.executeSearchMethod(httpClient, URIUtil.encodePath(folderPath), searchQuery);
for (MultiStatusResponse response : responses) { for (MultiStatusResponse response : responses) {
String instancetype = getPropertyIfExists(response.getProperties(HttpStatus.SC_OK), "instancetype", Namespace.getNamespace("urn:schemas:calendar:")); String instancetype = getPropertyIfExists(response.getProperties(HttpStatus.SC_OK), "instancetype", Namespace.getNamespace("urn:schemas:calendar:"));
Event event = buildEvent(response); Event event = new Event(response);
//noinspection VariableNotUsedInsideIf //noinspection VariableNotUsedInsideIf
if (instancetype == null) { if (instancetype == null) {
// check ics content // check ics content
try { try {
event.getICS(); event.getBody();
// getICS success => add event or task // getBody success => add event or task
events.add(event); events.add(event);
} catch (HttpException e) { } catch (HttpException e) {
// invalid event: exclude from list // invalid event: exclude from list
@ -2738,45 +2915,53 @@ public class ExchangeSession {
} }
/** /**
* Get event named eventName in folder * Get item named eventName in folder
* *
* @param folderPath Exchange folder path * @param folderPath Exchange folder path
* @param eventName event name * @param itemName event name
* @return event object * @return event object
* @throws IOException on error * @throws IOException on error
*/ */
public Event getEvent(String folderPath, String eventName) throws IOException { public Item getItem(String folderPath, String itemName) throws IOException {
String eventPath = folderPath + '/' + eventName; String itemPath = folderPath + '/' + itemName;
Event event; Item item;
try { try {
event = getEvent(eventPath); item = getItem(itemPath);
} catch (HttpNotFoundException hnfe) { } catch (HttpNotFoundException hnfe) {
// failover for Exchange 2007 plus encoding issue // failover for Exchange 2007 plus encoding issue
String decodedEventName = eventName.replaceAll("_xF8FF_", "/").replaceAll("_x003F_", "?").replaceAll("'", "''"); String decodedEventName = itemName.replaceAll("_xF8FF_", "/").replaceAll("_x003F_", "?").replaceAll("'", "''");
ExchangeSession.MessageList messages = searchMessages(folderPath, " AND \"DAV:displayname\"='" + decodedEventName + '\''); ExchangeSession.MessageList messages = searchMessages(folderPath, " AND \"DAV:displayname\"='" + decodedEventName + '\'');
if (!messages.isEmpty()) { if (!messages.isEmpty()) {
event = getEvent(messages.get(0).getPermanentUrl()); item = getItem(messages.get(0).getPermanentUrl());
} else { } else {
throw hnfe; throw hnfe;
} }
} }
return event; return item;
} }
/** /**
* Get event by url * Get item by url
* *
* @param eventPath Event path * @param itemPath Event path
* @return event object * @return event object
* @throws IOException on error * @throws IOException on error
*/ */
public Event getEvent(String eventPath) throws IOException { public Item getItem(String itemPath) throws IOException {
MultiStatusResponse[] responses = DavGatewayHttpClientFacade.executePropFindMethod(httpClient, URIUtil.encodePath(eventPath), 0, EVENT_REQUEST_PROPERTIES); MultiStatusResponse[] responses = DavGatewayHttpClientFacade.executePropFindMethod(httpClient, URIUtil.encodePath(itemPath), 0, EVENT_REQUEST_PROPERTIES);
if (responses.length == 0) { if (responses.length == 0) {
throw new DavMailException("EXCEPTION_EVENT_NOT_FOUND"); throw new DavMailException("EXCEPTION_EVENT_NOT_FOUND");
} }
return buildEvent(responses[0]); String contentClass = getPropertyIfExists( responses[0].getProperties(HttpStatus.SC_OK),
"contentclass", Namespace.getNamespace("DAV:"));
if ("urn:content-classes:person".equals(contentClass)) {
return new Contact(responses[0]);
} else if ("urn:content-classes:appointment".equals(contentClass)){
return new Event(responses[0]);
} else {
throw new DavMailException("EXCEPTION_EVENT_NOT_FOUND");
}
} }
/** /**
@ -2804,15 +2989,6 @@ public class ExchangeSession {
return status; return status;
} }
protected Event buildEvent(MultiStatusResponse calendarResponse) throws URIException {
Event event = new Event();
event.href = URIUtil.decode(calendarResponse.getHref());
event.permanentUrl = getPropertyIfExists(calendarResponse.getProperties(HttpStatus.SC_OK), "permanenturl", SCHEMAS_EXCHANGE);
event.etag = getPropertyIfExists(calendarResponse.getProperties(HttpStatus.SC_OK), "getetag", Namespace.getNamespace("DAV:"));
event.displayName = getPropertyIfExists(calendarResponse.getProperties(HttpStatus.SC_OK), "displayname", Namespace.getNamespace("DAV:"));
return event;
}
private static int dumpIndex; private static int dumpIndex;
/** /**

View File

@ -95,6 +95,7 @@ LOG_LDAP_UNSUPPORTED_FILTER_ATTRIBUTE=Unsupported filter attribute: {0}= {1}
LOG_LDAP_UNSUPPORTED_FILTER_VALUE=Unsupported filter value LOG_LDAP_UNSUPPORTED_FILTER_VALUE=Unsupported filter value
LOG_LDAP_UNSUPPORTED_OPERATION=Unsupported operation: {0} LOG_LDAP_UNSUPPORTED_OPERATION=Unsupported operation: {0}
LOG_LISTING_EVENT=Listing event {0}/{1} LOG_LISTING_EVENT=Listing event {0}/{1}
LOG_LISTING_CONTACT=Listing event {0}/{1}
LOG_MESSAGE={0} LOG_MESSAGE={0}
LOG_NEW_VERSION_AVAILABLE=A new version ({0}) of DavMail Gateway is available ! LOG_NEW_VERSION_AVAILABLE=A new version ({0}) of DavMail Gateway is available !
LOG_OPEN_LINK_NOT_SUPPORTED=Open link not supported (tried AWT Desktop and SWT Program) LOG_OPEN_LINK_NOT_SUPPORTED=Open link not supported (tried AWT Desktop and SWT Program)
@ -253,4 +254,4 @@ UI_USE_SYSTEM_PROXIES=Use system proxy settings :
UI_SHOW_STARTUP_BANNER=Display startup banner UI_SHOW_STARTUP_BANNER=Display startup banner
UI_SHOW_STARTUP_BANNER_HELP=Whether to show the initial startup notification window or not UI_SHOW_STARTUP_BANNER_HELP=Whether to show the initial startup notification window or not
UI_IMAP_IDLE_DELAY=IDLE folder monitor delay (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 UI_IMAP_IDLE_DELAY_HELP=IMAP folder idle monitor delay in minutes, leave empty to disable IDLE support