mirror of
https://github.com/etesync/android
synced 2025-02-16 17:42:03 +00:00
Improve ATTENDEE/ORGANIZER handling
This commit is contained in:
parent
072c763dec
commit
be80b6fde8
@ -10,7 +10,6 @@ package at.bitfire.davdroid.resource;
|
|||||||
import android.text.format.Time;
|
import android.text.format.Time;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import net.fortuna.ical4j.data.CalendarBuilder;
|
|
||||||
import net.fortuna.ical4j.data.CalendarOutputter;
|
import net.fortuna.ical4j.data.CalendarOutputter;
|
||||||
import net.fortuna.ical4j.data.ParserException;
|
import net.fortuna.ical4j.data.ParserException;
|
||||||
import net.fortuna.ical4j.model.Component;
|
import net.fortuna.ical4j.model.Component;
|
||||||
@ -105,12 +104,11 @@ public class Event extends iCalendar {
|
|||||||
public void parseEntity(@NonNull InputStream entity, Charset charset, AssetDownloader downloader) throws IOException, InvalidResourceException {
|
public void parseEntity(@NonNull InputStream entity, Charset charset, AssetDownloader downloader) throws IOException, InvalidResourceException {
|
||||||
final net.fortuna.ical4j.model.Calendar ical;
|
final net.fortuna.ical4j.model.Calendar ical;
|
||||||
try {
|
try {
|
||||||
CalendarBuilder builder = new CalendarBuilder();
|
|
||||||
if (charset != null) {
|
if (charset != null) {
|
||||||
@Cleanup InputStreamReader reader = new InputStreamReader(entity, charset);
|
@Cleanup InputStreamReader reader = new InputStreamReader(entity, charset);
|
||||||
ical = builder.build(reader);
|
ical = calendarBuilder.build(reader);
|
||||||
} else
|
} else
|
||||||
ical = builder.build(entity);
|
ical = calendarBuilder.build(entity);
|
||||||
|
|
||||||
if (ical == null)
|
if (ical == null)
|
||||||
throw new InvalidResourceException("No iCalendar found");
|
throw new InvalidResourceException("No iCalendar found");
|
||||||
@ -354,5 +352,4 @@ public class Event extends iCalendar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ import net.fortuna.ical4j.model.parameter.Cn;
|
|||||||
import net.fortuna.ical4j.model.parameter.CuType;
|
import net.fortuna.ical4j.model.parameter.CuType;
|
||||||
import net.fortuna.ical4j.model.parameter.PartStat;
|
import net.fortuna.ical4j.model.parameter.PartStat;
|
||||||
import net.fortuna.ical4j.model.parameter.Role;
|
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.Action;
|
||||||
import net.fortuna.ical4j.model.property.Attendee;
|
import net.fortuna.ical4j.model.property.Attendee;
|
||||||
import net.fortuna.ical4j.model.property.Description;
|
import net.fortuna.ical4j.model.property.Description;
|
||||||
@ -77,12 +78,11 @@ import lombok.Getter;
|
|||||||
public class LocalCalendar extends LocalCollection<Event> {
|
public class LocalCalendar extends LocalCollection<Event> {
|
||||||
private static final String TAG = "davdroid.LocalCalendar";
|
private static final String TAG = "davdroid.LocalCalendar";
|
||||||
|
|
||||||
@Getter protected String url;
|
@Getter private String url;
|
||||||
@Getter protected long id;
|
@Getter private long id;
|
||||||
|
|
||||||
protected static final String COLLECTION_COLUMN_CTAG = Calendars.CAL_SYNC1;
|
protected static final String COLLECTION_COLUMN_CTAG = Calendars.CAL_SYNC1;
|
||||||
|
|
||||||
|
|
||||||
/* database fields */
|
/* database fields */
|
||||||
|
|
||||||
@Override protected Uri entriesURI() { return syncAdapterURI(Events.CONTENT_URI); }
|
@Override protected Uri entriesURI() { return syncAdapterURI(Events.CONTENT_URI); }
|
||||||
@ -425,13 +425,12 @@ public class LocalCalendar extends LocalCollection<Event> {
|
|||||||
// availability
|
// availability
|
||||||
e.setOpaque(values.getAsInteger(Events.AVAILABILITY) != Events.AVAILABILITY_FREE);
|
e.setOpaque(values.getAsInteger(Events.AVAILABILITY) != Events.AVAILABILITY_FREE);
|
||||||
|
|
||||||
// set ORGANIZER only when there are attendees
|
// set ORGANIZER
|
||||||
if (values.getAsInteger(Events.HAS_ATTENDEE_DATA) != 0 && values.containsKey(Events.ORGANIZER))
|
try {
|
||||||
try {
|
e.setOrganizer(new Organizer(new URI("mailto", values.getAsString(Events.ORGANIZER), null)));
|
||||||
e.setOrganizer(new Organizer(new URI("mailto", values.getAsString(Events.ORGANIZER), null)));
|
} catch (URISyntaxException ex) {
|
||||||
} catch (URISyntaxException ex) {
|
Log.e(TAG, "Error when creating ORGANIZER mailto URI, ignoring", ex);
|
||||||
Log.e(TAG, "Error when creating ORGANIZER URI, ignoring", ex);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// classification
|
// classification
|
||||||
switch (values.getAsInteger(Events.ACCESS_LEVEL)) {
|
switch (values.getAsInteger(Events.ACCESS_LEVEL)) {
|
||||||
@ -463,8 +462,20 @@ public class LocalCalendar extends LocalCollection<Event> {
|
|||||||
|
|
||||||
void populateAttendee(Event event, ContentValues values) {
|
void populateAttendee(Event event, ContentValues values) {
|
||||||
try {
|
try {
|
||||||
Attendee attendee = new Attendee(new URI("mailto", values.getAsString(Attendees.ATTENDEE_EMAIL), null));
|
final Attendee attendee;
|
||||||
ParameterList params = attendee.getParameters();
|
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);
|
String cn = values.getAsString(Attendees.ATTENDEE_NAME);
|
||||||
if (cn != null)
|
if (cn != null)
|
||||||
@ -478,12 +489,11 @@ public class LocalCalendar extends LocalCollection<Event> {
|
|||||||
int relationship = values.getAsInteger(Attendees.ATTENDEE_RELATIONSHIP);
|
int relationship = values.getAsInteger(Attendees.ATTENDEE_RELATIONSHIP);
|
||||||
switch (relationship) {
|
switch (relationship) {
|
||||||
case Attendees.RELATIONSHIP_ORGANIZER:
|
case Attendees.RELATIONSHIP_ORGANIZER:
|
||||||
params.add(Role.CHAIR);
|
|
||||||
break;
|
|
||||||
case Attendees.RELATIONSHIP_ATTENDEE:
|
case Attendees.RELATIONSHIP_ATTENDEE:
|
||||||
case Attendees.RELATIONSHIP_PERFORMER:
|
case Attendees.RELATIONSHIP_PERFORMER:
|
||||||
case Attendees.RELATIONSHIP_SPEAKER:
|
case Attendees.RELATIONSHIP_SPEAKER:
|
||||||
params.add((type == Attendees.TYPE_REQUIRED) ? Role.REQ_PARTICIPANT : Role.OPT_PARTICIPANT);
|
params.add((type == Attendees.TYPE_REQUIRED) ? Role.REQ_PARTICIPANT : Role.OPT_PARTICIPANT);
|
||||||
|
params.add(new Rsvp(true));
|
||||||
break;
|
break;
|
||||||
case Attendees.RELATIONSHIP_NONE:
|
case Attendees.RELATIONSHIP_NONE:
|
||||||
params.add(Role.NON_PARTICIPANT);
|
params.add(Role.NON_PARTICIPANT);
|
||||||
@ -590,11 +600,22 @@ public class LocalCalendar extends LocalCollection<Event> {
|
|||||||
builder.withValue(Events.EVENT_LOCATION, event.getLocation());
|
builder.withValue(Events.EVENT_LOCATION, event.getLocation());
|
||||||
if (event.getDescription() != null)
|
if (event.getDescription() != null)
|
||||||
builder.withValue(Events.DESCRIPTION, event.getDescription());
|
builder.withValue(Events.DESCRIPTION, event.getDescription());
|
||||||
|
|
||||||
if (event.getOrganizer() != null && event.getOrganizer().getCalAddress() != null) {
|
Organizer organizer = event.getOrganizer();
|
||||||
URI organizer = event.getOrganizer().getCalAddress();
|
if (organizer != null) {
|
||||||
if (organizer.getScheme() != null && organizer.getScheme().equalsIgnoreCase("mailto"))
|
final URI uri = organizer.getCalAddress();
|
||||||
builder.withValue(Events.ORGANIZER, organizer.getSchemeSpecificPart());
|
|
||||||
|
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();
|
Status status = event.getStatus();
|
||||||
@ -673,7 +694,18 @@ public class LocalCalendar extends LocalCollection<Event> {
|
|||||||
@SuppressLint("InlinedApi")
|
@SuppressLint("InlinedApi")
|
||||||
protected Builder buildAttendee(Builder builder, Attendee attendee) {
|
protected Builder buildAttendee(Builder builder, Attendee attendee) {
|
||||||
final Uri member = Uri.parse(attendee.getValue());
|
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);
|
final Cn cn = (Cn)attendee.getParameter(Parameter.CN);
|
||||||
if (cn != null)
|
if (cn != null)
|
||||||
@ -682,9 +714,11 @@ public class LocalCalendar extends LocalCollection<Event> {
|
|||||||
int type = Attendees.TYPE_NONE;
|
int type = Attendees.TYPE_NONE;
|
||||||
|
|
||||||
CuType cutype = (CuType)attendee.getParameter(Parameter.CUTYPE);
|
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;
|
type = Attendees.TYPE_RESOURCE;
|
||||||
else {
|
else {
|
||||||
|
// attendee is not a (physical) resource
|
||||||
Role role = (Role)attendee.getParameter(Parameter.ROLE);
|
Role role = (Role)attendee.getParameter(Parameter.ROLE);
|
||||||
int relationship;
|
int relationship;
|
||||||
if (role == Role.CHAIR)
|
if (role == Role.CHAIR)
|
||||||
@ -711,7 +745,6 @@ public class LocalCalendar extends LocalCollection<Event> {
|
|||||||
status = Attendees.ATTENDEE_STATUS_TENTATIVE;
|
status = Attendees.ATTENDEE_STATUS_TENTATIVE;
|
||||||
|
|
||||||
return builder
|
return builder
|
||||||
.withValue(Attendees.ATTENDEE_EMAIL, email)
|
|
||||||
.withValue(Attendees.ATTENDEE_TYPE, type)
|
.withValue(Attendees.ATTENDEE_TYPE, type)
|
||||||
.withValue(Attendees.ATTENDEE_STATUS, status);
|
.withValue(Attendees.ATTENDEE_STATUS, status);
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ package at.bitfire.davdroid.resource;
|
|||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import net.fortuna.ical4j.data.CalendarBuilder;
|
|
||||||
import net.fortuna.ical4j.data.CalendarOutputter;
|
import net.fortuna.ical4j.data.CalendarOutputter;
|
||||||
import net.fortuna.ical4j.data.ParserException;
|
import net.fortuna.ical4j.data.ParserException;
|
||||||
import net.fortuna.ical4j.model.Component;
|
import net.fortuna.ical4j.model.Component;
|
||||||
@ -84,12 +83,11 @@ public class Task extends iCalendar {
|
|||||||
public void parseEntity(InputStream entity, Charset charset, AssetDownloader downloader) throws IOException, InvalidResourceException {
|
public void parseEntity(InputStream entity, Charset charset, AssetDownloader downloader) throws IOException, InvalidResourceException {
|
||||||
final net.fortuna.ical4j.model.Calendar ical;
|
final net.fortuna.ical4j.model.Calendar ical;
|
||||||
try {
|
try {
|
||||||
CalendarBuilder builder = new CalendarBuilder();
|
|
||||||
if (charset != null) {
|
if (charset != null) {
|
||||||
@Cleanup InputStreamReader reader = new InputStreamReader(entity, charset);
|
@Cleanup InputStreamReader reader = new InputStreamReader(entity, charset);
|
||||||
ical = builder.build(reader);
|
ical = calendarBuilder.build(reader);
|
||||||
} else
|
} else
|
||||||
ical = builder.build(entity);
|
ical = calendarBuilder.build(entity);
|
||||||
|
|
||||||
if (ical == null)
|
if (ical == null)
|
||||||
throw new InvalidResourceException("No iCalendar found");
|
throw new InvalidResourceException("No iCalendar found");
|
||||||
|
@ -11,12 +11,19 @@ package at.bitfire.davdroid.resource;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import net.fortuna.ical4j.data.CalendarBuilder;
|
import net.fortuna.ical4j.data.CalendarBuilder;
|
||||||
|
import net.fortuna.ical4j.data.CalendarParserFactory;
|
||||||
import net.fortuna.ical4j.data.ParserException;
|
import net.fortuna.ical4j.data.ParserException;
|
||||||
import net.fortuna.ical4j.model.DateTime;
|
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.component.VTimeZone;
|
||||||
import net.fortuna.ical4j.model.property.DateProperty;
|
import net.fortuna.ical4j.model.property.DateProperty;
|
||||||
import net.fortuna.ical4j.util.CompatibilityHints;
|
import net.fortuna.ical4j.util.CompatibilityHints;
|
||||||
import net.fortuna.ical4j.util.SimpleHostInfo;
|
import net.fortuna.ical4j.util.SimpleHostInfo;
|
||||||
|
import net.fortuna.ical4j.util.Strings;
|
||||||
import net.fortuna.ical4j.util.UidGenerator;
|
import net.fortuna.ical4j.util.UidGenerator;
|
||||||
|
|
||||||
import org.apache.commons.codec.CharEncoding;
|
import org.apache.commons.codec.CharEncoding;
|
||||||
@ -24,10 +31,12 @@ import org.apache.http.entity.ContentType;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import at.bitfire.davdroid.DateUtils;
|
import at.bitfire.davdroid.DateUtils;
|
||||||
import at.bitfire.davdroid.syncadapter.DavSyncAdapter;
|
import at.bitfire.davdroid.syncadapter.DavSyncAdapter;
|
||||||
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
|
|
||||||
public abstract class iCalendar extends Resource {
|
public abstract class iCalendar extends Resource {
|
||||||
@ -114,4 +123,42 @@ public abstract class iCalendar extends Resource {
|
|||||||
return null;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
4371
doc/rfc6638-scheduling-extensions-to-caldav.txt
Normal file
4371
doc/rfc6638-scheduling-extensions-to-caldav.txt
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user