Skip to content

Commit

Permalink
[buteo-sync-plugin-caldav] Ensure VTODO are properly imported, compar…
Browse files Browse the repository at this point in the history
…ed and exported.
  • Loading branch information
dcaliste committed Sep 16, 2019
1 parent ecc2a76 commit 4db2e6f
Showing 1 changed file with 82 additions and 69 deletions.
151 changes: 82 additions & 69 deletions src/incidencehandler.cpp
Expand Up @@ -444,6 +444,9 @@ void IncidenceHandler::prepareImportedIncidence(KCalCore::Incidence::Ptr inciden
LOG_WARNING("unable to handle imported non-event incidence; skipping");
return;
}

switch (incidence->type()) {
case KCalCore::IncidenceBase::TypeEvent: {
KCalCore::Event::Ptr event = incidence.staticCast<KCalCore::Event>();

if (event->allDay()) {
Expand All @@ -460,6 +463,11 @@ void IncidenceHandler::prepareImportedIncidence(KCalCore::Incidence::Ptr inciden
// setting dtStart/End changes the allDay value, so ensure it is still set to true
event->setAllDay(true);
}
break;
}
default:
break;
}
}

// A given incidence has been added or modified locally.
Expand Down Expand Up @@ -521,21 +529,79 @@ QString IncidenceHandler::toIcs(KCalCore::Incidence::Ptr incidence,

KCalCore::Incidence::Ptr IncidenceHandler::incidenceToExport(KCalCore::Incidence::Ptr sourceIncidence, const KCalCore::Incidence::List &instances)
{
if (sourceIncidence->type() != KCalCore::IncidenceBase::TypeEvent) {
LOG_DEBUG("Incidence not an event; cannot create exportable version");
return sourceIncidence;
}

KCalCore::Incidence::Ptr incidence = QSharedPointer<KCalCore::Incidence>(sourceIncidence->clone());
KCalCore::Event::Ptr event = incidence.staticCast<KCalCore::Event>();

// check to see if the UID is of the special form: NBUID:NotebookUid:EventUid. If so, trim it.
if (event->uid().startsWith(QStringLiteral("NBUID:"))) {
QString oldUid = event->uid();
if (incidence->uid().startsWith(QStringLiteral("NBUID:"))) {
QString oldUid = incidence->uid();
QString trimmedUid = oldUid.mid(oldUid.indexOf(':', 6)+1); // remove NBUID:NotebookUid:
event->setUid(trimmedUid); // leaving just the EventUid.
incidence->setUid(trimmedUid); // leaving just the EventUid.
}

// remove any (obsolete) markers that tell us that the time was added by us
incidence->removeCustomProperty("buteo", "dtstart-date_only");
incidence->removeCustomProperty("buteo", "dtend-date_only");

// remove any URI or ETAG data we insert into the event for sync purposes.
incidence->removeCustomProperty("buteo", "uri");
incidence->removeCustomProperty("buteo", "etag");
const QStringList &comments(incidence->comments());
Q_FOREACH (const QString &comment, comments) {
if (comment.startsWith("buteo:caldav:uri:") ||
comment.startsWith("buteo:caldav:detached-and-synced") ||
comment.startsWith("buteo:caldav:etag:")) {
LOG_DEBUG("Discarding buteo-prefixed comment:" << comment);
incidence->removeComment(comment);
}
}

// The default storage implementation applies the organizer as an attendee by default.
// Undo this as it turns the incidence into a scheduled event requiring acceptance/rejection/etc.
const KCalCore::Person::Ptr organizer = incidence->organizer();
if (organizer) {
Q_FOREACH (const KCalCore::Attendee::Ptr &attendee, incidence->attendees()) {
if (attendee->email() == organizer->email() && attendee->fullName() == organizer->fullName()) {
LOG_DEBUG("Discarding organizer as attendee" << attendee->fullName());
incidence->deleteAttendee(attendee);
} else {
LOG_DEBUG("Not discarding attendee:" << attendee->fullName() << attendee->email() << ": not organizer:" << organizer->fullName() << organizer->email());
}
}
}

// remove EXDATE values from the recurring incidence which correspond to the persistent occurrences (instances)
if (incidence->recurs()) {
Q_FOREACH (KCalCore::Incidence::Ptr instance, instances) {
KCalCore::DateTimeList exDateTimes = incidence->recurrence()->exDateTimes();
exDateTimes.removeAll(instance->recurrenceId());
incidence->recurrence()->setExDateTimes(exDateTimes);
LOG_DEBUG("Discarding exdate:" << instance->recurrenceId().toString());
}
}

// Icalformat from kcalcore converts second-type duration into day-type duration
// whenever possible. We do the same to have consistent comparisons.
KCalCore::Alarm::List alarms = incidence->alarms();
Q_FOREACH (KCalCore::Alarm::Ptr alarm, alarms) {
if (!alarm->hasTime()) {
KCalCore::Duration offset(0);
if (alarm->hasEndOffset())
offset = alarm->endOffset();
else
offset = alarm->startOffset();
if (!offset.isDaily() && !(offset.value() % (60 * 60 * 24))) {
LOG_DEBUG("Converting to day-type duration " << offset.asDays());
if (alarm->hasEndOffset())
alarm->setEndOffset(KCalCore::Duration(offset.asDays(), KCalCore::Duration::Days));
else
alarm->setStartOffset(KCalCore::Duration(offset.asDays(), KCalCore::Duration::Days));
}
}
}

switch (incidence->type()) {
case KCalCore::IncidenceBase::TypeEvent: {
KCalCore::Event::Ptr event = incidence.staticCast<KCalCore::Event>();
bool eventIsAllDay = event->allDay();
if (eventIsAllDay) {
bool sendWithoutDtEnd = !event->customProperty("buteo", PROP_DTEND_ADDED_USING_DTSTART).isEmpty()
Expand Down Expand Up @@ -575,67 +641,14 @@ KCalCore::Incidence::Ptr IncidenceHandler::incidenceToExport(KCalCore::Incidence
if (eventIsAllDay) {
event->setAllDay(true);
}

// remove any (obsolete) markers that tell us that the time was added by us
event->removeCustomProperty("buteo", "dtstart-date_only");
event->removeCustomProperty("buteo", "dtend-date_only");

// remove any URI or ETAG data we insert into the event for sync purposes.
event->removeCustomProperty("buteo", "uri");
event->removeCustomProperty("buteo", "etag");
const QStringList &comments(event->comments());
Q_FOREACH (const QString &comment, comments) {
if (comment.startsWith("buteo:caldav:uri:") ||
comment.startsWith("buteo:caldav:detached-and-synced") ||
comment.startsWith("buteo:caldav:etag:")) {
LOG_DEBUG("Discarding buteo-prefixed comment:" << comment);
event->removeComment(comment);
}
}

// Icalformat from kcalcore converts second-type duration into day-type duration
// whenever possible. We do the same to have consistent comparisons.
KCalCore::Alarm::List alarms = event->alarms();
Q_FOREACH (KCalCore::Alarm::Ptr alarm, alarms) {
if (!alarm->hasTime()) {
KCalCore::Duration offset(0);
if (alarm->hasEndOffset())
offset = alarm->endOffset();
else
offset = alarm->startOffset();
if (!offset.isDaily() && !(offset.value() % (60 * 60 * 24))) {
LOG_DEBUG("Converting to day-type duration " << offset.asDays());
if (alarm->hasEndOffset())
alarm->setEndOffset(KCalCore::Duration(offset.asDays(), KCalCore::Duration::Days));
else
alarm->setStartOffset(KCalCore::Duration(offset.asDays(), KCalCore::Duration::Days));
}
}
}

// The default storage implementation applies the organizer as an attendee by default.
// Undo this as it turns the incidence into a scheduled event requiring acceptance/rejection/etc.
const KCalCore::Person::Ptr organizer = event->organizer();
if (organizer) {
Q_FOREACH (const KCalCore::Attendee::Ptr &attendee, event->attendees()) {
if (attendee->email() == organizer->email() && attendee->fullName() == organizer->fullName()) {
LOG_DEBUG("Discarding organizer as attendee" << attendee->fullName());
event->deleteAttendee(attendee);
} else {
LOG_DEBUG("Not discarding attendee:" << attendee->fullName() << attendee->email() << ": not organizer:" << organizer->fullName() << organizer->email());
}
}
}

// remove EXDATE values from the recurring incidence which correspond to the persistent occurrences (instances)
if (incidence->recurs()) {
Q_FOREACH (KCalCore::Incidence::Ptr instance, instances) {
KCalCore::DateTimeList exDateTimes = incidence->recurrence()->exDateTimes();
exDateTimes.removeAll(instance->recurrenceId());
incidence->recurrence()->setExDateTimes(exDateTimes);
LOG_DEBUG("Discarding exdate:" << instance->recurrenceId().toString());
break;
}
case KCalCore::IncidenceBase::TypeTodo:
break;
default:
LOG_DEBUG("Incidence type not supported; cannot create proper exportable version");
break;
}

return event;
return incidence;
}

0 comments on commit 4db2e6f

Please sign in to comment.