diff --git a/src/incidencehandler.cpp b/src/incidencehandler.cpp index ad7df57..e612b3d 100644 --- a/src/incidencehandler.cpp +++ b/src/incidencehandler.cpp @@ -444,21 +444,29 @@ void IncidenceHandler::prepareImportedIncidence(KCalCore::Incidence::Ptr inciden LOG_WARNING("unable to handle imported non-event incidence; skipping"); return; } - KCalCore::Event::Ptr event = incidence.staticCast(); - if (event->allDay()) { - KDateTime dtStart = event->dtStart(); - KDateTime dtEnd = event->dtEnd(); + switch (incidence->type()) { + case KCalCore::IncidenceBase::TypeEvent: { + KCalCore::Event::Ptr event = incidence.staticCast(); - // calendar processing requires all-day events to have a dtEnd - if (!dtEnd.isValid()) { - LOG_DEBUG("Adding DTEND to" << incidence->uid() << "as" << dtStart.toString()); - event->setCustomProperty("buteo", PROP_DTEND_ADDED_USING_DTSTART, PROP_DTEND_ADDED_USING_DTSTART); - event->setDtEnd(dtStart); - } + if (event->allDay()) { + KDateTime dtStart = event->dtStart(); + KDateTime dtEnd = event->dtEnd(); + + // calendar processing requires all-day events to have a dtEnd + if (!dtEnd.isValid()) { + LOG_DEBUG("Adding DTEND to" << incidence->uid() << "as" << dtStart.toString()); + event->setCustomProperty("buteo", PROP_DTEND_ADDED_USING_DTSTART, PROP_DTEND_ADDED_USING_DTSTART); + event->setDtEnd(dtStart); + } - // setting dtStart/End changes the allDay value, so ensure it is still set to true - event->setAllDay(true); + // setting dtStart/End changes the allDay value, so ensure it is still set to true + event->setAllDay(true); + } + break; + } + default: + break; } } @@ -521,81 +529,59 @@ 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(sourceIncidence->clone()); - KCalCore::Event::Ptr event = incidence.staticCast(); // 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. - } - - bool eventIsAllDay = event->allDay(); - if (eventIsAllDay) { - bool sendWithoutDtEnd = !event->customProperty("buteo", PROP_DTEND_ADDED_USING_DTSTART).isEmpty() - && (event->dtStart() == event->dtEnd()); - event->removeCustomProperty("buteo", PROP_DTEND_ADDED_USING_DTSTART); - - if (sendWithoutDtEnd) { - // A single-day all-day event was received without a DTEND, and it is still a single-day - // all-day event, so remove the DTEND before upsyncing. - LOG_DEBUG("Removing DTEND from" << incidence->uid()); - event->setDtEnd(KDateTime()); - } else { - KDateTime dt; - if (event->hasEndDate()) { - // Event::dtEnd() is inclusive, but DTEND in iCalendar format is exclusive. - dt = KDateTime(event->dtEnd().addDays(1).date(), KDateTime::Spec::ClockTime()); - LOG_DEBUG("Adding +1 day to DTEND to make exclusive DTEND for" << incidence->uid() << ":" << dt.toString()); - } else { - // No DTEND exists in event, but it's all day. Set to DTSTART+1 to make exclusive DTEND. - dt = KDateTime(event->dtStart().addDays(1).date(), KDateTime::Spec::ClockTime()); - LOG_DEBUG("Setting DTEND to DTSTART+1 for" << incidence->uid() << ":" << dt.toString()); - } - dt.setDateOnly(true); - LOG_DEBUG("Stripping time from date-only DTEND:" << dt.toString()); - event->setDtEnd(dt); - } - } - - if (event->dtStart().isDateOnly()) { - KDateTime dt = KDateTime(event->dtStart().date(), KDateTime::Spec::ClockTime()); - dt.setDateOnly(true); - event->setDtStart(dt); - LOG_DEBUG("Stripping time from date-only DTSTART:" << dt.toString()); - } - - // setting dtStart/End changes the allDay value, so ensure it is still set to true if needed. - if (eventIsAllDay) { - event->setAllDay(true); + incidence->setUid(trimmedUid); // leaving just the EventUid. } // 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"); + 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. - event->removeCustomProperty("buteo", "uri"); - event->removeCustomProperty("buteo", "etag"); - const QStringList &comments(event->comments()); + 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); - event->removeComment(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 = event->alarms(); + KCalCore::Alarm::List alarms = incidence->alarms(); Q_FOREACH (KCalCore::Alarm::Ptr alarm, alarms) { if (!alarm->hasTime()) { KCalCore::Duration offset(0); @@ -613,29 +599,56 @@ KCalCore::Incidence::Ptr IncidenceHandler::incidenceToExport(KCalCore::Incidence } } - // 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); + switch (incidence->type()) { + case KCalCore::IncidenceBase::TypeEvent: { + KCalCore::Event::Ptr event = incidence.staticCast(); + bool eventIsAllDay = event->allDay(); + if (eventIsAllDay) { + bool sendWithoutDtEnd = !event->customProperty("buteo", PROP_DTEND_ADDED_USING_DTSTART).isEmpty() + && (event->dtStart() == event->dtEnd()); + event->removeCustomProperty("buteo", PROP_DTEND_ADDED_USING_DTSTART); + + if (sendWithoutDtEnd) { + // A single-day all-day event was received without a DTEND, and it is still a single-day + // all-day event, so remove the DTEND before upsyncing. + LOG_DEBUG("Removing DTEND from" << incidence->uid()); + event->setDtEnd(KDateTime()); } else { - LOG_DEBUG("Not discarding attendee:" << attendee->fullName() << attendee->email() << ": not organizer:" << organizer->fullName() << organizer->email()); + KDateTime dt; + if (event->hasEndDate()) { + // Event::dtEnd() is inclusive, but DTEND in iCalendar format is exclusive. + dt = KDateTime(event->dtEnd().addDays(1).date(), KDateTime::Spec::ClockTime()); + LOG_DEBUG("Adding +1 day to DTEND to make exclusive DTEND for" << incidence->uid() << ":" << dt.toString()); + } else { + // No DTEND exists in event, but it's all day. Set to DTSTART+1 to make exclusive DTEND. + dt = KDateTime(event->dtStart().addDays(1).date(), KDateTime::Spec::ClockTime()); + LOG_DEBUG("Setting DTEND to DTSTART+1 for" << incidence->uid() << ":" << dt.toString()); + } + dt.setDateOnly(true); + LOG_DEBUG("Stripping time from date-only DTEND:" << dt.toString()); + event->setDtEnd(dt); } } - } - // 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()); + if (event->dtStart().isDateOnly()) { + KDateTime dt = KDateTime(event->dtStart().date(), KDateTime::Spec::ClockTime()); + dt.setDateOnly(true); + event->setDtStart(dt); + LOG_DEBUG("Stripping time from date-only DTSTART:" << dt.toString()); + } + + // setting dtStart/End changes the allDay value, so ensure it is still set to true if needed. + if (eventIsAllDay) { + event->setAllDay(true); } + break; + } + case KCalCore::IncidenceBase::TypeTodo: + break; + default: + LOG_DEBUG("Incidence type not supported; cannot create proper exportable version"); + break; } - return event; + return incidence; }