Loading app/src/main/java/at/bitfire/davdroid/resource/Event.java +2 −5 Original line number Diff line number Diff line Loading @@ -10,7 +10,6 @@ package at.bitfire.davdroid.resource; import android.text.format.Time; import android.util.Log; import net.fortuna.ical4j.data.CalendarBuilder; import net.fortuna.ical4j.data.CalendarOutputter; import net.fortuna.ical4j.data.ParserException; import net.fortuna.ical4j.model.Component; Loading Loading @@ -105,12 +104,11 @@ public class Event extends iCalendar { public void parseEntity(@NonNull InputStream entity, Charset charset, AssetDownloader downloader) throws IOException, InvalidResourceException { final net.fortuna.ical4j.model.Calendar ical; try { CalendarBuilder builder = new CalendarBuilder(); if (charset != null) { @Cleanup InputStreamReader reader = new InputStreamReader(entity, charset); ical = builder.build(reader); ical = calendarBuilder.build(reader); } else ical = builder.build(entity); ical = calendarBuilder.build(entity); if (ical == null) throw new InvalidResourceException("No iCalendar found"); Loading Loading @@ -354,5 +352,4 @@ public class Event extends iCalendar { } } } app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.java +55 −22 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import net.fortuna.ical4j.model.parameter.Cn; import net.fortuna.ical4j.model.parameter.CuType; import net.fortuna.ical4j.model.parameter.PartStat; import net.fortuna.ical4j.model.parameter.Role; import net.fortuna.ical4j.model.parameter.Rsvp; import net.fortuna.ical4j.model.property.Action; import net.fortuna.ical4j.model.property.Attendee; import net.fortuna.ical4j.model.property.Description; Loading Loading @@ -77,12 +78,11 @@ import lombok.Getter; public class LocalCalendar extends LocalCollection<Event> { private static final String TAG = "davdroid.LocalCalendar"; @Getter protected String url; @Getter protected long id; @Getter private String url; @Getter private long id; protected static final String COLLECTION_COLUMN_CTAG = Calendars.CAL_SYNC1; /* database fields */ @Override protected Uri entriesURI() { return syncAdapterURI(Events.CONTENT_URI); } Loading Loading @@ -425,12 +425,11 @@ public class LocalCalendar extends LocalCollection<Event> { // availability e.setOpaque(values.getAsInteger(Events.AVAILABILITY) != Events.AVAILABILITY_FREE); // set ORGANIZER only when there are attendees if (values.getAsInteger(Events.HAS_ATTENDEE_DATA) != 0 && values.containsKey(Events.ORGANIZER)) // set ORGANIZER try { e.setOrganizer(new Organizer(new URI("mailto", values.getAsString(Events.ORGANIZER), null))); } catch (URISyntaxException ex) { Log.e(TAG, "Error when creating ORGANIZER URI, ignoring", ex); Log.e(TAG, "Error when creating ORGANIZER mailto URI, ignoring", ex); } // classification Loading Loading @@ -463,8 +462,20 @@ public class LocalCalendar extends LocalCollection<Event> { void populateAttendee(Event event, ContentValues values) { try { Attendee attendee = new Attendee(new URI("mailto", values.getAsString(Attendees.ATTENDEE_EMAIL), null)); ParameterList params = attendee.getParameters(); final Attendee attendee; final String email = values.getAsString(Attendees.ATTENDEE_EMAIL), idNS = values.getAsString(Attendees.ATTENDEE_ID_NAMESPACE), id = values.getAsString(Attendees.ATTENDEE_IDENTITY); if (idNS != null || id != null) { // attendee identified by namespace and ID attendee = new Attendee(new URI(idNS, id, null)); if (email != null) attendee.getParameters().add(new iCalendar.Email(email)); } else // attendee identified by email address attendee = new Attendee(new URI("mailto", email, null)); final ParameterList params = attendee.getParameters(); String cn = values.getAsString(Attendees.ATTENDEE_NAME); if (cn != null) Loading @@ -478,12 +489,11 @@ public class LocalCalendar extends LocalCollection<Event> { int relationship = values.getAsInteger(Attendees.ATTENDEE_RELATIONSHIP); switch (relationship) { case Attendees.RELATIONSHIP_ORGANIZER: params.add(Role.CHAIR); break; case Attendees.RELATIONSHIP_ATTENDEE: case Attendees.RELATIONSHIP_PERFORMER: case Attendees.RELATIONSHIP_SPEAKER: params.add((type == Attendees.TYPE_REQUIRED) ? Role.REQ_PARTICIPANT : Role.OPT_PARTICIPANT); params.add(new Rsvp(true)); break; case Attendees.RELATIONSHIP_NONE: params.add(Role.NON_PARTICIPANT); Loading Loading @@ -591,10 +601,21 @@ public class LocalCalendar extends LocalCollection<Event> { if (event.getDescription() != null) builder.withValue(Events.DESCRIPTION, event.getDescription()); if (event.getOrganizer() != null && event.getOrganizer().getCalAddress() != null) { URI organizer = event.getOrganizer().getCalAddress(); if (organizer.getScheme() != null && organizer.getScheme().equalsIgnoreCase("mailto")) builder.withValue(Events.ORGANIZER, organizer.getSchemeSpecificPart()); Organizer organizer = event.getOrganizer(); if (organizer != null) { final URI uri = organizer.getCalAddress(); String email = null; if (uri != null && "mailto".equalsIgnoreCase(uri.getScheme())) email = uri.getSchemeSpecificPart(); else { iCalendar.Email emailParam = (iCalendar.Email)organizer.getParameter(iCalendar.Email.PARAMETER_NAME); if (emailParam != null) email = emailParam.getValue(); else Log.w(TAG, "Got ORGANIZER without email address, using given URI instead (may cause Android to behave unexpectedly)"); } builder.withValue(Events.ORGANIZER, email != null ? email : uri.toString()); } Status status = event.getStatus(); Loading Loading @@ -673,7 +694,18 @@ public class LocalCalendar extends LocalCollection<Event> { @SuppressLint("InlinedApi") protected Builder buildAttendee(Builder builder, Attendee attendee) { final Uri member = Uri.parse(attendee.getValue()); final String email = member.getSchemeSpecificPart(); if ("mailto".equalsIgnoreCase(member.getScheme())) // attendee identified by email builder = builder.withValue(Attendees.ATTENDEE_EMAIL, member.getSchemeSpecificPart()); else { // attendee identified by other URI builder = builder .withValue(Attendees.ATTENDEE_ID_NAMESPACE, member.getScheme()) .withValue(Attendees.ATTENDEE_IDENTITY, member.getSchemeSpecificPart()); iCalendar.Email email = (iCalendar.Email)attendee.getParameter(iCalendar.Email.PARAMETER_NAME); if (email != null) builder = builder.withValue(Attendees.ATTENDEE_EMAIL, email.getValue()); } final Cn cn = (Cn)attendee.getParameter(Parameter.CN); if (cn != null) Loading @@ -682,9 +714,11 @@ public class LocalCalendar extends LocalCollection<Event> { int type = Attendees.TYPE_NONE; CuType cutype = (CuType)attendee.getParameter(Parameter.CUTYPE); if (cutype == CuType.RESOURCE) if (cutype == CuType.RESOURCE || cutype == CuType.ROOM) // "attendee" is a (physical) resource type = Attendees.TYPE_RESOURCE; else { // attendee is not a (physical) resource Role role = (Role)attendee.getParameter(Parameter.ROLE); int relationship; if (role == Role.CHAIR) Loading @@ -711,7 +745,6 @@ public class LocalCalendar extends LocalCollection<Event> { status = Attendees.ATTENDEE_STATUS_TENTATIVE; return builder .withValue(Attendees.ATTENDEE_EMAIL, email) .withValue(Attendees.ATTENDEE_TYPE, type) .withValue(Attendees.ATTENDEE_STATUS, status); } Loading app/src/main/java/at/bitfire/davdroid/resource/Task.java +2 −4 Original line number Diff line number Diff line Loading @@ -10,7 +10,6 @@ package at.bitfire.davdroid.resource; import android.util.Log; import net.fortuna.ical4j.data.CalendarBuilder; import net.fortuna.ical4j.data.CalendarOutputter; import net.fortuna.ical4j.data.ParserException; import net.fortuna.ical4j.model.Component; Loading Loading @@ -84,12 +83,11 @@ public class Task extends iCalendar { public void parseEntity(InputStream entity, Charset charset, AssetDownloader downloader) throws IOException, InvalidResourceException { final net.fortuna.ical4j.model.Calendar ical; try { CalendarBuilder builder = new CalendarBuilder(); if (charset != null) { @Cleanup InputStreamReader reader = new InputStreamReader(entity, charset); ical = builder.build(reader); ical = calendarBuilder.build(reader); } else ical = builder.build(entity); ical = calendarBuilder.build(entity); if (ical == null) throw new InvalidResourceException("No iCalendar found"); Loading app/src/main/java/at/bitfire/davdroid/resource/iCalendar.java +47 −0 Original line number Diff line number Diff line Loading @@ -11,12 +11,19 @@ package at.bitfire.davdroid.resource; import android.util.Log; import net.fortuna.ical4j.data.CalendarBuilder; import net.fortuna.ical4j.data.CalendarParserFactory; import net.fortuna.ical4j.data.ParserException; import net.fortuna.ical4j.model.DateTime; import net.fortuna.ical4j.model.Parameter; import net.fortuna.ical4j.model.ParameterFactory; import net.fortuna.ical4j.model.ParameterFactoryImpl; import net.fortuna.ical4j.model.ParameterFactoryRegistry; import net.fortuna.ical4j.model.PropertyFactoryRegistry; import net.fortuna.ical4j.model.component.VTimeZone; import net.fortuna.ical4j.model.property.DateProperty; import net.fortuna.ical4j.util.CompatibilityHints; import net.fortuna.ical4j.util.SimpleHostInfo; import net.fortuna.ical4j.util.Strings; import net.fortuna.ical4j.util.UidGenerator; import org.apache.commons.codec.CharEncoding; Loading @@ -24,10 +31,12 @@ import org.apache.http.entity.ContentType; import java.io.IOException; import java.io.StringReader; import java.net.URISyntaxException; import java.util.TimeZone; import at.bitfire.davdroid.DateUtils; import at.bitfire.davdroid.syncadapter.DavSyncAdapter; import lombok.Getter; import lombok.NonNull; public abstract class iCalendar extends Resource { Loading Loading @@ -114,4 +123,42 @@ public abstract class iCalendar extends Resource { return null; } // ical4j helpers and extensions private static final ParameterFactoryRegistry parameterFactoryRegistry = new ParameterFactoryRegistry(); static { parameterFactoryRegistry.register(Email.PARAMETER_NAME, Email.FACTORY); } protected static final CalendarBuilder calendarBuilder = new CalendarBuilder( CalendarParserFactory.getInstance().createParser(), new PropertyFactoryRegistry(), parameterFactoryRegistry, DateUtils.tzRegistry); public static class Email extends Parameter { /* EMAIL property for ATTENDEE properties, as used by iCloud: ATTENDEE;EMAIL=bla@domain.tld;/path/to/principal */ public static final ParameterFactory FACTORY = new Factory(); public static final String PARAMETER_NAME = "EMAIL"; @Getter private String value; protected Email() { super(PARAMETER_NAME, ParameterFactoryImpl.getInstance()); } public Email(String aValue) { super(PARAMETER_NAME, ParameterFactoryImpl.getInstance()); value = Strings.unquote(aValue); } public static class Factory implements ParameterFactory { @Override public Parameter createParameter(String name, String value) throws URISyntaxException { return new Email(value); } } } } doc/rfc6638-scheduling-extensions-to-caldav.txt 0 → 100644 +4371 −0 File added.Preview size limit exceeded, changes collapsed. Show changes Loading
app/src/main/java/at/bitfire/davdroid/resource/Event.java +2 −5 Original line number Diff line number Diff line Loading @@ -10,7 +10,6 @@ package at.bitfire.davdroid.resource; import android.text.format.Time; import android.util.Log; import net.fortuna.ical4j.data.CalendarBuilder; import net.fortuna.ical4j.data.CalendarOutputter; import net.fortuna.ical4j.data.ParserException; import net.fortuna.ical4j.model.Component; Loading Loading @@ -105,12 +104,11 @@ public class Event extends iCalendar { public void parseEntity(@NonNull InputStream entity, Charset charset, AssetDownloader downloader) throws IOException, InvalidResourceException { final net.fortuna.ical4j.model.Calendar ical; try { CalendarBuilder builder = new CalendarBuilder(); if (charset != null) { @Cleanup InputStreamReader reader = new InputStreamReader(entity, charset); ical = builder.build(reader); ical = calendarBuilder.build(reader); } else ical = builder.build(entity); ical = calendarBuilder.build(entity); if (ical == null) throw new InvalidResourceException("No iCalendar found"); Loading Loading @@ -354,5 +352,4 @@ public class Event extends iCalendar { } } }
app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.java +55 −22 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import net.fortuna.ical4j.model.parameter.Cn; import net.fortuna.ical4j.model.parameter.CuType; import net.fortuna.ical4j.model.parameter.PartStat; import net.fortuna.ical4j.model.parameter.Role; import net.fortuna.ical4j.model.parameter.Rsvp; import net.fortuna.ical4j.model.property.Action; import net.fortuna.ical4j.model.property.Attendee; import net.fortuna.ical4j.model.property.Description; Loading Loading @@ -77,12 +78,11 @@ import lombok.Getter; public class LocalCalendar extends LocalCollection<Event> { private static final String TAG = "davdroid.LocalCalendar"; @Getter protected String url; @Getter protected long id; @Getter private String url; @Getter private long id; protected static final String COLLECTION_COLUMN_CTAG = Calendars.CAL_SYNC1; /* database fields */ @Override protected Uri entriesURI() { return syncAdapterURI(Events.CONTENT_URI); } Loading Loading @@ -425,12 +425,11 @@ public class LocalCalendar extends LocalCollection<Event> { // availability e.setOpaque(values.getAsInteger(Events.AVAILABILITY) != Events.AVAILABILITY_FREE); // set ORGANIZER only when there are attendees if (values.getAsInteger(Events.HAS_ATTENDEE_DATA) != 0 && values.containsKey(Events.ORGANIZER)) // set ORGANIZER try { e.setOrganizer(new Organizer(new URI("mailto", values.getAsString(Events.ORGANIZER), null))); } catch (URISyntaxException ex) { Log.e(TAG, "Error when creating ORGANIZER URI, ignoring", ex); Log.e(TAG, "Error when creating ORGANIZER mailto URI, ignoring", ex); } // classification Loading Loading @@ -463,8 +462,20 @@ public class LocalCalendar extends LocalCollection<Event> { void populateAttendee(Event event, ContentValues values) { try { Attendee attendee = new Attendee(new URI("mailto", values.getAsString(Attendees.ATTENDEE_EMAIL), null)); ParameterList params = attendee.getParameters(); final Attendee attendee; final String email = values.getAsString(Attendees.ATTENDEE_EMAIL), idNS = values.getAsString(Attendees.ATTENDEE_ID_NAMESPACE), id = values.getAsString(Attendees.ATTENDEE_IDENTITY); if (idNS != null || id != null) { // attendee identified by namespace and ID attendee = new Attendee(new URI(idNS, id, null)); if (email != null) attendee.getParameters().add(new iCalendar.Email(email)); } else // attendee identified by email address attendee = new Attendee(new URI("mailto", email, null)); final ParameterList params = attendee.getParameters(); String cn = values.getAsString(Attendees.ATTENDEE_NAME); if (cn != null) Loading @@ -478,12 +489,11 @@ public class LocalCalendar extends LocalCollection<Event> { int relationship = values.getAsInteger(Attendees.ATTENDEE_RELATIONSHIP); switch (relationship) { case Attendees.RELATIONSHIP_ORGANIZER: params.add(Role.CHAIR); break; case Attendees.RELATIONSHIP_ATTENDEE: case Attendees.RELATIONSHIP_PERFORMER: case Attendees.RELATIONSHIP_SPEAKER: params.add((type == Attendees.TYPE_REQUIRED) ? Role.REQ_PARTICIPANT : Role.OPT_PARTICIPANT); params.add(new Rsvp(true)); break; case Attendees.RELATIONSHIP_NONE: params.add(Role.NON_PARTICIPANT); Loading Loading @@ -591,10 +601,21 @@ public class LocalCalendar extends LocalCollection<Event> { if (event.getDescription() != null) builder.withValue(Events.DESCRIPTION, event.getDescription()); if (event.getOrganizer() != null && event.getOrganizer().getCalAddress() != null) { URI organizer = event.getOrganizer().getCalAddress(); if (organizer.getScheme() != null && organizer.getScheme().equalsIgnoreCase("mailto")) builder.withValue(Events.ORGANIZER, organizer.getSchemeSpecificPart()); Organizer organizer = event.getOrganizer(); if (organizer != null) { final URI uri = organizer.getCalAddress(); String email = null; if (uri != null && "mailto".equalsIgnoreCase(uri.getScheme())) email = uri.getSchemeSpecificPart(); else { iCalendar.Email emailParam = (iCalendar.Email)organizer.getParameter(iCalendar.Email.PARAMETER_NAME); if (emailParam != null) email = emailParam.getValue(); else Log.w(TAG, "Got ORGANIZER without email address, using given URI instead (may cause Android to behave unexpectedly)"); } builder.withValue(Events.ORGANIZER, email != null ? email : uri.toString()); } Status status = event.getStatus(); Loading Loading @@ -673,7 +694,18 @@ public class LocalCalendar extends LocalCollection<Event> { @SuppressLint("InlinedApi") protected Builder buildAttendee(Builder builder, Attendee attendee) { final Uri member = Uri.parse(attendee.getValue()); final String email = member.getSchemeSpecificPart(); if ("mailto".equalsIgnoreCase(member.getScheme())) // attendee identified by email builder = builder.withValue(Attendees.ATTENDEE_EMAIL, member.getSchemeSpecificPart()); else { // attendee identified by other URI builder = builder .withValue(Attendees.ATTENDEE_ID_NAMESPACE, member.getScheme()) .withValue(Attendees.ATTENDEE_IDENTITY, member.getSchemeSpecificPart()); iCalendar.Email email = (iCalendar.Email)attendee.getParameter(iCalendar.Email.PARAMETER_NAME); if (email != null) builder = builder.withValue(Attendees.ATTENDEE_EMAIL, email.getValue()); } final Cn cn = (Cn)attendee.getParameter(Parameter.CN); if (cn != null) Loading @@ -682,9 +714,11 @@ public class LocalCalendar extends LocalCollection<Event> { int type = Attendees.TYPE_NONE; CuType cutype = (CuType)attendee.getParameter(Parameter.CUTYPE); if (cutype == CuType.RESOURCE) if (cutype == CuType.RESOURCE || cutype == CuType.ROOM) // "attendee" is a (physical) resource type = Attendees.TYPE_RESOURCE; else { // attendee is not a (physical) resource Role role = (Role)attendee.getParameter(Parameter.ROLE); int relationship; if (role == Role.CHAIR) Loading @@ -711,7 +745,6 @@ public class LocalCalendar extends LocalCollection<Event> { status = Attendees.ATTENDEE_STATUS_TENTATIVE; return builder .withValue(Attendees.ATTENDEE_EMAIL, email) .withValue(Attendees.ATTENDEE_TYPE, type) .withValue(Attendees.ATTENDEE_STATUS, status); } Loading
app/src/main/java/at/bitfire/davdroid/resource/Task.java +2 −4 Original line number Diff line number Diff line Loading @@ -10,7 +10,6 @@ package at.bitfire.davdroid.resource; import android.util.Log; import net.fortuna.ical4j.data.CalendarBuilder; import net.fortuna.ical4j.data.CalendarOutputter; import net.fortuna.ical4j.data.ParserException; import net.fortuna.ical4j.model.Component; Loading Loading @@ -84,12 +83,11 @@ public class Task extends iCalendar { public void parseEntity(InputStream entity, Charset charset, AssetDownloader downloader) throws IOException, InvalidResourceException { final net.fortuna.ical4j.model.Calendar ical; try { CalendarBuilder builder = new CalendarBuilder(); if (charset != null) { @Cleanup InputStreamReader reader = new InputStreamReader(entity, charset); ical = builder.build(reader); ical = calendarBuilder.build(reader); } else ical = builder.build(entity); ical = calendarBuilder.build(entity); if (ical == null) throw new InvalidResourceException("No iCalendar found"); Loading
app/src/main/java/at/bitfire/davdroid/resource/iCalendar.java +47 −0 Original line number Diff line number Diff line Loading @@ -11,12 +11,19 @@ package at.bitfire.davdroid.resource; import android.util.Log; import net.fortuna.ical4j.data.CalendarBuilder; import net.fortuna.ical4j.data.CalendarParserFactory; import net.fortuna.ical4j.data.ParserException; import net.fortuna.ical4j.model.DateTime; import net.fortuna.ical4j.model.Parameter; import net.fortuna.ical4j.model.ParameterFactory; import net.fortuna.ical4j.model.ParameterFactoryImpl; import net.fortuna.ical4j.model.ParameterFactoryRegistry; import net.fortuna.ical4j.model.PropertyFactoryRegistry; import net.fortuna.ical4j.model.component.VTimeZone; import net.fortuna.ical4j.model.property.DateProperty; import net.fortuna.ical4j.util.CompatibilityHints; import net.fortuna.ical4j.util.SimpleHostInfo; import net.fortuna.ical4j.util.Strings; import net.fortuna.ical4j.util.UidGenerator; import org.apache.commons.codec.CharEncoding; Loading @@ -24,10 +31,12 @@ import org.apache.http.entity.ContentType; import java.io.IOException; import java.io.StringReader; import java.net.URISyntaxException; import java.util.TimeZone; import at.bitfire.davdroid.DateUtils; import at.bitfire.davdroid.syncadapter.DavSyncAdapter; import lombok.Getter; import lombok.NonNull; public abstract class iCalendar extends Resource { Loading Loading @@ -114,4 +123,42 @@ public abstract class iCalendar extends Resource { return null; } // ical4j helpers and extensions private static final ParameterFactoryRegistry parameterFactoryRegistry = new ParameterFactoryRegistry(); static { parameterFactoryRegistry.register(Email.PARAMETER_NAME, Email.FACTORY); } protected static final CalendarBuilder calendarBuilder = new CalendarBuilder( CalendarParserFactory.getInstance().createParser(), new PropertyFactoryRegistry(), parameterFactoryRegistry, DateUtils.tzRegistry); public static class Email extends Parameter { /* EMAIL property for ATTENDEE properties, as used by iCloud: ATTENDEE;EMAIL=bla@domain.tld;/path/to/principal */ public static final ParameterFactory FACTORY = new Factory(); public static final String PARAMETER_NAME = "EMAIL"; @Getter private String value; protected Email() { super(PARAMETER_NAME, ParameterFactoryImpl.getInstance()); } public Email(String aValue) { super(PARAMETER_NAME, ParameterFactoryImpl.getInstance()); value = Strings.unquote(aValue); } public static class Factory implements ParameterFactory { @Override public Parameter createParameter(String name, String value) throws URISyntaxException { return new Email(value); } } } }
doc/rfc6638-scheduling-extensions-to-caldav.txt 0 → 100644 +4371 −0 File added.Preview size limit exceeded, changes collapsed. Show changes