diff --git a/conversion/kcalconversion.cpp b/conversion/kcalconversion.cpp index 49ad40f..1ac8748 100644 --- a/conversion/kcalconversion.cpp +++ b/conversion/kcalconversion.cpp @@ -1,861 +1,859 @@ /* * Copyright (C) 2011 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "kcalconversion.h" #include #include #include #include #include #include #include #include "kolabformat/errorhandler.h" #include "commonconversion.h" namespace Kolab { namespace Conversion { //The uid of a contact which refers to the uuid of a contact in the addressbook #define CUSTOM_KOLAB_CONTACT_UUID "X_KOLAB_CONTACT_UUID" #define CUSTOM_KOLAB_CONTACT_CUTYPE "X_KOLAB_CONTACT_CUTYPE" #define CUSTOM_KOLAB_URL "X-KOLAB-URL" KCalCore::Duration toDuration(const Kolab::Duration &d) { int value = 0; if (d.hours() || d.minutes() || d.seconds()) { value = ((((d.weeks() * 7 + d.days()) * 24 + d.hours()) * 60 + d.minutes()) * 60 + d.seconds()); if (d.isNegative()) { value = -value; } return KCalCore::Duration(value); } value = d.weeks() * 7 + d.days(); if (d.isNegative()) { value = -value; } return KCalCore::Duration(value, KCalCore::Duration::Days); } Kolab::Duration fromDuration(const KCalCore::Duration &d) { int value = d.value(); bool isNegative = false; if (value < 0) { isNegative = true; value = -value; } //We don't know how the seconds/days were distributed before, so no point in distributing them (probably) if (d.isDaily()) { int days = value; return Kolab::Duration(days, 0, 0, 0, isNegative); } int seconds = value; // int minutes = seconds / 60; // seconds = seconds % 60; // int hours = minutes / 60; // minutes = minutes % 60; return Kolab::Duration(0, 0, 0, seconds, isNegative); } KCalCore::Incidence::Secrecy toSecrecy(Kolab::Classification c) { switch(c) { case Kolab::ClassPublic: return KCalCore::Incidence::SecrecyPublic; case Kolab::ClassPrivate: return KCalCore::Incidence::SecrecyPrivate; case Kolab::ClassConfidential: return KCalCore::Incidence::SecrecyConfidential; default: Error() << "unhandled"; Q_ASSERT(0); } return KCalCore::Incidence::SecrecyPublic; } Kolab::Classification fromSecrecy(KCalCore::Incidence::Secrecy c) { switch(c) { case KCalCore::Incidence::SecrecyPublic: return Kolab::ClassPublic; case KCalCore::Incidence::SecrecyPrivate: return Kolab::ClassPrivate; case KCalCore::Incidence::SecrecyConfidential: return Kolab::ClassConfidential; default: Error() << "unhandled"; Q_ASSERT(0); } return Kolab::ClassPublic; } int toPriority(int priority) { //Same mapping return priority; } int fromPriority(int priority) { //Same mapping return priority; } KCalCore::Incidence::Status toStatus(Kolab::Status s) { switch (s) { case StatusUndefined: return KCalCore::Incidence::StatusNone; case StatusNeedsAction: return KCalCore::Incidence::StatusNeedsAction; case StatusCompleted: return KCalCore::Incidence::StatusCompleted; case StatusInProcess: return KCalCore::Incidence::StatusInProcess; case StatusCancelled: return KCalCore::Incidence::StatusCanceled; case StatusTentative: return KCalCore::Incidence::StatusTentative; case StatusConfirmed: return KCalCore::Incidence::StatusConfirmed; case StatusDraft: return KCalCore::Incidence::StatusDraft; case StatusFinal: return KCalCore::Incidence::StatusFinal; default: Error() << "unhandled"; Q_ASSERT(0); } return KCalCore::Incidence::StatusNone; } Kolab::Status fromStatus(KCalCore::Incidence::Status s) { switch (s) { case KCalCore::Incidence::StatusNone: return StatusUndefined; case KCalCore::Incidence::StatusNeedsAction: return StatusNeedsAction; case KCalCore::Incidence::StatusCompleted: return StatusCompleted; case KCalCore::Incidence::StatusInProcess: return StatusInProcess; case KCalCore::Incidence::StatusCanceled: return StatusCancelled; case KCalCore::Incidence::StatusTentative: return StatusTentative; case KCalCore::Incidence::StatusConfirmed: return StatusConfirmed; case KCalCore::Incidence::StatusDraft: return StatusDraft; case KCalCore::Incidence::StatusFinal: return StatusFinal; default: Error() << "unhandled"; Q_ASSERT(0); } return StatusUndefined; } KCalCore::Attendee::PartStat toPartStat(Kolab::PartStatus p) { switch (p) { case PartNeedsAction: return KCalCore::Attendee::NeedsAction; case PartAccepted: return KCalCore::Attendee::Accepted; case PartDeclined: return KCalCore::Attendee::Declined; case PartTentative: return KCalCore::Attendee::Tentative; case PartDelegated: return KCalCore::Attendee::Delegated; default: Error() << "unhandled"; Q_ASSERT(0); } return KCalCore::Attendee::NeedsAction; } Kolab::PartStatus fromPartStat(KCalCore::Attendee::PartStat p) { switch (p) { case KCalCore::Attendee::NeedsAction: return PartNeedsAction; case KCalCore::Attendee::Accepted: return PartAccepted; case KCalCore::Attendee::Declined: return PartDeclined; case KCalCore::Attendee::Tentative: return PartTentative; case KCalCore::Attendee::Delegated: return PartDelegated; default: Error() << "unhandled"; Q_ASSERT(0); } return PartNeedsAction; } KCalCore::Attendee::Role toRole(Kolab::Role r) { switch (r) { case Required: return KCalCore::Attendee::ReqParticipant; case Chair: return KCalCore::Attendee::Chair; case Optional: return KCalCore::Attendee::OptParticipant; case NonParticipant: return KCalCore::Attendee::NonParticipant; default: Error() << "unhandled"; Q_ASSERT(0); } return KCalCore::Attendee::ReqParticipant; } Kolab::Role fromRole(KCalCore::Attendee::Role r) { switch (r) { case KCalCore::Attendee::ReqParticipant: return Required; case KCalCore::Attendee::Chair: return Chair; case KCalCore::Attendee::OptParticipant: return Optional; case KCalCore::Attendee::NonParticipant: return NonParticipant; default: Error() << "unhandled"; Q_ASSERT(0); } return Required; } template QString getCustomProperty(const QString &id, const T &e) { std::vector &props = e.customProperties(); foreach (const CustomProperty &p, props) { if (fromStdString(p.identifier) == id) { return fromStdString(p.value); } } } template void setIncidence(KCalCore::Incidence &i, const T &e) { if (!e.uid().empty()) { i.setUid(fromStdString(e.uid())); } i.setCreated(toDate(e.created())); i.setLastModified(toDate(e.lastModified())); i.setRevision(e.sequence()); i.setSecrecy(toSecrecy(e.classification())); i.setCategories(toStringList(e.categories())); if (e.start().isValid()) { i.setDtStart(toDate(e.start())); } i.setSummary(fromStdString(e.summary())); //TODO detect richtext i.setDescription(fromStdString(e.description())); //TODO detect richtext i.setStatus(toStatus(e.status())); foreach (const Kolab::Attendee a, e.attendees()) { /* * KCalCore always sets a UID if empty, but that's just a pointer, and not the uid of a real contact. * Since that means the semantics of the two are different, we have to store the kolab uid as a custom property. */ KCalCore::Attendee::Ptr attendee = KCalCore::Attendee::Ptr(new KCalCore::Attendee(fromStdString(a.contact().name()), fromStdString(a.contact().email()), a.rsvp(), toPartStat(a.partStat()), toRole(a.role()) )); if (!a.contact().uid().empty()) { //TODO Identify contact from addressbook based on uid attendee->customProperties().setNonKDECustomProperty(CUSTOM_KOLAB_CONTACT_UUID, fromStdString(a.contact().uid())); } if (!a.delegatedTo().empty()) { if (a.delegatedTo().size() > 1) { WARNING("multiple delegatees are not supported"); } attendee->setDelegate(toMailto(a.delegatedTo().front().email(), a.delegatedTo().front().name()).toString()); } if (!a.delegatedFrom().empty()) { if (a.delegatedFrom().size() > 1) { WARNING("multiple delegators are not supported"); } attendee->setDelegator(toMailto(a.delegatedFrom().front().email(), a.delegatedFrom().front().name()).toString()); } if (a.cutype() != CutypeIndividual) { attendee->customProperties().setNonKDECustomProperty(CUSTOM_KOLAB_CONTACT_CUTYPE, QString::number(a.cutype())); } i.addAttendee(attendee); } foreach (const Kolab::Attachment a, e.attachments()) { KCalCore::Attachment::Ptr ptr; if (!a.uri().empty()) { - qDebug() << "with uri"; ptr = KCalCore::Attachment::Ptr(new KCalCore::Attachment(fromStdString(a.uri()), fromStdString(a.mimetype()))); } else { - qDebug() << "with data " << a.data(); ptr = KCalCore::Attachment::Ptr(new KCalCore::Attachment(QByteArray::fromRawData(a.data().c_str(), a.data().size()).toBase64(), fromStdString(a.mimetype()))); } if (!a.label().empty()) { ptr->setLabel(fromStdString(a.label())); } i.addAttachment(ptr); } QMap props; foreach (const Kolab::CustomProperty &prop, e.customProperties()) { QString key; if (prop.identifier.compare(0, 5, "X-KDE")) { key.append(QString::fromLatin1("X-KOLAB-")); } key.append(fromStdString(prop.identifier)); props.insert(key.toLatin1(), fromStdString(prop.value)); // i.setCustomProperty("KOLAB", fromStdString(prop.identifier).toLatin1(), fromStdString(prop.value)); } i.setCustomProperties(props); } template void getIncidence(T &i, const I &e) { i.setUid(toStdString(e.uid())); i.setCreated(fromDate(e.created())); i.setLastModified(fromDate(e.lastModified())); i.setSequence(e.revision()); i.setClassification(fromSecrecy(e.secrecy())); i.setCategories(fromStringList(e.categories())); i.setStart(fromDate(e.dtStart())); i.setSummary(toStdString(e.summary())); i.setDescription(toStdString(e.description())); i.setStatus(fromStatus(e.status())); std::vector attendees; foreach (const KCalCore::Attendee::Ptr ptr, e.attendees()) { const QString &uid = ptr->customProperties().nonKDECustomProperty(CUSTOM_KOLAB_CONTACT_UUID); Kolab::Attendee a(Kolab::ContactReference(toStdString(ptr->email()), toStdString(ptr->name()), toStdString(uid))); a.setRSVP(ptr->RSVP()); a.setPartStat(fromPartStat(ptr->status())); a.setRole(fromRole(ptr->role())); if (!ptr->delegate().isEmpty()) { std::string name; const std::string &email = fromMailto(QUrl(ptr->delegate()), name); a.setDelegatedTo(std::vector() << Kolab::ContactReference(email, name)); } if (!ptr->delegator().isEmpty()) { std::string name; const std::string &email = fromMailto(QUrl(ptr->delegator()), name); a.setDelegatedFrom(std::vector() << Kolab::ContactReference(email, name)); } const QString &cutype = ptr->customProperties().nonKDECustomProperty(CUSTOM_KOLAB_CONTACT_CUTYPE); if (!cutype.isEmpty()) { a.setCutype(static_cast(cutype.toInt())); } attendees.push_back(a); } i.setAttendees(attendees); std::vector attachments; foreach (const KCalCore::Attachment::Ptr &ptr, e.attachments()) { Kolab::Attachment a; if (ptr->isUri()) { a.setUri(toStdString(ptr->uri()), toStdString(ptr->mimeType())); } else { a.setData(std::string(ptr->decodedData().data(), ptr->decodedData().size()), toStdString(ptr->mimeType())); } a.setLabel(toStdString(ptr->label())); attachments.push_back(a); } i.setAttachments(attachments); std::vector customProperties; const QMap &props = e.customProperties(); for (QMap::const_iterator it = props.begin(); it != props.end(); it++) { QString key(it.key()); if (key == QLatin1String(CUSTOM_KOLAB_URL)) { continue; } customProperties.push_back(Kolab::CustomProperty(toStdString(key.remove("X-KOLAB-")), toStdString(it.value()))); } i.setCustomProperties(customProperties); } int toWeekDay(Kolab::Weekday wday) { switch (wday) { case Kolab::Monday: return 1; case Kolab::Tuesday: return 2; case Kolab::Wednesday: return 3; case Kolab::Thursday: return 4; case Kolab::Friday: return 5; case Kolab::Saturday: return 6; case Kolab::Sunday: return 7; default: Error() << "unhandled"; Q_ASSERT(0); } return 1; } Kolab::Weekday fromWeekDay(int wday) { switch (wday) { case 1: return Kolab::Monday; case 2: return Kolab::Tuesday; case 3: return Kolab::Wednesday; case 4: return Kolab::Thursday; case 5: return Kolab::Friday; case 6: return Kolab::Saturday; case 7: return Kolab::Sunday; default: Error() << "unhandled"; Q_ASSERT(0); } return Kolab::Monday; } KCalCore::RecurrenceRule::PeriodType toRecurrenceType(Kolab::RecurrenceRule::Frequency freq) { switch(freq) { case Kolab::RecurrenceRule::FreqNone: Warning() << "no recurrence?"; break; case Kolab::RecurrenceRule::Yearly: return KCalCore::RecurrenceRule::rYearly; case Kolab::RecurrenceRule::Monthly: return KCalCore::RecurrenceRule::rMonthly; case Kolab::RecurrenceRule::Weekly: return KCalCore::RecurrenceRule::rWeekly; case Kolab::RecurrenceRule::Daily: return KCalCore::RecurrenceRule::rDaily; case Kolab::RecurrenceRule::Hourly: return KCalCore::RecurrenceRule::rHourly; case Kolab::RecurrenceRule::Minutely: return KCalCore::RecurrenceRule::rMinutely; case Kolab::RecurrenceRule::Secondly: return KCalCore::RecurrenceRule::rSecondly; default: Error() << "unhandled"; Q_ASSERT(0); } return KCalCore::RecurrenceRule::rNone; } Kolab::RecurrenceRule::Frequency fromRecurrenceType(KCalCore::RecurrenceRule::PeriodType freq) { switch(freq) { case KCalCore::RecurrenceRule::rNone: Warning() << "no recurrence?"; break; case KCalCore::RecurrenceRule::rYearly: return Kolab::RecurrenceRule::Yearly; case KCalCore::RecurrenceRule::rMonthly: return Kolab::RecurrenceRule::Monthly; case KCalCore::RecurrenceRule::rWeekly: return Kolab::RecurrenceRule::Weekly; case KCalCore::RecurrenceRule::rDaily: return Kolab::RecurrenceRule::Daily; case KCalCore::RecurrenceRule::rHourly: return Kolab::RecurrenceRule::Hourly; case KCalCore::RecurrenceRule::rMinutely: return Kolab::RecurrenceRule::Minutely; case KCalCore::RecurrenceRule::rSecondly: return Kolab::RecurrenceRule::Secondly; default: Error() << "unhandled"; Q_ASSERT(0); } return Kolab::RecurrenceRule::FreqNone; } KCalCore::RecurrenceRule::WDayPos toWeekDayPos(const Kolab::DayPos &dp) { return KCalCore::RecurrenceRule::WDayPos(dp.occurence(), toWeekDay(dp.weekday())); } Kolab::DayPos fromWeekDayPos(const KCalCore::RecurrenceRule::WDayPos &dp) { return Kolab::DayPos(dp.pos(), fromWeekDay(dp.day())); } template void setRecurrence(KCalCore::Incidence &e, const T &event) { const Kolab::RecurrenceRule &rrule = event.recurrenceRule(); if (rrule.isValid()) { KCalCore::Recurrence *rec = e.recurrence(); KCalCore::RecurrenceRule *defaultRR = rec->defaultRRule(true); Q_ASSERT(defaultRR); defaultRR->setWeekStart(toWeekDay(rrule.weekStart())); defaultRR->setRecurrenceType(toRecurrenceType(rrule.frequency())); defaultRR->setFrequency(rrule.interval()); if (rrule.end().isValid()) { rec->setEndDateTime(toDate(rrule.end())); //TODO date/datetime setEndDate(). With date-only the start date has to be taken into account. } else { rec->setDuration(rrule.count()); } if (!rrule.bysecond().empty()) { defaultRR->setBySeconds(QVector::fromStdVector(rrule.bysecond()).toList()); } if (!rrule.byminute().empty()) { defaultRR->setByMinutes(QVector::fromStdVector(rrule.byminute()).toList()); } if (!rrule.byhour().empty()) { defaultRR->setByHours(QVector::fromStdVector(rrule.byhour()).toList()); } if (!rrule.byday().empty()) { QList daypos; foreach(const Kolab::DayPos &dp, rrule.byday()) { daypos.append(toWeekDayPos(dp)); } defaultRR->setByDays(daypos); } if (!rrule.bymonthday().empty()) { defaultRR->setByMonthDays(QVector::fromStdVector(rrule.bymonthday()).toList()); } if (!rrule.byyearday().empty()) { defaultRR->setByYearDays(QVector::fromStdVector(rrule.byyearday()).toList()); } if (!rrule.byweekno().empty()) { defaultRR->setByWeekNumbers(QVector::fromStdVector(rrule.byweekno()).toList()); } if (!rrule.bymonth().empty()) { defaultRR->setByMonths(QVector::fromStdVector(rrule.bymonth()).toList()); } } foreach (const Kolab::cDateTime &dt, event.recurrenceDates()) { const KDateTime &date = toDate(dt); if (date.isDateOnly()) { e.recurrence()->addRDate(date.date()); } else { e.recurrence()->addRDateTime(date); } } foreach (const Kolab::cDateTime &dt, event.exceptionDates()) { const KDateTime &date = toDate(dt); if (date.isDateOnly()) { e.recurrence()->addExDate(date.date()); } else { e.recurrence()->addExDateTime(date); } } } template void getRecurrence(T &i, const I &e) { if (!e.recurs()) { return; } KCalCore::Recurrence *rec = e.recurrence(); KCalCore::RecurrenceRule *defaultRR = rec->defaultRRule(false); if (!defaultRR) { Warning() << "no recurrence"; return; } Q_ASSERT(defaultRR); Kolab::RecurrenceRule rrule; rrule.setWeekStart(fromWeekDay(defaultRR->weekStart())); rrule.setFrequency(fromRecurrenceType(defaultRR->recurrenceType())); rrule.setInterval(defaultRR->frequency()); if (defaultRR->duration() != 0) { //Inidcates if end date is set or not if (defaultRR->duration() > 0) { rrule.setCount(defaultRR->duration()); } } else { rrule.setEnd(fromDate(defaultRR->endDt())); } rrule.setBysecond(defaultRR->bySeconds().toVector().toStdVector()); rrule.setByminute(defaultRR->byMinutes().toVector().toStdVector()); rrule.setByhour(defaultRR->byHours().toVector().toStdVector()); std::vector daypos; foreach (const KCalCore::RecurrenceRule::WDayPos &dp, defaultRR->byDays()) { daypos.push_back(fromWeekDayPos(dp)); } rrule.setByday(daypos); rrule.setBymonthday(defaultRR->byMonthDays().toVector().toStdVector()); rrule.setByyearday(defaultRR->byYearDays().toVector().toStdVector()); rrule.setByweekno(defaultRR->byWeekNumbers().toVector().toStdVector()); rrule.setBymonth(defaultRR->byMonths().toVector().toStdVector()); i.setRecurrenceRule(rrule); std::vector rdates; foreach (const KDateTime &dt, rec->rDateTimes()) { rdates.push_back(fromDate(dt)); } foreach (const QDate &dt, rec->rDates()) { rdates.push_back(fromDate(KDateTime(dt))); } i.setRecurrenceDates(rdates); std::vector exdates; foreach (const KDateTime &dt, rec->exDateTimes()) { exdates.push_back(fromDate(dt)); } foreach (const QDate &dt, rec->exDates()) { exdates.push_back(fromDate(KDateTime(dt))); } i.setExceptionDates(exdates); if (!rec->exRules().empty()) { Warning() << "exrules are not supported"; } } template void setTodoEvent(KCalCore::Incidence &i, const T &e) { i.setPriority(toPriority(e.priority())); if (!e.location().empty()) { i.setLocation(fromStdString(e.location())); //TODO detect richtext } if (e.organizer().isValid()) { i.setOrganizer(KCalCore::Person::Ptr(new KCalCore::Person(fromStdString(e.organizer().name()), fromStdString(e.organizer().email())))); //TODO handle uid too } if (!e.url().empty()) { i.setNonKDECustomProperty(CUSTOM_KOLAB_URL, fromStdString(e.url())); } if (e.recurrenceID().isValid()) { i.setRecurrenceId(toDate(e.recurrenceID())); //TODO THISANDFUTURE } setRecurrence(i, e); foreach (const Kolab::Alarm a, e.alarms()) { KCalCore::Alarm::Ptr alarm = KCalCore::Alarm::Ptr(new KCalCore::Alarm(&i)); switch (a.type()) { case Kolab::Alarm::EMailAlarm: { KCalCore::Person::List receipents; foreach (Kolab::ContactReference c ,a.attendees()) { KCalCore::Person::Ptr person = KCalCore::Person::Ptr(new KCalCore::Person(fromStdString(c.name()), fromStdString(c.email()))); receipents.append(person); } alarm->setEmailAlarm(fromStdString(a.summary()), fromStdString(a.description()), receipents); } break; case Kolab::Alarm::DisplayAlarm: alarm->setDisplayAlarm(fromStdString(a.text())); break; case Kolab::Alarm::AudioAlarm: alarm->setAudioAlarm(fromStdString(a.audioFile().uri())); break; default: Error() << "invalid alarm"; } if (a.start().isValid()) { alarm->setTime(toDate(a.start())); } else if (a.relativeStart().isValid()) { if (a.relativeTo() == Kolab::End) { alarm->setEndOffset(toDuration(a.relativeStart())); } else { alarm->setStartOffset(toDuration(a.relativeStart())); } } alarm->setSnoozeTime(toDuration(a.duration())); alarm->setRepeatCount(a.numrepeat()); alarm->setEnabled(true); i.addAlarm(alarm); } } template void getTodoEvent(T &i, const I &e) { i.setPriority(fromPriority(e.priority())); i.setLocation(toStdString(e.location())); if (e.organizer() && !e.organizer()->email().isEmpty()) { i.setOrganizer(Kolab::ContactReference(Kolab::ContactReference::EmailReference, toStdString(e.organizer()->email()), toStdString(e.organizer()->name()))); //TODO handle uid too } i.setUrl(toStdString(e.nonKDECustomProperty(CUSTOM_KOLAB_URL))); i.setRecurrenceID(fromDate(e.recurrenceId()), false); //TODO THISANDFUTURE getRecurrence(i, e); std::vector alarms; foreach (const KCalCore::Alarm::Ptr &a, e.alarms()) { Kolab::Alarm alarm; //TODO KCalCore disables alarms using KCalCore::Alarm::enabled() (X-KDE-KCALCORE-ENABLED) We should either delete the alarm, or store the attribute . //Ideally we would store the alarm somewhere and temporarily delete it, so we can restore it when parsing. For now we just remove disabled alarms. if (!a->enabled()) { Warning() << "skipping disabled alarm"; continue; } switch (a->type()) { case KCalCore::Alarm::Display: alarm = Kolab::Alarm(toStdString(a->text())); break; case KCalCore::Alarm::Email: { std::vector receipents; foreach(const KCalCore::Person::Ptr &p, a->mailAddresses()) { receipents.push_back(Kolab::ContactReference(toStdString(p->email()), toStdString(p->name()))); } alarm = Kolab::Alarm(toStdString(a->mailSubject()), toStdString(a->mailText()), receipents); } break; case KCalCore::Alarm::Audio: { Kolab::Attachment audioFile; audioFile.setUri(toStdString(a->audioFile()), std::string()); alarm = Kolab::Alarm(audioFile); } break; default: Error() << "unhandled alarm"; } if (a->hasTime()) { alarm.setStart(fromDate(a->time())); } else if (a->hasStartOffset()) { alarm.setRelativeStart(fromDuration(a->startOffset()), Start); } else if (a->hasEndOffset()) { alarm.setRelativeStart(fromDuration(a->endOffset()), End); } else { Error() << "alarm trigger is missing"; continue; } alarm.setDuration(fromDuration(a->snoozeTime()), a->repeatCount()); alarms.push_back(alarm); } i.setAlarms(alarms); } KCalCore::Event::Ptr toKCalCore(const Kolab::Event &event) { KCalCore::Event::Ptr e(new KCalCore::Event); setIncidence(*e, event); setTodoEvent(*e, event); if (event.end().isValid()) { e->setDtEnd(toDate(event.end())); } if (event.duration().isValid()) { e->setDuration(toDuration(event.duration())); } if (event.transparency()) { e->setTransparency(KCalCore::Event::Transparent); } else { e->setTransparency(KCalCore::Event::Opaque); } return e; } Event fromKCalCore(const KCalCore::Event &event) { Event e; getIncidence(e, event); getTodoEvent(e, event); if (event.hasEndDate()) { e.setEnd(fromDate(event.dtEnd())); } else if (event.hasDuration()) { e.setDuration(fromDuration(event.duration())); } if (event.transparency() == KCalCore::Event::Transparent) { e.setTransparency(true); } else { e.setTransparency(false); } return e; } KCalCore::Todo::Ptr toKCalCore ( const Todo &todo ) { KCalCore::Todo::Ptr e(new KCalCore::Todo); setIncidence(*e, todo); setTodoEvent(*e, todo); if (todo.due().isValid()) { e->setDtDue(toDate(todo.due())); } if (!todo.relatedTo().empty()) { e->setRelatedTo(Conversion::fromStdString(todo.relatedTo().front()), KCalCore::Incidence::RelTypeParent); if (todo.relatedTo().size() > 1) { Error() << "only one relation support but got multiple"; } } e->setPercentComplete(todo.percentComplete()); return e; } Todo fromKCalCore ( const KCalCore::Todo &todo ) { Todo t; getIncidence(t, todo); getTodoEvent(t, todo); t.setDue(fromDate(todo.dtDue(true))); t.setPercentComplete(todo.percentComplete()); const QString relatedTo = todo.relatedTo(KCalCore::Incidence::RelTypeParent); if (!relatedTo.isEmpty()) { std::vector relateds; relateds.push_back(Conversion::toStdString(relatedTo)); t.setRelatedTo(relateds); } return t; } KCalCore::Journal::Ptr toKCalCore ( const Journal &journal ) { KCalCore::Journal::Ptr e(new KCalCore::Journal); setIncidence(*e, journal); //TODO contacts return e; } Journal fromKCalCore ( const KCalCore::Journal &journal ) { Journal j; getIncidence(j, journal); //TODO contacts return j; } } } diff --git a/kolabformat/mimeobject.cpp b/kolabformat/mimeobject.cpp index a4403ef..d5b21e1 100644 --- a/kolabformat/mimeobject.cpp +++ b/kolabformat/mimeobject.cpp @@ -1,753 +1,753 @@ /* * Copyright (C) 2012 Sofia Balicka + * Copyright (C) 2014 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "mimeobject.h" #include "conversion/kcalconversion.h" #include "conversion/kolabconversion.h" #include "conversion/kabcconversion.h" #include "conversion/commonconversion.h" #include "kolabformat/kolabobject.h" #include "kolabformat/xmlobject.h" #include "kolabformat/errorhandler.h" #include "kolabformat/v2helpers.h" #include "mime/mimeutils.h" #include "libkolab-version.h" #include #include #include Q_DECLARE_METATYPE(Kolab::Event); Q_DECLARE_METATYPE(Kolab::Todo); Q_DECLARE_METATYPE(Kolab::Journal); Q_DECLARE_METATYPE(Kolab::Contact); Q_DECLARE_METATYPE(Kolab::DistList); Q_DECLARE_METATYPE(Kolab::Note); Q_DECLARE_METATYPE(Kolab::Freebusy); Q_DECLARE_METATYPE(Kolab::Configuration); static inline std::string eventKolabType() { return std::string(KOLAB_TYPE_EVENT); }; static inline std::string todoKolabType() { return std::string(KOLAB_TYPE_TASK); }; static inline std::string journalKolabType() { return std::string(KOLAB_TYPE_JOURNAL); }; static inline std::string contactKolabType() { return std::string(KOLAB_TYPE_CONTACT); }; static inline std::string distlistKolabType() { return std::string(KOLAB_TYPE_DISTLIST); } static inline std::string distlistKolabTypeCompat() { return std::string(KOLAB_TYPE_DISTLIST_V2); } static inline std::string noteKolabType() { return std::string(KOLAB_TYPE_NOTE); } static inline std::string configurationKolabType() { return std::string(KOLAB_TYPE_CONFIGURATION); } static inline std::string dictKolabType() { return std::string(KOLAB_TYPE_DICT); } static inline std::string freebusyKolabType() { return std::string(KOLAB_TYPE_FREEBUSY); } static inline std::string relationKolabType() { return std::string(KOLAB_TYPE_RELATION); } static inline std::string xCalMimeType() { return std::string(MIME_TYPE_XCAL); }; static inline std::string xCardMimeType() { return std::string(MIME_TYPE_XCARD); }; static inline std::string kolabMimeType() { return std::string(MIME_TYPE_KOLAB); }; static std::string getProductId(const std::string &pId) { if (pId.empty()) { return LIBKOLAB_LIB_VERSION_STRING; } return pId + " " + LIBKOLAB_LIB_VERSION_STRING; } namespace Kolab { static Kolab::ObjectType getObjectType(const std::string &type) { if (type == eventKolabType()) { return EventObject; } else if (type == todoKolabType()) { return TodoObject; } else if (type == journalKolabType()) { return JournalObject; } else if (type == contactKolabType()) { return ContactObject; } else if (type == distlistKolabType() || type == distlistKolabTypeCompat()) { return DistlistObject; } else if (type == noteKolabType()) { return NoteObject; } else if (type == freebusyKolabType()) { return FreebusyObject; } else if (boost::contains(type, dictKolabType())) { //Previous versions appended the language to the type return DictionaryConfigurationObject; } else if (type == relationKolabType()) { return RelationConfigurationObject; } Warning() << "Unknown object type: " << type; return Kolab::InvalidObject; } static QByteArray getTypeString(Kolab::ObjectType type) { switch (type) { case EventObject: return KOLAB_TYPE_EVENT; case TodoObject: return KOLAB_TYPE_TASK; case JournalObject: return KOLAB_TYPE_JOURNAL; case FreebusyObject: return KOLAB_TYPE_FREEBUSY; case ContactObject: return KOLAB_TYPE_CONTACT; case DistlistObject: return KOLAB_TYPE_DISTLIST; case NoteObject: return KOLAB_TYPE_NOTE; case DictionaryConfigurationObject: return KOLAB_TYPE_CONFIGURATION; case RelationConfigurationObject: return KOLAB_TYPE_RELATION; default: Critical() << "unknown type "<< type; } return QByteArray(); } static QByteArray getMimeType(Kolab::ObjectType type) { switch (type) { case EventObject: case TodoObject: case JournalObject: case FreebusyObject: return MIME_TYPE_XCAL; case ContactObject: case DistlistObject: return MIME_TYPE_XCARD; case NoteObject: case DictionaryConfigurationObject: case RelationConfigurationObject: return MIME_TYPE_KOLAB; default: Critical() << "unknown type "<< type; } return QByteArray(); } static Kolab::ObjectType detectType(const KMime::Message::Ptr &msg) { Q_FOREACH(const QByteArray &type, Mime::getContentMimeTypeList(msg)) { Kolab::ObjectType t = getObjectType(type.toStdString()); //works for v2 types if (t != InvalidObject) { return t; } } return InvalidObject; } static void printMessageDebugInfo(const KMime::Message::Ptr &msg) { //TODO replace by Debug stream for Mimemessage Debug() << "MessageId: " << msg->messageID()->asUnicodeString(); Debug() << "Subject: " << msg->subject()->asUnicodeString(); // Debug() << msg->encodedContent(); } //@cond PRIVATE class MIMEObject::Private { public: Private() : mObjectType(InvalidObject), mVersion(KolabV3), mOverrideObjectType(InvalidObject), mDoOverrideVersion(false) { } QVariant readKolabV2(const KMime::Message::Ptr &msg, Kolab::ObjectType objectType); QVariant readKolabV3(const KMime::Message::Ptr &msg, Kolab::ObjectType objectType); QVariant parseMimeMessage(const KMime::Message::Ptr &msg); QVariant parseMimeMessage(const std::string &s); ObjectType mObjectType; Version mVersion; ObjectType mOverrideObjectType; Version mOverrideVersion; bool mDoOverrideVersion; QVariant mObject; }; //@endcond static std::vector getAttachments(const std::vector &attachments, const KMime::Message::Ptr &msg) { std::vector allAttachments; foreach (const Kolab::Attachment &attachment, attachments) { if (!attachment.uri().empty()) { const Kolab::Attachment extracted = Mime::getAttachment(attachment.uri(), msg); if (extracted.isValid()) { allAttachments.push_back(extracted); } } else { allAttachments.push_back(attachment); } } return allAttachments; } static std::vector getAttachments(const QStringList &attachmentNames, const KMime::Message::Ptr &msg) { std::vector allAttachments; foreach (const QString &name, attachmentNames) { const Kolab::Attachment extracted = Mime::getAttachmentByName(name, msg); if (extracted.isValid()) { allAttachments.push_back(extracted); } } return allAttachments; } QVariant MIMEObject::Private::readKolabV2(const KMime::Message::Ptr &msg, Kolab::ObjectType objectType) { if (objectType == DictionaryConfigurationObject) { KMime::Content *xmlContent = Mime::findContentByType(msg, "application/xml"); if (!xmlContent) { Critical() << "no application/xml part found"; printMessageDebugInfo(msg); return InvalidObject; } const QByteArray &xmlData = xmlContent->decodedContent(); QString dictionaryLanguage; const QStringList entries = Kolab::readLegacyDictionaryConfiguration(xmlData, dictionaryLanguage); mObjectType = objectType; Kolab::Dictionary dictionary(Conversion::toStdString(dictionaryLanguage)); std::vector convertedEntries; foreach (const QString &value, entries) { convertedEntries.push_back(Conversion::toStdString(value)); } dictionary.setEntries(convertedEntries); return QVariant::fromValue(Kolab::Configuration(dictionary)); } KMime::Content *xmlContent = Mime::findContentByType(msg, getTypeString(objectType)); if (!xmlContent) { Critical() << "no part with type" << getTypeString(objectType) << " found"; printMessageDebugInfo(msg); return QVariant(); } const QByteArray &xmlData = xmlContent->decodedContent(); Q_ASSERT(!xmlData.isEmpty()); QVariant variant; switch (objectType) { case EventObject: { QStringList attachments; KCalCore::Event::Ptr kEvent = fromXML(xmlData, attachments); Kolab::Event event = Kolab::Conversion::fromKCalCore(*kEvent); event.setAttachments(getAttachments(attachments, msg)); variant = QVariant::fromValue(event); break; } case TodoObject: { QStringList attachments; KCalCore::Todo::Ptr kTodo = fromXML(xmlData, attachments); Kolab::Todo todo = Kolab::Conversion::fromKCalCore(*kTodo); todo.setAttachments(getAttachments(attachments, msg)); variant = QVariant::fromValue(todo); break; } case JournalObject: { QStringList attachments; KCalCore::Journal::Ptr kJournal = fromXML(xmlData, attachments); Kolab::Journal journal = Kolab::Conversion::fromKCalCore(*kJournal); journal.setAttachments(getAttachments(attachments, msg)); variant = QVariant::fromValue(journal); break; } case ContactObject: { KContacts::Addressee kContact= addresseeFromKolab(xmlData, msg); Kolab::Contact contact = Kolab::Conversion::fromKABC(kContact); variant = QVariant::fromValue(contact); break; } case DistlistObject: { KContacts::ContactGroup kContactGroup= contactGroupFromKolab(xmlData); Kolab::DistList distlist = Kolab::Conversion::fromKABC(kContactGroup); variant = QVariant::fromValue(distlist); break; } case NoteObject: { KMime::Message::Ptr kNote = noteFromKolab(xmlData, KDateTime(msg->date()->dateTime())); Kolab::Note note = Kolab::Conversion::fromNote(kNote); variant = QVariant::fromValue(note); break; } default: CRITICAL("no kolab object found "); break; } if (ErrorHandler::errorOccured()) { printMessageDebugInfo(msg); return QVariant(); } mObjectType = objectType; return variant; } QVariant MIMEObject::Private::readKolabV3(const KMime::Message::Ptr &msg, Kolab::ObjectType objectType) { KMime::Content * const xmlContent = Mime::findContentByType(msg, getMimeType(objectType)); if (!xmlContent) { Critical() << "no " << getMimeType(objectType) << " part found"; printMessageDebugInfo(msg); return InvalidObject; } const QByteArray &content = xmlContent->decodedContent(); const std::string xml = std::string(content.data(), content.size()); QVariant variant; switch (objectType) { case EventObject: { Kolab::Event event = Kolab::readEvent(xml, false); event.setAttachments(getAttachments(event.attachments(), msg)); variant = QVariant::fromValue(event); break; } case TodoObject: { Kolab::Todo todo = Kolab::readTodo(xml, false); todo.setAttachments(getAttachments(todo.attachments(), msg)); variant = QVariant::fromValue(todo); break; } case JournalObject: { Kolab::Journal journal = Kolab::readJournal(xml, false); journal.setAttachments(getAttachments(journal.attachments(), msg)); variant = QVariant::fromValue(journal); break; } case ContactObject: variant = QVariant::fromValue(Kolab::readContact(xml, false)); break; case DistlistObject: variant = QVariant::fromValue(Kolab::readDistlist(xml, false)); break; case NoteObject: variant = QVariant::fromValue(Kolab::readNote(xml, false)); break; case FreebusyObject: variant = QVariant::fromValue(Kolab::readFreebusy(xml, false)); break; case DictionaryConfigurationObject: case RelationConfigurationObject: variant = QVariant::fromValue(Kolab::readConfiguration(xml, false)); break; default: Critical() << "no kolab object found "; printMessageDebugInfo(msg); break; } - ErrorHandler::handleLibkolabxmlErrors(); if (ErrorHandler::errorOccured()) { printMessageDebugInfo(msg); return QVariant(); } mObjectType = objectType; return variant; } QVariant MIMEObject::Private::parseMimeMessage(const KMime::Message::Ptr &msg) { ErrorHandler::clearErrors(); mObjectType = InvalidObject; if (msg->contents().isEmpty()) { Critical() << "message has no contents (we likely failed to parse it correctly)"; printMessageDebugInfo(msg); return QVariant(); } Kolab::ObjectType objectType = InvalidObject; if (mOverrideObjectType == InvalidObject) { if (KMime::Headers::Base *xKolabHeader = msg->getHeaderByType(X_KOLAB_TYPE_HEADER)) { objectType = getObjectType(xKolabHeader->asUnicodeString().trimmed().toStdString()); } else { Warning() << "could not find the X-Kolab-Type Header, trying autodetection" ; //This works only for v2 messages atm. objectType = detectType(msg); } } else { objectType = mOverrideObjectType; } if (objectType == InvalidObject) { Critical() << "unable to detect object type"; printMessageDebugInfo(msg); return QVariant(); } if (!mDoOverrideVersion) { KMime::Headers::Base *xKolabVersion = msg->getHeaderByType(X_KOLAB_MIME_VERSION_HEADER); if (!xKolabVersion) { //For backwards compatibility to development versions, can be removed in future versions xKolabVersion = msg->getHeaderByType(X_KOLAB_MIME_VERSION_HEADER_COMPAT); } if (!xKolabVersion || xKolabVersion->asUnicodeString() == KOLAB_VERSION_V2) { mVersion = KolabV2; } else { if (xKolabVersion->asUnicodeString() != KOLAB_VERSION_V3) { //TODO version compatibility check? Warning() << "Kolab Version Header available but not on the same version as the implementation: " << xKolabVersion->asUnicodeString(); } mVersion = KolabV3; } } else { mVersion = mOverrideVersion; } if (mVersion == KolabV2) { return readKolabV2(msg, objectType); } return readKolabV3(msg, objectType); } QVariant MIMEObject::Private::parseMimeMessage(const std::string &s) { KMime::Message::Ptr msg(new KMime::Message); msg->setContent(QByteArray(s.c_str())); msg->parse(); return parseMimeMessage(msg); } MIMEObject::MIMEObject() : d(new MIMEObject::Private) { } void MIMEObject::setObjectType(ObjectType type) { d->mOverrideObjectType = type; } void MIMEObject::setVersion(Version version) { d->mOverrideVersion = version; d->mDoOverrideVersion = true; } static std::string createCid() { return QString::fromLatin1("cid:%1@%2").arg(QString::fromLatin1(KMime::uniqueString())).arg("kolab.resource.akonadi").toStdString(); } std::vector convertToReferences(const std::vector &attachments, std::vector &attachmentCids) { std::vector attachmentsWithReferences; Q_FOREACH (const Kolab::Attachment &a, attachments) { Kolab::Attachment attachment; attachment.setLabel(a.label()); const std::string cid = a.uri().empty() ? createCid() : a.uri(); attachmentCids.push_back(cid); attachment.setUri(cid, a.mimetype()); //Serialize the attachment as attachment with uri, referencing the created mime-part attachmentsWithReferences.push_back(attachment); } return attachmentsWithReferences; } template static T convertAttachmentsToReferences(const T &incidence, std::vector &attachmentCids) { T removedAttachments = incidence; removedAttachments.setAttachments(convertToReferences(incidence.attachments(), attachmentCids)); return removedAttachments; } static void addAttachments(KMime::Message::Ptr msg, const std::vector &attachments, std::vector &attachmentCids) { int index = 0; foreach (const Attachment &attachment, attachments) { const std::string data = attachment.data(); const std::string cid = attachmentCids.empty() ? attachment.uri() : attachmentCids.at(index); msg->addContent(Mime::createAttachmentPart(Mime::fromCid(QByteArray(cid.c_str())).toLatin1(), QByteArray(attachment.mimetype().c_str()), QString::fromStdString(attachment.label()), QByteArray::fromRawData(data.c_str(), data.size()))); index++; } } ObjectType MIMEObject::parseMessage(const std::string &msg) { d->mObject = d->parseMimeMessage(msg); return d->mObjectType; } ObjectType MIMEObject::getType() const { return d->mObjectType; } Version MIMEObject::getVersion() const { return d->mVersion; } Kolab::Event MIMEObject::getEvent() const { return d->mObject.value(); } Kolab::Todo MIMEObject::getTodo() const { return d->mObject.value(); } Kolab::Journal MIMEObject::getJournal() const { return d->mObject.value(); } Kolab::Note MIMEObject::getNote() const { return d->mObject.value(); } Kolab::Contact MIMEObject::getContact() const { return d->mObject.value(); } Kolab::DistList MIMEObject::getDistlist() const { return d->mObject.value(); } Kolab::Freebusy MIMEObject::getFreebusy() const { return d->mObject.value(); } Kolab::Configuration MIMEObject::getConfiguration() const { return d->mObject.value(); } std::string MIMEObject::writeEvent(const Event &event, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; std::vector attachmentCids; if (version == KolabV3) { const std::string xml = xmlObject.writeEvent(convertAttachmentsToReferences(event, attachmentCids), version, productId); msg = Mime::createMessage(xCalMimeType(), eventKolabType(), xml, true, productId, event.organizer().email(), event.organizer().name(), event.uid()); } else if (version == KolabV2) { const std::string xml = xmlObject.writeEvent(event, version, productId); msg = Mime::createMessage(eventKolabType(), eventKolabType(), xml, false, productId, event.organizer().email(), event.organizer().name(), event.uid()); } addAttachments(msg, event.attachments(), attachmentCids); msg->assemble(); return msg->encodedContent().data(); } Event MIMEObject::readEvent(const std::string &s) { return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeTodo(const Todo &todo, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; std::vector attachmentCids; if (version == KolabV3) { const std::string xml = xmlObject.writeTodo(convertAttachmentsToReferences(todo, attachmentCids), version, productId); msg = Mime::createMessage(xCalMimeType(), todoKolabType(), xml, true, productId, todo.organizer().email(), todo.organizer().name(), todo.uid()); } else if (version == KolabV2) { const std::string xml = xmlObject.writeTodo(todo, version, productId); msg = Mime::createMessage(todoKolabType(), todoKolabType(), xml, false, productId, todo.organizer().email(), todo.organizer().name(), todo.uid()); } addAttachments(msg, todo.attachments(), attachmentCids); msg->assemble(); return msg->encodedContent().data(); } Todo MIMEObject::readTodo(const std::string &s) { return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeJournal(const Journal &journal, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; std::vector attachmentCids; if (version == KolabV3) { const std::string xml = xmlObject.writeJournal(convertAttachmentsToReferences(journal, attachmentCids), version, productId); msg = Mime::createMessage(xCalMimeType(), journalKolabType(), xml, true, productId, std::string(), std::string(), journal.uid()); } else if (version == KolabV2) { const std::string xml = xmlObject.writeJournal(journal, version, productId); msg = Mime::createMessage(journalKolabType(), journalKolabType(), xml, false, productId, std::string(), std::string(), journal.uid()); } addAttachments(msg, journal.attachments(), attachmentCids); msg->assemble(); return msg->encodedContent().data(); } Journal MIMEObject::readJournal(const std::string &s){ return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeNote(const Note ¬e, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; std::vector attachmentCids; if (version == KolabV3) { const std::string xml = xmlObject.writeNote(convertAttachmentsToReferences(note, attachmentCids), version, productId); msg = Mime::createMessage(kolabMimeType(), noteKolabType(), xml, true, productId, std::string(), std::string(), note.uid()); } else if (version == KolabV2) { const std::string xml = xmlObject.writeNote(note, version, productId); msg = Mime::createMessage(noteKolabType(), noteKolabType(), xml, false, productId, std::string(), std::string(), note.uid()); } addAttachments(msg, note.attachments(), attachmentCids); msg->assemble(); return msg->encodedContent().data(); } Note MIMEObject::readNote(const std::string &s){ return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeContact(const Contact &contact, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; const std::string xml = xmlObject.writeContact(contact, version, productId); Email preferredEmail = !contact.emailAddresses().empty() ? contact.emailAddresses().at(contact.emailAddressPreferredIndex()) : Email(); QPair pair = Conversion::fromMailto(preferredEmail.address()); std::string name = pair.second; std::string email = pair.first; if (name.empty()) { name = contact.name(); } if (version == KolabV3) { msg = Mime::createMessage(xCardMimeType(), contactKolabType(), xml, true, productId, email, name, contact.uid()); } else if (version == KolabV2) { msg = Mime::createMessage(contactKolabType(), contactKolabType(), xml, false, productId, email, name, contact.uid()); } msg->assemble(); return msg->encodedContent().data(); } Contact MIMEObject::readContact(const std::string &s){ return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeDistlist(const DistList &distlist, Version version, const std::string &pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; const std::string xml = xmlObject.writeDistlist(distlist, version, productId); if (version == KolabV3) { msg = Mime::createMessage(xCardMimeType(), distlistKolabType(), xml, true, productId, std::string(), std::string(), distlist.uid()); } else if (version == KolabV2) { msg = Mime::createMessage(distlistKolabType(), distlistKolabType(), xml, false, productId, std::string(), std::string(), distlist.uid()); } msg->assemble(); return msg->encodedContent().data(); } DistList MIMEObject::readDistlist(const std::string &s) { return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeConfiguration(const Configuration &configuration, Version version, const std::string& pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; const std::string xml = xmlObject.writeConfiguration(configuration, version, productId); std::string kolabType; switch (configuration.type()) { case Kolab::Configuration::TypeDictionary: kolabType = dictKolabType(); break; case Kolab::Configuration::TypeRelation: kolabType = relationKolabType(); break; case Kolab::Configuration::TypeSnippet: kolabType = configurationKolabType(); break; case Kolab::Configuration::TypeFileDriver: kolabType = configurationKolabType(); break; case Kolab::Configuration::TypeCategoryColor: kolabType = configurationKolabType(); break; default: break; } if (version == KolabV3) { msg = Mime::createMessage(kolabMimeType(), kolabType, xml, true, productId, std::string(), std::string(), configuration.uid()); } else if (version == KolabV2) { Critical() << "Not available in KolabV2"; } msg->assemble(); return msg->encodedContent().data(); } Configuration MIMEObject::readConfiguration(const std::string &s) { return d->parseMimeMessage(s).value(); } std::string MIMEObject::writeFreebusy(const Freebusy &freebusy, Version version, const std::string& pId) { ErrorHandler::clearErrors(); const std::string productId = getProductId(pId); KMime::Message::Ptr msg; Kolab::XMLObject xmlObject; const std::string xml = xmlObject.writeFreebusy(freebusy, version, productId); if (version == KolabV3) { msg = Mime::createMessage(xCalMimeType(), freebusyKolabType(), xml, true, productId, std::string(), std::string(), freebusy.uid()); } else if (version == KolabV2) { Critical() << "Not available in KolabV2"; } msg->assemble(); return msg->encodedContent().data(); } Freebusy MIMEObject::readFreebusy(const std::string &s) { return d->parseMimeMessage(s).value(); } } diff --git a/kolabformat/mimeobject.h b/kolabformat/mimeobject.h index b6c6eb0..d6a5726 100644 --- a/kolabformat/mimeobject.h +++ b/kolabformat/mimeobject.h @@ -1,105 +1,106 @@ /* * Copyright (C) 2012 Sofia Balicka + * Copyright (C) 2014 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef MIMEOBJECT_H #define MIMEOBJECT_H #ifndef SWIG #include "kolab_export.h" #else /* No export/import SWIG interface files */ #define KOLAB_EXPORT #endif #include #include "kolabdefinitions.h" namespace Kolab { class KOLAB_EXPORT MIMEObject { public: MIMEObject(); ObjectType parseMessage(const std::string &msg); /** * Set to override the autodetected object type, before parsing the message. */ void setObjectType(ObjectType); /** * Set to override the autodetected version, before parsing the message. */ void setVersion(Version); /** * Returns the Object type of the parsed kolab object. */ ObjectType getType() const; /** * Returns the kolab-format version of the parsed kolab object. */ Version getVersion() const; Kolab::Event getEvent() const; Kolab::Todo getTodo() const; Kolab::Journal getJournal() const; Kolab::Note getNote() const; Kolab::Contact getContact() const; Kolab::DistList getDistlist() const; Kolab::Freebusy getFreebusy() const; Kolab::Configuration getConfiguration() const; std::string writeEvent(const Kolab::Event &event, Version version, const std::string &productId = std::string()); Kolab::Event readEvent(const std::string &s); std::string writeTodo(const Kolab::Todo &todo, Version version, const std::string &productId = std::string()); Kolab::Todo readTodo(const std::string &s); std::string writeJournal(const Kolab::Journal &journal, Version version, const std::string &productId = std::string()); Kolab::Journal readJournal(const std::string &s); std::string writeNote(const Kolab::Note ¬e, Version version, const std::string &productId = std::string()); Kolab::Note readNote(const std::string &s); std::string writeContact(const Kolab::Contact &contact, Version version, const std::string &productId = std::string()); Kolab::Contact readContact(const std::string &s); std::string writeDistlist(const Kolab::DistList &distlist, Version version, const std::string &productId = std::string()); Kolab::DistList readDistlist(const std::string &s); std::string writeFreebusy(const Kolab::Freebusy &freebusy, Version version, const std::string &productId = std::string()); Kolab::Freebusy readFreebusy(const std::string &s); std::string writeConfiguration(const Kolab::Configuration &freebusy, Version version, const std::string &productId = std::string()); Kolab::Configuration readConfiguration(const std::string &s); private: //@cond PRIVATE MIMEObject(const MIMEObject &other); MIMEObject &operator=(const MIMEObject &rhs); class Private; Private *const d; //@endcond }; } #endif diff --git a/tests/testhelpers.h b/tests/testhelpers.h index b0c00b7..f050ef3 100644 --- a/tests/testhelpers.h +++ b/tests/testhelpers.h @@ -1,324 +1,324 @@ /* * Copyright (C) 2012 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef TESTHELPERS_H #define TESTHELPERS_H #include #include #include #include #include #include #include #include #include Q_DECLARE_METATYPE(Kolab::Duration); Q_DECLARE_METATYPE(Kolab::cDateTime); Q_DECLARE_METATYPE(std::vector); Q_DECLARE_METATYPE(Kolab::Event); Q_DECLARE_METATYPE(std::vector); Q_DECLARE_METATYPE(Kolab::Todo); Q_DECLARE_METATYPE(Kolab::Journal); Q_DECLARE_METATYPE(Kolab::Contact); Q_DECLARE_METATYPE(Kolab::Period); Q_DECLARE_METATYPE(std::vector); Q_DECLARE_METATYPE(KCalCore::Event); Q_DECLARE_METATYPE(KCalCore::Todo); Q_DECLARE_METATYPE(KCalCore::Journal); namespace QTest { template<> char *toString(const Kolab::cDateTime &dt) { QByteArray ba = "Kolab::cDateTime("; ba += QByteArray::number(dt.year()) + ", " + QByteArray::number(dt.month())+ ", " + QByteArray::number(dt.day()) + ", "; ba += QByteArray::number(dt.hour()) + ", " + QByteArray::number(dt.minute()) + ", " + QByteArray::number(dt.second())+ ", "; ba += QString(dt.isUTC()?QString("UTC"):QString("TZ: "+QString::fromStdString(dt.timezone()))).toAscii(); ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const KDateTime &dt) { QByteArray ba = "KDateTime("; ba += dt.toString().toAscii(); ba += dt.timeZone().name(); ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const KCalCore::Attendee &at) { QByteArray ba = "Attendee("; ba += at.name().toAscii() + ", "; ba += at.email().toAscii() + ", "; ba += QString::number(at.role()) + ", "; ba += QString::number(at.status()) + ", "; ba += QString::number(at.RSVP()) + ", "; ba += at.delegate().toAscii() + ", "; ba += at.delegator().toAscii() + ", "; ba += at.uid().toAscii() + ", "; ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const QList &l) { QByteArray ba = "QList("; foreach(int i, l) { ba += QString::number(i) + ", "; } ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const QList &l) { QByteArray ba = "QList("; foreach(const KCalCore::RecurrenceRule::WDayPos &i, l) { ba += QString::number(i.pos()) + " "; ba += QString::number(i.day()) + ", "; } ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const KCalCore::DateList &l) { QByteArray ba = "KCalCore::DateList("; foreach(const QDate &i, l) { ba += i.toString(); } ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const KCalCore::DateTimeList &l) { QByteArray ba = "KCalCore::DateTimeList("; foreach(const KDateTime &i, l) { ba += toString(i); } ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const KCalCore::Recurrence &at) { - at.dump(); + // at.dump(); KCalCore::RecurrenceRule *r = at.defaultRRule(); QByteArray ba; if (!r) { ba += "Recurrence( )"; } else { Q_ASSERT(r); Q_ASSERT(at.rRules().size() == 1); ba += "Recurrence("; ba += QString::number(r->recurrenceType()) + "\n"; ba += QString::number(r->frequency()) + "\n"; ba += QString::number(r->duration()) + "\n"; ba += QByteArray(toString(r->startDt())) + "\n"; ba += QByteArray(toString(r->endDt())) + "\n"; ba += QByteArray(toString(r->bySeconds())) + "\n"; ba += QByteArray(toString(r->byMinutes())) + "\n"; ba += QByteArray(toString(r->byHours())) + "\n"; ba += QByteArray(toString(r->byDays())) + "\n"; ba += QByteArray(toString(r->byMonthDays())) + "\n"; ba += QByteArray(toString(r->byYearDays())) + "\n"; ba += QByteArray(toString(r->byMonths())) + "\n"; ba += ")\n"; ba += QByteArray(toString(at.exDates())) + "\n"; ba += QByteArray(toString(at.exDateTimes())) + "\n"; ba += QByteArray(toString(at.rDates())) + "\n"; ba += QByteArray(toString(at.rDateTimes())) + "\n"; } return qstrdup(ba.data()); } template<> char *toString(const Kolab::RecurrenceRule &at) { QByteArray ba; ba += "KolabRecurrenceRule("; ba += QString::number(at.weekStart()) + "\n"; ba += QString::number(at.frequency()) + "\n"; ba += QString::number(at.interval()) + "\n"; ba += QString::number(at.count()) + "\n"; ba += QByteArray(toString(at.end())) + "\n"; ba += QByteArray(toString(at.bysecond())) + "\n"; ba += QByteArray(toString(at.byminute())) + "\n"; ba += QByteArray(toString(at.byhour())) + "\n"; ba += QByteArray(toString(at.byday())) + "\n"; ba += QByteArray(toString(at.bymonthday())) + "\n"; ba += QByteArray(toString(at.byyearday())) + "\n"; ba += QByteArray(toString(at.byweekno())) + "\n"; ba += QByteArray(toString(at.bymonth())) + "\n"; ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const KCalCore::Duration &d) { QByteArray ba; ba += "KCalCore::Duration("; ba += QString::number(d.isDaily()) + ", "; ba += QString::number(d.value()) + " "; ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const Kolab::ContactReference &a) { QByteArray ba = "Kolab::ContactReference("; ba += QString::fromStdString(a.email()).toAscii()+ ", "; ba += QString::fromStdString(a.name()).toAscii()+ ", "; ba += QString::fromStdString(a.uid()).toAscii(); ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const std::vector &v) { QByteArray ba = "vector("; for (std::size_t i = 0; i < v.size(); i++) { ba += QByteArray(toString(v.at(i)))+ "\n"; } ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const Kolab::Attendee &a) { QByteArray ba = "Kolab::Attendee("; ba += QString::fromStdString(a.contact().email()).toAscii() + "\n"; ba += QString::fromStdString(a.contact().name()).toAscii()+ "\n"; ba += QByteArray::number(a.partStat()) + "\n"; ba += QByteArray::number(a.role()) + "\n"; ba += QByteArray::number(a.rsvp()) + "\n"; ba += QString::fromStdString(a.contact().uid()).toAscii()+"\n"; ba += QByteArray(toString(a.delegatedTo()))+"\n"; ba += QByteArray(toString(a.delegatedFrom()))+ "\n"; ba += QByteArray::number(a.cutype())+ "\n"; ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const std::vector &v) { QByteArray ba = "vector("; for (std::size_t i = 0; i < v.size(); i++) { ba += QByteArray(toString(v.at(i)))+ "\n"; ba += QByteArray("#######################")+ "\n"; } ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const Kolab::CustomProperty &a) { QByteArray ba = "Kolab::CustomProperty("; ba += QString::fromStdString(a.identifier).toAscii()+ ", "; ba += QString::fromStdString(a.value).toAscii(); ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const std::vector &v) { QByteArray ba = "vector("; for (std::size_t i = 0; i < v.size(); i++) { ba += QByteArray(toString(v.at(i)))+ "\n"; } ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const Kolab::Period &p) { QByteArray ba = "Kolab::Period("; ba += QByteArray(toString(p.start))+ "\n"; ba += QByteArray(toString(p.end))+ "\n"; ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const std::vector &v) { QByteArray ba = "vector("; for (std::size_t i = 0; i < v.size(); i++) { ba += QByteArray(toString(v.at(i)))+ "\n"; } ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const Kolab::FreebusyPeriod &p) { QByteArray ba = "Kolab::FreebusyPeriod("; ba += QString::number(p.type())+ "\n"; ba += QString::fromStdString(p.eventUid())+ "\n"; ba += QString::fromStdString(p.eventLocation())+ "\n"; ba += QString::fromStdString(p.eventSummary())+ "\n"; ba += QByteArray(toString(p.periods()))+ "\n"; ba += ")"; return qstrdup(ba.data()); } template<> char *toString(const Kolab::Duration &p) { QByteArray ba = "Kolab::Duration"; ba += p.isNegative() ? "-": "+"; ba += "("; ba += QString::number(p.weeks())+ ", "; ba += QString::number(p.days())+ ", "; ba += QString::number(p.hours())+ ", "; ba += QString::number(p.minutes())+ ", "; ba += QString::number(p.seconds()); ba += ")"; return qstrdup(ba.data()); } } #endif