mirror of
https://github.com/moparisthebest/davmail
synced 2025-01-13 06:28:19 -05:00
Caldav: experimental principal switch (access another user calendar) - untested
git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@475 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
parent
cc61a50a39
commit
0889191527
@ -154,7 +154,7 @@ public class CaldavConnection extends AbstractConnection {
|
||||
DavGatewayTray.error(e);
|
||||
}
|
||||
try {
|
||||
sendErr(HttpStatus.SC_SERVICE_UNAVAILABLE, e);
|
||||
sendErr(e);
|
||||
} catch (IOException e2) {
|
||||
DavGatewayTray.debug("Exception sending error to client", e2);
|
||||
}
|
||||
@ -220,7 +220,7 @@ public class CaldavConnection extends AbstractConnection {
|
||||
} else if ("PROPFIND".equals(command) && "users".equals(paths[1]) && paths.length == 4 && "inbox".equals(paths[3])) {
|
||||
sendInbox(request, depth, paths[2]);
|
||||
} else if ("REPORT".equals(command) && "users".equals(paths[1]) && paths.length == 4 && "inbox".equals(paths[3])) {
|
||||
reportEvents(request, "INBOX");
|
||||
reportEvents(request, paths[2], "INBOX");
|
||||
} else if ("PROPFIND".equals(command) && "users".equals(paths[1]) && paths.length == 4 && "outbox".equals(paths[3])) {
|
||||
sendOutbox(request, paths[2]);
|
||||
} else if ("POST".equals(command) && "users".equals(paths[1]) && paths.length == 4 && "outbox".equals(paths[3])) {
|
||||
@ -228,43 +228,37 @@ public class CaldavConnection extends AbstractConnection {
|
||||
sendFreeBusy(body);
|
||||
} else {
|
||||
int status = session.sendEvent(body);
|
||||
sendHttpResponse(status, true);
|
||||
sendHttpResponse(status);
|
||||
}
|
||||
} else if ("PROPFIND".equals(command) && "users".equals(paths[1]) && paths.length == 4 && "calendar".equals(paths[3])) {
|
||||
sendCalendar(request, depth, paths[2]);
|
||||
} else if ("PROPPATCH".equals(command) && "users".equals(paths[1]) && paths.length == 4 && "calendar".equals(paths[3])) {
|
||||
patchCalendar(request, depth, paths[2]);
|
||||
} else if ("REPORT".equals(command) && "users".equals(paths[1]) && paths.length == 4 && "calendar".equals(paths[3])
|
||||
// only current user for now
|
||||
&& session.getEmail().equalsIgnoreCase(paths[2])) {
|
||||
reportEvents(request, "calendar");
|
||||
patchCalendar();
|
||||
} else if ("REPORT".equals(command) && "users".equals(paths[1]) && paths.length == 4 && "calendar".equals(paths[3])) {
|
||||
reportEvents(request, paths[2], "calendar");
|
||||
|
||||
} else if ("PUT".equals(command) && "users".equals(paths[1]) && paths.length == 5 && "calendar".equals(paths[3])
|
||||
// only current user for now
|
||||
&& session.getEmail().equalsIgnoreCase(paths[2])) {
|
||||
} else if ("PUT".equals(command) && "users".equals(paths[1]) && paths.length == 5 && "calendar".equals(paths[3])) {
|
||||
String etag = headers.get("if-match");
|
||||
String noneMatch = headers.get("if-none-match");
|
||||
ExchangeSession.EventResult eventResult = session.createOrUpdateEvent(paths[4].replaceAll("&", "&"), body, etag, noneMatch);
|
||||
ExchangeSession.EventResult eventResult = session.createOrUpdateEvent(paths[2], paths[4].replaceAll("&", "&"), body, etag, noneMatch);
|
||||
if (eventResult.etag != null) {
|
||||
HashMap<String, String> responseHeaders = new HashMap<String, String>();
|
||||
responseHeaders.put("ETag", eventResult.etag);
|
||||
sendHttpResponse(eventResult.status, responseHeaders, null, "", true);
|
||||
} else {
|
||||
sendHttpResponse(eventResult.status, true);
|
||||
sendHttpResponse(eventResult.status);
|
||||
}
|
||||
|
||||
} else if ("DELETE".equals(command) && "users".equals(paths[1]) && paths.length == 5
|
||||
// only current user for now
|
||||
&& session.getEmail().equalsIgnoreCase(paths[2])) {
|
||||
} else if ("DELETE".equals(command) && "users".equals(paths[1]) && paths.length == 5) {
|
||||
if ("inbox".equals(paths[3])) {
|
||||
paths[3] = "INBOX";
|
||||
}
|
||||
int status = session.deleteEvent(paths[3], paths[4].replaceAll("&", "&"));
|
||||
sendHttpResponse(status, true);
|
||||
int status = session.deleteEvent(paths[2], paths[3], paths[4].replaceAll("&", "&"));
|
||||
sendHttpResponse(status);
|
||||
} else if ("GET".equals(command) && "users".equals(paths[1]) && paths.length == 5 && "calendar".equals(paths[3])
|
||||
// only current user for now
|
||||
&& session.getEmail().equalsIgnoreCase(paths[2])) {
|
||||
ExchangeSession.Event event = session.getEvent(paths[3], paths[4]);
|
||||
ExchangeSession.Event event = session.getEvent(paths[2], paths[3], paths[4]);
|
||||
sendHttpResponse(HttpStatus.SC_OK, null, "text/calendar;charset=UTF-8", event.getICS(), true);
|
||||
|
||||
} else {
|
||||
@ -281,6 +275,7 @@ public class CaldavConnection extends AbstractConnection {
|
||||
int count = 0;
|
||||
for (ExchangeSession.Event event : events) {
|
||||
DavGatewayTray.debug("Retrieving event " + (++count) + "/" + size);
|
||||
DavGatewayTray.switchIcon();
|
||||
appendEventResponse(response, request, path, event);
|
||||
}
|
||||
}
|
||||
@ -391,7 +386,7 @@ public class CaldavConnection extends AbstractConnection {
|
||||
appendInbox(response, principal, request);
|
||||
if (depth == 1) {
|
||||
DavGatewayTray.debug("Searching calendar messages...");
|
||||
List<ExchangeSession.Event> events = session.getEventMessages();
|
||||
List<ExchangeSession.Event> events = session.getEventMessages(principal);
|
||||
DavGatewayTray.debug("Found " + events.size() + " calendar messages");
|
||||
appendEventsResponses(response, request, "inbox", events);
|
||||
}
|
||||
@ -413,7 +408,7 @@ public class CaldavConnection extends AbstractConnection {
|
||||
appendCalendar(response, principal, request);
|
||||
if (depth == 1) {
|
||||
DavGatewayTray.debug("Searching calendar events...");
|
||||
List<ExchangeSession.Event> events = session.getAllEvents();
|
||||
List<ExchangeSession.Event> events = session.getAllEvents(principal);
|
||||
DavGatewayTray.debug("Found " + events.size() + " calendar events");
|
||||
appendEventsResponses(response, request, "calendar", events);
|
||||
}
|
||||
@ -421,7 +416,7 @@ public class CaldavConnection extends AbstractConnection {
|
||||
response.close();
|
||||
}
|
||||
|
||||
public void patchCalendar(CaldavRequest request, int depth, String principal) throws IOException {
|
||||
public void patchCalendar() throws IOException {
|
||||
CaldavResponse response = new CaldavResponse(HttpStatus.SC_MULTI_STATUS);
|
||||
response.startMultistatus();
|
||||
// just ignore calendar folder proppatch (color not supported in Exchange)
|
||||
@ -438,7 +433,7 @@ public class CaldavConnection extends AbstractConnection {
|
||||
}
|
||||
}
|
||||
|
||||
public void reportEvents(CaldavRequest request, String path) throws IOException {
|
||||
public void reportEvents(CaldavRequest request, String principal, String path) throws IOException {
|
||||
List<ExchangeSession.Event> events;
|
||||
List<String> notFound = new ArrayList<String>();
|
||||
if (request.isMultiGet()) {
|
||||
@ -451,19 +446,19 @@ public class CaldavConnection extends AbstractConnection {
|
||||
String eventName = getEventFileNameFromPath(href);
|
||||
if (eventName == null) {
|
||||
notFound.add(href);
|
||||
} else if ("inbox".equals(eventName)) {
|
||||
} else if ("inbox".equals(eventName)|| "calendar".equals(eventName)) {
|
||||
// Sunbird: just ignore
|
||||
} else {
|
||||
events.add(session.getEvent(path, eventName));
|
||||
events.add(session.getEvent(principal, path, eventName));
|
||||
}
|
||||
} catch (HttpException e) {
|
||||
notFound.add(href);
|
||||
}
|
||||
}
|
||||
} else if ("INBOX".equals(path)) {
|
||||
events = session.getEventMessages();
|
||||
events = session.getEventMessages(principal);
|
||||
} else {
|
||||
events = session.getAllEvents();
|
||||
events = session.getAllEvents(principal);
|
||||
}
|
||||
|
||||
CaldavResponse response = new CaldavResponse(HttpStatus.SC_MULTI_STATUS);
|
||||
@ -529,11 +524,11 @@ public class CaldavConnection extends AbstractConnection {
|
||||
actualPrincipal = session.getEmail();
|
||||
}
|
||||
|
||||
if (!session.getEmail().equals(principal)) {
|
||||
String message = "Invalid principal path, try /principals/users/" + session.getEmail();
|
||||
DavGatewayTray.error(message);
|
||||
sendErr(HttpStatus.SC_NOT_FOUND, message);
|
||||
} else {
|
||||
//if (!session.getEmail().equals(principal)) {
|
||||
// String message = "Invalid principal path, try /principals/users/" + session.getEmail();
|
||||
// DavGatewayTray.error(message);
|
||||
// sendErr(HttpStatus.SC_NOT_FOUND, message);
|
||||
//} else {
|
||||
CaldavResponse response = new CaldavResponse(HttpStatus.SC_MULTI_STATUS);
|
||||
response.startMultistatus();
|
||||
response.startResponse("/principals/users/" + principal);
|
||||
@ -565,7 +560,7 @@ public class CaldavConnection extends AbstractConnection {
|
||||
response.endResponse();
|
||||
response.endMultistatus();
|
||||
response.close();
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
public void sendFreeBusy(String body) throws IOException {
|
||||
@ -647,15 +642,15 @@ public class CaldavConnection extends AbstractConnection {
|
||||
buffer.append(path);
|
||||
Map<String, String> responseHeaders = new HashMap<String, String>();
|
||||
responseHeaders.put("Location", buffer.toString());
|
||||
sendHttpResponse(HttpStatus.SC_MOVED_PERMANENTLY, responseHeaders, true);
|
||||
sendHttpResponse(HttpStatus.SC_MOVED_PERMANENTLY, responseHeaders);
|
||||
}
|
||||
|
||||
public void sendErr(int status, Exception e) throws IOException {
|
||||
public void sendErr(Exception e) throws IOException {
|
||||
String message = e.getMessage();
|
||||
if (message == null) {
|
||||
message = e.toString();
|
||||
}
|
||||
sendErr(status, message);
|
||||
sendErr(HttpStatus.SC_SERVICE_UNAVAILABLE, message);
|
||||
}
|
||||
|
||||
public void sendErr(int status, String message) throws IOException {
|
||||
@ -665,21 +660,21 @@ public class CaldavConnection extends AbstractConnection {
|
||||
public void sendOptions() throws IOException {
|
||||
HashMap<String, String> headers = new HashMap<String, String>();
|
||||
headers.put("Allow", "OPTIONS, GET, PROPFIND, PUT, POST");
|
||||
sendHttpResponse(HttpStatus.SC_OK, headers, true);
|
||||
sendHttpResponse(HttpStatus.SC_OK, headers);
|
||||
}
|
||||
|
||||
public void sendUnauthorized() throws IOException {
|
||||
HashMap<String, String> headers = new HashMap<String, String>();
|
||||
headers.put("WWW-Authenticate", "Basic realm=\"" + Settings.getProperty("davmail.url") + "\"");
|
||||
sendHttpResponse(HttpStatus.SC_UNAUTHORIZED, headers, true);
|
||||
sendHttpResponse(HttpStatus.SC_UNAUTHORIZED, headers);
|
||||
}
|
||||
|
||||
public void sendHttpResponse(int status, boolean keepAlive) throws IOException {
|
||||
sendHttpResponse(status, null, null, (byte[]) null, keepAlive);
|
||||
public void sendHttpResponse(int status) throws IOException {
|
||||
sendHttpResponse(status, null, null, (byte[]) null, true);
|
||||
}
|
||||
|
||||
public void sendHttpResponse(int status, Map<String, String> headers, boolean keepAlive) throws IOException {
|
||||
sendHttpResponse(status, headers, null, (byte[]) null, keepAlive);
|
||||
public void sendHttpResponse(int status, Map<String, String> headers) throws IOException {
|
||||
sendHttpResponse(status, headers, null, (byte[]) null, true);
|
||||
}
|
||||
|
||||
public void sendChunkedHttpResponse(int status) throws IOException {
|
||||
|
@ -109,10 +109,6 @@ public class ExchangeSession {
|
||||
|
||||
private boolean disableGalLookup = false;
|
||||
|
||||
ExchangeSessionFactory.PoolKey getPoolKey() {
|
||||
return poolKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an exchange session for the given URL.
|
||||
* The session is not actually established until a call to login()
|
||||
@ -1170,15 +1166,17 @@ public class ExchangeSession {
|
||||
}
|
||||
}
|
||||
|
||||
public List<Event> getEventMessages() throws IOException {
|
||||
public List<Event> getEventMessages(String principal) throws IOException {
|
||||
String folderUrl = replacePrincipal(inboxUrl, principal);
|
||||
String searchQuery = "Select \"DAV:getetag\"" +
|
||||
" FROM Scope('SHALLOW TRAVERSAL OF \"" + inboxUrl + "\"')\n" +
|
||||
" FROM Scope('SHALLOW TRAVERSAL OF \"" + folderUrl + "\"')\n" +
|
||||
" WHERE \"DAV:contentclass\" = 'urn:content-classes:calendarmessage'\n" +
|
||||
" ORDER BY \"urn:schemas:calendar:dtstart\" DESC\n";
|
||||
return getEvents(inboxUrl, searchQuery);
|
||||
return getEvents(folderUrl, searchQuery);
|
||||
}
|
||||
|
||||
public List<Event> getAllEvents() throws IOException {
|
||||
public List<Event> getAllEvents(String principal) throws IOException {
|
||||
String folderUrl = replacePrincipal(calendarUrl, principal);
|
||||
int caldavPastDelay = Settings.getIntProperty("davmail.caldavPastDelay", Integer.MAX_VALUE);
|
||||
String dateCondition = "";
|
||||
if (caldavPastDelay != Integer.MAX_VALUE) {
|
||||
@ -1188,7 +1186,7 @@ public class ExchangeSession {
|
||||
}
|
||||
|
||||
String searchQuery = "Select \"DAV:getetag\"" +
|
||||
" FROM Scope('SHALLOW TRAVERSAL OF \"" + calendarUrl + "\"')\n" +
|
||||
" FROM Scope('SHALLOW TRAVERSAL OF \"" + folderUrl + "\"')\n" +
|
||||
" WHERE (" +
|
||||
" \"urn:schemas:calendar:instancetype\" is null OR" +
|
||||
" \"urn:schemas:calendar:instancetype\" = 1\n" +
|
||||
@ -1196,7 +1194,7 @@ public class ExchangeSession {
|
||||
dateCondition +
|
||||
" )) AND \"DAV:contentclass\" = 'urn:content-classes:appointment'\n" +
|
||||
" ORDER BY \"urn:schemas:calendar:dtstart\" DESC\n";
|
||||
return getEvents(calendarUrl, searchQuery);
|
||||
return getEvents(folderUrl, searchQuery);
|
||||
}
|
||||
|
||||
public List<Event> getEvents(String path, String searchQuery) throws IOException {
|
||||
@ -1208,8 +1206,8 @@ public class ExchangeSession {
|
||||
return events;
|
||||
}
|
||||
|
||||
public Event getEvent(String path, String eventName) throws IOException {
|
||||
String eventPath = URIUtil.encodePath(getFolderPath(path)) + "/" + URIUtil.encodeWithinQuery(eventName);
|
||||
public Event getEvent(String principal, String path, String eventName) throws IOException {
|
||||
String eventPath = URIUtil.encodePath(replacePrincipal(getFolderPath(path), principal)) + "/" + URIUtil.encodeWithinQuery(eventName);
|
||||
LOGGER.debug("getEvent(" + eventPath + "/" + eventName + ")");
|
||||
Enumeration calendarEnum = DavGatewayHttpClientFacade.executePropFindMethod(httpClient, eventPath, 0, EVENT_REQUEST_PROPERTIES);
|
||||
if (!calendarEnum.hasMoreElements()) {
|
||||
@ -1400,8 +1398,8 @@ public class ExchangeSession {
|
||||
}
|
||||
}
|
||||
|
||||
public EventResult createOrUpdateEvent(String path, String icsBody, String etag, String noneMatch) throws IOException {
|
||||
String messageUrl = URIUtil.encodePathQuery(calendarUrl + "/" + URIUtil.decode(path));
|
||||
public EventResult createOrUpdateEvent(String principal, String path, String icsBody, String etag, String noneMatch) throws IOException {
|
||||
String messageUrl = URIUtil.encodePathQuery(replacePrincipal(calendarUrl, principal) + "/" + URIUtil.decode(path));
|
||||
return internalCreateOrUpdateEvent(messageUrl, "urn:content-classes:appointment", icsBody, etag, noneMatch);
|
||||
}
|
||||
|
||||
@ -1567,18 +1565,15 @@ public class ExchangeSession {
|
||||
DavGatewayHttpClientFacade.executeDeleteMethod(httpClient, URIUtil.encodePath(getFolderPath(path)));
|
||||
}
|
||||
|
||||
public int deleteMessage(String path) throws IOException {
|
||||
return DavGatewayHttpClientFacade.executeDeleteMethod(httpClient, URIUtil.encodePath(path));
|
||||
}
|
||||
|
||||
public int deleteEvent(String path, String eventName) throws IOException {
|
||||
public int deleteEvent(String principal, String path, String eventName) throws IOException {
|
||||
int status;
|
||||
if (path.startsWith("INBOX")) {
|
||||
// do not delete calendar messages, move to trash
|
||||
moveToTrash(URIUtil.encodePath(getFolderPath(URIUtil.decode(path))), eventName);
|
||||
moveToTrash(URIUtil.encodePath(replacePrincipal(getFolderPath(URIUtil.decode(path)), principal)), eventName);
|
||||
status = HttpStatus.SC_OK;
|
||||
} else {
|
||||
status = DavGatewayHttpClientFacade.executeDeleteMethod(httpClient, URIUtil.encodePath(getFolderPath(URIUtil.decode(path))) + "/" + eventName);
|
||||
status = DavGatewayHttpClientFacade.executeDeleteMethod(httpClient,
|
||||
URIUtil.encodePath(replacePrincipal(getFolderPath(URIUtil.decode(path)), principal)) + "/" + eventName);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@ -1699,6 +1694,19 @@ public class ExchangeSession {
|
||||
return alias;
|
||||
}
|
||||
|
||||
public String replacePrincipal(String folderUrl, String principal) throws IOException {
|
||||
if (!alias.equals(principal) && !email.equals(principal)) {
|
||||
int index = mailPath.lastIndexOf("/", mailPath.length() - 2);
|
||||
if (index >= 0 && mailPath.endsWith("/")) {
|
||||
return mailPath.substring(0, index) + "/" + principal + "/" + folderUrl.substring(inboxUrl.lastIndexOf("/"));
|
||||
} else {
|
||||
throw new IOException("Invalid mail path: " + mailPath);
|
||||
}
|
||||
} else {
|
||||
return folderUrl;
|
||||
}
|
||||
}
|
||||
|
||||
public String getEmail(String alias) throws IOException {
|
||||
String emailResult = null;
|
||||
if (alias != null) {
|
||||
@ -1921,7 +1929,7 @@ public class ExchangeSession {
|
||||
* Free time returns 0, Tentative returns 1, Busy returns 2, and Out of Office (OOF) returns 3
|
||||
*/
|
||||
public static final class FreeBusy {
|
||||
SimpleDateFormat icalParser;
|
||||
final SimpleDateFormat icalParser;
|
||||
boolean knownAttendee = true;
|
||||
static final HashMap<Character, String> FBTYPES = new HashMap<Character, String>();
|
||||
|
||||
@ -1931,7 +1939,7 @@ public class ExchangeSession {
|
||||
FBTYPES.put('3', "BUSY-UNAVAILABLE");
|
||||
}
|
||||
|
||||
HashMap<String, StringBuilder> busyMap = new HashMap<String, StringBuilder>();
|
||||
final HashMap<String, StringBuilder> busyMap = new HashMap<String, StringBuilder>();
|
||||
|
||||
protected StringBuilder getBusyBuffer(char type) {
|
||||
String fbType = FBTYPES.get(Character.valueOf(type));
|
||||
|
Loading…
Reference in New Issue
Block a user