diff --git a/src/containers/kolabcontainers.cpp b/src/containers/kolabcontainers.cpp index b883657..bf10646 100644 --- a/src/containers/kolabcontainers.cpp +++ b/src/containers/kolabcontainers.cpp @@ -1,771 +1,777 @@ /* * 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 "kolabcontainers.h" #include "incidence_p.h" namespace Kolab { struct cDateTime::Private { Private() : year(-1), month(-1), day(-1), hour(-1), minute(-1), second(-1), isUtc(false){} int year; int month; int day; int hour; int minute; int second; bool isUtc; std::string timezone; }; cDateTime::cDateTime() : d(new cDateTime::Private()) { } cDateTime::cDateTime(int year, int month, int day, int hour, int minute, int second, bool isUtc) : d(new cDateTime::Private()) { d->year = year; d->month = month; d->day = day; d->hour = hour; d->minute = minute; d->second = second; d->isUtc = isUtc; } cDateTime::cDateTime(const std::string& timezone, int year, int month, int day, int hour, int minute, int second) : d(new cDateTime::Private()) { d->year = year; d->month = month; d->day = day; d->hour = hour; d->minute = minute; d->second = second; d->timezone = timezone; } cDateTime::cDateTime(int year, int month, int day) : d(new cDateTime::Private()) { d->year = year; d->month = month; d->day = day; } cDateTime::cDateTime(const Kolab::cDateTime &other) : d(new cDateTime::Private()) { *d = *other.d; } cDateTime::~cDateTime() { } void cDateTime::operator=(const Kolab::cDateTime &other) { *d = *other.d; } bool cDateTime::operator==(const Kolab::cDateTime &other) const { if ( d->year == other.year() && d->month == other.month() && d->day == other.day() && d->hour == other.hour() && d->minute == other.minute() && d->second== other.second() && d->isUtc== other.isUTC() && d->timezone== other.timezone()) { return true; } return false; } int cDateTime::year() const { return d->year; } int cDateTime::month() const { return d->month; } int cDateTime::day() const { return d->day; } int cDateTime::hour() const { return d->hour; } int cDateTime::minute() const { return d->minute; } int cDateTime::second() const { return d->second; } bool cDateTime::isDateOnly() const { if ((d->hour < 0) && (d->minute < 0) && (d->second < 0)) { return true; } return false; } void cDateTime::setDate(int year, int month, int day) { d->year = year; d->month = month; d->day = day; } void cDateTime::setTime(int hour, int minute, int second) { d->hour = hour; d->minute = minute; d->second = second; } void cDateTime::setTimezone(const std::string &tz) { d->timezone = tz; } void cDateTime::setUTC(bool utc) { d->isUtc = utc; } bool cDateTime::isUTC() const { return d->isUtc; } std::string cDateTime::timezone() const { return d->timezone; } bool cDateTime::isValid() const { return (d->year >= 0 && d->month >= 0 && d->day >= 0); } struct RecurrenceRule::Private { Private() : freq(FreqNone), weekstart(Monday), count(-1), interval(1){} Frequency freq; Weekday weekstart; cDateTime end; int count; int interval; std::vector bysecond; std::vector byminute; std::vector byhour; std::vector byday; std::vector bymonthday; std::vector byyearday; std::vector byweekno; std::vector bymonth; }; RecurrenceRule::RecurrenceRule() : d(new RecurrenceRule::Private) { } RecurrenceRule::RecurrenceRule(const Kolab::RecurrenceRule &other) : d(new RecurrenceRule::Private) { *d = *other.d; } void RecurrenceRule::operator=(const Kolab::RecurrenceRule &other) { *d = *other.d; } bool RecurrenceRule::operator==(const Kolab::RecurrenceRule &other) const { if ( d->freq == other.frequency() && d->weekstart == other.weekStart() && d->end == other.end() && d->count == other.count() && d->interval == other.interval() && d->bysecond == other.bysecond() && d->byminute == other.byminute() && d->byhour == other.byhour() && d->byday == other.byday() && d->bymonthday == other.bymonthday() && d->byyearday == other.byyearday() && d->byweekno == other.byweekno() && d->bymonth == other.bymonth()) { return true; } return false; } RecurrenceRule::~RecurrenceRule() { } void RecurrenceRule::setFrequency(RecurrenceRule::Frequency freq) { d->freq = freq; } RecurrenceRule::Frequency RecurrenceRule::frequency() const { return d->freq; } void RecurrenceRule::setWeekStart(Kolab::Weekday weekstart) { d->weekstart = weekstart; } Kolab::Weekday RecurrenceRule::weekStart() const { return d->weekstart; } void RecurrenceRule::setEnd(const Kolab::cDateTime &end) { d->end = end; } cDateTime RecurrenceRule::end() const { return d->end; } void RecurrenceRule::setCount(int count) { d->count = count; } int RecurrenceRule::count() const { return d->count; } void RecurrenceRule::setInterval(int interval) { d->interval = interval; } int RecurrenceRule::interval() const { return d->interval; } void RecurrenceRule::setBysecond(const std::vector< int >&by) { d->bysecond = by; } std::vector< int > RecurrenceRule::bysecond() const { return d->bysecond; } void RecurrenceRule::setByminute(const std::vector< int > &by) { d->byminute = by; } std::vector< int > RecurrenceRule::byminute() const { return d->byminute; } void RecurrenceRule::setByhour(const std::vector< int > &by) { d->byhour = by; } std::vector< int > RecurrenceRule::byhour() const { return d->byhour; } void RecurrenceRule::setByday(const std::vector< DayPos > &by) { d->byday = by; } std::vector< DayPos > RecurrenceRule::byday() const { return d->byday; } void RecurrenceRule::setBymonthday(const std::vector< int > &by) { d->bymonthday = by; } std::vector< int > RecurrenceRule::bymonthday() const { return d->bymonthday; } void RecurrenceRule::setByyearday(const std::vector< int > &by) { d->byyearday = by; } std::vector< int > RecurrenceRule::byyearday() const { return d->byyearday; } void RecurrenceRule::setByweekno(const std::vector< int > &by) { d->byweekno = by; } std::vector< int > RecurrenceRule::byweekno() const { return d->byweekno; } void RecurrenceRule::setBymonth(const std::vector< int > &by) { d->bymonth = by; } std::vector< int > RecurrenceRule::bymonth() const { return d->bymonth; } bool RecurrenceRule::isValid() const { if (d->freq == FreqNone) { return false; } return true; } struct Attendee::Private { Private() : partStat(PartNeedsAction), role(Required), rsvp(false), cutype(CutypeIndividual) {} ContactReference contact; PartStatus partStat; Role role; bool rsvp; std::vector delegatedTo; std::vector delegatedFrom; Cutype cutype; }; Attendee::Attendee() : d(new Attendee::Private) { } Attendee::Attendee(const ContactReference& contact) : d(new Attendee::Private) { d->contact = contact; } Attendee::Attendee(const Kolab::Attendee &other) : d(new Attendee::Private) { *d = *other.d; } void Attendee::operator=(const Kolab::Attendee &other) { *d = *other.d; } Attendee::~Attendee() { } bool Attendee::operator==(const Kolab::Attendee &other) const { if ( d->contact == other.contact() && d->partStat == other.partStat() && d->role == other.role() && d->rsvp == other.rsvp() && d->delegatedTo == other.delegatedTo() && d->delegatedFrom == other.delegatedFrom() && d->cutype == other.cutype() ) { return true; } return false; } bool Attendee::isValid() const { return d->contact.isValid(); } void Attendee::setContact(const ContactReference &c) { d->contact = c; } ContactReference Attendee::contact() const { return d->contact; } void Attendee::setPartStat(PartStatus partStat) { d->partStat = partStat; } PartStatus Attendee::partStat() const { return d->partStat; } void Attendee::setRole(Role role) { d->role = role; } Role Attendee::role() const { return d->role; } void Attendee::setRSVP(bool rsvp) { d->rsvp = rsvp; } bool Attendee::rsvp() const { return d->rsvp; } void Attendee::setDelegatedTo(const std::vector< ContactReference > &del) { d->delegatedTo = del; } std::vector< ContactReference > Attendee::delegatedTo() const { return d->delegatedTo; } void Attendee::setDelegatedFrom(const std::vector< ContactReference > &del) { d->delegatedFrom = del; } std::vector< ContactReference > Attendee::delegatedFrom() const { return d->delegatedFrom; } void Attendee::setCutype(Cutype type) { d->cutype = type; } Cutype Attendee::cutype() const { return d->cutype; } struct Attachment::Private { std::string uri; std::string data; std::string mimetype; std::string label; bool isValid; }; Attachment::Attachment() : d(new Attachment::Private) { d->isValid = false; } Attachment::Attachment(const Kolab::Attachment &other) : d(new Attachment::Private) { *d = *other.d; } void Attachment::operator=(const Kolab::Attachment &other) { *d = *other.d; } Attachment::~Attachment() { } bool Attachment::operator==(const Kolab::Attachment &other) const { return ( d->uri == other.uri() && d->data == other.data() && d->label == other.label() && d->mimetype == other.mimetype() ); } void Attachment::setUri(const std::string &uri, const std::string& mimetype) { d->isValid = true; d->uri = uri; d->mimetype = mimetype; } std::string Attachment::uri() const { return d->uri; } std::string Attachment::mimetype() const { return d->mimetype; } void Attachment::setLabel(const std::string &label) { d->label = label; } std::string Attachment::label() const { return d->label; } void Attachment::setData(const std::string &data, const std::string& mimetype) { d->isValid = true; d->data = data; d->mimetype = mimetype; } std::string Attachment::data() const { return d->data; } bool Attachment::isValid() const { return d->isValid; } struct Alarm::Private { Private(): relativeTo(Start), numrepeat(0), type(Alarm::InvalidAlarm) {} std::string text; Attachment audioFile; std::string summary; std::vector attendees; cDateTime start; Duration relativeDuration; Relative relativeTo; Duration duration; int numrepeat; Type type; }; Alarm::Alarm() : d(new Alarm::Private) { } +Alarm::Alarm(Alarm::Type type) +: d(new Alarm::Private) +{ + d->type = AudioAlarm; +} + Alarm::Alarm(const std::string &text) : d(new Alarm::Private) { d->text = text; d->type = DisplayAlarm; } Alarm::Alarm(const Kolab::Attachment& audio) : d(new Alarm::Private) { d->audioFile = audio; d->type = AudioAlarm; } Alarm::Alarm(const std::string& summary, const std::string& description, const std::vector attendees) : d(new Alarm::Private) { d->summary = summary; d->text = description; d->attendees = attendees; d->type = EMailAlarm; } Alarm::Alarm(const Kolab::Alarm &other) : d(new Alarm::Private) { *d = *other.d; } void Alarm::operator=(const Kolab::Alarm &other) { *d = *other.d; } Alarm::~Alarm() { } bool Alarm::operator==(const Kolab::Alarm &other) const { return ( d->text == other.description() && d->text == other.description() && d->audioFile == other.audioFile() && d->summary == other.summary() && d->attendees == other.attendees() && d->start == other.start() && d->relativeDuration == other.relativeStart() && d->relativeTo == other.relativeTo() && d->duration == other.duration() && d->numrepeat == other.numrepeat() ); } std::string Alarm::text() const { return d->text; } Attachment Alarm::audioFile() const { return d->audioFile; } std::string Alarm::summary() const { return d->summary; } std::string Alarm::description() const { return d->text; } std::vector Alarm::attendees() const { return d->attendees; } void Alarm::setStart(const Kolab::cDateTime &start) { d->start = start; } cDateTime Alarm::start() const { return d->start; } void Alarm::setRelativeStart(const Kolab::Duration &duration, Relative relativeTo) { d->relativeDuration = duration; d->relativeTo = relativeTo; } Duration Alarm::relativeStart() const { return d->relativeDuration; } Relative Alarm::relativeTo() const { return d->relativeTo; } void Alarm::setDuration(const Kolab::Duration &duration, int numrepeat) { d->numrepeat = numrepeat; d->duration = duration; } Duration Alarm::duration() const { return d->duration; } int Alarm::numrepeat() const { return d->numrepeat; } Alarm::Type Alarm::type() const { return d->type; } }//Namespace diff --git a/src/containers/kolabcontainers.h b/src/containers/kolabcontainers.h index ae25039..31250ae 100644 --- a/src/containers/kolabcontainers.h +++ b/src/containers/kolabcontainers.h @@ -1,416 +1,417 @@ /* * 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 . */ #ifndef KOLAB_CONTAINERS_H #define KOLAB_CONTAINERS_H #include #include #include namespace Kolab { /** * - months: 1-12 * - days: 1-31 * - hour: 0-23 * - minute: 0-59 * - second: 0-59 */ class cDateTime { public: cDateTime(); cDateTime(int year, int month, int day, int hour, int minute, int second, bool isUtc=false); cDateTime(const std::string &timezone, int year, int month, int day, int hour, int minute, int second); cDateTime(int year, int month, int day); ~cDateTime(); cDateTime(const cDateTime &); void operator=(const cDateTime &); bool operator==(const cDateTime &) const; void setDate(int year, int month, int day); int year() const; int month() const; int day() const; bool isDateOnly() const; void setTime(int hour, int minute, int second); int hour() const; int minute() const; int second() const; void setUTC(bool); bool isUTC() const; void setTimezone(const std::string &); std::string timezone() const; bool isValid() const; private: struct Private; boost::scoped_ptr d; }; enum Classification { ClassPublic, ClassPrivate, ClassConfidential }; enum Status { StatusUndefined, StatusNeedsAction, StatusCompleted, StatusInProcess, StatusCancelled, StatusTentative, StatusConfirmed, StatusDraft, StatusFinal }; enum Weekday { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }; struct DayPos { DayPos(): mIsValid(false){} DayPos(int occurrence, Weekday weekday): mOccurrence(occurrence), mWeekday(weekday), mIsValid(true){} bool operator==(const DayPos &other) const { return mOccurrence == other.mOccurrence && mWeekday == other.mWeekday; } int occurence() const { return mOccurrence; } Weekday weekday() const { return mWeekday; } bool isValid() { return mIsValid; } private: int mOccurrence; Weekday mWeekday; bool mIsValid; }; class Attachment { public: Attachment(); Attachment(const Kolab::Attachment &); ~Attachment(); void operator=(const Attachment &); bool operator==(const Attachment &) const; void setUri(const std::string &uri, const std::string &mimetype); std::string uri() const; ///Un-encoded binary content, Implies embedded, will be encoded void setData(const std::string &, const std::string &mimetype); ///Decoded binary content. std::string data() const; //TODO add possibility to set already encoded data and uri to be embedded as performance/convenience improvement? // ///Base64 encoded binary content, Implies embedded // void setEncodedData(const std::string &, const std::string &mimetype); std::string mimetype() const; ///User visible label void setLabel(const std::string &); std::string label() const; bool isValid() const; private: struct Private; boost::scoped_ptr d; }; enum Relative { Start, End }; struct Duration { Duration():mWeeks(0), mDays(0), mHours(0), mMinutes(0), mSeconds(0), mNegative(false), valid(false){} Duration(int weeks, bool negative = false): mWeeks(weeks), mDays(0), mHours(0), mMinutes(0), mSeconds(0), mNegative(negative), valid(true){} Duration(int days, int hours, int minutes, int seconds, bool negative = false): mWeeks(0), mDays(days), mHours(hours), mMinutes(minutes), mSeconds(seconds), mNegative(negative), valid(true){} bool operator==(const Duration &other) const{ return (/*mWeeks == other.mWeeks && mDays == other.mDays && mHours == other.mHours && mMinutes == other.mMinutes && mSeconds == other.mSeconds && mNegative == other.mNegative &&*/ ( ((((mWeeks * 7 + mDays) * 24 + mHours) * 60 + mMinutes) * 60 + mSeconds) == ((((other.mWeeks * 7 + other.mDays) * 24 + other.mHours) * 60 + other.mMinutes) * 60 + other.mSeconds) ) && valid == other.valid );} int weeks() const { return mWeeks; } int days() const { return mDays; } int hours() const { return mHours; } int minutes() const { return mMinutes; } int seconds() const { return mSeconds; } bool isNegative() const { return mNegative; } bool isValid() const { return valid; } private: int mWeeks; int mDays; int mHours; int mMinutes; int mSeconds; bool mNegative; bool valid; }; struct ContactReference { enum ReferenceType { Invalid, EmailReference, UidReference, EmailAndUidReference }; ContactReference(): mType(Invalid) {} ///For xCal ContactReference(const std::string &email, const std::string &name = std::string(), const std::string &uid = std::string()): mType(EmailAndUidReference), mEmail(email), mUid(uid), mName(name) {} ///For xCard ContactReference(ReferenceType type, const std::string &emailOrUID, const std::string &name = std::string()): mType(type), mName(name) { if (type == EmailReference) { mEmail = emailOrUID; } else { mUid = emailOrUID; } } bool operator==(const ContactReference &other) const { return mEmail == other.mEmail && mName == other.mName && mUid == other.mUid; } bool isValid() const { return mType != Invalid; } void setName(const std::string &name) { mName = name; } std::string email() const { return mEmail; } std::string uid() const { return mUid; } std::string name() const { return mName; } ReferenceType type() const { return mType; } private: ReferenceType mType; std::string mEmail; std::string mUid; std::string mName; }; class Alarm { public: enum Type { InvalidAlarm, EMailAlarm, DisplayAlarm, AudioAlarm }; Alarm(); + Alarm(Type); Alarm(const Alarm &); ~Alarm(); void operator=(const Alarm &); bool operator==(const Alarm &other) const; ///EMail Alarm, @param attendees accepts only email + name and no uid Alarm(const std::string &summary, const std::string &description, const std::vector attendees); std::string summary() const; std::string description() const; std::vector attendees() const; ///Display Alarm Alarm(const std::string &text); std::string text() const; ///Audio Alarm Alarm(const Attachment &audio); Attachment audioFile() const; void setRelativeStart(const Duration &, Relative); Duration relativeStart() const; Relative relativeTo() const; void setStart(const cDateTime &); cDateTime start() const; void setDuration(const Duration &, int numrepeat); Duration duration() const; int numrepeat() const; Type type() const; private: struct Private; boost::scoped_ptr d; }; class RecurrenceRule { public: RecurrenceRule(); RecurrenceRule(const RecurrenceRule &); ~RecurrenceRule(); void operator=(const RecurrenceRule &); bool operator==(const RecurrenceRule &other) const; enum Frequency { FreqNone, Yearly, Monthly, Weekly, Daily, Hourly, Minutely, Secondly }; void setFrequency(Frequency); Frequency frequency() const; void setWeekStart(Weekday); Weekday weekStart() const; void setEnd(const cDateTime &); cDateTime end() const; void setCount(int count); int count() const; void setInterval(int); int interval() const; void setBysecond(const std::vector &); std::vector bysecond() const; void setByminute(const std::vector &); std::vector byminute() const; void setByhour(const std::vector &); std::vector byhour() const; void setByday(const std::vector &); std::vector byday() const; void setBymonthday(const std::vector &); std::vector bymonthday() const; void setByyearday(const std::vector &); std::vector byyearday() const; void setByweekno(const std::vector &); std::vector byweekno() const; void setBymonth(const std::vector &); std::vector bymonth() const; bool isValid() const; private: struct Private; boost::scoped_ptr d; }; enum PartStatus { PartNeedsAction, PartAccepted, PartDeclined, PartTentative, PartDelegated, PartInProcess, PartCompleted }; enum Role { Required, Chair, Optional, NonParticipant }; enum Cutype { CutypeUnknown, CutypeGroup, CutypeIndividual, CutypeResource, CutypeRoom }; class Attendee { public: Attendee(); Attendee(const ContactReference &contact); Attendee(const Attendee &); ~Attendee(); void operator=(const Attendee &); bool operator==(const Attendee &) const; bool isValid() const; void setContact(const ContactReference &); ContactReference contact() const; void setPartStat(PartStatus); PartStatus partStat() const; void setRole(Role); Role role() const; void setRSVP(bool); bool rsvp() const; void setDelegatedTo(const std::vector &); std::vector delegatedTo() const; void setDelegatedFrom(const std::vector &); std::vector delegatedFrom() const; void setCutype(Cutype); Cutype cutype() const; private: struct Private; boost::scoped_ptr d; }; struct CustomProperty { CustomProperty(){} CustomProperty(const std::string &i, const std::string &v) : identifier(i), value(v) {} bool operator==(const CustomProperty &other) const{ return (identifier == other.identifier && value == other.value);} std::string identifier; std::string value; }; //WARNING this function copies the vector and does not modify it template std::vector operator<< ( std::vector v, const T &s) { v.push_back(s); return v; } } #endif diff --git a/src/xcalconversions.h b/src/xcalconversions.h index 92309a9..b62a739 100644 --- a/src/xcalconversions.h +++ b/src/xcalconversions.h @@ -1,2022 +1,2025 @@ /* * 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 . */ #ifndef XCALCONVERSIONS_H #define XCALCONVERSIONS_H #include "global_definitions.h" #include "libkolabxml-version.h" #include #include #include #include #include #include #include #include #include #include #include "kolabcontainers.h" #include "kolabtodo.h" #include "kolabevent.h" #include "kolabjournal.h" #include #include "utils.h" #include "base64.h" #include "shared_conversions.h" namespace Kolab { namespace XCAL { const char* const XCAL_VERSION = "2.0"; const char* const XCAL_NAMESPACE = "urn:ietf:params:xml:ns:icalendar-2.0"; const char* const TZ_PREFIX = "/kolab.org/"; const char* const THISANDFUTURE = "THISANDFUTURE"; const char* const BASE64 = "BASE64"; const char* const NEEDSACTION = "NEEDS-ACTION"; const char* const COMPLETED = "COMPLETED"; const char* const COMPLETED_COMPAT = "OPAQUE"; const char* const INPROCESS = "IN-PROCESS"; const char* const CANCELLED = "CANCELLED"; const char* const TENTATIVE = "TENTATIVE"; const char* const CONFIRMED = "CONFIRMED"; const char* const DRAFT = "DRAFT"; const char* const FINAL = "FINAL"; const char* const CONFIDENTIAL = "CONFIDENTIAL"; const char* const PRIVATE = "PRIVATE"; const char* const PUBLIC = "PUBLIC"; const char* const PARTACCEPTED = "ACCEPTED"; const char* const PARTDECLINED = "DECLINED"; const char* const PARTDELEGATED = "DELEGATED"; const char* const PARTNEEDSACTION = "NEEDS-ACTION"; const char* const PARTTENTATIVE = "TENTATIVE"; const char* const PARTINPROCESS = "IN-PROCESS"; const char* const PARTCOMPLETED = "COMPLETED"; const char* const CHAIR = "CHAIR"; const char* const NONPARTICIPANT = "NON-PARTICIPANT"; const char* const OPTIONAL = "OPT-PARTICIPANT"; const char* const REQUIRED = "REQ-PARTICIPANT"; const char* const DISPLAYALARM = "DISPLAY"; const char* const EMAILALARM = "EMAIL"; const char* const AUDIOALARM = "AUDIO"; const char* const TRANSPARENT = "TRANSPARENT"; const char* const OPAQUE = "OPAQUE"; const char* const MO = "MO"; const char* const TU = "TU"; const char* const WE = "WE"; const char* const TH = "TH"; const char* const FR = "FR"; const char* const SA = "SA"; const char* const SU = "SU"; const char* const GROUP = "GROUP"; const char* const INDIVIDUAL = "INDIVIDUAL"; const char* const RESOURCE = "RESOURCE"; const char* const UNKNOWN = "UNKNOWN"; const char* const ROOM = "ROOM"; //Alarms const char* const START = "START"; const char* const END = "END"; //Freebusy const char* const BUSY = "BUSY"; const char* const BUSY_TENTATIVE = "BUSY-TENTATIVE"; const char* const BUSY_OUTOFOFFICE = "X-OUT-OF-OFFICE"; using namespace Kolab::Utils; using namespace Kolab::Shared; //=== Generic Conversions === int toInt(const icalendar_2_0::IntegerPropertyType &prop) { return convertToInt(prop.integer()); } std::vector toStringList(const icalendar_2_0::TextListPropertyType &s) { std::vector d; std::copy(s.text().begin(), s.text().end(), std::back_inserter(d)); return d; } template std::auto_ptr fromStringList(const std::vector &list) { std::auto_ptr ptr(new T()); std::copy(list.begin(), list.end(), std::back_inserter(ptr->text())); return ptr; } //TODO doesn't seem very useful after all, remove std::string toString(const icalendar_2_0::TextPropertyType &s) { return s.text(); } std::string fromDayPos(const Kolab::DayPos &d) { std::string s; if (d.occurence() != 0) { s.append(boost::lexical_cast(d.occurence())); } switch (d.weekday()) { case Kolab::Monday: s.append(MO); break; case Kolab::Tuesday: s.append(TU); break; case Kolab::Wednesday: s.append(WE); break; case Kolab::Thursday: s.append(TH); break; case Kolab::Friday: s.append(FR); break; case Kolab::Saturday: s.append(SA); break; case Kolab::Sunday: s.append(SU); break; } return s; } Kolab::DayPos toDayPos(const std::string &s) { std::string number; bool gotOccurrence = false; int occurrence = 0; for (std::string::const_iterator it = s.begin(); it != s.end(); it++) { switch(*it) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '+': case '-': number.push_back(*it); break; default: if (!gotOccurrence && !number.empty()) { try { occurrence = boost::lexical_cast(number); } catch(boost::bad_lexical_cast &) { ERROR("failed to convert: " + number); return DayPos(); } number.clear(); } gotOccurrence = true; number.push_back(*it); break; } } if (number == MO) { return DayPos(occurrence, Kolab::Monday); } else if (number == TU) { return DayPos(occurrence, Kolab::Tuesday); } else if (number == WE) { return DayPos(occurrence, Kolab::Wednesday); } else if (number == TH) { return DayPos(occurrence, Kolab::Thursday); } else if (number == FR) { return DayPos(occurrence, Kolab::Friday); } else if (number == SA) { return DayPos(occurrence, Kolab::Saturday); } else if (number == SU) { return DayPos(occurrence, Kolab::Sunday); } return DayPos(); } std::string fromDuration(const Kolab::Duration &d) { std::string s; if (!d.isValid()) { return s; } if (d.isNegative()) { s.push_back('-'); } s.push_back('P'); try { if (d.weeks() > 0) { s.append(boost::lexical_cast(d.weeks())); s.push_back('W'); } if (d.days() > 0) { s.append(boost::lexical_cast(d.days())); s.push_back('D'); } if (d.hours() > 0 || d.minutes() > 0 || d.seconds() > 0) { s.push_back('T'); if (d.hours() > 0) { s.append(boost::lexical_cast(d.hours())); s.push_back('H'); } if (d.minutes() > 0) { s.append(boost::lexical_cast(d.minutes())); s.push_back('M'); } if (d.seconds() > 0) { s.append(boost::lexical_cast(d.seconds())); s.push_back('S'); } } } catch(boost::bad_lexical_cast &) { ERROR("failed to convert duration"); return std::string(); } return s; } Kolab::Duration toDuration(const icalendar_2_0::DurationValueType &d) { int weeks = 0; int days = 0; int hours = 0; int minutes = 0; int seconds = 0; bool negative = false; std::string number; for (std::string::const_iterator it = d.begin(); it != d.end(); it++) { switch(*it) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': number.push_back(*it); break; case 'H': try { hours = boost::lexical_cast(number); } catch(boost::bad_lexical_cast &) { ERROR("failed to convert: " + number); return Duration(); } number.clear(); break; case 'M': try { minutes = boost::lexical_cast(number); } catch(boost::bad_lexical_cast &) { ERROR("failed to convert: " + number); return Duration(); } number.clear(); break; case 'S': try { seconds = boost::lexical_cast(number); } catch(boost::bad_lexical_cast &) { ERROR("failed to convert: " + number); return Duration(); } number.clear(); break; case 'T': break; case 'W': try { weeks = boost::lexical_cast(number); } catch(boost::bad_lexical_cast &) { ERROR("failed to convert: " + number); return Duration(); } return Duration(weeks, negative); case 'D': try { days = boost::lexical_cast(number); } catch(boost::bad_lexical_cast &) { ERROR("failed to convert: " + number); return Duration(); } number.clear(); break; case '+': break; case '-': negative = true; break; case 'P': break; default: { std::ostringstream s; s << "failed to convert duration: " << *it; ERROR(s.str()); return Duration(); } } } return Duration(days, hours, minutes, seconds, negative); } template T fromContactReference(const Kolab::ContactReference &c) { T organizer(toMailto(c.email())); typename T::parameters_type p; if (!c.name().empty()) { icalendar_2_0::CnParamType name(c.name()); p.baseParameter().push_back(name); } if (!c.uid().empty()) { icalendar_2_0::DirParamType dir(toURN(c.uid())); p.baseParameter().push_back(dir); } organizer.parameters(p); return organizer; } Kolab::ContactReference toContactReference(const icalendar_2_0::CalAddressPropertyType &cal) { const std::string &email = fromMailto(cal.cal_address());; std::string name; std::string uid; if (cal.parameters()) { for (icalendar_2_0::ArrayOfParameters::baseParameter_const_iterator it((*cal.parameters()).baseParameter().begin()); it != (*cal.parameters()).baseParameter().end(); it++) { if (const icalendar_2_0::CnParamType * tz = dynamic_cast (&*it)) { name = tz->text(); continue; } if (const icalendar_2_0::DirParamType * tz = dynamic_cast (&*it)) { uid = fromURN(tz->uri()); continue; } } } return Kolab::ContactReference(email, name, uid); } template Kolab::Attachment toAttachment(T aProp) { Kolab::Attachment a; std::string mimetype; if (aProp.parameters()) { const icalendar_2_0::AttachPropType ::parameters_type ¶meters = *aProp.parameters(); for (icalendar_2_0::AttachPropType::parameters_type::baseParameter_const_iterator it(parameters.baseParameter().begin()); it != parameters.baseParameter().end(); it++) { if (const icalendar_2_0::FmttypeParamType *p = dynamic_cast (&*it)) { mimetype = p->text(); } if (const icalendar_2_0::EncodingParamType *p = dynamic_cast (&*it)) { if (p->text() != BASE64) { ERROR("wrong encoding"); return Kolab::Attachment(); } } if (const icalendar_2_0::XlabelParamType *p = dynamic_cast (&*it)) { a.setLabel(p->text()); } } } if (aProp.uri()) { a.setUri(*aProp.uri(), mimetype); } else if (aProp.binary()) { a.setData(base64_decode(*aProp.binary()), mimetype); } else { ERROR("no uri and no data available"); } return a; } icalendar_2_0::AttachPropType fromAttachment(const Kolab::Attachment &a) { icalendar_2_0::AttachPropType attachment; icalendar_2_0::AttachPropType::parameters_type p; p.baseParameter().push_back(icalendar_2_0::FmttypeParamType(a.mimetype())); if (!a.label().empty()) { p.baseParameter().push_back(icalendar_2_0::XlabelParamType(a.label())); } if (!a.uri().empty()) { attachment.uri(a.uri()); } else if (!a.data().empty()) { attachment.binary(base64_encode(reinterpret_cast(a.data().c_str()), static_cast(a.data().length()))); p.baseParameter().push_back(icalendar_2_0::EncodingParamType(BASE64)); } else { ERROR("no uri and no data"); } attachment.parameters(p); return attachment; } //==== cDateTime ==== std::string getTimezone(const icalendar_2_0::ArrayOfParameters ¶meters) { for (icalendar_2_0::DateDatetimePropertyType::parameters_type::baseParameter_const_iterator it(parameters.baseParameter().begin()); it != parameters.baseParameter().end(); it++) { if (const icalendar_2_0::TzidParamType* tz = dynamic_cast (&*it)) { std::string tzid = tz->text(); if (tzid.find(TZ_PREFIX) != std::string::npos) { tzid.erase(0, strlen(TZ_PREFIX)); } else { WARNING("/kolab.org/ timezone prefix is missing"); } return tzid; } } return std::string(); } cDateTimePtr toDate(const icalendar_2_0::DateDatetimePropertyType &dtProperty) { cDateTimePtr date; if (dtProperty.date_time()) { date = Shared::toDate(*dtProperty.date_time()); } else if (dtProperty.date()) { date = Shared::toDate(*dtProperty.date()); } if (dtProperty.parameters()) { const std::string &tzid = getTimezone(*dtProperty.parameters()); if (tzid.size()) { date->setTimezone(tzid); } } return date; } cDateTimePtr toDate(const icalendar_2_0::UtcDatetimePropertyType &dtProperty) { cDateTimePtr date; if (dtProperty.date_time()) { date = Shared::toDate(*dtProperty.date_time()); } else { //The utc-date-time element shouldn't even exist date = cDateTimePtr(new cDateTime()); ERROR("This element shouldn't even be existing"); //TODO Implement anyways? return date; } date->setUTC(true); return date; } template std::auto_ptr fromDate(const cDateTime &dt) { std::auto_ptr ptr(new I); if (dt.isDateOnly()) { ptr->date(Shared::fromDate(dt)); } else { ptr->date_time(Shared::fromDateTime(dt)); const std::string &timezone = dt.timezone(); if (timezone.size() != 0) { std::string tz(TZ_PREFIX); tz.append(timezone); icalendar_2_0::TzidParamType tzidParam(tz); icalendar_2_0::ArrayOfParameters parameters; parameters.baseParameter().push_back(tzidParam); ptr->parameters(parameters); } } return ptr; } template std::vector toDateTimeList(I datelistProperty) { std::vector list; std::string tzid; if (datelistProperty.parameters()) { tzid = getTimezone(*datelistProperty.parameters()); } if (!datelistProperty.date().empty()) { BOOST_FOREACH(const xml_schema::date &d, datelistProperty.date()) { list.push_back(*Shared::toDate(d)); } } else if (!datelistProperty.date_time().empty()) { BOOST_FOREACH(const xml_schema::date_time &d, datelistProperty.date_time()) { cDateTimePtr date = Shared::toDate(d); if (tzid.size()) { date->setTimezone(tzid); } list.push_back(*date); } } return list; } template std::auto_ptr fromDateTimeList(const std::vector &dtlist) { std::auto_ptr ptr(new I); BOOST_FOREACH(const cDateTime &dt, dtlist) { if (dt.isDateOnly()) { ptr->date().push_back(Shared::fromDate(dt)); } else { ptr->date_time().push_back(Shared::fromDateTime(dt)); } //TODO handle utc } if (!dtlist.empty() && !dtlist.at(0).timezone().empty()) { const std::string &timezone = dtlist.at(0).timezone(); if (timezone.size() != 0) { std::string tz(TZ_PREFIX); tz.append(timezone); icalendar_2_0::TzidParamType tzidParam(tz); icalendar_2_0::ArrayOfParameters parameters; parameters.baseParameter().push_back(tzidParam); ptr->parameters(parameters); } } return ptr; } //---- cDateTime ---- //=== Attendee === std::string mapPartStat(PartStatus status) { switch (status) { case PartAccepted: return PARTACCEPTED; case PartDeclined: return PARTDECLINED; case PartDelegated: return PARTDELEGATED; case PartNeedsAction: return PARTNEEDSACTION; case PartTentative: return PARTTENTATIVE; case PartInProcess: return PARTINPROCESS; case PartCompleted: return PARTCOMPLETED; } std::ostringstream s; s << "PartStat not handled: " << status; ERROR(s.str()); return std::string(); } PartStatus mapPartStat(const std::string &status) { if (status == PARTACCEPTED) { return PartAccepted; } else if (status == PARTDECLINED) { return PartDeclined; } else if (status == PARTDELEGATED) { return PartDelegated; } else if (status == PARTNEEDSACTION) { return PartNeedsAction; } else if (status == PARTTENTATIVE) { return PartTentative; } else if (status == PARTINPROCESS) { return PartInProcess; } else if (status == PARTCOMPLETED) { return PartCompleted; } ERROR("PartStat not handled: " + status); return PartNeedsAction; } std::string mapRole(Role status) { switch (status) { case Chair: return std::string(CHAIR); case NonParticipant: return NONPARTICIPANT; case Optional: return OPTIONAL; case Required: return REQUIRED; } std::ostringstream s; s << "Role not handled: " << status; ERROR(s.str()); return std::string(); } Role mapRole(const std::string &status) { if (status == CHAIR) { return Chair; } else if (status == NONPARTICIPANT) { return NonParticipant; } else if (status == OPTIONAL) { return Optional; } else if (status == REQUIRED) { return Required; } ERROR("Unhandled status " + status); return Required; } //---------------- //=== Recurrence Rule === typedef std::auto_ptr RecurrencePtr; RecurrenceRule::Frequency mapRecurrenceFrequency(const icalendar_2_0::RecurType::freq_type &freq) { using namespace icalendar_2_0; switch (freq) { case FreqRecurType::YEARLY: return RecurrenceRule::Yearly; case FreqRecurType::MONTHLY: return RecurrenceRule::Monthly; case FreqRecurType::WEEKLY: return RecurrenceRule::Weekly; case FreqRecurType::DAILY: return RecurrenceRule::Daily; case FreqRecurType::HOURLY: return RecurrenceRule::Hourly; case FreqRecurType::MINUTELY: return RecurrenceRule::Minutely; case FreqRecurType::SECONDLY: return RecurrenceRule::Secondly; } return RecurrenceRule::FreqNone; } icalendar_2_0::RecurType::freq_type mapRecurrenceFrequency(RecurrenceRule::Frequency freq) { using namespace icalendar_2_0; switch (freq) { case RecurrenceRule::Yearly: return FreqRecurType::YEARLY; case RecurrenceRule::Monthly: return FreqRecurType::MONTHLY; case RecurrenceRule::Weekly: return FreqRecurType::WEEKLY; case RecurrenceRule::Daily: return FreqRecurType::DAILY; case RecurrenceRule::Hourly: return FreqRecurType::HOURLY; case RecurrenceRule::Minutely: return FreqRecurType::MINUTELY; case RecurrenceRule::Secondly: return FreqRecurType::SECONDLY; case RecurrenceRule::FreqNone: return 0; } return 0; } static void setWeekStart(RecurrencePtr &r, const icalendar_2_0::RecurType::wkst_type &wkst) { using namespace icalendar_2_0; switch (wkst) { case WeekdayRecurType::MO: r->setWeekStart(Kolab::Monday); break; case WeekdayRecurType::TU: r->setWeekStart(Kolab::Tuesday); break; case WeekdayRecurType::WE: r->setWeekStart(Kolab::Wednesday); break; case WeekdayRecurType::TH: r->setWeekStart(Kolab::Thursday); break; case WeekdayRecurType::FR: r->setWeekStart(Kolab::Friday); break; case WeekdayRecurType::SA: r->setWeekStart(Kolab::Saturday); break; case WeekdayRecurType::SU: r->setWeekStart(Kolab::Sunday); break; } } static void setByday(RecurrencePtr &r, const icalendar_2_0::RecurType::byday_sequence &list) { std::vector by; for (icalendar_2_0::RecurType::byday_const_iterator it(list.begin()); it != list.end(); it++) { by.push_back(toDayPos(*it)); } r->setByday(by); } template std::vector bylist(const xsd::cxx::tree::sequence &list) { std::vector by; BOOST_FOREACH(const T i, list) { by.push_back(convertToInt(i)); } return by; } RecurrencePtr toRRule(const icalendar_2_0::RecurType &rrule) { using namespace icalendar_2_0; RecurrencePtr r(new RecurrenceRule()); r->setFrequency(mapRecurrenceFrequency(rrule.freq())); if (rrule.until()) { cDateTimePtr date; if ((*rrule.until()).date_time()) { date = Shared::toDate(*(*rrule.until()).date_time()); } else if ((*rrule.until()).date()) { date = Shared::toDate(*(*rrule.until()).date()); } r->setEnd(*date); } else if (rrule.count()) { r->setCount(toInt(*rrule.count())); } if (rrule.interval()) { r->setInterval(toInt(*rrule.interval())); } else { r->setInterval(1); } r->setBysecond(bylist(rrule.bysecond())); r->setByminute(bylist(rrule.byminute())); r->setByhour(bylist(rrule.byhour())); setByday(r, rrule.byday()); r->setBymonthday(bylist(rrule.bymonthday())); r->setByyearday(bylist(rrule.byyearday())); r->setByweekno(bylist(rrule.byweekno())); r->setBymonth(bylist(rrule.bymonth())); if (rrule.wkst()) { setWeekStart(r, *rrule.wkst()); } return r; } //--- Recurrence Rule --- template void setIncidenceProperties(I &inc, const T &prop) { inc.setUid(toString(prop.uid())); inc.setCreated(*toDate(prop.created())); inc.setLastModified(*toDate(prop.dtstamp())); if (prop.sequence()) { inc.setSequence(toInt(*prop.sequence())); } if (prop.class_()) { std::string string(toString(*prop.class_())); Kolab::Classification sec = ClassPublic; if (string == PRIVATE) { sec = ClassPrivate; } else if (string == CONFIDENTIAL) { sec = ClassConfidential; } inc.setClassification(sec); } if (prop.categories()) { inc.setCategories(toStringList(*prop.categories())); } if (prop.dtstart()) { const cDateTimePtr date = toDate(*prop.dtstart()); inc.setStart(*date); } if (prop.summary()) { inc.setSummary(toString(*prop.summary())); } if (prop.description()) { inc.setDescription(toString(*prop.description())); } if (prop.comment()) { inc.setComment(toString(*prop.comment())); } if (prop.status()) { const std::string &status = toString(*prop.status()); if (status == NEEDSACTION) { inc.setStatus(StatusNeedsAction); } else if (status == COMPLETED || status == COMPLETED_COMPAT) { inc.setStatus(StatusCompleted); } else if (status == INPROCESS) { inc.setStatus(StatusInProcess); } else if (status == CANCELLED) { inc.setStatus(StatusCancelled); } else if (status == TENTATIVE) { inc.setStatus(StatusTentative); } else if (status == CONFIRMED) { inc.setStatus(StatusConfirmed); } else if (status == DRAFT) { inc.setStatus(StatusDraft); } else if (status == FINAL) { inc.setStatus(StatusFinal); } else { ERROR("Unhandled status"); } } if (prop.attendee().size()) { std::vector attendees; BOOST_FOREACH(typename T::attendee_type aProp, prop.attendee()) { Kolab::Attendee a; std::string name; if (aProp.parameters()) { const icalendar_2_0::AttendeePropType::parameters_type ¶meters = *aProp.parameters(); for (icalendar_2_0::AttendeePropType::parameters_type::baseParameter_const_iterator it(parameters.baseParameter().begin()); it != parameters.baseParameter().end(); it++) { if (const icalendar_2_0::CnParamType * p = dynamic_cast (&*it)) { name = p->text(); } if (const icalendar_2_0::PartstatParamType * p = dynamic_cast (&*it)) { PartStatus s = mapPartStat(p->text()); if (s != PartNeedsAction) { a.setPartStat(s); } } if (const icalendar_2_0::RoleParamType * p = dynamic_cast (&*it)) { Role s = mapRole(p->text()); if (s != Required) { a.setRole(s); } } if (const icalendar_2_0::RsvpParamType * p = dynamic_cast (&*it)) { a.setRSVP(p->boolean()); } if (const icalendar_2_0::DelegatedToParamType * p = dynamic_cast (&*it)) { std::vector list; BOOST_FOREACH(const icalendar_2_0::CalAddressListParamType::cal_address_type &adr, p->cal_address()) { list.push_back(Shared::toContactReference(adr)); } a.setDelegatedTo(list); } if (const icalendar_2_0::DelegatedFromParamType * p = dynamic_cast (&*it)) { std::vector list; BOOST_FOREACH(const icalendar_2_0::CalAddressListParamType::cal_address_type &adr, p->cal_address()) { list.push_back(Shared::toContactReference(adr)); } a.setDelegatedFrom(list); } if (const icalendar_2_0::CutypeParamType * p = dynamic_cast (&*it)) { if (p->text() == RESOURCE) { a.setCutype(CutypeResource); } else if (p->text() == INDIVIDUAL) { a.setCutype(CutypeIndividual); } else if (p->text() == GROUP) { a.setCutype(CutypeGroup); } else if (p->text() == ROOM) { a.setCutype(CutypeGroup); } else if (p->text() == UNKNOWN) { a.setCutype(CutypeGroup); } else { WARNING("Invalid attendee cutype"); } } } } Kolab::ContactReference ref = toContactReference(aProp); a.setContact(ref); attendees.push_back(a); } inc.setAttendees(attendees); } if (prop.attach().size()) { std::vector attachments; BOOST_FOREACH(typename T::attach_type aProp, prop.attach()) { const Kolab::Attachment &a = toAttachment(aProp); if (!a.isValid()) { ERROR("invalid attachment"); continue; } attachments.push_back(a); } inc.setAttachments(attachments); } if (prop.x_custom().size()) { std::vector customProperties; BOOST_FOREACH(typename T::x_custom_type p, prop.x_custom()) { customProperties.push_back(CustomProperty(p.identifier(), p.value())); } inc.setCustomProperties(customProperties); } } template void setTodoEventProperties(I &inc, const T &prop) { if (prop.rrule()) { RecurrencePtr rrule = toRRule(prop.rrule()->recur()); inc.setRecurrenceRule(*rrule); } if (prop.rdate()) { inc.setRecurrenceDates(toDateTimeList(*prop.rdate())); if (!prop.rdate()->period().empty()) { ERROR("the period element must not be used, ignored."); } } if (prop.exdate()) { inc.setExceptionDates(toDateTimeList(*prop.exdate())); } if (prop.recurrence_id()) { bool thisandfuture = false; if (prop.recurrence_id()->parameters()) { const icalendar_2_0::RecurrenceIdPropType::parameters_type ¶meters = *prop.recurrence_id()->parameters(); for (icalendar_2_0::RecurrenceIdPropType::parameters_type::baseParameter_const_iterator it(parameters.baseParameter().begin()); it != parameters.baseParameter().end(); it++) { if (dynamic_cast (&*it)) { thisandfuture = true; } } } inc.setRecurrenceID(*toDate(*prop.recurrence_id()), thisandfuture); } if (prop.priority()) { inc.setPriority(toInt(*prop.priority())); } if (prop.location()) { inc.setLocation(toString(*prop.location())); } if (prop.organizer()) { inc.setOrganizer(toContactReference(*prop.organizer())); } if (prop.url()) { inc.setUrl((*prop.url()).uri()); } } template T fromList(const std::vector &input) { T list; BOOST_FOREACH(int i, input) { list.push_back(convertToInt(i)); } return list; } std::auto_ptr< icalendar_2_0::RrulePropType > recurrenceProperty(const RecurrenceRule &r) { using namespace icalendar_2_0; std::auto_ptr< RrulePropType > rruleProp(new RrulePropType(mapRecurrenceFrequency(r.frequency()))); RecurPropertyType::recur_type &recur = rruleProp->recur(); const cDateTime &endDate = r.end(); if (endDate.isValid()) { RecurPropertyType::recur_type::until_type until; if (endDate.isDateOnly()) { until.date(Shared::fromDate(endDate)); } else { until.date_time(Shared::fromDateTime(endDate)); } recur.until(until); } else if (r.count() > 0) { recur.count(fromInt(r.count())); } if (r.interval() > 1) { recur.interval(fromInt(r.interval())); } if (!r.bysecond().empty()) { recur.bysecond(fromList(r.bysecond())); } if (!r.byminute().empty()) { recur.byminute(fromList(r.byminute())); } if (!r.byhour().empty()) { recur.byhour(fromList(r.byhour())); } if (!r.byday().empty()) { RecurType::byday_sequence byday; const std::vector &l = r.byday(); BOOST_FOREACH(Kolab::DayPos daypos, l) { byday.push_back(fromDayPos(daypos)); } recur.byday(byday); } if (!r.bymonthday().empty()) { recur.bymonthday(fromList(r.bymonthday())); } if (!r.byyearday().empty()) { recur.byyearday(fromList(r.byyearday())); } if (!r.byweekno().empty()) { recur.byweekno(fromList(r.byweekno())); } if (!r.bymonth().empty()) { recur.bymonth(fromList(r.bymonth())); } return rruleProp; } template void getIncidenceProperties(T &prop, const I &inc) { using namespace icalendar_2_0; typedef T properties; prop.sequence(fromInt(inc.sequence())); switch (inc.classification()) { case Kolab::ClassConfidential: prop.class_(typename properties::class_type(CONFIDENTIAL)); break; case Kolab::ClassPrivate: prop.class_(typename properties::class_type(PRIVATE)); break; case Kolab::ClassPublic: prop.class_(typename properties::class_type(PUBLIC)); break; } if (!inc.categories().empty()) { prop.categories(*fromStringList(inc.categories())); } if (inc.start().isValid()) { prop.dtstart(fromDate(inc.start())); } if (!inc.summary().empty()) { prop.summary(typename properties::summary_type(inc.summary())); } if (!inc.description().empty()) { prop.description(typename properties::description_type(inc.description())); } if (!inc.comment().empty()) { prop.comment(typename properties::comment_type(inc.comment())); } switch (inc.status()) { case StatusNeedsAction: prop.status(typename properties::status_type(NEEDSACTION)); break; case StatusCompleted: prop.status(typename properties::status_type(COMPLETED)); break; case StatusInProcess: prop.status(typename properties::status_type(INPROCESS)); break; case StatusCancelled: prop.status(typename properties::status_type(CANCELLED)); break; case StatusTentative: prop.status(typename properties::status_type(TENTATIVE)); break; case StatusConfirmed: prop.status(typename properties::status_type(CONFIRMED)); break; case StatusDraft: prop.status(typename properties::status_type(DRAFT)); break; case StatusFinal: prop.status(typename properties::status_type(FINAL)); break; case StatusUndefined: break; } if (!inc.attendees().empty()) { const std::vector &l = inc.attendees(); BOOST_FOREACH(const Kolab::Attendee &a, l) { const Kolab::ContactReference &c = a.contact(); typename properties::attendee_type attendee = fromContactReference(c); typename properties::attendee_type::parameters_type &p = *attendee.parameters(); std::string stat = mapPartStat(a.partStat()); if (!stat.empty()) { p.baseParameter().push_back(icalendar_2_0::PartstatParamType(stat)); } std::string r = mapRole(a.role()); if (!r.empty()) { p.baseParameter().push_back(icalendar_2_0::RoleParamType(r)); } if (a.rsvp()) { p.baseParameter().push_back(icalendar_2_0::RsvpParamType(true)); } if (!a.delegatedTo().empty()) { icalendar_2_0::DelegatedToParamType delegatedTo; BOOST_FOREACH(const Kolab::ContactReference &ref, a.delegatedTo()) { delegatedTo.cal_address().push_back(CalAddressListParamType::cal_address_type(toMailto(ref.email(), ref.name()))); } p.baseParameter().push_back(delegatedTo); } if (!a.delegatedFrom().empty()) { icalendar_2_0::DelegatedFromParamType delegatedFrom; BOOST_FOREACH(const Kolab::ContactReference &ref, a.delegatedFrom()) { delegatedFrom.cal_address().push_back(CalAddressListParamType::cal_address_type(toMailto(ref.email(), ref.name()))); } p.baseParameter().push_back(delegatedFrom); } if (a.cutype() != CutypeIndividual) { std::string type; switch (a.cutype()) { case CutypeGroup: type = GROUP; break; case CutypeResource: type = RESOURCE; break; case CutypeRoom: type = ROOM; break; case CutypeUnknown: type = UNKNOWN; break; case CutypeIndividual: // silence compiler warning break; } p.baseParameter().push_back(icalendar_2_0::CutypeParamType(type)); } prop.attendee().push_back(attendee); } } if (!inc.attachments().empty()) { const std::vector &l = inc.attachments(); BOOST_FOREACH(const Kolab::Attachment &a, l) { prop.attach().push_back(fromAttachment(a)); } } if (!inc.customProperties().empty()) { const std::vector &l = inc.customProperties(); BOOST_FOREACH(const Kolab::CustomProperty &a, l) { prop.x_custom().push_back(typename properties::x_custom_type(a.identifier, a.value)); } } } template void getTodoEventProperties(T &prop, const I &inc) { using namespace icalendar_2_0; typedef T properties; if (inc.recurrenceRule().isValid()) { const RecurrenceRule &r = inc.recurrenceRule(); prop.rrule(recurrenceProperty(r)); //TODO check if startdate is allDay if recurrence is allDay //TODO check if startdate matches the one of the event (it MUST) } if (!inc.recurrenceDates().empty()) { prop.rdate(fromDateTimeList(inc.recurrenceDates())); } if (!inc.exceptionDates().empty()) { prop.exdate(fromDateTimeList(inc.exceptionDates())); } if (inc.recurrenceID().isValid()) { std::auto_ptr recurrenceId = fromDate(inc.recurrenceID()); if (inc.thisAndFuture()) { if (!recurrenceId->parameters()) { recurrenceId->parameters(typename properties::recurrence_id_type::parameters_type()); } typename properties::recurrence_id_type::parameters_type ¶meters = *recurrenceId->parameters(); //There is maybe already a timezone set icalendar_2_0::RangeParamType range(THISANDFUTURE); parameters.baseParameter().push_back(range); } prop.recurrence_id(recurrenceId); } if (inc.priority() != 0) { prop.priority(typename properties::priority_type(fromInt(inc.priority()))); } if (!inc.location().empty()) { prop.location(typename properties::location_type(inc.location())); } if (inc.organizer().isValid()) { prop.organizer(fromContactReference(inc.organizer())); } if (!inc.url().empty()) { prop.url(typename properties::url_type(inc.url())); } } //=== Alarms === template void setAlarms(typename KolabType::components_type& components, const IncidenceType &incidence) { const std::vector &alarms = incidence.alarms(); BOOST_FOREACH(const Kolab::Alarm &alarm, alarms) { typedef icalendar_2_0::ValarmType::properties_type PropType; PropType::trigger_type trigger; if (alarm.start().isValid()) { if (!alarm.start().isUTC()) { ERROR("alarm start date is not UTC but MUST be UTC"); continue; } trigger.date_time(fromDateTime(alarm.start())); } else { if (!alarm.relativeStart().isValid()) { ERROR("no start and no relativeStart"); continue; } trigger.duration(PropType::trigger_type::duration_type(fromDuration(alarm.relativeStart()))); icalendar_2_0::ArrayOfParameters parameters; if (alarm.relativeTo() == Kolab::End) { parameters.baseParameter().push_back(icalendar_2_0::RelatedParamType(END)); } else { parameters.baseParameter().push_back(icalendar_2_0::RelatedParamType(START)); } trigger.parameters(parameters); } std::auto_ptr p; switch(alarm.type()) { case Kolab::Alarm::DisplayAlarm: p = std::auto_ptr(new PropType(PropType::action_type(DISPLAYALARM), trigger)); p->description(PropType::description_type(alarm.description())); break; case Kolab::Alarm::EMailAlarm: { p = std::auto_ptr(new PropType(PropType::action_type(EMAILALARM), trigger)); p->summary(PropType::summary_type(alarm.summary())); p->description(PropType::description_type(alarm.description())); const std::vector &l = alarm.attendees(); BOOST_FOREACH(const Kolab::ContactReference &attendee, l) { p->attendee().push_back(icalendar_2_0::ContactType(toMailto(attendee.email(), attendee.name()))); } break; } case Kolab::Alarm::AudioAlarm: p = std::auto_ptr(new PropType(PropType::action_type(AUDIOALARM), trigger)); p->description(PropType::description_type(alarm.description())); - p->attach(fromAttachment(alarm.audioFile())); + if (alarm.audioFile().isValid()) { + p->attach(fromAttachment(alarm.audioFile())); + } break; case Kolab::Alarm::InvalidAlarm: break; } if (alarm.duration().isValid()) { p->duration(PropType::duration_type(fromDuration(alarm.duration()))); p->repeat(PropType::repeat_type(fromInt(alarm.numrepeat()))); } components.valarm().push_back(icalendar_2_0::ValarmType(p)); } } template void getAlarms(IncidenceType &incidence, const typename KolabType::components_type &components) { typedef icalendar_2_0::ValarmType::properties_type PropType; std::vector alarms; BOOST_FOREACH(const typename KolabType::components_type::valarm_type &valarm, components.valarm()) { const icalendar_2_0::ValarmType::properties_type &prop = valarm.properties(); Kolab::Alarm alarm; if (prop.action().text() == DISPLAYALARM) { if (!prop.description()) { ERROR("description is missing"); continue; } alarm = Kolab::Alarm((*prop.description()).text()); } else if (prop.action().text() == EMAILALARM) { std::vector attendees; if (prop.attendee().empty()) { WARNING("No receipents for email alarm"); } for (typename PropType::attendee_const_iterator at(prop.attendee().begin()); at != prop.attendee().end(); at++) { std::string name; const std::string &email = fromMailto((*at).cal_address(), name); attendees.push_back(Kolab::ContactReference(Kolab::ContactReference::EmailReference, email, name)); } if (!prop.description() || !prop.summary()) { ERROR("description or summary is missing"); continue; } alarm = Kolab::Alarm((*prop.summary()).text(), (*prop.description()).text(), attendees); } else if (prop.action().text() == AUDIOALARM) { - if (!prop.attach()) { - ERROR("audio file is missing"); - continue; - } - const Kolab::Attachment &attach = toAttachment(*prop.attach()); - if (!attach.isValid()) { - ERROR("audio file is invalid"); - continue; + if (prop.attach()) { + const Kolab::Attachment &attach = toAttachment(*prop.attach()); + if (!attach.isValid()) { + ERROR("audio file is invalid"); + continue; + } + alarm = Kolab::Alarm(attach); + } else { + //An audio alarm without an audio file is valid according to spec + alarm = Kolab::Alarm(Kolab::Alarm::AudioAlarm); } - alarm = Kolab::Alarm(attach); } else { ERROR("unknown alarm type " + prop.action().text()); continue; } if (prop.trigger().date_time()) { alarm.setStart(*Shared::toDate(*prop.trigger().date_time())); if (!alarm.start().isUTC()) { ERROR("The start date time must be in UTC "); continue; } } else if (prop.trigger().duration()) { Kolab::Relative relativeTo = Kolab::Start; if (prop.trigger().parameters()) { BOOST_FOREACH(const icalendar_2_0::ArrayOfParameters::baseParameter_type ¶m, (*prop.trigger().parameters()).baseParameter()) { if (const icalendar_2_0::RelatedParamType *rel = dynamic_cast (¶m)) { if (rel->text() == START) { relativeTo = Kolab::Start; } else if (rel->text() == END) { relativeTo = Kolab::End; } else { LOG("relativeTo not specified, default to start "); } } } } alarm.setRelativeStart(toDuration(*prop.trigger().duration()), relativeTo); } else { ERROR("no duration and not starttime "); continue; } if (prop.duration()) { int repeat = 0; if (prop.repeat()) { repeat = toInt(*prop.repeat()); } alarm.setDuration(toDuration((*prop.duration()).duration()), repeat); //TODO check duration? } alarms.push_back(alarm); } incidence.setAlarms(alarms); } //--- Alarms --- ///Trait for incidence properties specialized for Event/Todo/Journal template struct IncidenceTrait; template < > struct IncidenceTrait { typedef icalendar_2_0::KolabEvent KolabType; typedef Kolab::Event IncidenceType; typedef boost::shared_ptr IncidencePtr; static void writeIncidence(icalendar_2_0::KolabEvent& vevent, const Kolab::Event &event) { KolabType::components_type eventComponents; setAlarms(eventComponents, event); if (!eventComponents.valarm().empty()) { vevent.components(eventComponents); } icalendar_2_0::KolabEvent::properties_type &prop = vevent.properties(); getIncidenceProperties(prop, event); getTodoEventProperties(prop, event); if (event.end().isValid()) { prop.dtend(fromDate(event.end())); } else if (event.duration().isValid()) { prop.duration(icalendar_2_0::KolabEvent::properties_type::duration_type(fromDuration(event.duration()))); } if (event.transparency()) { prop.transp( icalendar_2_0::KolabEvent::properties_type::transp_type(TRANSPARENT)); } } static void addIncidence(icalendar_2_0::VcalendarType::components_type &components, icalendar_2_0::KolabEvent inc) //TODO to base trait { components.vevent().push_back(inc); } static void readIncidence(Kolab::Event &event, const icalendar_2_0::KolabEvent& vevent) { const icalendar_2_0::KolabEvent::properties_type &prop = vevent.properties(); if (!prop.dtstart()) { ERROR("Start date is missing, but is mandatory for events"); } setIncidenceProperties(event, prop); setTodoEventProperties(event, prop); if (prop.dtend()) { event.setEnd(*toDate(*prop.dtend())); } else if (prop.duration()) { event.setDuration(toDuration((*prop.duration()).duration())); } if (prop.transp()) { if (toString(*prop.transp()) == TRANSPARENT) { event.setTransparency(true); } else { event.setTransparency(false); if (toString(*prop.transp()) != OPAQUE) { ERROR("wrong transparency value " + toString(*prop.transp())); } } } if (vevent.components()) { getAlarms(event, *vevent.components()); } } static icalendar_2_0::VcalendarType::components_type::vevent_const_iterator begin(const icalendar_2_0::VcalendarType::components_type &components) { return components.vevent().begin(); } static icalendar_2_0::VcalendarType::components_type::vevent_const_iterator end(const icalendar_2_0::VcalendarType::components_type &components) { return components.vevent().end(); } static IncidencePtr resolveExceptions(const std::vector &list) { IncidencePtr incidence = *list.begin(); std::vector exceptions; for (std::vector < IncidencePtr >::const_iterator it = list.begin()+1; it != list.end(); it++) { exceptions.push_back(**it); } incidence->setExceptions(exceptions); return incidence; } static void addExceptions(icalendar_2_0::VcalendarType::components_type &components, const Kolab::Event &event, KolabType::properties_type props) { BOOST_FOREACH(const Kolab::Event &exception, event.exceptions()) { KolabType ex(props); writeIncidence(ex, exception); addIncidence(components, ex); } } }; template < > struct IncidenceTrait { typedef icalendar_2_0::KolabTodo KolabType; typedef Kolab::Todo IncidenceType; typedef boost::shared_ptr IncidencePtr; static void writeIncidence(icalendar_2_0::KolabTodo& vevent, const Kolab::Todo &todo) { KolabType::components_type eventComponents; setAlarms(eventComponents, todo); if (!eventComponents.valarm().empty()) { vevent.components(eventComponents); } icalendar_2_0::KolabTodo::properties_type &prop = vevent.properties(); getIncidenceProperties(prop, todo); getTodoEventProperties(prop, todo); if (!todo.relatedTo().empty()) { icalendar_2_0::KolabTodo::properties_type::related_to_sequence list; const std::vector &l = todo.relatedTo(); BOOST_FOREACH(const std::string &relatedTo, l) { list.push_back(icalendar_2_0::KolabTodo::properties_type::related_to_type(relatedTo)); } prop.related_to(list); } if (todo.due().isValid()) { prop.due(fromDate(todo.due())); } if (todo.percentComplete() > 0) { prop.percent_complete(icalendar_2_0::KolabTodo::properties_type::percent_complete_type(fromInt(todo.percentComplete()))); } } static void addIncidence(icalendar_2_0::VcalendarType::components_type &components, icalendar_2_0::KolabTodo inc) //TODO to base trait { components.vtodo().push_back(inc); } static void readIncidence(Kolab::Todo &todo, const icalendar_2_0::KolabTodo& vevent) { const icalendar_2_0::KolabTodo::properties_type &prop = vevent.properties(); setIncidenceProperties(todo, prop); setTodoEventProperties(todo, prop); if (!prop.related_to().empty()) { BOOST_FOREACH(icalendar_2_0::KolabTodo::properties_type::related_to_type p, prop.related_to()) { todo.addRelatedTo(p.text()); } } if (prop.due()) { todo.setDue(*toDate(*prop.due())); } if (prop.percent_complete()) { todo.setPercentComplete(toInt(*prop.percent_complete())); } if (vevent.components()) { getAlarms(todo, *vevent.components()); } } static icalendar_2_0::VcalendarType::components_type::vevent_const_iterator begin(const icalendar_2_0::VcalendarType::components_type &components) { return components.vtodo().begin(); } static icalendar_2_0::VcalendarType::components_type::vevent_const_iterator end(const icalendar_2_0::VcalendarType::components_type &components) { return components.vtodo().end(); } static IncidencePtr resolveExceptions(const std::vector &list) { IncidencePtr incidence = *list.begin(); std::vector exceptions; for (std::vector < IncidencePtr >::const_iterator it = list.begin()+1; it != list.end(); it++) { exceptions.push_back(**it); } incidence->setExceptions(exceptions); return incidence; } static void addExceptions(icalendar_2_0::VcalendarType::components_type &components, const Kolab::Todo &event, KolabType::properties_type props) { BOOST_FOREACH(const Kolab::Todo &exception, event.exceptions()) { KolabType ex(props); writeIncidence(ex, exception); addIncidence(components, ex); } } }; template < > struct IncidenceTrait { typedef icalendar_2_0::KolabJournal KolabType; typedef Kolab::Journal IncidenceType; typedef boost::shared_ptr IncidencePtr; static void writeIncidence(icalendar_2_0::KolabJournal& vjournal, const Kolab::Journal &journal) { icalendar_2_0::KolabJournal::properties_type &prop = vjournal.properties(); getIncidenceProperties(prop, journal); } static void addIncidence(icalendar_2_0::VcalendarType::components_type &components, icalendar_2_0::KolabJournal inc) { components.vjournal().push_back(inc); } static void readIncidence(Kolab::Journal &journal, const icalendar_2_0::KolabJournal& vjournal) { const icalendar_2_0::KolabJournal::properties_type &prop = vjournal.properties(); setIncidenceProperties(journal, prop); } static icalendar_2_0::VcalendarType::components_type::vjournal_const_iterator begin(const icalendar_2_0::VcalendarType::components_type &components) { return components.vjournal().begin(); } static icalendar_2_0::VcalendarType::components_type::vjournal_const_iterator end(const icalendar_2_0::VcalendarType::components_type &components) { return components.vjournal().end(); } static IncidencePtr resolveExceptions(const std::vector &list) { return *list.begin(); } static void addExceptions(icalendar_2_0::VcalendarType::components_type &, const Kolab::Journal &, KolabType::properties_type) { } }; template < > struct IncidenceTrait { typedef icalendar_2_0::KolabFreebusy KolabType; typedef Kolab::Freebusy IncidenceType; typedef boost::shared_ptr IncidencePtr; static void writeIncidence(icalendar_2_0::KolabFreebusy& vfreebusy, const Kolab::Freebusy &fb) { icalendar_2_0::KolabFreebusy::properties_type &prop = vfreebusy.properties(); if (fb.start().isValid() && fb.end().isValid()) { if ((fb.start().isUTC() || fb.start().isDateOnly()) && (fb.end().isUTC() || fb.end().isDateOnly())) { prop.dtstart(fromDate(fb.start())); prop.dtend(fromDate(fb.end())); } else { WARNING("Start/end is not in UTC, but it MUST be, skipping"); } } if (fb.organizer().isValid()) { prop.organizer(fromContactReference(fb.organizer())); } if (!fb.periods().empty()) { BOOST_FOREACH (const Kolab::FreebusyPeriod &fbPeriod, fb.periods()) { icalendar_2_0::KolabFreebusy::properties_type::freebusy_type fb; icalendar_2_0::BasePropertyType::parameters_type params; std::string fbtype; switch (fbPeriod.type()) { case FreebusyPeriod::Busy: fbtype = BUSY; break; case FreebusyPeriod::Tentative: fbtype = BUSY_TENTATIVE; break; case FreebusyPeriod::OutOfOffice: fbtype = BUSY_OUTOFOFFICE; break; case FreebusyPeriod::Invalid: WARNING("Invalid fb type"); continue; } params.baseParameter().push_back(icalendar_2_0::FbtypeParamType(fbtype)); if (!fbPeriod.eventUid().empty() || fbPeriod.eventSummary().empty() || fbPeriod.eventLocation().empty()) { params.baseParameter().push_back(icalendar_2_0::XFBevent(fbPeriod.eventUid(), fbPeriod.eventSummary(), fbPeriod.eventLocation())); } fb.parameters(params); BOOST_FOREACH (const Kolab::Period &period, fbPeriod.periods()) { if (period.start.isDateOnly() || period.end.isDateOnly()) { WARNING("Period is date-only but must be date-time"); continue; } if (!period.start.isUTC() || !period.end.isUTC()) { WARNING("Period is not in UTC, but it MUST be, skipping"); continue; } icalendar_2_0::PeriodType p(Shared::fromDateTime(period.start)); p.end(Shared::fromDateTime(period.end)); fb.period().push_back(p); } prop.freebusy().push_back(fb); } } } static void addIncidence(icalendar_2_0::VcalendarType::components_type &components, icalendar_2_0::KolabFreebusy inc) { components.vfreebusy().push_back(inc); } static void readIncidence(Kolab::Freebusy &freebusy, const icalendar_2_0::KolabFreebusy& vfreebusy) { const icalendar_2_0::KolabFreebusy::properties_type &prop = vfreebusy.properties(); freebusy.setUid(toString(prop.uid())); freebusy.setTimestamp(*toDate(prop.dtstamp())); if (prop.dtstart()) { freebusy.setStart(*toDate(*prop.dtstart())); } if (prop.dtend()) { freebusy.setEnd(*toDate(*prop.dtend())); } if (prop.organizer()) { freebusy.setOrganizer(toContactReference(*prop.organizer())); } if (!prop.freebusy().empty()) { std::vector fbperiods; BOOST_FOREACH(icalendar_2_0::FreebusyPropType aProp, prop.freebusy()) { Kolab::FreebusyPeriod fbPeriod; fbPeriod.setType(Kolab::FreebusyPeriod::Busy); if (aProp.parameters()) { const icalendar_2_0::FreebusyPropType::parameters_type ¶meters = *aProp.parameters(); for (icalendar_2_0::FreebusyPropType::parameters_type::baseParameter_const_iterator it(parameters.baseParameter().begin()); it != parameters.baseParameter().end(); it++) { if (const icalendar_2_0::FbtypeParamType * p = dynamic_cast (&*it)) { if (p->text() == BUSY) { fbPeriod.setType(Kolab::FreebusyPeriod::Busy); } else if (p->text() == BUSY_OUTOFOFFICE) { fbPeriod.setType(Kolab::FreebusyPeriod::OutOfOffice); } else if (p->text() == BUSY_TENTATIVE) { fbPeriod.setType(Kolab::FreebusyPeriod::Tentative); } else { WARNING("Invalid fb type, default to busy"); } } if (const icalendar_2_0::XFBevent * p = dynamic_cast (&*it)) { fbPeriod.setEvent(p->uid(), p->summary(), p->location()); } } } std::vector periods; BOOST_FOREACH(icalendar_2_0::FreebusyPropType::period_type period, aProp.period()) { if (!period.end()) { WARNING("Period end date is required and duration is not supported, skipping period"); continue; } periods.push_back(Kolab::Period(*Shared::toDate(period.start()), *Shared::toDate(*period.end()))); } fbPeriod.setPeriods(periods); fbperiods.push_back(fbPeriod); } freebusy.setPeriods(fbperiods); } } static icalendar_2_0::VcalendarType::components_type::vfreebusy_const_iterator begin(const icalendar_2_0::VcalendarType::components_type &components) { return components.vfreebusy().begin(); } static icalendar_2_0::VcalendarType::components_type::vfreebusy_const_iterator end(const icalendar_2_0::VcalendarType::components_type &components) { return components.vfreebusy().end(); } static IncidencePtr resolveExceptions(const std::vector &list) { return *list.begin(); } static void addExceptions(icalendar_2_0::VcalendarType::components_type &, const Kolab::Freebusy &, KolabType::properties_type) { } }; //////////////////////////////////========================================= template std::string serializeIncidence(const typename T::IncidenceType &incidence, const std::string productid = std::string()) { using namespace icalendar_2_0; typedef typename T::KolabType KolabType; try { typename KolabType::properties_type::uid_type uid( getUID(incidence.uid())); setCreatedUid(uid.text()); typename KolabType::properties_type::dtstamp_type dtstamp; if (incidence.lastModified().isValid()) { dtstamp.date_time(fromDateTime(incidence.lastModified())); } else { dtstamp.date_time(fromDateTime(timestamp())); } typename KolabType::properties_type::created_type created; if (incidence.created().isValid() && !incidence.created().isDateOnly()) { created.date_time(fromDateTime(incidence.created())); } else { created.date_time(fromDateTime(timestamp())); } typename KolabType::properties_type eventProps(uid, created, dtstamp); KolabType inc(eventProps); T::writeIncidence(inc, incidence); VcalendarType::components_type components; T::addIncidence(components, inc); T::addExceptions(components, incidence, eventProps); VcalendarType::properties_type::prodid_type prodid(getProductId(productid)); VcalendarType::properties_type::version_type version(XCAL_VERSION); VcalendarType::properties_type::x_kolab_version_type x_kolab_version(KOLAB_FORMAT_VERSION); VcalendarType::properties_type properties(prodid, version, x_kolab_version); VcalendarType vcalendar(properties, components); IcalendarType icalendar(vcalendar); xml_schema::namespace_infomap map; map[""].name = XCAL_NAMESPACE; std::ostringstream ostringstream; icalendar_2_0::icalendar(ostringstream, icalendar, map); return ostringstream.str(); } catch (const xml_schema::exception&) { CRITICAL("failed to write Incidence"); } catch (...) { CRITICAL("Unhandled exception"); } return std::string(); } template typename T::IncidencePtr deserializeIncidence(const std::string& s, bool isUrl) { using namespace icalendar_2_0; typedef typename T::IncidencePtr IncidencePtr; typedef typename T::IncidenceType IncidenceType; typedef typename T::KolabType KolabType; try { std::auto_ptr icalendar; if (isUrl) { xsd::cxx::xml::dom::auto_ptr doc = XMLParserWrapper::inst().parseFile(s); if (doc.get()) { icalendar = icalendar_2_0::icalendar(doc); } } else { xsd::cxx::xml::dom::auto_ptr doc = XMLParserWrapper::inst().parseString(s); if (doc.get()) { icalendar = icalendar_2_0::icalendar(doc); } } if (!icalendar.get()) { CRITICAL("Failed to parse calendar!"); return IncidencePtr(); } const icalendar_2_0::VcalendarType &vcalendar = icalendar->vcalendar(); std::vector < IncidencePtr > incidences; for (typename xsd::cxx::tree::sequence< KolabType >::const_iterator it(T::begin(vcalendar.components())); it != T::end(vcalendar.components()); it++) { IncidencePtr e = IncidencePtr(new IncidenceType); const KolabType &event = *it; T::readIncidence(*e, event); incidences.push_back(e); } setProductId( vcalendar.properties().prodid().text() ); setXCalVersion(vcalendar.properties().version().text()); setKolabVersion( vcalendar.properties().x_kolab_version().text() ); if (incidences.empty()) { CRITICAL("no incidence in object"); return IncidencePtr(); } return T::resolveExceptions(incidences); } catch (const xml_schema::exception& e) { std::cerr << e << std::endl; } catch (...) { CRITICAL("Unhandled exception"); } CRITICAL("Failed to read incidence!"); return IncidencePtr(); } template std::string serializeFreebusy(const Kolab::Freebusy &incidence, const std::string productid = std::string()) { using namespace icalendar_2_0; typedef typename T::KolabType KolabType; try { typename KolabType::properties_type::uid_type uid( getUID(incidence.uid())); setCreatedUid(uid.text()); typename KolabType::properties_type::dtstamp_type dtstamp; dtstamp.date_time(fromDateTime(timestamp())); typename KolabType::properties_type eventProps(uid, dtstamp); KolabType inc(eventProps); T::writeIncidence(inc, incidence); VcalendarType::components_type components; T::addIncidence(components, inc); VcalendarType::properties_type::prodid_type prodid(getProductId(productid)); VcalendarType::properties_type::version_type version(XCAL_VERSION); VcalendarType::properties_type::x_kolab_version_type x_kolab_version(KOLAB_FORMAT_VERSION); VcalendarType::properties_type properties(prodid, version, x_kolab_version); VcalendarType vcalendar(properties, components); IcalendarType icalendar(vcalendar); xml_schema::namespace_infomap map; map[""].name = XCAL_NAMESPACE; std::ostringstream ostringstream; icalendar_2_0::icalendar(ostringstream, icalendar, map); return ostringstream.str(); } catch (const xml_schema::exception& e) { std::cerr << e << std::endl; } catch (...) { CRITICAL("Unhandled exception"); } CRITICAL("failed to write Incidence"); return std::string(); } } }//Namespace #endif diff --git a/tests/bindingstest.cpp b/tests/bindingstest.cpp index e87fcd9..a59e0f7 100644 --- a/tests/bindingstest.cpp +++ b/tests/bindingstest.cpp @@ -1,923 +1,921 @@ #include "bindingstest.h" #include #include #include "bindings/iCalendar-props.hxx" #include "bindings/iCalendar-valtypes.hxx" #include "bindings/kolabformat.hxx" #include #include #include #include // #include #include #include #include "serializers.h" #include #include "src/containers/kolabjournal.h" #include "libkolabxml-version.h" void BindingsTest::categorycolorConfigurationCompletness() { Kolab::CategoryColor color("name"); color.setColor("color"); std::vector entries; entries.push_back(color); color.setSubcategories(entries); entries.push_back(color); color.setSubcategories(entries); entries.push_back(color); Kolab::Configuration configuration(entries); configuration.setUid("uid"); configuration.setCreated(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC configuration.setLastModified(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC const std::string &result = Kolab::writeConfiguration(configuration); QCOMPARE(Kolab::error(), Kolab::NoError); // std::cout << result << std::endl; const Kolab::Configuration &re = Kolab::readConfiguration(result, false); QCOMPARE(Kolab::error(), Kolab::NoError); QCOMPARE(re.uid(), configuration.uid()); QCOMPARE(re.created(), configuration.created()); QCOMPARE(re.lastModified(), configuration.lastModified()); QCOMPARE(re.type(), Kolab::Configuration::TypeCategoryColor); QCOMPARE(re.categoryColor(), entries); } void BindingsTest::dictionaryConfigurationCompletness() { Kolab::Dictionary dict("en"); std::vector entries; entries.push_back("entry1"); entries.push_back("entry2"); entries.push_back("entry3"); dict.setEntries(entries); Kolab::Configuration configuration(dict); configuration.setUid("uid"); configuration.setCreated(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC configuration.setLastModified(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC const std::string &result = Kolab::writeConfiguration(configuration); QCOMPARE(Kolab::error(), Kolab::NoError); // std::cout << result << std::endl; const Kolab::Configuration &re = Kolab::readConfiguration(result, false); QCOMPARE(Kolab::error(), Kolab::NoError); QCOMPARE(re.uid(), configuration.uid()); QCOMPARE(re.created(), configuration.created()); QCOMPARE(re.lastModified(), configuration.lastModified()); QCOMPARE(re.type(), Kolab::Configuration::TypeDictionary); QCOMPARE(re.dictionary(), dict); } void BindingsTest::snippetConfigurationCompletness() { std::vector list; Kolab::Snippet snippet1("name1", "text1"); snippet1.setShortCut("shrtct1"); list.push_back(snippet1); Kolab::Snippet snippet2("name1", "text1"); snippet2.setTextType(Kolab::Snippet::HTML); list.push_back(snippet2); Kolab::SnippetsCollection snippets("collectionname"); snippets.setSnippets(list); Kolab::Configuration configuration(snippets); configuration.setUid("uid"); configuration.setCreated(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC configuration.setLastModified(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC const std::string &result = Kolab::writeConfiguration(configuration); QCOMPARE(Kolab::error(), Kolab::NoError); // std::cout << result << std::endl; const Kolab::Configuration &re = Kolab::readConfiguration(result, false); QCOMPARE(Kolab::error(), Kolab::NoError); QCOMPARE(re.uid(), configuration.uid()); QCOMPARE(re.created(), configuration.created()); QCOMPARE(re.lastModified(), configuration.lastModified()); QCOMPARE(re.type(), Kolab::Configuration::TypeSnippet); QCOMPARE(re.snippets(), snippets); } void BindingsTest::relationConfigurationCompletness() { Kolab::Relation relation("name1", "type1"); relation.setColor("color"); relation.setIconName("icon"); relation.setParent("parent"); relation.setPriority(3); std::vector members; members.push_back("member1"); members.push_back("member2"); relation.setMembers(members); Kolab::Configuration configuration(relation); configuration.setUid("uid"); configuration.setCreated(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC configuration.setLastModified(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC const std::string &result = Kolab::writeConfiguration(configuration); QCOMPARE(Kolab::error(), Kolab::NoError); // std::cout << result << std::endl; const Kolab::Configuration &re = Kolab::readConfiguration(result, false); QCOMPARE(Kolab::error(), Kolab::NoError); QCOMPARE(re.uid(), configuration.uid()); QCOMPARE(re.created(), configuration.created()); QCOMPARE(re.lastModified(), configuration.lastModified()); QCOMPARE(re.type(), Kolab::Configuration::TypeRelation); QCOMPARE(re.relation(), relation); } void BindingsTest::fileDriverConfigurationCompletness() { Kolab::FileDriver fileDriver("driver", "title"); fileDriver.setEnabled(false); fileDriver.setHost("host"); fileDriver.setPort(9); fileDriver.setUsername("username"); fileDriver.setPassword("password"); Kolab::Configuration configuration(fileDriver); configuration.setUid("uid"); configuration.setCreated(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC configuration.setLastModified(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC const std::string &result = Kolab::writeConfiguration(configuration); QCOMPARE(Kolab::error(), Kolab::NoError); // std::cout << result << std::endl; const Kolab::Configuration &re = Kolab::readConfiguration(result, false); QCOMPARE(Kolab::error(), Kolab::NoError); QCOMPARE(re.uid(), configuration.uid()); QCOMPARE(re.created(), configuration.created()); QCOMPARE(re.lastModified(), configuration.lastModified()); QCOMPARE(re.type(), Kolab::Configuration::TypeFileDriver); QCOMPARE(re.fileDriver(), fileDriver); } void BindingsTest::noteCompletness() { Kolab::Note note; note.setUid("UID"); note.setCreated(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC note.setLastModified(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC note.setClassification(Kolab::ClassConfidential); note.addCategory("Category"); note.setSummary("summary"); note.setDescription("description"); note.setColor("color"); std::vector attachments; Kolab::Attachment attachment; attachment.setData("data", "mimetype"); attachment.setLabel("label"); attachments.push_back(attachment); Kolab::Attachment attachment2; attachment2.setUri("data", "mimetype"); attachment2.setLabel("label2"); attachments.push_back(attachment2); note.setAttachments(attachments); const std::string &result = Kolab::writeNote(note); QCOMPARE(Kolab::error(), Kolab::NoError); // std::cout << result << std::endl; const Kolab::Note &re = Kolab::readNote(result, false); QCOMPARE(Kolab::error(), Kolab::NoError); QCOMPARE(re.uid(), note.uid()); QCOMPARE(re.created(), note.created()); QCOMPARE(re.lastModified(), note.lastModified()); QCOMPARE(re.classification(), note.classification()); QCOMPARE(re.categories(), note.categories()); QCOMPARE(re.summary(), note.summary()); QCOMPARE(re.description(), note.description()); QCOMPARE(re.color(), note.color()); QCOMPARE(re.attachments(), note.attachments()); } void BindingsTest::fileCompletness() { Kolab::File file; file.setUid("UID"); file.setCreated(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC file.setLastModified(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC file.setClassification(Kolab::ClassConfidential); file.addCategory("Category"); file.setNote("summary"); Kolab::Attachment attachment; attachment.setData("data", "mimetype"); attachment.setLabel("label"); file.setFile(attachment); const std::string &result = Kolab::writeFile(file); QCOMPARE(Kolab::error(), Kolab::NoError); // std::cout << result << std::endl; const Kolab::File &re = Kolab::readFile(result, false); QCOMPARE(Kolab::error(), Kolab::NoError); QCOMPARE(re.uid(), file.uid()); QCOMPARE(re.created(), file.created()); QCOMPARE(re.lastModified(), file.lastModified()); QCOMPARE(re.classification(), file.classification()); QCOMPARE(re.categories(), file.categories()); QCOMPARE(re.note(), file.note()); QCOMPARE(re.file(), file.file()); } // void BindingsTest::eventCompletness_data() template void setIncidence(T &ev) { ev.setUid("UID"); ev.setCreated(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC ev.setLastModified(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC ev.setSequence(1); ev.setClassification(Kolab::ClassConfidential); ev.addCategory("Category"); ev.setStart(Kolab::cDateTime("Europe/Zurich", 2006,1,6,12,0,0)); Kolab::RecurrenceRule rule; rule.setFrequency(Kolab::RecurrenceRule::Daily); rule.setCount(5); std::vector list; list.push_back(1); list.push_back(3); rule.setBysecond(list); rule.setByminute(list); rule.setByhour(list); std::vector byday; byday.push_back(Kolab::DayPos(15, Kolab::Friday)); byday.push_back(Kolab::DayPos(0, Kolab::Monday)); byday.push_back(Kolab::DayPos(-3, Kolab::Monday)); rule.setByday(byday); rule.setBymonthday(list); rule.setByyearday(list); rule.setByweekno(list); rule.setBymonth(list); ev.setRecurrenceRule(rule); ev.addRecurrenceDate(Kolab::cDateTime("Europe/Zurich", 2006,1,6,12,0,0)); ev.addExceptionDate(Kolab::cDateTime("Europe/Zurich", 2006,1,6,12,0,0)); ev.setRecurrenceID(Kolab::cDateTime("Europe/Zurich", 2006,1,6,12,0,0), true); ev.setSummary("summary"); ev.setDescription("description"); ev.setComment("comment"); ev.setPriority(3); ev.setStatus(Kolab::StatusConfirmed); ev.setLocation("location"); ev.setOrganizer(Kolab::ContactReference("mail", "name", "uid")); ev.setUrl("http://example.com"); Kolab::Attendee attendee(Kolab::ContactReference("mail", "name", "uid")); attendee.setPartStat(Kolab::PartDelegated); attendee.setRole(Kolab::Chair); attendee.setRSVP(true); std::vector reflist; reflist.push_back(Kolab::ContactReference(Kolab::ContactReference::EmailReference, "mail", "name")); reflist.push_back(Kolab::ContactReference(Kolab::ContactReference::EmailReference, "mail2", "name2")); attendee.setDelegatedTo(reflist); attendee.setDelegatedFrom(reflist); attendee.setCutype(Kolab::CutypeResource); ev.setAttendees(std::vector() << attendee << attendee); std::vector attachments; Kolab::Attachment attach; attach.setData("data????*?*?*?*?*?", "mimetype"); attach.setLabel("label"); attachments.push_back(attach); Kolab::Attachment attach2; attach2.setUri(TEST_DATA_PATH "/testfiles/icalEvent.xml", "mimetype"); attach2.setLabel("labe2l"); attachments.push_back(attach2); Kolab::Attachment attach3; using namespace std; ifstream file (TEST_DATA_PATH "/testfiles/icalEvent.xml", ios::in|ios::binary|ios::ate); if (file.is_open()) { int size = file.tellg(); char *memblock = new char [size]; file.seekg (0, ios::beg); file.read (memblock, size); file.close(); attach3.setData(string(memblock, size), "mimetype"); delete[] memblock; } else { qWarning() << "Testfile not found"; } attach3.setLabel("labe3l"); attachments.push_back(attach3); ev.setAttachments(attachments); std::vector properties; properties.push_back(Kolab::CustomProperty("ident", "value")); properties.push_back(Kolab::CustomProperty("ident", "value")); ev.setCustomProperties(properties); std::vector alarms; // Kolab::Alarm dispAlarm("ident"); // dispAlarm.setRelativeStart(Kolab::Duration(3, true), Kolab::Start); // alarms.push_back(dispAlarm); std::vector att; att.push_back(Kolab::ContactReference(Kolab::ContactReference::EmailReference, "mail", "name")); att.push_back(Kolab::ContactReference(Kolab::ContactReference::EmailReference, "mail", "name")); Kolab::Alarm emailAlarm("ident", "value", att); emailAlarm.setStart(Kolab::cDateTime(2003,2,3,2,3,4, true)); alarms.push_back(emailAlarm); -// Kolab::Attachment audiofile; -// audiofile.setUri("ksdjlksdflj", "sdkljdfl"); -// Kolab::Alarm audio(audiofile); -// audio.setStart(Kolab::cDateTime(2003,2,3,2,3,4, true)); -// alarms.push_back(audio); + Kolab::Alarm audio(Kolab::Alarm::AudioAlarm); + audio.setStart(Kolab::cDateTime(2003,2,3,2,3,4, true)); + alarms.push_back(audio); ev.setAlarms(alarms); } template void checkIncidence(const T &ev, const T &re) { //Common to all QCOMPARE(ev.uid(), re.uid()); QCOMPARE(ev.created(), re.created()); QCOMPARE(ev.lastModified(), re.lastModified()); QCOMPARE(ev.sequence(), re.sequence()); QCOMPARE(ev.classification(), re.classification()); QCOMPARE(ev.categories(), re.categories()); QCOMPARE(ev.start(), re.start()); //Recurrence const Kolab::RecurrenceRule &r1 = ev.recurrenceRule(); const Kolab::RecurrenceRule &r2 = re.recurrenceRule(); QCOMPARE(r1.isValid(), r2.isValid()); QCOMPARE(r1.frequency(), r2.frequency()); QCOMPARE(r1.interval(), r2.interval()); QCOMPARE(r1.weekStart(), r2.weekStart()); QCOMPARE(r1.count(), r2.count()); QCOMPARE(r1.end(), r2.end()); QCOMPARE(r1.bysecond(), r2.bysecond()); QCOMPARE(r1.byminute(), r2.byminute()); QCOMPARE(r1.byhour(), r2.byhour()); QCOMPARE(r1.byday(), r2.byday()); QCOMPARE(r1.bymonthday(), r2.bymonthday()); QCOMPARE(r1.byyearday(), r2.byyearday()); QCOMPARE(r1.byweekno(), r2.byweekno()); QCOMPARE(r1.bymonth(), r2.bymonth()); //Rest QCOMPARE(ev.recurrenceDates(), re.recurrenceDates()); QCOMPARE(ev.exceptionDates(), re.exceptionDates()); QCOMPARE(ev.recurrenceID(), re.recurrenceID()); QCOMPARE(ev.thisAndFuture(), re.thisAndFuture()); QCOMPARE(ev.summary(), re.summary()); QCOMPARE(ev.description(), re.description()); QCOMPARE(ev.comment(), re.comment()); QCOMPARE(ev.priority(), re.priority()); QCOMPARE(ev.status(), re.status()); QCOMPARE(ev.location(), re.location()); QCOMPARE(ev.organizer(), re.organizer()); QCOMPARE(ev.url(), re.url()); QCOMPARE(ev.attendees(), re.attendees()); QCOMPARE(ev.attachments(), re.attachments()); QCOMPARE(ev.customProperties(), re.customProperties()); QCOMPARE(ev.alarms(), re.alarms()); } void BindingsTest::eventCompletness() { Kolab::Event ev; setIncidence(ev); ev.setEnd(Kolab::cDateTime("Europe/Zurich", 2006,1,8,12,0,0)); ev.setTransparency(true); std::string result = Kolab::writeEvent(ev); QVERIFY(Kolab::error() == Kolab::NoError); // std::cout << result << endl; Kolab::Event e = Kolab::readEvent(result, false); QVERIFY(Kolab::error() == Kolab::NoError); checkIncidence(ev, e); QCOMPARE(ev.end(), e.end()); QCOMPARE(ev.transparency(), e.transparency()); } void BindingsTest::eventDuration() { Kolab::Event ev; ev.setCreated(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC ev.setStart(Kolab::cDateTime("Europe/Zurich", 2006,1,8,12,0,0)); ev.setDuration(Kolab::Duration(11,22,33,44, true)); const std::string result = Kolab::writeEvent(ev); QVERIFY(Kolab::error() == Kolab::NoError); // std::cout << result << endl; const Kolab::Event e = Kolab::readEvent(result, false); QVERIFY(Kolab::error() == Kolab::NoError); QVERIFY(ev.duration().isValid()); QCOMPARE(ev.duration(), e.duration()); } void BindingsTest::eventExceptions() { Kolab::Event ev; ev.setUid("uid1"); ev.setCreated(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC ev.setStart(Kolab::cDateTime("Europe/Zurich", 2006,1,8,12,0,0)); std::vector exceptions; Kolab::Event ex1; ex1.setStart(Kolab::cDateTime("Europe/Zurich", 2006,1,8,12,0,0)); ex1.setUid("uid1"); ex1.setRecurrenceID(Kolab::cDateTime("Europe/Zurich", 2006,1,8,12,0,0), true); exceptions.push_back(ex1); Kolab::Event ex2; ex2.setStart(Kolab::cDateTime("Europe/Zurich", 2006,1,8,12,0,0)); ex2.setUid("uid1"); ex2.setRecurrenceID(Kolab::cDateTime("Europe/Zurich", 2007,1,8,12,0,0), false); exceptions.push_back(ex2); ev.setExceptions(exceptions); const std::string result = Kolab::writeEvent(ev); QVERIFY(Kolab::error() == Kolab::NoError); // std::cout << result << endl; const Kolab::Event e = Kolab::readEvent(result, false); QVERIFY(Kolab::error() == Kolab::NoError); QCOMPARE(e.exceptions().size(), std::size_t(2)); QCOMPARE(ev.exceptions().at(0).uid(), e.exceptions().at(0).uid()); QCOMPARE(ev.exceptions().at(0).recurrenceID(), e.exceptions().at(0).recurrenceID()); QCOMPARE(ev.exceptions().at(1).uid(), e.exceptions().at(1).uid()); QCOMPARE(ev.exceptions().at(1).recurrenceID(), e.exceptions().at(1).recurrenceID()); } void BindingsTest::todoCompletness() { Kolab::Todo ev; setIncidence(ev); ev.setDue(Kolab::cDateTime("Europe/Zurich", 2006,1,8,12,0,0)); ev.addRelatedTo("rel1"); ev.addRelatedTo("rel2"); ev.setPercentComplete(50); std::string result = Kolab::writeTodo(ev); QVERIFY(Kolab::error() == Kolab::NoError); // std::cout << result << endl; Kolab::Todo e = Kolab::readTodo(result, false); QVERIFY(Kolab::error() == Kolab::NoError); checkIncidence(ev, e); QCOMPARE(ev.due(), e.due()); QCOMPARE(ev.relatedTo(), e.relatedTo()); QCOMPARE(ev.percentComplete(), e.percentComplete()); } void BindingsTest::dueDateDateOnly() { Kolab::Todo ev; ev.setCreated(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC ev.setDue(Kolab::cDateTime(2006,1,8)); std::string result = Kolab::writeTodo(ev); QVERIFY(Kolab::error() == Kolab::NoError); // std::cout << result << endl; Kolab::Todo e = Kolab::readTodo(result, false); QVERIFY(Kolab::error() == Kolab::NoError); QCOMPARE(ev.due(), e.due()); } void BindingsTest::journalCompletness() { Kolab::Journal ev; ev.setUid("UID"); ev.setCreated(Kolab::cDateTime(2006,1,6,12,0,0,true)); //UTC ev.setLastModified(Kolab::cDateTime(2006,1,6,12,0,0,true)); ev.setSequence(1); ev.setClassification(Kolab::ClassConfidential); ev.addCategory("Category"); ev.setStart(Kolab::cDateTime("Europe/Zurich", 2006,1,6,12,0,0)); Kolab::Attendee attendee(Kolab::ContactReference("mail", "name", "uid")); attendee.setPartStat(Kolab::PartDelegated); attendee.setRole(Kolab::Chair); attendee.setRSVP(true); std::vector reflist; reflist.push_back(Kolab::ContactReference(Kolab::ContactReference::EmailReference, "mail", "name")); reflist.push_back(Kolab::ContactReference(Kolab::ContactReference::EmailReference, "mail2", "name2")); attendee.setDelegatedTo(reflist); attendee.setDelegatedFrom(reflist); attendee.setCutype(Kolab::CutypeResource); ev.setAttendees(std::vector() << attendee << attendee); std::vector attachments; Kolab::Attachment attach; attach.setData("data????*?*?*?*?*?", "mimetype"); attach.setLabel("label"); attachments.push_back(attach); Kolab::Attachment attach2; attach2.setUri(TEST_DATA_PATH "/testfiles/icalEvent.xml", "mimetype"); attach2.setLabel("labe2l"); attachments.push_back(attach2); Kolab::Attachment attach3; using namespace std; ifstream file (TEST_DATA_PATH "/testfiles/icalEvent.xml", ios::in|ios::binary|ios::ate); if (file.is_open()) { int size = file.tellg(); char *memblock = new char [size]; file.seekg (0, ios::beg); file.read (memblock, size); file.close(); attach3.setData(string(memblock, size), "mimetype"); delete[] memblock; } else { qWarning() << "Testfile not found"; } attach3.setLabel("labe3l"); attachments.push_back(attach3); ev.setAttachments(attachments); std::vector properties; properties.push_back(Kolab::CustomProperty("ident", "value")); properties.push_back(Kolab::CustomProperty("ident", "value")); ev.setCustomProperties(properties); std::string result = Kolab::writeJournal(ev); QVERIFY(Kolab::error() == Kolab::NoError); // std::cout << result << endl; Kolab::Journal re = Kolab::readJournal(result, false); QVERIFY(Kolab::error() == Kolab::NoError); QCOMPARE(ev.uid(), re.uid()); QCOMPARE(ev.created(), re.created()); QCOMPARE(ev.lastModified(), re.lastModified()); QCOMPARE(ev.sequence(), re.sequence()); QCOMPARE(ev.classification(), re.classification()); QCOMPARE(ev.categories(), re.categories()); QCOMPARE(ev.start(), re.start()); QCOMPARE(ev.summary(), re.summary()); QCOMPARE(ev.description(), re.description()); QCOMPARE(ev.status(), re.status()); QCOMPARE(ev.attendees(), re.attendees()); QCOMPARE(ev.attachments(), re.attachments()); QCOMPARE(ev.customProperties(), re.customProperties()); } void BindingsTest::freebusyCompletness() { Kolab::Freebusy ev; ev.setUid("UID"); ev.setTimestamp(Kolab::cDateTime(2006,1,6,12,0,0, true)); ev.setStart(Kolab::cDateTime(2006,1,6,12,0,0, true)); ev.setEnd(Kolab::cDateTime(2006,1,6,12,0,0, true)); ev.setOrganizer(Kolab::ContactReference(Kolab::ContactReference::EmailReference, "mail", "name")); std::vector fbperiods; Kolab::FreebusyPeriod fbp; fbp.setType(Kolab::FreebusyPeriod::OutOfOffice); fbp.setEvent("summary", "uid", "location"); std::vector periods; periods.push_back(Kolab::Period(Kolab::cDateTime(2006,1,6,12,0,0, true),Kolab::cDateTime(2007,1,6,12,0,0, true))); periods.push_back(Kolab::Period(Kolab::cDateTime(2006,1,6,12,0,0, true),Kolab::cDateTime(2007,1,6,12,0,0, true))); fbp.setPeriods(periods); fbperiods.push_back(fbp); fbperiods.push_back(fbp); ev.setPeriods(fbperiods); Kolab::overrideTimestamp(ev.timestamp()); std::string result = Kolab::writeFreebusy(ev); QVERIFY(Kolab::error() == Kolab::NoError); // std::cout << result << endl; Kolab::Freebusy re = Kolab::readFreebusy(result, false); QVERIFY(Kolab::error() == Kolab::NoError); QCOMPARE(ev.uid(), re.uid()); QCOMPARE(ev.timestamp(), re.timestamp()); QCOMPARE(ev.start(), re.start()); QCOMPARE(ev.end(), re.end()); QCOMPARE(ev.organizer(), re.organizer()); QCOMPARE(ev.periods(), re.periods()); } void BindingsTest::contactCompletness() { std::vector stringlist; stringlist.push_back("lbksdfbklsd"); stringlist.push_back("sdf"); Kolab::Contact c; c.setUid("1045b57d-ff7f-0000-d814-867b4d7f0000"); c.setLastModified(Kolab::cDateTime(2006,1,6,12,0,0, true)); c.setCategories(stringlist); c.setName("name"); Kolab::NameComponents nc; nc.setSurnames(stringlist); nc.setGiven(stringlist); nc.setAdditional(stringlist); nc.setPrefixes(stringlist); nc.setSuffixes(stringlist); c.setNameComponents(nc); c.setNote("note"); c.setFreeBusyUrl("freebusy"); c.setUrls(std::vector() << Kolab::Url("url1") << Kolab::Url("url1", Kolab::Url::Blog)); c.setNickNames(stringlist); std::vector relateds; Kolab::Related r1(Kolab::Related::Text, "text"); r1.setRelationTypes(Kolab::Related::Child); relateds.push_back(r1); Kolab::Related r2(Kolab::Related::Uid, "urn"); r2.setRelationTypes(Kolab::Related::Child|Kolab::Related::Spouse); relateds.push_back(r2); c.setRelateds(relateds); c.setBDay(Kolab::cDateTime(2001,12,10,12,12,12,false)); c.setAnniversary(Kolab::cDateTime(2001,3,2,1,1,1,false)); c.setPhoto("photo", "mimetype"); c.setGender(Kolab::Contact::Male); c.setLanguages(stringlist); c.setIMaddresses(stringlist,1); std::vector emails; emails.push_back(Kolab::Email("email1@example.org", Kolab::Email::NoType)); emails.push_back(Kolab::Email("email2@example.org", Kolab::Email::Work)); emails.push_back(Kolab::Email("email3@example.org", Kolab::Email::Work|Kolab::Email::Home)); c.setEmailAddresses(emails,0); c.setTitles(stringlist); std::vector list; Kolab::Affiliation aff; aff.setOrganisation("org"); aff.setOrganisationalUnits(stringlist); aff.setLogo("logo", "mime/miem"); aff.setRoles(stringlist); std::vector relateds2; relateds2.push_back(Kolab::Related(Kolab::Related::Text, "textRelation", Kolab::Related::Assistant)); relateds2.push_back(Kolab::Related(Kolab::Related::Uid, "textRelation", Kolab::Related::Manager)); aff.setRelateds(relateds2); std::vector adrs; Kolab::Address adr1; adr1.setLabel("label"); adrs.push_back(adr1); Kolab::Address adr2; adr2.setStreet("street"); adr2.setTypes(Kolab::Address::Work); adrs.push_back(adr2); aff.setAddresses(adrs); list.push_back(aff); Kolab::Affiliation aff2; aff2.setOrganisation("org2"); list.push_back(aff2); c.setAffiliations(list); Kolab::Address address; address.setCode("oiuoiu"); address.setCountry("werwer"); address.setLabel("lkjlkj"); address.setLocality("alla"); address.setRegion("skjdfkd"); address.setStreet("sldkflsdfj"); address.setTypes( Kolab::Address::Work | Kolab::Address::Home ); std::vector addresses; addresses.push_back(address); addresses.push_back(address); c.setAddresses(addresses); Kolab::Telephone phone; phone.setNumber("lkjsdflkjfds"); phone.setTypes(Kolab::Telephone::Work| Kolab::Telephone::Home| Kolab::Telephone::Text| Kolab::Telephone::Voice| Kolab::Telephone::Fax| Kolab::Telephone::Cell| Kolab::Telephone::Video| Kolab::Telephone::Pager| Kolab::Telephone::Textphone| Kolab::Telephone::Car ); std::vector telephones; telephones.push_back(phone); telephones.push_back(phone); c.setTelephones(telephones, 1); std::vector geo; geo << Kolab::Geo(1.3, -40.3); c.setGPSpos(geo); Kolab::Crypto crypto; crypto.setAllowed(Kolab::Crypto::PGPinline | Kolab::Crypto::SMIMEopaque); crypto.setSignPref(Kolab::Crypto::IfPossible); crypto.setEncryptPref(Kolab::Crypto::Never); c.setCrypto(crypto); std::vector keys; keys.push_back(Kolab::Key("pgp", Kolab::Key::PGP)); keys.push_back(Kolab::Key("smime", Kolab::Key::PKCS7_MIME)); c.setKeys(keys); std::vector properties; properties.push_back(Kolab::CustomProperty("ident", "value")); properties.push_back(Kolab::CustomProperty("ident", "value")); c.setCustomProperties(properties); const std::string result = Kolab::writeContact(c); QVERIFY(Kolab::error() == Kolab::NoError); // std::cout << result << endl; Kolab::Contact e = Kolab::readContact(result, false); QVERIFY(Kolab::error() == Kolab::NoError); QCOMPARE(e.uid(), c.uid()); QCOMPARE(e.lastModified(), c.lastModified()); QCOMPARE(e.categories(), c.categories()); QCOMPARE(e.name(), c.name()); QCOMPARE(e.nameComponents(), c.nameComponents()); QCOMPARE(e.note(), c.note()); QCOMPARE(e.freeBusyUrl(), c.freeBusyUrl()); QCOMPARE(e.titles(), c.titles()); QCOMPARE(e.affiliations(), c.affiliations()); QCOMPARE(e.urls(), c.urls()); QCOMPARE(e.addresses(), c.addresses()); QCOMPARE(e.addressPreferredIndex(), c.addressPreferredIndex()); QCOMPARE(e.nickNames(), c.nickNames()); QCOMPARE(e.relateds(), c.relateds()); QCOMPARE(e.bDay(), c.bDay()); QCOMPARE(e.anniversary(), c.anniversary()); QCOMPARE(e.photo(), c.photo()); QCOMPARE(e.photoMimetype(), c.photoMimetype()); QCOMPARE(e.gender(), c.gender()); QCOMPARE(e.languages(), c.languages()); QCOMPARE(e.telephones(), c.telephones()); QCOMPARE(e.telephonesPreferredIndex(), c.telephonesPreferredIndex()); QCOMPARE(e.imAddresses(), c.imAddresses()); QCOMPARE(e.imAddressPreferredIndex(), c.imAddressPreferredIndex()); QCOMPARE(e.emailAddresses(), c.emailAddresses()); QCOMPARE(e.emailAddressPreferredIndex(), c.emailAddressPreferredIndex()); QCOMPARE(e.emailAddressPreferredIndex(), 0); QCOMPARE(e.gpsPos(), c.gpsPos()); QCOMPARE(e.keys(), c.keys()); QCOMPARE(e.crypto(), c.crypto()); QCOMPARE(e.customProperties(), c.customProperties()); } void BindingsTest::dateOnlyDates() { Kolab::Contact c; c.setUid("1045b57d-ff7f-0000-d814-867b4d7f0000"); c.setName("name"); c.setBDay(Kolab::cDateTime(2001,12,10)); c.setAnniversary(Kolab::cDateTime(2001,3,2)); const std::string result = Kolab::writeContact(c); QVERIFY(Kolab::error() == Kolab::NoError); // std::cout << result << endl; Kolab::Contact e = Kolab::readContact(result, false); QVERIFY(Kolab::error() == Kolab::NoError); QCOMPARE(e.bDay(), c.bDay()); QCOMPARE(e.anniversary(), c.anniversary()); } void BindingsTest::distlistCompletness() { std::vector stringlist; stringlist.push_back("lbksdfbklsd"); stringlist.push_back("sdf"); Kolab::DistList c; c.setName("name"); c.setUid("uid"); std::vector members; members.push_back(Kolab::ContactReference(Kolab::ContactReference::EmailReference, "mail", "name")); members.push_back(Kolab::ContactReference(Kolab::ContactReference::UidReference, "urn")); c.setMembers(members); std::vector properties; properties.push_back(Kolab::CustomProperty("ident", "value")); properties.push_back(Kolab::CustomProperty("ident", "value")); c.setCustomProperties(properties); const std::string result = Kolab::writeDistlist(c); QVERIFY(Kolab::error() == Kolab::NoError); // std::cout << result << endl; Kolab::DistList e = Kolab::readDistlist(result, false); QVERIFY(Kolab::error() == Kolab::NoError); QCOMPARE(e.uid(), c.uid()); QCOMPARE(e.name(), c.name()); QCOMPARE(e.members(), c.members()); QCOMPARE(e.customProperties(), c.customProperties()); } void BindingsTest::generateTimestampIfEmpty() { //xcal Kolab::Event ev; setIncidence(ev); ev.setLastModified(Kolab::cDateTime()); std::string result = Kolab::writeEvent(ev); Kolab::Event e = Kolab::readEvent(result, false); QVERIFY(e.lastModified().isValid()); QVERIFY(e.lastModified().isUTC()); //xcard Kolab::Contact c; c.setUid("1045b57d-ff7f-0000-d814-867b4d7f0000"); const std::string contactResult = Kolab::writeContact(c); Kolab::Contact retContact = Kolab::readContact(contactResult, false); QVERIFY(retContact.lastModified().isValid()); QVERIFY(retContact.lastModified().isUTC()); } void BindingsTest::versionTest() { Kolab::Todo ev; setIncidence(ev); std::string result = Kolab::writeTodo(ev); Kolab::Todo e = Kolab::readTodo(result, false); QCOMPARE(Kolab::productId(), std::string(KOLAB_LIB_VERSION_STRING)); QCOMPARE(Kolab::xKolabVersion(), std::string(KOLAB_FORMAT_VERSION)); QCOMPARE(Kolab::xCalVersion(), std::string("2.0")); } void BindingsTest::errorTest() { Kolab::Todo e = Kolab::readTodo("klbsdfbklsdbkl", false); QCOMPARE(Kolab::error(), Kolab::Critical); QVERIFY(!Kolab::errorMessage().empty()); } //Don't break due to an error void BindingsTest::errorRecoveryTest() { Kolab::Todo e = Kolab::readTodo("klbsdfbklsdbkl", false); QCOMPARE(Kolab::error(), Kolab::Critical); Kolab::Todo ev; setIncidence(ev); const std::string result = Kolab::writeTodo(ev); Kolab::readTodo(result, false); QCOMPARE(Kolab::error(), Kolab::NoError); } void BindingsTest::BenchmarkRoundtripKolab() { const Kolab::Event &event = Kolab::readEvent(TEST_DATA_PATH "/testfiles/icalEvent.xml", true); QVERIFY(!Kolab::errorOccurred()); std::string result = Kolab::writeEvent(event); QBENCHMARK { Kolab::readEvent(result, false); } } void BindingsTest::BenchmarkRoundtrip() { const Kolab::Event &event = Kolab::readEvent(TEST_DATA_PATH "/testfiles/icalEvent.xml", true); QVERIFY(!Kolab::errorOccurred()); std::string result; QBENCHMARK { result = Kolab::writeEvent(event); Kolab::readEvent(result, false); } } void BindingsTest::preserveLatin1() { Kolab::Event event; event.setSummary("äöü%@$£é¤¼²°"); std::string result = Kolab::writeEvent(event); // std::cout << result << std::endl; Kolab::Event readEvent = Kolab::readEvent(result, false); // std::cout << readEvent.summary() << std::endl; QCOMPARE(readEvent.summary(), event.summary()); } void BindingsTest::preserveUnicode() { Kolab::Event event; event.setSummary("€Š�ـأبـ"); std::string result = Kolab::writeEvent(event); // std::cout << result << std::endl; Kolab::Event readEvent = Kolab::readEvent(result, false); // std::cout << readEvent.summary() << std::endl; QCOMPARE(readEvent.summary(), event.summary()); } QTEST_MAIN( BindingsTest ) #include "bindingstest.moc"