Skip to content

Commit

Permalink
[buteo-sync-plugin-caldav] Add support for VTODO on received ICS data.
Browse files Browse the repository at this point in the history
  • Loading branch information
dcaliste committed Sep 16, 2019
1 parent 2692a7d commit ecc2a76
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 36 deletions.
59 changes: 25 additions & 34 deletions src/reader.cpp
Expand Up @@ -200,7 +200,7 @@ void Reader::readResponse()
if (mReader->name() == "href") {
resource.href = QUrl::fromPercentEncoding(mReader->readElementText().toLatin1());
} else if (mReader->name() == "propstat") {
readPropStat(&resource);
readPropStat(resource);
}
}
if (resource.href.isEmpty()) {
Expand All @@ -209,16 +209,14 @@ void Reader::readResponse()
}
if (!resource.iCalData.trimmed().isEmpty()) {
bool parsed = true;
bool isVCalFormat = false;
QString icsData = preprocessIcsData(resource.iCalData);
KCalCore::ICalFormat iCalFormat;
KCalCore::MemoryCalendar::Ptr cal(new KCalCore::MemoryCalendar(KDateTime::UTC));
if (!iCalFormat.fromString(cal, icsData)) {
if (iCalFormat.exception() && iCalFormat.exception()->code()
== KCalCore::Exception::CalVersion1) {
KCalCore::VCalFormat vCalFormat;
isVCalFormat = vCalFormat.fromString(cal, icsData);
if (!isVCalFormat) {
if (!vCalFormat.fromString(cal, icsData)) {
LOG_WARNING("unable to parse vCal data");
parsed = false;
}
Expand All @@ -240,61 +238,54 @@ void Reader::readResponse()
}
}
if (parsed) {
KCalCore::Event::List events = cal->events(); // TODO: incidences() not just events()
LOG_DEBUG("iCal data contains" << cal->events().count() << "VEVENT instances");
if (events.count() <= 1) {
// single event, or journal/todos
if (isVCalFormat && events.count() == 1) {
resource.incidences = KCalCore::Incidence::List() << events.first();
} else {
KCalCore::Incidence::Ptr incidence = iCalFormat.fromString(icsData);
if (!incidence.isNull()) {
resource.incidences = KCalCore::Incidence::List() << incidence;
} else {
LOG_WARNING("iCal data doesn't contain a valid incidence");
}
}
} else {
// contains some recurring event information, with exception / RECURRENCE-ID defined.
QString eventUid = events.first()->uid();
Q_FOREACH (const KCalCore::Event::Ptr &event, events) {
if (event->uid() != eventUid) {
LOG_WARNING("iCal data contains invalid events with conflicting uids");
eventUid.clear();
KCalCore::Incidence::List incidences = cal->incidences();
LOG_DEBUG("iCal data contains" << incidences.count() << " incidences");
if (incidences.count()) {
QString uid = incidences.first()->uid();
// In case of more than one incidence, it contains some
// recurring event information, with exception / RECURRENCE-ID defined.
Q_FOREACH (const KCalCore::Incidence::Ptr &incidence, incidences) {
if (incidence->uid() != uid) {
LOG_WARNING("iCal data contains invalid incidences with conflicting uids");
uid.clear();
break;
}
}
if (!eventUid.isEmpty()) {
Q_FOREACH (const KCalCore::Event::Ptr &event, events) {
resource.incidences.append(event);
if (!uid.isEmpty()) {
Q_FOREACH (const KCalCore::Incidence::Ptr &incidence, incidences) {
if (incidence->type() == KCalCore::IncidenceBase::TypeEvent
|| incidence->type() == KCalCore::IncidenceBase::TypeTodo)
resource.incidences.append(incidence);
}
}
LOG_DEBUG("parsed" << resource.incidences.count() << "events from the iCal data");
LOG_DEBUG("parsed" << resource.incidences.count() << "events or todos from the iCal data");
} else {
LOG_WARNING("iCal data doesn't contain a valid incidence");
}
}
}

mResults.append(resource);
}

void Reader::readPropStat(CalendarResource *resource)
void Reader::readPropStat(CalendarResource &resource)
{
while (mReader->readNextStartElement()) {
if (mReader->name() == "prop") {
readProp(resource);
} else if (mReader->name() == "status") {
resource->status = mReader->readElementText();
resource.status = mReader->readElementText();
}
}
}

void Reader::readProp(CalendarResource *resource)
void Reader::readProp(CalendarResource &resource)
{
while (mReader->readNextStartElement()) {
if (mReader->name() == "getetag") {
resource->etag = mReader->readElementText();
resource.etag = mReader->readElementText();
} else if (mReader->name() == "calendar-data") {
resource->iCalData = mReader->readElementText(QXmlStreamReader::IncludeChildElements);
resource.iCalData = mReader->readElementText(QXmlStreamReader::IncludeChildElements);
}
}
}
4 changes: 2 additions & 2 deletions src/reader.h
Expand Up @@ -52,8 +52,8 @@ class Reader : public QObject
private:
void readMultiStatus();
void readResponse();
void readPropStat(CalendarResource *resource);
void readProp(CalendarResource *resource);
void readPropStat(CalendarResource &resource);
void readProp(CalendarResource &resource);

private:
QXmlStreamReader *mReader;
Expand Down
26 changes: 26 additions & 0 deletions tests/reader/data/reader_todo_pending.xml
@@ -0,0 +1,26 @@
<multistatus xmlns:d="DAV:" xmlns:cal="urn:ietf:params:xml:ns:caldav">
<response>
<href>/dcaliste/Prive.ics/20070313T123432Z-456553.ics</href>
<propstat>
<prop>
<getetag>\"78e30cfc6a537db0221a67584eea36f3\"</getetag>
<cal:calendar-data>BEGIN:VCALENDAR
PRODID:-//K Desktop Environment//NONSGML libkcal 4.3//EN
VERSION:2.0
X-KDE-ICAL-IMPLEMENTATION-VERSION:1.0
BEGIN:VTODO
UID:20070313T123432Z-456553@example.com
DTSTAMP:20070313T123432Z
DUE;VALUE=DATE:20070501
SUMMARY:Submit Quebec Income Tax Return for 2006
CLASS:CONFIDENTIAL
CATEGORIES:FAMILY,FINANCE
STATUS:NEEDS-ACTION
END:VTODO
END:VCALENDAR
</cal:calendar-data>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
</multistatus>
10 changes: 10 additions & 0 deletions tests/reader/tst_reader.cpp
Expand Up @@ -227,6 +227,16 @@ void tst_Reader::readICal_data()
<< QStringLiteral("Alarm with relative time.")
<< false
<< 1;
QTest::newRow("pending todo")
<< QStringLiteral("data/reader_todo_pending.xml")
<< true
<< 1
<< 1
<< QStringLiteral("20070313T123432Z-456553@example.com")
<< QStringLiteral("Submit Quebec Income Tax Return for 2006")
<< QString()
<< false
<< 0;
}

void tst_Reader::readICal()
Expand Down

0 comments on commit ecc2a76

Please sign in to comment.