diff --git a/src/at/bitfire/davdroid/resource/Contact.java b/src/at/bitfire/davdroid/resource/Contact.java index 75b2b02d..48a6f815 100644 --- a/src/at/bitfire/davdroid/resource/Contact.java +++ b/src/at/bitfire/davdroid/resource/Contact.java @@ -247,4 +247,8 @@ public class Contact extends Resource { return null; } + + @Override + public void validate() throws ValidationException { + } } diff --git a/src/at/bitfire/davdroid/resource/Event.java b/src/at/bitfire/davdroid/resource/Event.java index d48c6d6d..c6179ef3 100644 --- a/src/at/bitfire/davdroid/resource/Event.java +++ b/src/at/bitfire/davdroid/resource/Event.java @@ -26,6 +26,7 @@ import net.fortuna.ical4j.model.DefaultTimeZoneRegistryFactory; import net.fortuna.ical4j.model.Property; import net.fortuna.ical4j.model.PropertyList; import net.fortuna.ical4j.model.TimeZoneRegistry; +import net.fortuna.ical4j.model.ValidationException; import net.fortuna.ical4j.model.component.VEvent; import net.fortuna.ical4j.model.parameter.Value; import net.fortuna.ical4j.model.property.Attendee; @@ -290,4 +291,11 @@ public class Event extends Resource { Log.i(TAG, "Assuming time zone " + localTZ + " for " + tzID); date.setTimeZone(tzRegistry.getTimeZone(localTZ)); } + + + @Override + public void validate() throws ValidationException { + if (dtStart == null) + throw new ValidationException("dtStart empty"); + } } diff --git a/src/at/bitfire/davdroid/resource/LocalCollection.java b/src/at/bitfire/davdroid/resource/LocalCollection.java index e181fe4e..47307e23 100644 --- a/src/at/bitfire/davdroid/resource/LocalCollection.java +++ b/src/at/bitfire/davdroid/resource/LocalCollection.java @@ -12,6 +12,8 @@ import java.util.LinkedList; import java.util.List; import java.util.UUID; +import net.fortuna.ical4j.model.ValidationException; + import org.apache.commons.lang.StringUtils; import android.accounts.Account; @@ -111,7 +113,9 @@ public abstract class LocalCollection { // create/update/delete - public void add(ResourceType resource) { + public void add(ResourceType resource) throws ValidationException { + resource.validate(); + int idx = pendingOperations.size(); pendingOperations.add( buildEntry(ContentProviderOperation.newInsert(entriesURI()), resource) @@ -121,8 +125,10 @@ public abstract class LocalCollection { addDataRows(resource, -1, idx); } - public void updateByRemoteName(ResourceType remoteResource) throws RemoteException { + public void updateByRemoteName(ResourceType remoteResource) throws RemoteException, ValidationException { ResourceType localResource = findByRemoteName(remoteResource.getName()); + + remoteResource.validate(); pendingOperations.add( buildEntry(ContentProviderOperation.newUpdate(ContentUris.withAppendedId(entriesURI(), localResource.getLocalID())), remoteResource) diff --git a/src/at/bitfire/davdroid/resource/Resource.java b/src/at/bitfire/davdroid/resource/Resource.java index f3265208..c1726161 100644 --- a/src/at/bitfire/davdroid/resource/Resource.java +++ b/src/at/bitfire/davdroid/resource/Resource.java @@ -38,4 +38,6 @@ public abstract class Resource { public abstract void parseEntity(InputStream entity) throws IOException, ParserException; public abstract String toEntity() throws IOException, ValidationException; + + public abstract void validate() throws ValidationException; } diff --git a/src/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.java b/src/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.java index 44886586..fa477e38 100644 --- a/src/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.java +++ b/src/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.java @@ -93,13 +93,13 @@ public class CalendarsSyncAdapterService extends Service { Log.e(TAG, e.getLocalizedMessage()); } catch (IOException e) { syncResult.stats.numIoExceptions++; - Log.e(TAG, e.getLocalizedMessage()); + Log.e(TAG, e.toString()); } catch (IncapableResourceException e) { syncResult.stats.numParseExceptions++; - Log.e(TAG, e.getLocalizedMessage()); + Log.e(TAG, e.toString()); } catch (URISyntaxException e) { syncResult.stats.numParseExceptions++; - Log.e(TAG, e.getLocalizedMessage()); + Log.e(TAG, e.toString()); } } } diff --git a/src/at/bitfire/davdroid/syncadapter/SelectCollectionsAdapter.java b/src/at/bitfire/davdroid/syncadapter/SelectCollectionsAdapter.java index 26162a7d..ef110785 100644 --- a/src/at/bitfire/davdroid/syncadapter/SelectCollectionsAdapter.java +++ b/src/at/bitfire/davdroid/syncadapter/SelectCollectionsAdapter.java @@ -29,8 +29,8 @@ public class SelectCollectionsAdapter extends BaseAdapter implements ListAdapter public SelectCollectionsAdapter(ServerInfo serverInfo) { this.serverInfo = serverInfo; - nAddressBooks = serverInfo.getAddressBooks().size(); - nCalendars = serverInfo.getCalendars().size(); + nAddressBooks = (serverInfo.getAddressBooks() == null) ? 0 : serverInfo.getAddressBooks().size(); + nCalendars = (serverInfo.getCalendars() == null) ? 0 : serverInfo.getCalendars().size(); } diff --git a/src/at/bitfire/davdroid/syncadapter/SyncManager.java b/src/at/bitfire/davdroid/syncadapter/SyncManager.java index aaf55d3d..8b72a21c 100644 --- a/src/at/bitfire/davdroid/syncadapter/SyncManager.java +++ b/src/at/bitfire/davdroid/syncadapter/SyncManager.java @@ -137,7 +137,11 @@ public class SyncManager { if (!resourcesToAdd.isEmpty()) for (Resource res : dav.multiGet(resourcesToAdd.toArray(new Resource[0]))) { Log.i(TAG, "Adding " + res.getName()); - local.add(res); + try { + local.add(res); + } catch (ValidationException e) { + Log.e(TAG, "Invalid resource: " + res.getName()); + } syncResult.stats.numInserts++; } local.commit(); @@ -145,7 +149,11 @@ public class SyncManager { Log.i(TAG, "Updating " + resourcesToUpdate.size() + " remote resource(s)"); if (!resourcesToUpdate.isEmpty()) for (Resource res : dav.multiGet(resourcesToUpdate.toArray(new Resource[0]))) { - local.updateByRemoteName(res); + try { + local.updateByRemoteName(res); + } catch (ValidationException e) { + Log.e(TAG, "Invalid resource: " + res.getName()); + } Log.i(TAG, "Updating " + res.getName()); syncResult.stats.numInserts++; } diff --git a/src/at/bitfire/davdroid/webdav/DavCalendarMultiget.java b/src/at/bitfire/davdroid/webdav/DavCalendarMultiget.java index 518ffb47..cae3b76e 100644 --- a/src/at/bitfire/davdroid/webdav/DavCalendarMultiget.java +++ b/src/at/bitfire/davdroid/webdav/DavCalendarMultiget.java @@ -14,8 +14,8 @@ import org.simpleframework.xml.Root; @Root(name="calendar-multiget") @NamespaceList({ @Namespace(reference="DAV:"), - @Namespace(prefix="CD",reference="urn:ietf:params:xml:ns:caldav") + @Namespace(prefix="C",reference="urn:ietf:params:xml:ns:caldav") }) -@Namespace(prefix="CD",reference="urn:ietf:params:xml:ns:caldav") +@Namespace(prefix="C",reference="urn:ietf:params:xml:ns:caldav") public class DavCalendarMultiget extends DavMultiget { } diff --git a/src/at/bitfire/davdroid/webdav/DavProp.java b/src/at/bitfire/davdroid/webdav/DavProp.java index 8c02a45d..976543b1 100644 --- a/src/at/bitfire/davdroid/webdav/DavProp.java +++ b/src/at/bitfire/davdroid/webdav/DavProp.java @@ -47,6 +47,9 @@ public class DavProp { @Element(name="address-data",required=false) DavPropAddressData addressData; + @Element(name="calendar-data",required=false) + DavPropCalendarData calendarData; + public static class DavCurrentUserPrincipal { @Element(required=false) @@ -112,4 +115,10 @@ public class DavProp { @Text(required=false) @Getter String vcard; } + + @Namespace(prefix="C",reference="urn:ietf:params:xml:ns:caldav") + public static class DavPropCalendarData { + @Text(required=false) + @Getter String ical; + } } diff --git a/src/at/bitfire/davdroid/webdav/HttpPropfind.java b/src/at/bitfire/davdroid/webdav/HttpPropfind.java index 243d2f5d..5edb501a 100644 --- a/src/at/bitfire/davdroid/webdav/HttpPropfind.java +++ b/src/at/bitfire/davdroid/webdav/HttpPropfind.java @@ -73,7 +73,7 @@ public class HttpPropfind extends HttpEntityEnclosingRequestBase { setHeader("Depth", String.valueOf(depth)); setEntity(new StringEntity(writer.toString(), "UTF-8")); - Log.d(TAG, "Sending PROPFIND request: " + writer.toString()); + Log.d(TAG, "Prepared PROPFIND request: " + writer.toString()); } catch(Exception e) { Log.w(TAG, e.getMessage()); abort(); diff --git a/src/at/bitfire/davdroid/webdav/HttpReport.java b/src/at/bitfire/davdroid/webdav/HttpReport.java index 4b55fef9..52ef09a4 100644 --- a/src/at/bitfire/davdroid/webdav/HttpReport.java +++ b/src/at/bitfire/davdroid/webdav/HttpReport.java @@ -8,11 +8,14 @@ package at.bitfire.davdroid.webdav; +import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.net.URI; import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; import org.apache.http.entity.StringEntity; +import org.simpleframework.xml.Serializer; +import org.simpleframework.xml.core.Persister; import android.util.Log; @@ -26,6 +29,8 @@ public class HttpReport extends HttpEntityEnclosingRequestBase { try { setEntity(new StringEntity(entity, "UTF-8")); + + Log.d(TAG, "Prepared REPORT request: " + entity); } catch (UnsupportedEncodingException e) { Log.e(TAG, e.getMessage()); } diff --git a/src/at/bitfire/davdroid/webdav/WebDavCollection.java b/src/at/bitfire/davdroid/webdav/WebDavCollection.java index 1877a314..b3eb8cea 100644 --- a/src/at/bitfire/davdroid/webdav/WebDavCollection.java +++ b/src/at/bitfire/davdroid/webdav/WebDavCollection.java @@ -8,7 +8,9 @@ package at.bitfire.davdroid.webdav; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.StringWriter; import java.net.URI; import java.util.ArrayList; @@ -17,6 +19,7 @@ import java.util.List; import lombok.Getter; +import org.apache.commons.io.input.TeeInputStream; import org.apache.http.HttpException; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; @@ -65,9 +68,11 @@ public class WebDavCollection extends WebDavResource { DavMultistatus multistatus; try { Serializer serializer = new Persister(); - multistatus = serializer.read(DavMultistatus.class, response.getEntity().getContent()); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + InputStream is = new TeeInputStream(response.getEntity().getContent(), baos); + multistatus = serializer.read(DavMultistatus.class, is); - Log.d(TAG, "Got PROPFIND response: " + multistatus.toString()); + Log.d(TAG, "Received multistatus response: " + baos.toString("UTF-8")); } catch (Exception e) { Log.w(TAG, e); throw new IncapableResourceException(); @@ -80,15 +85,15 @@ public class WebDavCollection extends WebDavResource { } public boolean multiGet(String[] names, MultigetType type) throws IOException, IncapableResourceException, HttpException { - DavMultiget multiget; - if (type == MultigetType.ADDRESS_BOOK) - multiget = new DavAddressbookMultiget(); - else // MultigetType.CALENDAR - multiget = new DavCalendarMultiget(); + DavMultiget multiget = (type == MultigetType.ADDRESS_BOOK) ? new DavAddressbookMultiget() : new DavCalendarMultiget(); multiget.prop = new DavProp(); multiget.prop.getetag = new DavProp.DavPropGetETag(); - multiget.prop.addressData = new DavProp.DavPropAddressData(); + + if (type == MultigetType.ADDRESS_BOOK) + multiget.prop.addressData = new DavProp.DavPropAddressData(); + else if (type == MultigetType.CALENDAR) + multiget.prop.calendarData = new DavProp.DavPropCalendarData(); multiget.hrefs = new ArrayList(names.length); for (String name : names) @@ -110,7 +115,11 @@ public class WebDavCollection extends WebDavResource { if (response.getStatusLine().getStatusCode() == HttpStatus.SC_MULTI_STATUS) { DavMultistatus multistatus; try { - multistatus = serializer.read(DavMultistatus.class, response.getEntity().getContent()); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + InputStream is = new TeeInputStream(response.getEntity().getContent(), baos); + multistatus = serializer.read(DavMultistatus.class, is); + + Log.d(TAG, "Received multistatus response: " + baos.toString("UTF-8")); } catch (Exception e) { Log.e(TAG, e.getLocalizedMessage()); return false; @@ -208,8 +217,10 @@ public class WebDavCollection extends WebDavResource { if (prop.getetag != null) referenced.properties.put(Property.ETAG, prop.getetag.getETag()); - - if (prop.addressData != null) + + if (prop.calendarData != null) + referenced.content = new ByteArrayInputStream(prop.calendarData.ical.getBytes()); + else if (prop.addressData != null) referenced.content = new ByteArrayInputStream(prop.addressData.vcard.getBytes()); } } diff --git a/src/at/bitfire/davdroid/webdav/WebDavResource.java b/src/at/bitfire/davdroid/webdav/WebDavResource.java index e9e1682a..5f48d2d6 100644 --- a/src/at/bitfire/davdroid/webdav/WebDavResource.java +++ b/src/at/bitfire/davdroid/webdav/WebDavResource.java @@ -9,6 +9,8 @@ package at.bitfire.davdroid.webdav; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; +import java.io.StringWriter; import java.net.URI; import java.util.Arrays; import java.util.HashMap; @@ -18,6 +20,8 @@ import java.util.Set; import lombok.Getter; import lombok.ToString; +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.input.TeeInputStream; import org.apache.commons.lang.StringUtils; import org.apache.http.Header; import org.apache.http.HttpException; @@ -36,10 +40,12 @@ import org.apache.http.impl.EnglishReasonPhraseCatalog; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.CoreProtocolPNames; +import android.util.Log; + @ToString public class WebDavResource { - //private static final String TAG = "davdroid.WebDavResource"; + private static final String TAG = "davdroid.WebDavResource"; public enum Property { CURRENT_USER_PRINCIPAL, diff --git a/todo b/todo new file mode 100644 index 00000000..176a8a72 --- /dev/null +++ b/todo @@ -0,0 +1,7 @@ + +* Owncloud - calendars working, address book: no addressbook-nome-set from server +? SoGo +? Baikal +? Davical +? Apple +? Exchange-Müll