mirror of
https://github.com/etesync/android
synced 2024-11-26 01:48:34 +00:00
Resource detection with dav4android
* handle authentication (only Basic auth yet) * rewrite DavResourceFinder to use dav4android
This commit is contained in:
parent
0bc1a8178a
commit
bc2d1ba96d
@ -8,17 +8,12 @@
|
||||
|
||||
package at.bitfire.davdroid;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class DAVUtils {
|
||||
private static final String TAG = "davdroid.DAVutils";
|
||||
|
||||
public class DavUtils {
|
||||
public static final int calendarGreen = 0xFFC3EA6E;
|
||||
|
||||
|
||||
public static int CalDAVtoARGBColor(String davColor) {
|
||||
int color = calendarGreen; // fallback: "DAVdroid green"
|
||||
if (davColor != null) {
|
||||
@ -29,9 +24,8 @@ public class DAVUtils {
|
||||
int color_alpha = m.group(2) != null ? (Integer.parseInt(m.group(2), 16) & 0xFF) : 0xFF;
|
||||
color = (color_alpha << 24) | color_rgb;
|
||||
} else
|
||||
Log.w(TAG, "Couldn't parse color " + davColor + ", using DAVdroid green");
|
||||
Constants.log.warn("Couldn't parse color " + davColor + ", using DAVdroid green");
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
}
|
116
app/src/main/java/at/bitfire/davdroid/HttpClient.java
Normal file
116
app/src/main/java/at/bitfire/davdroid/HttpClient.java
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright © 2013 – 2015 Ricki Hirner (bitfire web engineering).
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the GNU Public License v3.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*/
|
||||
|
||||
package at.bitfire.davdroid;
|
||||
|
||||
import com.squareup.okhttp.Authenticator;
|
||||
import com.squareup.okhttp.Credentials;
|
||||
import com.squareup.okhttp.Interceptor;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
import com.squareup.okhttp.logging.HttpLoggingInterceptor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Proxy;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import at.bitfire.dav4android.HttpUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
public class HttpClient extends OkHttpClient {
|
||||
|
||||
protected static final String
|
||||
HEADER_AUTHORIZATION = "Authorization";
|
||||
|
||||
|
||||
public HttpClient() {
|
||||
super();
|
||||
initialize();
|
||||
enableLogs();
|
||||
}
|
||||
|
||||
public HttpClient(String username, String password, boolean preemptive) {
|
||||
super();
|
||||
initialize();
|
||||
|
||||
// authentication
|
||||
if (preemptive)
|
||||
networkInterceptors().add(new PreemptiveAuthenticationInterceptor(username, password));
|
||||
else
|
||||
setAuthenticator(new DavAuthenticator(username, password));
|
||||
|
||||
enableLogs();
|
||||
}
|
||||
|
||||
|
||||
protected void initialize() {
|
||||
// don't follow redirects automatically because this may rewrite DAV methods to GET
|
||||
setFollowRedirects(false);
|
||||
|
||||
// timeouts
|
||||
setConnectTimeout(20, TimeUnit.SECONDS);
|
||||
setWriteTimeout(15, TimeUnit.SECONDS);
|
||||
setReadTimeout(45, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
protected void enableLogs() {
|
||||
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
|
||||
@Override
|
||||
public void log(String message) {
|
||||
at.bitfire.dav4android.Constants.log.trace(message);
|
||||
}
|
||||
});
|
||||
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
|
||||
networkInterceptors().add(logging);
|
||||
}
|
||||
|
||||
|
||||
@RequiredArgsConstructor
|
||||
static class PreemptiveAuthenticationInterceptor implements Interceptor {
|
||||
final String username, password;
|
||||
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
Request request = chain.request();
|
||||
request = request.newBuilder()
|
||||
.header("Authorization", Credentials.basic(username, password))
|
||||
.build();
|
||||
return chain.proceed(request);
|
||||
}
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
static class DavAuthenticator implements Authenticator {
|
||||
final String username, password;
|
||||
|
||||
@Override
|
||||
public Request authenticate(Proxy proxy, Response response) throws IOException {
|
||||
// check whether this is the first authentication try with our credentials
|
||||
Response priorResponse = response.priorResponse();
|
||||
boolean triedBefore = priorResponse != null ? priorResponse.request().header(HEADER_AUTHORIZATION) != null : false;
|
||||
if (triedBefore)
|
||||
// credentials didn't work last time, and they won't work now → stop here
|
||||
return null;
|
||||
|
||||
//List<HttpUtils.AuthScheme> schemes = HttpUtils.parseWwwAuthenticate(response.headers("WWW-Authenticate"));
|
||||
// TODO Digest auth
|
||||
|
||||
return response.request().newBuilder()
|
||||
.header(HEADER_AUTHORIZATION, Credentials.basic(username, password))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request authenticateProxy(Proxy proxy, Response response) throws IOException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -27,7 +27,6 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import at.bitfire.dav4android.DavResource;
|
||||
import at.bitfire.dav4android.HttpClient;
|
||||
import at.bitfire.dav4android.exception.DavException;
|
||||
import at.bitfire.dav4android.exception.HttpException;
|
||||
import at.bitfire.dav4android.property.AddressbookDescription;
|
||||
@ -35,11 +34,15 @@ import at.bitfire.dav4android.property.AddressbookHomeSet;
|
||||
import at.bitfire.dav4android.property.CalendarColor;
|
||||
import at.bitfire.dav4android.property.CalendarDescription;
|
||||
import at.bitfire.dav4android.property.CalendarHomeSet;
|
||||
import at.bitfire.dav4android.property.CalendarTimezone;
|
||||
import at.bitfire.dav4android.property.CurrentUserPrincipal;
|
||||
import at.bitfire.dav4android.property.CurrentUserPrivilegeSet;
|
||||
import at.bitfire.dav4android.property.DisplayName;
|
||||
import at.bitfire.dav4android.property.ResourceType;
|
||||
import at.bitfire.dav4android.property.SupportedCalendarComponentSet;
|
||||
import at.bitfire.davdroid.Constants;
|
||||
import at.bitfire.davdroid.DAVUtils;
|
||||
import at.bitfire.davdroid.DavUtils;
|
||||
import at.bitfire.davdroid.HttpClient;
|
||||
|
||||
public class DavResourceFinder {
|
||||
private final static String TAG = "davdroid.ResourceFinder";
|
||||
@ -52,21 +55,7 @@ public class DavResourceFinder {
|
||||
}
|
||||
|
||||
public void findResources(final ServerInfo serverInfo) throws URISyntaxException, IOException, HttpException, DavException {
|
||||
final HttpClient httpClient = new HttpClient();
|
||||
/*httpClient.setAuthenticator(new Authenticator() {
|
||||
@Override
|
||||
public Request authenticate(Proxy proxy, Response response) throws IOException {
|
||||
String credential = Credentials.basic(serverInfo.getUserName(), serverInfo.getPassword());
|
||||
return response.request().newBuilder()
|
||||
.header("Authorization", credential)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request authenticateProxy(Proxy proxy, Response response) throws IOException {
|
||||
return null;
|
||||
}
|
||||
});*/
|
||||
final HttpClient httpClient = new HttpClient(serverInfo.getUserName(), serverInfo.getPassword(), serverInfo.authPreemptive);
|
||||
|
||||
// CardDAV
|
||||
Constants.log.info("*** CardDAV resource detection ***");
|
||||
@ -77,23 +66,26 @@ public class DavResourceFinder {
|
||||
AddressbookHomeSet addrHomeSet = (AddressbookHomeSet)principal.properties.get(AddressbookHomeSet.NAME);
|
||||
if (addrHomeSet != null && !addrHomeSet.hrefs.isEmpty()) {
|
||||
Constants.log.info("Found addressbook home set(s): " + addrHomeSet);
|
||||
serverInfo.setCardDAV(true);
|
||||
|
||||
// enumerate address books
|
||||
List<ServerInfo.ResourceInfo> addressBooks = new LinkedList<>();
|
||||
for (String href : addrHomeSet.hrefs) {
|
||||
DavResource homeSet = new DavResource(httpClient, principalUrl.resolve(href));
|
||||
homeSet.propfind(1, ResourceType.NAME, DisplayName.NAME, AddressbookDescription.NAME);
|
||||
homeSet.propfind(1, ResourceType.NAME, CurrentUserPrivilegeSet.NAME, DisplayName.NAME, AddressbookDescription.NAME);
|
||||
for (DavResource member : homeSet.members) {
|
||||
ResourceType type = (ResourceType)member.properties.get(ResourceType.NAME);
|
||||
if (type != null && type.types.contains(ResourceType.ADDRESSBOOK)) {
|
||||
Constants.log.info("Found address book: " + member.location);
|
||||
|
||||
CurrentUserPrivilegeSet privs = (CurrentUserPrivilegeSet)member.properties.get(CurrentUserPrivilegeSet.NAME);
|
||||
if (privs != null && (!privs.mayRead || !privs.mayWriteContent)) {
|
||||
Constants.log.info("Only read/write address books are supported, ignoring this one");
|
||||
continue;
|
||||
}
|
||||
|
||||
DisplayName displayName = (DisplayName)member.properties.get(DisplayName.NAME);
|
||||
AddressbookDescription description = (AddressbookDescription)member.properties.get(AddressbookDescription.NAME);
|
||||
|
||||
// TODO read-only
|
||||
|
||||
addressBooks.add(new ServerInfo.ResourceInfo(
|
||||
ServerInfo.ResourceInfo.Type.ADDRESS_BOOK,
|
||||
false,
|
||||
@ -117,13 +109,16 @@ public class DavResourceFinder {
|
||||
CalendarHomeSet calHomeSet = (CalendarHomeSet)principal.properties.get(CalendarHomeSet.NAME);
|
||||
if (calHomeSet != null && !calHomeSet.hrefs.isEmpty()) {
|
||||
Constants.log.info("Found calendar home set(s): " + calHomeSet);
|
||||
serverInfo.setCalDAV(true);
|
||||
|
||||
// enumerate address books
|
||||
List<ServerInfo.ResourceInfo> calendars = new LinkedList<>();
|
||||
List<ServerInfo.ResourceInfo>
|
||||
calendars = new LinkedList<>(),
|
||||
taskLists = new LinkedList<>();
|
||||
|
||||
for (String href : calHomeSet.hrefs) {
|
||||
DavResource homeSet = new DavResource(httpClient, principalUrl.resolve(href));
|
||||
homeSet.propfind(1, ResourceType.NAME, DisplayName.NAME, CalendarDescription.NAME, CalendarColor.NAME);
|
||||
homeSet.propfind(1, ResourceType.NAME, CurrentUserPrivilegeSet.NAME, DisplayName.NAME,
|
||||
CalendarDescription.NAME, CalendarColor.NAME, CalendarTimezone.NAME, SupportedCalendarComponentSet.NAME);
|
||||
for (DavResource member : homeSet.members) {
|
||||
ResourceType type = (ResourceType)member.properties.get(ResourceType.NAME);
|
||||
if (type != null && type.types.contains(ResourceType.CALENDAR)) {
|
||||
@ -133,20 +128,45 @@ public class DavResourceFinder {
|
||||
CalendarDescription description = (CalendarDescription)member.properties.get(CalendarDescription.NAME);
|
||||
CalendarColor color = (CalendarColor)member.properties.get(CalendarColor.NAME);
|
||||
|
||||
// TODO read-only, time-zone, supported components
|
||||
CurrentUserPrivilegeSet privs = (CurrentUserPrivilegeSet)member.properties.get(CurrentUserPrivilegeSet.NAME);
|
||||
boolean readOnly = false;
|
||||
if (privs != null) {
|
||||
if (!privs.mayRead) {
|
||||
Constants.log.info("Calendar not readable, ignoring this one");
|
||||
continue;
|
||||
}
|
||||
readOnly = !privs.mayWriteContent;
|
||||
}
|
||||
|
||||
calendars.add(new ServerInfo.ResourceInfo(
|
||||
ServerInfo.ResourceInfo collection = new ServerInfo.ResourceInfo(
|
||||
ServerInfo.ResourceInfo.Type.ADDRESS_BOOK,
|
||||
false,
|
||||
readOnly,
|
||||
member.location.toString(),
|
||||
displayName != null ? displayName.displayName : null,
|
||||
description != null ? description.description : null,
|
||||
color != null ? DAVUtils.CalDAVtoARGBColor(color.color) : null
|
||||
));
|
||||
color != null ? DavUtils.CalDAVtoARGBColor(color.color) : null
|
||||
);
|
||||
|
||||
CalendarTimezone tz = (CalendarTimezone)member.properties.get(CalendarTimezone.NAME);
|
||||
if (tz != null)
|
||||
collection.timezone = tz.vTimeZone;
|
||||
|
||||
boolean isCalendar = true, isTaskList = true;
|
||||
SupportedCalendarComponentSet comp = (SupportedCalendarComponentSet)member.properties.get(SupportedCalendarComponentSet.NAME);
|
||||
if (comp != null) {
|
||||
isCalendar = comp.supportsEvents;
|
||||
isTaskList = comp.supportsTasks;
|
||||
}
|
||||
|
||||
if (isCalendar)
|
||||
calendars.add(collection);
|
||||
if (isTaskList)
|
||||
taskLists.add(collection);
|
||||
}
|
||||
}
|
||||
}
|
||||
serverInfo.setCalendars(calendars);
|
||||
serverInfo.setTaskLists(taskLists);
|
||||
}
|
||||
|
||||
/*if (!serverInfo.isCalDAV() && !serverInfo.isCardDAV())
|
||||
|
@ -64,7 +64,7 @@ import java.text.SimpleDateFormat;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import at.bitfire.davdroid.DAVUtils;
|
||||
import at.bitfire.davdroid.DavUtils;
|
||||
import at.bitfire.davdroid.DateUtils;
|
||||
import at.bitfire.davdroid.webdav.WebDavResource;
|
||||
import lombok.Cleanup;
|
||||
@ -116,7 +116,7 @@ public class LocalCalendar extends LocalCollection<Event> {
|
||||
values.put(Calendars.ACCOUNT_TYPE, account.type);
|
||||
values.put(Calendars.NAME, info.getURL());
|
||||
values.put(Calendars.CALENDAR_DISPLAY_NAME, info.getTitle());
|
||||
values.put(Calendars.CALENDAR_COLOR, info.getColor() != null ? info.getColor() : DAVUtils.calendarGreen);
|
||||
values.put(Calendars.CALENDAR_COLOR, info.getColor() != null ? info.getColor() : DavUtils.calendarGreen);
|
||||
values.put(Calendars.OWNER_ACCOUNT, account.name);
|
||||
values.put(Calendars.SYNC_EVENTS, 1);
|
||||
values.put(Calendars.VISIBLE, 1);
|
||||
|
@ -37,7 +37,7 @@ import org.dmfs.provider.tasks.TaskContract;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import at.bitfire.davdroid.DAVUtils;
|
||||
import at.bitfire.davdroid.DavUtils;
|
||||
import at.bitfire.davdroid.DateUtils;
|
||||
import at.bitfire.davdroid.webdav.WebDavResource;
|
||||
import lombok.Cleanup;
|
||||
@ -75,7 +75,7 @@ public class LocalTaskList extends LocalCollection<Task> {
|
||||
values.put(TaskContract.TaskLists.ACCOUNT_TYPE, account.type);
|
||||
values.put(TaskContract.TaskLists._SYNC_ID, info.getURL());
|
||||
values.put(TaskContract.TaskLists.LIST_NAME, info.getTitle());
|
||||
values.put(TaskContract.TaskLists.LIST_COLOR, info.getColor() != null ? info.getColor() : DAVUtils.calendarGreen);
|
||||
values.put(TaskContract.TaskLists.LIST_COLOR, info.getColor() != null ? info.getColor() : DavUtils.calendarGreen);
|
||||
values.put(TaskContract.TaskLists.OWNER, account.name);
|
||||
values.put(TaskContract.TaskLists.ACCESS_LEVEL, 0);
|
||||
values.put(TaskContract.TaskLists.SYNC_ENABLED, 1);
|
||||
|
@ -25,11 +25,10 @@ public class ServerInfo implements Serializable {
|
||||
|
||||
private String errorMessage;
|
||||
|
||||
private boolean calDAV = false, cardDAV = false;
|
||||
private List<ResourceInfo>
|
||||
addressBooks = new LinkedList<>(),
|
||||
calendars = new LinkedList<>(),
|
||||
todoLists = new LinkedList<>();
|
||||
taskLists = new LinkedList<>();
|
||||
|
||||
|
||||
public boolean hasEnabledCalendars() {
|
||||
|
@ -101,7 +101,7 @@ public class AccountDetailsFragment extends Fragment implements TextWatcher {
|
||||
}
|
||||
});
|
||||
|
||||
addSync(account, LocalTaskList.TASKS_AUTHORITY, serverInfo.getTodoLists(), new AddSyncCallback() {
|
||||
addSync(account, LocalTaskList.TASKS_AUTHORITY, serverInfo.getTaskLists(), new AddSyncCallback() {
|
||||
@Override
|
||||
public void createLocalCollection(Account account, ServerInfo.ResourceInfo todoList) throws LocalStorageException {
|
||||
LocalTaskList.create(account, getActivity().getContentResolver(), todoList);
|
||||
|
@ -72,7 +72,7 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC
|
||||
((AddAccountActivity)getActivity()).serverInfo = serverInfo;
|
||||
|
||||
Fragment nextFragment;
|
||||
if (!serverInfo.getTodoLists().isEmpty() && !LocalTaskList.isAvailable(getActivity()))
|
||||
if (!serverInfo.getTaskLists().isEmpty() && !LocalTaskList.isAvailable(getActivity()))
|
||||
nextFragment = new InstallAppsFragment();
|
||||
else
|
||||
nextFragment = new SelectCollectionsFragment();
|
||||
|
@ -60,7 +60,7 @@ public class SelectCollectionsAdapter extends BaseAdapter implements ListAdapter
|
||||
nAddressBookHeadings = nAddressBooks == 0 ? 0 : 1;
|
||||
nCalendars = serverInfo.getCalendars().size();
|
||||
nCalendarHeadings = nCalendars == 0 ? 0 : 1;
|
||||
nTaskLists = serverInfo.getTodoLists().size();
|
||||
nTaskLists = serverInfo.getTaskLists().size();
|
||||
nTaskListHeadings = nTaskLists == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ public class SelectCollectionsAdapter extends BaseAdapter implements ListAdapter
|
||||
|
||||
else if (position >= (nAddressBookHeadings + nAddressBooks + nCalendarHeadings + nCalendars + nTaskListHeadings) &&
|
||||
(position < (nAddressBookHeadings + nAddressBooks + nCalendarHeadings + nCalendars + nTaskListHeadings + nTaskLists)))
|
||||
return serverInfo.getTodoLists().get(position - (nAddressBookHeadings + nAddressBooks + nCalendarHeadings + nCalendars + nTaskListHeadings));
|
||||
return serverInfo.getTaskLists().get(position - (nAddressBookHeadings + nAddressBooks + nCalendarHeadings + nCalendars + nTaskListHeadings));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ public class SelectCollectionsFragment extends ListFragment {
|
||||
addressBook.setEnabled(false);
|
||||
for (ServerInfo.ResourceInfo calendar : serverInfo.getCalendars())
|
||||
calendar.setEnabled(false);
|
||||
for (ServerInfo.ResourceInfo todoList : serverInfo.getTodoLists())
|
||||
for (ServerInfo.ResourceInfo todoList : serverInfo.getTaskLists())
|
||||
todoList.setEnabled(false);
|
||||
|
||||
ListAdapter adapter = getListView().getAdapter();
|
||||
|
@ -47,7 +47,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import at.bitfire.davdroid.DAVUtils;
|
||||
import at.bitfire.davdroid.DavUtils;
|
||||
import at.bitfire.davdroid.URIUtils;
|
||||
import at.bitfire.davdroid.resource.iCalendar;
|
||||
import at.bitfire.davdroid.webdav.DavProp.Comp;
|
||||
@ -547,7 +547,7 @@ public class WebDavResource {
|
||||
// getters / setters
|
||||
|
||||
public Integer getColor() {
|
||||
return color != null ? DAVUtils.CalDAVtoARGBColor(color) : null;
|
||||
return color != null ? DavUtils.CalDAVtoARGBColor(color) : null;
|
||||
}
|
||||
|
||||
public URI getCurrentUserPrincipal() throws URISyntaxException {
|
||||
|
@ -1 +1,2 @@
|
||||
lombok.addGeneratedAnnotation = false
|
||||
lombok.anyConstructor.suppressConstructorProperties = true
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit c8dffb7fa114a3ca46917ac18088cda981f0afd5
|
||||
Subproject commit 57e1f34c45f070ca9b269f2bea109f6b1cdcb385
|
Loading…
Reference in New Issue
Block a user