17 commits - calendaring/calendaring.cpp CMakeLists.txt cmake/modules conversion/kabcconversion.cpp freebusy/CMakeLists.txt freebusy/freebusy.cpp freebusy/freebusy.h icalendar/icalendar.cpp icalendar/imip.cpp kolabformat/errorhandler.cpp kolabformat/errorhandler.h kolabformat/kolabdefinitions.h kolabformat/kolabobject.cpp kolabformat/kolabobject.h kolabformatV2/contact.cpp kolabformatV2/distributionlist.cpp mime/mimeutils.cpp tests/calendaringtest.cpp tests/CMakeLists.txt tests/freebusytest.cpp tests/freebusytest.h tests/testhelpers.h tests/testutils.h

Christian Mollekopf mollekopf at kolabsys.com
Thu Jun 28 10:07:48 CEST 2012


 CMakeLists.txt                         |   68 ++++++--
 calendaring/calendaring.cpp            |    2 
 cmake/modules/FindLibcalendaring.cmake |   20 ++
 conversion/kabcconversion.cpp          |    8 
 freebusy/CMakeLists.txt                |    3 
 freebusy/freebusy.cpp                  |  272 +++++++++++++++++++++++++++++++++
 freebusy/freebusy.h                    |   38 ++++
 icalendar/icalendar.cpp                |    6 
 icalendar/imip.cpp                     |    8 
 kolabformat/errorhandler.cpp           |    6 
 kolabformat/errorhandler.h             |    2 
 kolabformat/kolabdefinitions.h         |    4 
 kolabformat/kolabobject.cpp            |   40 +++-
 kolabformat/kolabobject.h              |    7 
 kolabformatV2/contact.cpp              |   24 +-
 kolabformatV2/distributionlist.cpp     |   55 +++---
 mime/mimeutils.cpp                     |    2 
 tests/CMakeLists.txt                   |   18 +-
 tests/calendaringtest.cpp              |   10 -
 tests/freebusytest.cpp                 |  160 +++++++++++++++++++
 tests/freebusytest.h                   |   32 +++
 tests/testhelpers.h                    |   43 ++++-
 tests/testutils.h                      |    9 +
 23 files changed, 734 insertions(+), 103 deletions(-)

New commits:
commit 47e5f743922eed70cf5d7913224d2bb4ecf27837
Merge: e04661b 614e083
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Thu Jun 28 10:07:37 2012 +0200

    Merge branch 'libcalendaring'
    
    Conflicts:
    	freebusy/freebusy.h



commit e04661bd08e03cb35ab2724daffddc15e94d504e
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Tue Jun 26 15:15:42 2012 +0200

    freebusy serializing, a couple of fixes for the generateFreeBusy code

diff --git a/freebusy/freebusy.cpp b/freebusy/freebusy.cpp
index ceb5bc2..c7f853e 100644
--- a/freebusy/freebusy.cpp
+++ b/freebusy/freebusy.cpp
@@ -24,6 +24,105 @@
 #include <quuid.h>
 
 
+// namespace KCalCore {
+//     struct KCalFreebusy
+// {
+//
+// void init( const Event::List &eventList, const KDateTime &start, const KDateTime &end )
+// {
+//     mDtStart = start.toUtc();
+//     mDtEnd = end.toUtc();
+//
+//   // Loops through every event in the calendar
+//   Event::List::ConstIterator it;
+//   for ( it = eventList.constBegin(); it != eventList.constEnd(); ++it ) {
+//     Event::Ptr event = *it;
+//
+//     // If this event is transparent it shouldn't be in the freebusy list.
+//     if ( event->transparency() == Event::Transparent ) {
+//       continue;
+//     }
+//
+//     if ( event->hasRecurrenceId() ) {
+//       continue; //TODO apply special period exception (duration could be different)
+//     }
+//
+//     const KDateTime eventStart = event->dtStart().toUtc();
+//     const KDateTime eventEnd = event->dtEnd().toUtc();
+//
+//     if ( event->recurs() ) {
+//         const KCalCore::Duration duration( eventStart, eventEnd );
+//         const KCalCore::DateTimeList list = event->recurrence()->timesInInterval(start, end);
+//         foreach (const KDateTime &dt, list) {
+//             const KDateTime utc = dt.toUtc();
+//             addLocalPeriod(utc, duration.end(utc) );
+//         }
+//     } else {
+//         addLocalPeriod( eventStart, eventEnd );
+//     }
+//   }
+//
+// //   q->sortList();
+// }
+//
+// bool addLocalPeriod(
+//                                         const KDateTime &eventStart,
+//                                         const KDateTime &eventEnd )
+// {
+//   KDateTime tmpStart;
+//   KDateTime tmpEnd;
+//
+//   //Check to see if the start *or* end of the event is
+//   //between the start and end of the freebusy dates.
+//   if ( !( ( ( mDtStart.secsTo( eventStart ) >= 0 ) &&
+//             ( eventStart.secsTo( mDtEnd ) >= 0 ) ) ||
+//           ( ( mDtStart.secsTo( eventEnd ) >= 0 ) &&
+//             ( eventEnd.secsTo( mDtEnd ) >= 0 ) ) ) ) {
+//       qDebug() << "out of scope";
+//     return false;
+//   }
+//
+// //   qDebug() << eventStart.date().toString() << eventStart.time().toString() << mDtStart.toString();
+//   if ( eventStart < mDtStart ) { //eventStart is before start
+// //       qDebug() << "use start";
+//     tmpStart = mDtStart;
+//   } else {
+//     tmpStart = eventStart;
+//   }
+//
+//   qDebug() << eventEnd.date().toString() << eventEnd.time().toString() << mDtEnd.toString();
+//   if ( eventEnd > mDtEnd ) { //event end is after dtEnd
+// //     qDebug() << "use end";
+//     tmpEnd = mDtEnd;
+//   } else {
+//     tmpEnd = eventEnd;
+//   }
+//
+// //   qDebug() << "########## " << tmpStart.isValid();
+//   Q_ASSERT(tmpStart.isValid());
+//   Q_ASSERT(tmpEnd.isValid());
+// //   qDebug() << tmpStart.date().toString() << tmpStart.time().toString() << tmpStart.toString();
+//
+//   FreeBusyPeriod p( tmpStart, tmpEnd );
+//   mBusyPeriods.append( p );
+//
+//   return true;
+// }
+//
+//     KDateTime mDtStart;
+//     KDateTime mDtEnd;                  // end datetime
+//     FreeBusyPeriod::List mBusyPeriods; // list of periods
+//
+// };
+//
+// } // Namespace
+
+
+
+
+
+
+
 namespace Kolab {
     namespace FreebusyUtils {
 
@@ -57,21 +156,43 @@ Kolab::Period addLocalPeriod(  const KDateTime &eventStart, const KDateTime &eve
   }
   Q_ASSERT(tmpStart.isValid());
   Q_ASSERT(tmpEnd.isValid());
+  if (tmpStart.isDateOnly()) {
+    tmpStart.setTime(QTime(0,0,0,0));
+  }
+  if (tmpEnd.isDateOnly()) {
+    tmpEnd.setTime(QTime(23,59,59,999)); //The window is inclusive
+  }
   return Kolab::Period(Kolab::Conversion::fromDate(tmpStart), Kolab::Conversion::fromDate(tmpEnd));
 }
 
-        
+Freebusy generateFreeBusy(const std::vector< Event >& events, const cDateTime& startDate, const cDateTime& endDate)
+{
+    QList<KCalCore::Event::Ptr> list;
+    foreach (const Kolab::Event &e, events) {
+        list.append(Kolab::Conversion::toKCalCore(e));
+    }
+    KCalCore::Person::Ptr person(new KCalCore::Person("dummyname", "dummyemail"));
+    return generateFreeBusy(list, Kolab::Conversion::toDate(startDate), Kolab::Conversion::toDate(endDate), person);
+}
 
-Freebusy generateFreeBusy(const std::vector< Event >& events, const cDateTime& startDate, const cDateTime& endDate, const Freebusy& existing)
+Freebusy generateFreeBusy(const QList<KCalCore::Event::Ptr>& events, const KDateTime& startDate, const KDateTime& endDate, const KCalCore::Person::Ptr &organizer)
 {
-    const KDateTime start = Kolab::Conversion::toDate(startDate).toUtc();
-    const KDateTime end = Kolab::Conversion::toDate(endDate).toUtc();
+    /*
+     * TODO the conversion of date-only values to date-time is only necessary because xCal doesn't allow date only. iCalendar doesn't seem to make this restriction so it looks like a bug.
+     */
+    KDateTime start = startDate.toUtc();
+    if (start.isDateOnly()) {
+        start.setTime(QTime(0,0,0,0));
+    }
+    KDateTime end = endDate.toUtc();
+    if (end.isDateOnly()) {
+        end.addDays(1);
+        end.setTime(QTime(0,0,0,0)); //The window is inclusive
+    }
 
     //TODO try to merge that with KCalCore::Freebusy
     std::vector<Kolab::FreebusyPeriod> freebusyPeriods;
-    foreach (const Kolab::Event &e, events) {
-        KCalCore::Event::Ptr event = Kolab::Conversion::toKCalCore(e);
-    
+    Q_FOREACH (KCalCore::Event::Ptr event, events) {    
         // If this event is transparent it shouldn't be in the freebusy list.
         if ( event->transparency() == KCalCore::Event::Transparent ) {
             continue;
@@ -88,7 +209,7 @@ Freebusy generateFreeBusy(const std::vector< Event >& events, const cDateTime& s
         if ( event->recurs() ) {
             const KCalCore::Duration duration( eventStart, eventEnd );
             const KCalCore::DateTimeList list = event->recurrence()->timesInInterval(start, end);
-            foreach (const KDateTime &dt, list) {
+            Q_FOREACH (const KDateTime &dt, list) {
                 const KDateTime utc = dt.toUtc();
                 const Kolab::Period &period = addLocalPeriod(utc, duration.end(utc), start, end);
                 if (period.isValid()) {
@@ -104,21 +225,21 @@ Freebusy generateFreeBusy(const std::vector< Event >& events, const cDateTime& s
         if (!periods.empty()) {
             Kolab::FreebusyPeriod period;
             period.setPeriods(periods);
-            //TODO get out of office from event
+            //TODO get busy type from event (out-of-office, tentative)
             period.setType(Kolab::FreebusyPeriod::Busy);
-    //         period.setEvent(event->summary().toStdString(), event->uid().toStdString(), event->location().toStdString());
-            //TODO event uid etc.
+            period.setEvent(event->uid().toStdString(), event->summary().toStdString(), event->location().toStdString());
             freebusyPeriods.push_back(period);
         }
     }
 
     Kolab::Freebusy freebusy;
-    freebusy.setStart(startDate);
-    freebusy.setEnd(endDate);
+    
+    freebusy.setStart(Kolab::Conversion::fromDate(start));
+    freebusy.setEnd(Kolab::Conversion::fromDate(end));
     freebusy.setPeriods(freebusyPeriods);
     freebusy.setUid(QUuid::createUuid().toString().toStdString());
     freebusy.setTimestamp(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime()));
-    freebusy.setOrganizer(ContactReference(Kolab::ContactReference::EmailReference, "email", "name"));
+    freebusy.setOrganizer(ContactReference(Kolab::ContactReference::EmailReference, organizer->email().toStdString(), organizer->name().toStdString()));
     
     return freebusy;
 }
diff --git a/freebusy/freebusy.h b/freebusy/freebusy.h
index fbea05f..a61e1c4 100644
--- a/freebusy/freebusy.h
+++ b/freebusy/freebusy.h
@@ -22,12 +22,15 @@
 #include "kolab_export.h"
 #include <kolabevent.h>
 #include <kolabfreebusy.h>
+#include <KCalCore/Event>
 
 namespace Kolab {
     namespace FreebusyUtils {
 
-Kolab::Freebusy generateFreeBusy(const std::vector<Kolab::Event> &events, const Kolab::cDateTime &startDate, const Kolab::cDateTime &endDate, const Kolab::Freebusy &existing = Kolab::Freebusy());
-std::string toIFB(const Kolab::Freebusy &);
+KOLAB_EXPORT Freebusy generateFreeBusy(const QList<KCalCore::Event::Ptr>& events, const KDateTime& startDate, const KDateTime& endDate, const KCalCore::Person::Ptr &organizer);
+KOLAB_EXPORT std::string toIFB(const Kolab::Freebusy &);
+
+Kolab::Freebusy generateFreeBusy(const std::vector<Kolab::Event> &events, const Kolab::cDateTime &startDate, const Kolab::cDateTime &endDate);
 
     }
 }
diff --git a/kolabformat/kolabdefinitions.h b/kolabformat/kolabdefinitions.h
index 2fdcf70..0d53c8e 100644
--- a/kolabformat/kolabdefinitions.h
+++ b/kolabformat/kolabdefinitions.h
@@ -28,7 +28,8 @@ namespace Kolab {
 #define KOLAB_FOLDER_TYPE_TASK    "task"
 #define KOLAB_FOLDER_TYPE_JOURNAL "journal"
 #define KOLAB_FOLDER_TYPE_NOTE    "note"
-#define KOLAB_FOLDER_TYPE_CONFIGURATION    "configuration"
+#define KOLAB_FOLDER_TYPE_CONFIGURATION "configuration"
+#define KOLAB_FOLDER_TYPE_FREEBUSY      "freebusy"
 
 #define KOLAB_FOLDER_TYPE_DEFAULT_SUFFIX ".default"
 
@@ -50,6 +51,7 @@ static QString distlistKolabTypeCompat() { return QString::fromLatin1("applicati
 static QString noteKolabType() { return QString::fromLatin1("application/x-vnd.kolab.note"); }
 static QString configurationKolabType() { return QString::fromLatin1("application/x-vnd.kolab.configuration"); }
 static QString dictKolabType() { return QString::fromLatin1("application/x-vnd.kolab.configuration.dictionary"); }
+static QString freebusyKolabType() { return QString::fromLatin1("application/x-vnd.kolab.freebusy"); }
 
 static QString xCalMimeType() { return QString::fromLatin1("application/calendar+xml"); };
 static QString xCardMimeType() { return QString::fromLatin1("application/vcard+xml"); };
diff --git a/kolabformat/kolabobject.cpp b/kolabformat/kolabobject.cpp
index 0af095d..4e76444 100644
--- a/kolabformat/kolabobject.cpp
+++ b/kolabformat/kolabobject.cpp
@@ -468,6 +468,16 @@ KMime::Message::Ptr KolabObjectWriter::writeDictionary(const QStringList &entrie
     return  Mime::createMessage(QString::fromStdString(configuration.uid()), kolabMimeType(), dictKolabType(), QString::fromStdString(v3String).toLocal8Bit(), true, getProductId(productId));
 }
 
+KMime::Message::Ptr KolabObjectWriter::writeFreebusy(const Freebusy &freebusy, Version v, const QString& productId)
+{
+    ErrorHandler::clearErrors();
+    if (v != KolabV3) {
+        Critical() << "only v3 implementation available";
+    }
+    const std::string &v3String = Kolab::writeFreebusy(freebusy, getProductId(productId).toStdString());
+    ErrorHandler::handleLibkolabxmlErrors();
+    return  Mime::createMessage(QString::fromStdString(freebusy.uid()), xCalMimeType(), freebusyKolabType(), QString::fromStdString(v3String).toLocal8Bit(), true, getProductId(productId));
+}
 
 
 
diff --git a/kolabformat/kolabobject.h b/kolabformat/kolabobject.h
index ecde1f1..7cea7bb 100644
--- a/kolabformat/kolabobject.h
+++ b/kolabformat/kolabobject.h
@@ -30,6 +30,8 @@
 
 namespace Kolab {
 
+class Freebusy;
+
 enum Version {
     KolabV2,
     KolabV3
@@ -43,7 +45,8 @@ enum ObjectType {
     ContactObject,
     DistlistObject,
     NoteObject,
-    DictionaryConfigurationObject
+    DictionaryConfigurationObject,
+    FreebusyObject
 };
 
 KOLAB_EXPORT KCalCore::Event::Ptr readV2EventXML(const QByteArray &xmlData, QStringList &attachments);
@@ -109,6 +112,8 @@ public:
     static KMime::Message::Ptr writeDistlist(const KABC::ContactGroup &, Version v = KolabV3, const QString &productId = QString());
     static KMime::Message::Ptr writeNote(const KMime::Message::Ptr &, Version v = KolabV3, const QString &productId = QString());
     static KMime::Message::Ptr writeDictionary(const QStringList &, const QString &lang, Version v = KolabV3, const QString &productId = QString());
+    static KMime::Message::Ptr writeFreebusy(const Kolab::Freebusy &, Version v = KolabV3, const QString &productId = QString());
+    
 };
 
 }; //Namespace


commit 03dcd483cce6e7dfd6aafcb071bb7c5806a93522
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Tue Jun 26 15:14:47 2012 +0200

    better error messages

diff --git a/kolabformat/kolabobject.cpp b/kolabformat/kolabobject.cpp
index 27f7ef7..0af095d 100644
--- a/kolabformat/kolabobject.cpp
+++ b/kolabformat/kolabobject.cpp
@@ -121,6 +121,14 @@ QByteArray getMimeType(Kolab::ObjectType type)
     return QByteArray();
 }
 
+void printMessageDebugInfo(const KMime::Message::Ptr &msg)
+{
+    //TODO replace by Debug stream for Mimemessage
+    Debug() << "MessageId: " << msg->messageID()->asUnicodeString();
+    Debug() << "Subject: " << msg->subject()->asUnicodeString();
+//     Debug() << msg->encodedContent();
+}
+
 ObjectType KolabObjectReader::parseMimeMessage(const KMime::Message::Ptr &msg)
 {
     ErrorHandler::clearErrors();
@@ -128,6 +136,7 @@ ObjectType KolabObjectReader::parseMimeMessage(const KMime::Message::Ptr &msg)
     KMime::Headers::Base *xKolabHeader = msg->getHeaderByType(X_KOLAB_TYPE_HEADER);
     if (!xKolabHeader) {
         CRITICAL("could not find the X-Kolab-Type Header");
+        printMessageDebugInfo(msg);
         return InvalidObject;
     }
     const QString &kolabType = xKolabHeader->asUnicodeString(); //TODO we probably shouldn't use unicodeString
@@ -141,7 +150,7 @@ ObjectType KolabObjectReader::parseMimeMessage(const KMime::Message::Ptr &msg)
         d->mVersion = KolabV2;
     } else {
         if (xKolabVersion->asUnicodeString() != KOLAB_VERSION_V3) { //TODO version compatibility check?
-            WARNING("Kolab Version Header available but not on the same version as the implementation");
+            Warning() << "Kolab Version Header available but not on the same version as the implementation: " << xKolabVersion->asUnicodeString();
         }
         d->mVersion = KolabV3;
     }
@@ -150,7 +159,8 @@ ObjectType KolabObjectReader::parseMimeMessage(const KMime::Message::Ptr &msg)
         if (d->mObjectType == DictionaryConfigurationObject) {
             KMime::Content *xmlContent = Mime::findContentByType( msg, "application/xml" );
             if ( !xmlContent ) {
-                CRITICAL("no part found");
+                Critical() << "no application/xml part found";
+                printMessageDebugInfo(msg);
                 return InvalidObject;
             }
             const QByteArray &xmlData = xmlContent->decodedContent();
@@ -160,7 +170,8 @@ ObjectType KolabObjectReader::parseMimeMessage(const KMime::Message::Ptr &msg)
         }
         KMime::Content *xmlContent = Mime::findContentByType( msg, kolabType.toLocal8Bit() );
         if ( !xmlContent ) {
-            CRITICAL("no part found");
+            Critical() << "no part with type" << kolabType.toLocal8Bit() << " found";
+            printMessageDebugInfo(msg);
             return InvalidObject;
         }
         const QByteArray &xmlData = xmlContent->decodedContent();
@@ -199,7 +210,8 @@ ObjectType KolabObjectReader::parseMimeMessage(const KMime::Message::Ptr &msg)
     } else { //V3
         KMime::Content *xmlContent = Mime::findContentByType( msg, getMimeType(d->mObjectType) );
         if ( !xmlContent ) {
-            CRITICAL("no part found");
+            Critical() << "no " << getMimeType(d->mObjectType) << " part found";
+            printMessageDebugInfo(msg);
             return InvalidObject;
         }
         switch (d->mObjectType) {
@@ -244,7 +256,8 @@ ObjectType KolabObjectReader::parseMimeMessage(const KMime::Message::Ptr &msg)
             }
                 break;
             default:
-                CRITICAL("no kolab object found "+kolabType);
+                Critical() << "no kolab object found " << kolabType;
+                printMessageDebugInfo(msg);
                 break;
         }
 


commit 7412e6d6fd37f5a18024ae631ae3f3b4df0f3353
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Tue Jun 26 15:14:29 2012 +0200

    uid in subject

diff --git a/kolabformat/kolabobject.cpp b/kolabformat/kolabobject.cpp
index 1f46d95..27f7ef7 100644
--- a/kolabformat/kolabobject.cpp
+++ b/kolabformat/kolabobject.cpp
@@ -417,7 +417,7 @@ KMime::Message::Ptr KolabObjectWriter::writeDistlist(const KABC::ContactGroup &d
         const Kolab::DistList &dist = Kolab::Conversion::fromKABC(distlist);
         const std::string &v3String = Kolab::writeDistlist(dist, getProductId(productId).toStdString());
         ErrorHandler::handleLibkolabxmlErrors();
-        return  Mime::createMessage(QString(), xCardMimeType(), contactKolabType(), QString::fromStdString(v3String).toLocal8Bit(), true, getProductId(productId));
+        return  Mime::createMessage(QString::fromStdString(dist.uid()), xCardMimeType(), contactKolabType(), QString::fromStdString(v3String).toLocal8Bit(), true, getProductId(productId));
     }
     KolabV2::DistributionList d(&distlist);
     return distListToKolabFormat(d, getProductId(productId));
@@ -431,7 +431,7 @@ KMime::Message::Ptr KolabObjectWriter::writeNote(const KMime::Message::Ptr &note
         const Kolab::Note &n = Kolab::Conversion::fromNote(note);
         const std::string &v3String = Kolab::writeNote(n, getProductId(productId).toStdString());
         ErrorHandler::handleLibkolabxmlErrors();
-        return  Mime::createMessage(QString::fromStdString(n.summary()), kolabMimeType(), noteKolabType(), QString::fromStdString(v3String).toLocal8Bit(), true, getProductId(productId));
+        return  Mime::createMessage(QString::fromStdString(n.uid()), kolabMimeType(), noteKolabType(), QString::fromStdString(v3String).toLocal8Bit(), true, getProductId(productId));
     }
     return noteToKolab(note, getProductId(productId));
 }
@@ -452,8 +452,7 @@ KMime::Message::Ptr KolabObjectWriter::writeDictionary(const QStringList &entrie
     Kolab::Configuration configuration(dictionary); //TODO preserve creation/lastModified date
     const std::string &v3String = Kolab::writeConfiguration(configuration, getProductId(productId).toStdString());
     ErrorHandler::handleLibkolabxmlErrors();
-    //TODO uid in subject?
-    return  Mime::createMessage(QString(), kolabMimeType(), dictKolabType(), QString::fromStdString(v3String).toLocal8Bit(), true, getProductId(productId));
+    return  Mime::createMessage(QString::fromStdString(configuration.uid()), kolabMimeType(), dictKolabType(), QString::fromStdString(v3String).toLocal8Bit(), true, getProductId(productId));
 }
 
 


commit 0a13780403fa30f2f4f9474239f2a18ff0d1f017
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Tue Jun 26 15:12:47 2012 +0200

    make it easy to print an error.

diff --git a/kolabformat/errorhandler.cpp b/kolabformat/errorhandler.cpp
index 4fc5147..3b2f98a 100644
--- a/kolabformat/errorhandler.cpp
+++ b/kolabformat/errorhandler.cpp
@@ -40,6 +40,7 @@ void ErrorHandler::addError(ErrorHandler::Severity s, const QString& message, co
     }
     if (s > m_worstError) {
         m_worstError = s;
+        m_worstErrorMessage = message;
     }
     m_errorQueue.append(Err(s, message, location));
 }
@@ -49,6 +50,11 @@ ErrorHandler::Severity ErrorHandler::error() const
     return m_worstError;
 }
 
+QString ErrorHandler::errorMessage() const
+{
+    return m_worstErrorMessage;
+}
+
 const QList< ErrorHandler::Err >& ErrorHandler::getErrors() const
 {
     return m_errorQueue;
diff --git a/kolabformat/errorhandler.h b/kolabformat/errorhandler.h
index 73047cc..254a741 100644
--- a/kolabformat/errorhandler.h
+++ b/kolabformat/errorhandler.h
@@ -66,6 +66,7 @@ public:
     void addError(Severity s, const QString &message, const QString &location);
     const QList <Err> &getErrors() const;
     Severity error() const;
+    QString errorMessage() const;
     void clear();
     
     /**
@@ -84,6 +85,7 @@ private:
     ErrorHandler & operator= (const ErrorHandler &);
     
     Severity m_worstError;
+    QString m_worstErrorMessage;
     QList <Err> m_errorQueue;
 };
 


commit 2dc0f49a574325bdddf505983b3d4f6e15c8a023
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Thu Jun 21 17:16:10 2012 +0200

    Freebusy generation from events and ical file writing

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3f3186d..30c84a0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -73,6 +73,7 @@ add_subdirectory(kolabformatV2)
 add_subdirectory(conversion)
 add_subdirectory(calendaring)
 add_subdirectory(icalendar)
+add_subdirectory(freebusy)
 
 QT4_WRAP_CPP(CALENDARING_MOC calendaring/event.h)
 # QT4_WRAP_CPP(CONVERSION_MOC conversion/qtevent.h conversion/qtduration.h)
@@ -87,6 +88,7 @@ set(KOLAB_SRCS
     ${ICALENDAR_SRCS}
     ${CALENDARING_MOC}
     ${CONVERSION_MOC}
+    ${FREEBUSY_SRCS}
 )
 
 set(KOLAB_LINK_LIBRARIES
diff --git a/freebusy/CMakeLists.txt b/freebusy/CMakeLists.txt
new file mode 100644
index 0000000..f1f584e
--- /dev/null
+++ b/freebusy/CMakeLists.txt
@@ -0,0 +1,3 @@
+set (FREEBUSY_SRCS
+    ${CMAKE_CURRENT_SOURCE_DIR}/freebusy.cpp
+    PARENT_SCOPE)
diff --git a/freebusy/freebusy.cpp b/freebusy/freebusy.cpp
new file mode 100644
index 0000000..ceb5bc2
--- /dev/null
+++ b/freebusy/freebusy.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2012  Christian Mollekopf <mollekopf at kolabsys.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "freebusy.h"
+#include "conversion/kcalconversion.h"
+#include <kcalcore/freebusy.h>
+#include <kcalcore/icalformat.h>
+#include <kdebug.h>
+#include <quuid.h>
+
+
+namespace Kolab {
+    namespace FreebusyUtils {
+
+
+Kolab::Period addLocalPeriod(  const KDateTime &eventStart, const KDateTime &eventEnd, const KDateTime &mDtStart, const KDateTime &mDtEnd)
+{
+  KDateTime tmpStart;
+  KDateTime tmpEnd;
+
+  //Check to see if the start *or* end of the event is
+  //between the start and end of the freebusy dates.
+  if ( !( ( ( mDtStart <= eventStart) &&
+            ( eventStart <= mDtEnd ) ) ||
+          ( ( mDtStart <= eventEnd ) &&
+            ( eventEnd <= mDtEnd ) ) ) ) {
+    qDebug() << "out of scope";
+    return Kolab::Period();
+  }
+
+  if ( eventStart < mDtStart ) { //eventStart is before start
+    tmpStart = mDtStart;
+  } else {
+    tmpStart = eventStart;
+  }
+
+  qDebug() << eventEnd.date().toString() << eventEnd.time().toString() << mDtEnd.toString();
+  if ( eventEnd > mDtEnd ) { //event end is after dtEnd
+    tmpEnd = mDtEnd;
+  } else {
+    tmpEnd = eventEnd;
+  }
+  Q_ASSERT(tmpStart.isValid());
+  Q_ASSERT(tmpEnd.isValid());
+  return Kolab::Period(Kolab::Conversion::fromDate(tmpStart), Kolab::Conversion::fromDate(tmpEnd));
+}
+
+        
+
+Freebusy generateFreeBusy(const std::vector< Event >& events, const cDateTime& startDate, const cDateTime& endDate, const Freebusy& existing)
+{
+    const KDateTime start = Kolab::Conversion::toDate(startDate).toUtc();
+    const KDateTime end = Kolab::Conversion::toDate(endDate).toUtc();
+
+    //TODO try to merge that with KCalCore::Freebusy
+    std::vector<Kolab::FreebusyPeriod> freebusyPeriods;
+    foreach (const Kolab::Event &e, events) {
+        KCalCore::Event::Ptr event = Kolab::Conversion::toKCalCore(e);
+    
+        // If this event is transparent it shouldn't be in the freebusy list.
+        if ( event->transparency() == KCalCore::Event::Transparent ) {
+            continue;
+        }
+
+        if ( event->hasRecurrenceId() ) {
+            continue; //TODO apply special period exception (duration could be different)
+        }
+
+        const KDateTime eventStart = event->dtStart().toUtc();
+        const KDateTime eventEnd = event->dtEnd().toUtc();
+
+        std::vector <Kolab::Period> periods;
+        if ( event->recurs() ) {
+            const KCalCore::Duration duration( eventStart, eventEnd );
+            const KCalCore::DateTimeList list = event->recurrence()->timesInInterval(start, end);
+            foreach (const KDateTime &dt, list) {
+                const KDateTime utc = dt.toUtc();
+                const Kolab::Period &period = addLocalPeriod(utc, duration.end(utc), start, end);
+                if (period.isValid()) {
+                    periods.push_back(period);
+                }
+            }
+        } else {
+            const Kolab::Period &period = addLocalPeriod(eventStart, eventEnd, start, end);
+            if (period.isValid()) {
+                periods.push_back(period);
+            }
+        }
+        if (!periods.empty()) {
+            Kolab::FreebusyPeriod period;
+            period.setPeriods(periods);
+            //TODO get out of office from event
+            period.setType(Kolab::FreebusyPeriod::Busy);
+    //         period.setEvent(event->summary().toStdString(), event->uid().toStdString(), event->location().toStdString());
+            //TODO event uid etc.
+            freebusyPeriods.push_back(period);
+        }
+    }
+
+    Kolab::Freebusy freebusy;
+    freebusy.setStart(startDate);
+    freebusy.setEnd(endDate);
+    freebusy.setPeriods(freebusyPeriods);
+    freebusy.setUid(QUuid::createUuid().toString().toStdString());
+    freebusy.setTimestamp(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime()));
+    freebusy.setOrganizer(ContactReference(Kolab::ContactReference::EmailReference, "email", "name"));
+    
+    return freebusy;
+}
+
+std::string toIFB(const Kolab::Freebusy &freebusy)
+{
+    KCalCore::FreeBusy::Ptr fb(new KCalCore::FreeBusy(Kolab::Conversion::toDate(freebusy.start()), Kolab::Conversion::toDate(freebusy.end())));
+    KCalCore::FreeBusyPeriod::List list;
+    Q_FOREACH (const Kolab::FreebusyPeriod &fbPeriod, freebusy.periods()) {
+        Q_FOREACH (const Kolab::Period &p, fbPeriod.periods()) {
+            KCalCore::FreeBusyPeriod period(Kolab::Conversion::toDate(p.start), Kolab::Conversion::toDate(p.end));
+//             period.setSummary("summary"); Doesn't even work. X-SUMMARY is read though (just not written out)
+            //TODO
+            list.append(period);
+            
+        }
+    }
+    fb->addPeriods(list);
+
+    fb->setUid(QString::fromStdString(freebusy.uid()));
+    fb->setOrganizer(KCalCore::Person::Ptr(new KCalCore::Person(QString::fromStdString(freebusy.organizer().name()), QString::fromStdString(freebusy.organizer().email()))));
+    fb->setLastModified(Kolab::Conversion::toDate(freebusy.timestamp()));
+
+    KCalCore::ICalFormat format;
+    QString data = format.createScheduleMessage( fb, KCalCore::iTIPPublish );
+    return data.toStdString();
+}
+
+    }
+}
diff --git a/freebusy/freebusy.h b/freebusy/freebusy.h
new file mode 100644
index 0000000..fbea05f
--- /dev/null
+++ b/freebusy/freebusy.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012  Christian Mollekopf <mollekopf at kolabsys.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef FREEBUSY_H
+#define FREEBUSY_H
+
+#include "kolab_export.h"
+#include <kolabevent.h>
+#include <kolabfreebusy.h>
+
+namespace Kolab {
+    namespace FreebusyUtils {
+
+Kolab::Freebusy generateFreeBusy(const std::vector<Kolab::Event> &events, const Kolab::cDateTime &startDate, const Kolab::cDateTime &endDate, const Kolab::Freebusy &existing = Kolab::Freebusy());
+std::string toIFB(const Kolab::Freebusy &);
+
+    }
+}
+
+#endif // FREEBUSY_H
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 2f1f80e..a9df2b6 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -2,25 +2,29 @@
 include_directories(${CMAKE_CURRENT_BINARY_DIR})
 
 QT4_AUTOMOC(benchmark.cpp)
-add_executable(benchmarktest benchmark.cpp  ${CMAKE_CURRENT_BINARY_DIR}/${BINDINGSTEST_MOC})
+add_executable(benchmarktest benchmark.cpp)
 target_link_libraries(benchmarktest ${QT_QTTEST_LIBRARY} kolab_static)
 
 QT4_AUTOMOC(formattest.cpp)
-add_executable(formattest formattest.cpp  ${CMAKE_CURRENT_BINARY_DIR}/${BINDINGSTEST_MOC})
+add_executable(formattest formattest.cpp)
 target_link_libraries(formattest ${QT_QTTEST_LIBRARY} kolab_static)
 
 QT4_AUTOMOC(upgradetest.cpp)
-add_executable(upgradetest upgradetest.cpp  ${CMAKE_CURRENT_BINARY_DIR}/${BINDINGSTEST_MOC})
+add_executable(upgradetest upgradetest.cpp)
 target_link_libraries(upgradetest ${QT_QTTEST_LIBRARY} kolab_static)
 
 QT4_AUTOMOC(kcalconversiontest.cpp)
-add_executable(kcalconversiontest kcalconversiontest.cpp ${CMAKE_CURRENT_BINARY_DIR}/${BINDINGSTEST_MOC})
+add_executable(kcalconversiontest kcalconversiontest.cpp)
 target_link_libraries(kcalconversiontest ${QT_QTTEST_LIBRARY} kolab_static)
 
 QT4_AUTOMOC(calendaringtest.cpp)
-add_executable(calendaringtest calendaringtest.cpp ${CMAKE_CURRENT_BINARY_DIR}/${BINDINGSTEST_MOC})
+add_executable(calendaringtest calendaringtest.cpp)
 target_link_libraries(calendaringtest ${QT_QTTEST_LIBRARY} kolab_static)
 
 QT4_AUTOMOC(icalendartest.cpp)
-add_executable(icalendartest icalendartest.cpp ${CMAKE_CURRENT_BINARY_DIR}/${BINDINGSTEST_MOC})
-target_link_libraries(icalendartest ${QT_QTTEST_LIBRARY} kolab_static)
\ No newline at end of file
+add_executable(icalendartest icalendartest.cpp)
+target_link_libraries(icalendartest ${QT_QTTEST_LIBRARY} kolab_static)
+
+QT4_AUTOMOC(freebusytest.cpp)
+add_executable(freebusytest freebusytest.cpp)
+target_link_libraries(freebusytest ${QT_QTTEST_LIBRARY} kolab_static)
\ No newline at end of file
diff --git a/tests/calendaringtest.cpp b/tests/calendaringtest.cpp
index 3671ecb..9ad29bf 100644
--- a/tests/calendaringtest.cpp
+++ b/tests/calendaringtest.cpp
@@ -26,15 +26,7 @@
 #include <calendaring/event.h>
 
 #include "testhelpers.h"
-
-
-Kolab::Event createEvent(const Kolab::cDateTime &start, const Kolab::cDateTime &end)
-{
-    Kolab::Event event;
-    event.setStart(start);
-    event.setEnd(end);
-    return event;
-}
+#include "testutils.h"
 
 void compareEvents(const std::vector<Kolab::Event> &list1, const std::vector<Kolab::Event> &list2)
 {
diff --git a/tests/freebusytest.cpp b/tests/freebusytest.cpp
new file mode 100644
index 0000000..40adf6b
--- /dev/null
+++ b/tests/freebusytest.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2012  Christian Mollekopf <mollekopf at kolabsys.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "freebusytest.h"
+#include "testutils.h"
+#include "testhelpers.h"
+
+#include <QTest>
+#include "freebusy/freebusy.h"
+#include <kolabfreebusy.h>
+
+
+void FreebusyTest::testFB_data()
+{
+    QTest::addColumn<Kolab::cDateTime>( "start" );
+    QTest::addColumn<Kolab::cDateTime>( "end" );
+    QTest::addColumn< std::vector<Kolab::Event> >( "events" );
+    QTest::addColumn< std::vector<Kolab::FreebusyPeriod> >( "output" );
+
+
+    //UTC check
+    {
+        Kolab::Period p1(Kolab::cDateTime(2011,10,6,12,1,1,true), Kolab::cDateTime(2011,10,7,12,1,1,true));
+        Kolab::Period p2(Kolab::cDateTime(2011,10,8,12,1,1,true), Kolab::cDateTime(2011,10,9,12,1,1,true));
+        Kolab::Period p3(Kolab::cDateTime(2011,10,10,12,1,1,true), Kolab::cDateTime(2011,10,11,12,1,1,true));
+
+        std::vector<Kolab::Event> events;
+        events.push_back(createEvent(p1.start, p1.end));
+        events.push_back(createEvent(p2.start, p2.end));
+        events.push_back(createEvent(p3.start, p3.end));
+
+        Kolab::FreebusyPeriod period1;
+        period1.setType(Kolab::FreebusyPeriod::Busy);
+        period1.setPeriods(std::vector<Kolab::Period>() << p1);
+
+        Kolab::FreebusyPeriod period2;
+        period2.setType(Kolab::FreebusyPeriod::Busy);
+        period2.setPeriods(std::vector<Kolab::Period>() << p2);
+
+        Kolab::FreebusyPeriod period3;
+        period3.setType(Kolab::FreebusyPeriod::Busy);
+        period3.setPeriods(std::vector<Kolab::Period>() << p3);
+
+        {
+            std::vector<Kolab::FreebusyPeriod> output;
+            output.push_back(period1);
+            output.push_back(period2);
+            output.push_back(period3);
+
+            QTest::newRow( "simple utc" ) << Kolab::cDateTime(2010, 1, 1,1,1,1,true) << Kolab::cDateTime(2012, 1, 1,1,1,1,true) << events << output;
+        }
+
+        {
+            std::vector<Kolab::FreebusyPeriod> output;
+            output.push_back(period2);
+            output.push_back(period3);
+
+            QTest::newRow( "limit utc below" ) << Kolab::cDateTime(2011,10,8,12,1,1,true) << Kolab::cDateTime(2012, 1, 1,1,1,1,true) << events << output;
+        }
+        {
+            std::vector<Kolab::FreebusyPeriod> output;
+            output.push_back(period1);
+            output.push_back(period2);
+
+            QTest::newRow( "limit utc above" ) << Kolab::cDateTime(2010, 1, 1,1,1,1,true) << Kolab::cDateTime(2011,10,9,12,1,1,true) << events << output;
+        }
+    }
+    {
+        Kolab::Event event;
+        event.setStart(Kolab::cDateTime(2011,1,1,0,0,0,true));
+        event.setEnd(Kolab::cDateTime(2011,1,1,1,0,0,true));
+        Kolab::RecurrenceRule rrule;
+        rrule.setFrequency(Kolab::RecurrenceRule::Daily);
+        rrule.setInterval(1);
+        rrule.setCount(2);
+        event.setRecurrenceRule(rrule);
+        
+        std::vector<Kolab::Event> events;
+        events.push_back(event);
+
+        std::vector<Kolab::FreebusyPeriod> output;
+        Kolab::FreebusyPeriod period1;
+        period1.setType(Kolab::FreebusyPeriod::Busy);
+        period1.setPeriods(std::vector<Kolab::Period>() << Kolab::Period(Kolab::cDateTime(2011,1,1,0,0,0,true), Kolab::cDateTime(2011,1,1,1,0,0,true))
+                                                        << Kolab::Period(Kolab::cDateTime(2011,1,2,0,0,0,true), Kolab::cDateTime(2011,1,2,1,0,0,true))
+        );
+        output.push_back(period1);
+
+        QTest::newRow( "fullday recurrence" ) << Kolab::cDateTime(2010, 1, 1,1,1,1,true) << Kolab::cDateTime(2012,10,9,12,1,1,true) << events << output;
+    }
+}
+
+
+void FreebusyTest::testFB()
+{
+    QFETCH(Kolab::cDateTime, start);
+    QFETCH(Kolab::cDateTime, end);
+    QFETCH(std::vector<Kolab::Event>, events);
+    QFETCH(std::vector<Kolab::FreebusyPeriod>, output);
+
+    Kolab::Freebusy fb = Kolab::FreebusyUtils::generateFreeBusy(events, start, end);
+        
+    QCOMPARE((int)fb.periods().size(), (int)output.size());
+    for (int i = 0; i<output.size(); i++) {
+        QCOMPARE(fb.periods().at(i), output.at(i));
+    }
+
+    std::cout << Kolab::FreebusyUtils::toIFB(fb);
+}
+
+// void FreebusyTest::testHonorTimeFrame()
+// {
+// 
+//     Kolab::Period p1(Kolab::cDateTime(2011,10,6,12,1,1,true), Kolab::cDateTime(2011,10,8,12,1,1,true));
+//     Kolab::Period p2(Kolab::cDateTime(2011,10,7,12,1,1,true), Kolab::cDateTime(2011,10,10,12,1,1,true));
+//     Kolab::Period p3(Kolab::cDateTime(2011,10,9,12,1,1,true), Kolab::cDateTime(2011,10,11,12,1,1,true));
+// 
+//     std::vector<Kolab::Event> events;
+//     events.push_back(createEvent(p1.start, p1.end));
+//     events.push_back(createEvent(p2.start, p2.end));
+//     events.push_back(createEvent(p3.start, p3.end));
+// 
+//     Kolab::FreebusyPeriod period1;
+//     period1.setType(Kolab::FreebusyPeriod::Busy);
+//     period1.setPeriods(std::vector<Kolab::Period>() << p1);
+// 
+//     Kolab::FreebusyPeriod period2;
+//     period2.setType(Kolab::FreebusyPeriod::Busy);
+//     period2.setPeriods(std::vector<Kolab::Period>() << p2);
+// 
+//     Kolab::FreebusyPeriod period3;
+//     period3.setType(Kolab::FreebusyPeriod::Busy);
+//     period3.setPeriods(std::vector<Kolab::Period>() << p3);
+// 
+// 
+//     Kolab::Freebusy fb =  Kolab::FreebusyUtils::generateFreeBusy(events, Kolab::cDateTime(2010, 1, 1,1,1,1,true), Kolab::cDateTime(2012, 1, 1,1,1,1,true));
+//     QCOMPARE((int)fb.periods().size(), 3);
+//     QCOMPARE(fb.periods().at(0), period1);
+//     QCOMPARE(fb.periods().at(1), period2);
+//     QCOMPARE(fb.periods().at(2), period3);
+// }
+
+QTEST_MAIN( FreebusyTest )
+
+#include "freebusytest.moc"
\ No newline at end of file
diff --git a/tests/freebusytest.h b/tests/freebusytest.h
new file mode 100644
index 0000000..a27b9b5
--- /dev/null
+++ b/tests/freebusytest.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012  Christian Mollekopf <mollekopf at kolabsys.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef FREEBUSYTEST_H
+#define FREEBUSYTEST_H
+#include <QObject>
+
+class FreebusyTest: public QObject
+{
+    Q_OBJECT
+private slots:
+
+    void testFB_data();
+    void testFB();
+};
+
+#endif // FREEBUSYTEST_H
diff --git a/tests/testhelpers.h b/tests/testhelpers.h
index 614ddd2..02ef659 100644
--- a/tests/testhelpers.h
+++ b/tests/testhelpers.h
@@ -38,14 +38,16 @@ Q_DECLARE_METATYPE(std::vector<Kolab::Event>);
 Q_DECLARE_METATYPE(Kolab::Todo);
 Q_DECLARE_METATYPE(Kolab::Journal);
 Q_DECLARE_METATYPE(Kolab::Contact);
+Q_DECLARE_METATYPE(Kolab::Period);
+Q_DECLARE_METATYPE(std::vector<Kolab::FreebusyPeriod>);
+
 Q_DECLARE_METATYPE(KCalCore::Event);
 Q_DECLARE_METATYPE(KCalCore::Todo);
 Q_DECLARE_METATYPE(KCalCore::Journal);
 Q_DECLARE_METATYPE(KCalCore::Duration);
 
 namespace QTest {
-
-
+    
     template<>
     char *toString(const Kolab::cDateTime &dt)
     {
@@ -263,13 +265,42 @@ namespace QTest {
     {
         QByteArray ba = "vector<Kolab::CustomProperty>(";
         for (int i = 0; i < v.size(); i++) {
-                ba += QByteArray(toString(v.at(i)))+ "\n";
-            }
-            ba += ")";
-            return qstrdup(ba.data());
+            ba += QByteArray(toString(v.at(i)))+ "\n";
+        }
+        ba += ")";
+        return qstrdup(ba.data());
     }
 
+    template<>
+    char *toString(const Kolab::Period &p)
+    {
+        QByteArray ba = "Kolab::Period(";
+        ba += QByteArray(toString(p.start))+ "\n";
+        ba += QByteArray(toString(p.end))+ "\n";
+        ba += ")";
+        return qstrdup(ba.data());
+    }
 
+    template<>
+    char *toString(const std::vector<Kolab::Period> &v)
+    {
+        QByteArray ba = "vector<Kolab::Period>(";
+        for (int i = 0; i < v.size(); i++) {
+            ba += QByteArray(toString(v.at(i)))+ "\n";
+        }
+        ba += ")";
+        return qstrdup(ba.data());
+    }
+
+    template<>
+    char *toString(const Kolab::FreebusyPeriod &p)
+    {
+        QByteArray ba = "Kolab::FreebusyPeriod(";
+        ba += QString::number(p.type())+ "\n";
+        ba += QByteArray(toString(p.periods()))+ "\n";
+        ba += ")";
+        return qstrdup(ba.data());
+    }
 
 }
 
diff --git a/tests/testutils.h b/tests/testutils.h
index 82c4541..32842ae 100644
--- a/tests/testutils.h
+++ b/tests/testutils.h
@@ -23,6 +23,7 @@
 #include <qtemporaryfile.h>
 #include <qprocess.h>
 #include <kdebug.h>
+#include <kolabevent.h>
 #include <kmime/kmime_message.h>
 
 #include "kolabformat/kolabobject.h"
@@ -180,3 +181,11 @@ void normalizeContact(KABC::Addressee &addressee)
     addressee.removeCustom("KOLAB", "SoundAttachmentName");
     
 }
+
+Kolab::Event createEvent(const Kolab::cDateTime &start, const Kolab::cDateTime &end)
+{
+    Kolab::Event event;
+    event.setStart(start);
+    event.setEnd(end);
+    return event;
+}
\ No newline at end of file


commit fbae47849490c8ddba0bd092a0522b1b617fd1c0
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Thu Jun 21 17:13:04 2012 +0200

    resolved merge conflict (something was messed up)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index f26b32d..3f3186d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -74,7 +74,21 @@ add_subdirectory(conversion)
 add_subdirectory(calendaring)
 add_subdirectory(icalendar)
 
-set(KOLAB_SRCS kolabformat/kolabobject.cpp kolabformat/errorhandler.cpp mime/mimeutils.cpp ${CONVERSION_SRCS} ${kolabformatv2_SRCS} ${CALENDARING_SRCS} ${ICALENDAR_SRCS})
+QT4_WRAP_CPP(CALENDARING_MOC calendaring/event.h)
+# QT4_WRAP_CPP(CONVERSION_MOC conversion/qtevent.h conversion/qtduration.h)
+
+set(KOLAB_SRCS
+    kolabformat/kolabobject.cpp
+    kolabformat/errorhandler.cpp
+    mime/mimeutils.cpp
+    ${CONVERSION_SRCS}
+    ${kolabformatv2_SRCS}
+    ${CALENDARING_SRCS}
+    ${ICALENDAR_SRCS}
+    ${CALENDARING_MOC}
+    ${CONVERSION_MOC}
+)
+
 set(KOLAB_LINK_LIBRARIES
     ${Libkolabxml_LIBRARIES}
     ${KDEPIMLIBS_KCALCORE_LIBS}


commit 1423ad9aa65d62f5f962acc25d3fe785f2a3e7ed
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Tue Jun 19 23:38:33 2012 +0200

    Use UTC timestamp in mime-message.

diff --git a/mime/mimeutils.cpp b/mime/mimeutils.cpp
index 3a7ee6c..23fd9c1 100644
--- a/mime/mimeutils.cpp
+++ b/mime/mimeutils.cpp
@@ -192,7 +192,7 @@ KMime::Content* createExplanationPart(bool v3)
 KMime::Message::Ptr createMessage(const QString& xKolabType, bool v3, const QString &prodid)
 {
     KMime::Message::Ptr message( new KMime::Message );
-    message->date()->setDateTime( KDateTime::currentLocalDateTime() );
+    message->date()->setDateTime( KDateTime::currentUtcDateTime() );
     KMime::Headers::Generic *h = new KMime::Headers::Generic( X_KOLAB_TYPE_HEADER, message.get(), xKolabType, "utf-8" );
     message->appendHeader( h );
     if (v3) {


commit 614e083f3bf5c59fd3ab3035697d25cbf9295d7a
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Thu Jun 28 10:05:30 2012 +0200

    Make libcalendaring an option

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 67ac3a5..af4d2a5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,6 +4,7 @@ cmake_minimum_required(VERSION 2.6.4)
 
 option( BUILD_TESTS "Build the tests" TRUE )
 option( PYTHON_BINDINGS "Build bindings for python" FALSE )
+option( USE_LIBCALENDARING "Use libcalendaring" FALSE )
 
 set(Libkolab_MODULE_DIR ${Libkolab_SOURCE_DIR}/cmake/modules)
 set(CMAKE_MODULE_PATH ${Libkolab_MODULE_DIR})
@@ -45,9 +46,10 @@ set(CMAKECONFIG_INSTALL_DIR ${LIB_INSTALL_DIR}/cmake/Libkolab )
 find_package(Libkolabxml 0.7 REQUIRED)
 find_package(Qt4 4.6.0 REQUIRED)
 find_package(Libcalendaring)
-
-# find_package(KDE4 4.8 REQUIRED)
-# find_package(KdepimLibs 4.8 REQUIRED)
+if (NOT USE_LIBCALENDARING)
+    find_package(KDE4 4.8 REQUIRED)
+    find_package(KdepimLibs 4.8 REQUIRED)
+endif()
 
 
 # add_definitions(-DKDEPIMLIBS_VERSION=0x${KdepimLibs_VERSION_MAJOR}0${KdepimLibs_VERSION_MINOR}${KDEPIMLIBS_VERSION_PATCH})
@@ -59,22 +61,25 @@ endif()
 
 set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS} -fPIC -g" )
 
-# set( KDE_INCLUDES ${KDEPIMLIBS_INCLUDE_DIRS} ${KDE4_INCLUDE_DIR})
-# set( KDE_LIBRARIES
-#     ${KDEPIMLIBS_KCALCORE_LIBS}
-#     ${KDEPIMLIBS_KABC_LIBS}
-#     ${KDEPIMLIBS_KMIME_LIBS}
-#     ${KDEPIMLIBS_AKONADI_LIBS}
-#     ${KDEPIMLIBS_AKONADI_NOTES_LIBS}
-#     ${KDEPIMLIBS_KCALUTILS_LIBS}
-#     ${KDEPIMLIBS_KPIMUTILS_LIBS}
-#     ${KDE4_KDECORE_LIBRARY}
-#     ${KDE4_KIO_LIBRARY}
-#     )
-set( KDE_INCLUDES ${Libcalendaring_INCLUDE_DIRS} )
-set( KDE_LIBRARIES ${Libcalendaring_LIBRARIES} )
-
-message("${Libcalendaring_INCLUDE_DIRS} ${Libcalendaring_LIBRARIES}")
+if (USE_LIBCALENDARING)
+    set( KDE_INCLUDES ${Libcalendaring_INCLUDE_DIRS} )
+    set( KDE_LIBRARIES ${Libcalendaring_LIBRARIES} )
+    message("${Libcalendaring_INCLUDE_DIRS} ${Libcalendaring_LIBRARIES}")
+else()
+    set( KDE_INCLUDES ${KDEPIMLIBS_INCLUDE_DIRS} ${KDE4_INCLUDE_DIR})
+    set( KDE_LIBRARIES
+        ${KDEPIMLIBS_KCALCORE_LIBS}
+        ${KDEPIMLIBS_KABC_LIBS}
+        ${KDEPIMLIBS_KMIME_LIBS}
+        ${KDEPIMLIBS_AKONADI_LIBS}
+        ${KDEPIMLIBS_AKONADI_NOTES_LIBS}
+        ${KDEPIMLIBS_KCALUTILS_LIBS}
+        ${KDEPIMLIBS_KPIMUTILS_LIBS}
+        ${KDE4_KDECORE_LIBRARY}
+        ${KDE4_KIO_LIBRARY}
+        )
+endif()
+
 
 include_directories(    
     ${QT_INCLUDES}


commit b99d69b8f85c5920989e1df1f0e40126779d0255
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Wed Jun 27 10:53:02 2012 +0200

    Compile with libcalendaring

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 30c84a0..67ac3a5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -42,11 +42,13 @@ set(INCLUDE_INSTALL_DIR include/libkolab CACHE STRING "The directories where to
 set(CMAKECONFIG_INSTALL_DIR ${LIB_INSTALL_DIR}/cmake/Libkolab )
 
 # Do the building
+find_package(Libkolabxml 0.7 REQUIRED)
+find_package(Qt4 4.6.0 REQUIRED)
+find_package(Libcalendaring)
+
+# find_package(KDE4 4.8 REQUIRED)
+# find_package(KdepimLibs 4.8 REQUIRED)
 
-find_package(Qt4 4.7.0 REQUIRED)
-find_package(KDE4 4.8 REQUIRED)
-find_package(KdepimLibs 4.8 REQUIRED)
-find_package(Libkolabxml 0.6 REQUIRED)
 
 # add_definitions(-DKDEPIMLIBS_VERSION=0x${KdepimLibs_VERSION_MAJOR}0${KdepimLibs_VERSION_MINOR}${KDEPIMLIBS_VERSION_PATCH})
 # add_definitions( -DKDEPIMLIBS_VERSION=((${KdepimLibs_VERSION_MAJOR}<<16)|(${KdepimLibs_VERSION_MINOR}<<8)|(${KDEPIMLIBS_VERSION_PATCH})) )
@@ -55,12 +57,28 @@ if("${KdepimLibs_VERSION}" VERSION_GREATER "4.8.40" )
     add_definitions(-DKDEPIMLIBS_VERSION_DEVEL)
 endif()
 
-set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS} -fPIC" )
+set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS} -fPIC -g" )
+
+# set( KDE_INCLUDES ${KDEPIMLIBS_INCLUDE_DIRS} ${KDE4_INCLUDE_DIR})
+# set( KDE_LIBRARIES
+#     ${KDEPIMLIBS_KCALCORE_LIBS}
+#     ${KDEPIMLIBS_KABC_LIBS}
+#     ${KDEPIMLIBS_KMIME_LIBS}
+#     ${KDEPIMLIBS_AKONADI_LIBS}
+#     ${KDEPIMLIBS_AKONADI_NOTES_LIBS}
+#     ${KDEPIMLIBS_KCALUTILS_LIBS}
+#     ${KDEPIMLIBS_KPIMUTILS_LIBS}
+#     ${KDE4_KDECORE_LIBRARY}
+#     ${KDE4_KIO_LIBRARY}
+#     )
+set( KDE_INCLUDES ${Libcalendaring_INCLUDE_DIRS} )
+set( KDE_LIBRARIES ${Libcalendaring_LIBRARIES} )
+
+message("${Libcalendaring_INCLUDE_DIRS} ${Libcalendaring_LIBRARIES}")
 
 include_directories(    
     ${QT_INCLUDES}
-    ${KDEPIMLIBS_INCLUDE_DIRS}
-    ${KDE4_INCLUDE_DIR}
+    ${KDE_INCLUDES}
     ${CMAKE_BINARY_DIR}
     ${CMAKE_CURRENT_SOURCE_DIR}/kolabformatV2
     ${Libkolabxml_INCLUDES}
@@ -93,22 +111,14 @@ set(KOLAB_SRCS
 
 set(KOLAB_LINK_LIBRARIES
     ${Libkolabxml_LIBRARIES}
-    ${KDEPIMLIBS_KCALCORE_LIBS}
-    ${KDEPIMLIBS_KABC_LIBS}
-    ${KDEPIMLIBS_KMIME_LIBS}
-    ${KDEPIMLIBS_AKONADI_LIBS}
-    ${KDEPIMLIBS_AKONADI_NOTES_LIBS}
-    ${KDEPIMLIBS_KCALUTILS_LIBS}
-    ${KDEPIMLIBS_KPIMUTILS_LIBS}
     ${QT_QTCORE_LIBRARY}
     ${QT_QTXML_LIBRARY}
     ${QT_QTGUI_LIBRARY}
-    ${KDE4_KDECORE_LIBRARY}
-    ${KDE4_KIO_LIBRARY}
+    ${KDE_LIBRARIES}
 )
 if(BUILD_TESTS)
     #for tests only
-    kde4_add_library(kolab_static STATIC ${KOLAB_SRCS})
+    add_library(kolab_static STATIC ${KOLAB_SRCS})
     target_link_libraries(kolab_static ${KOLAB_LINK_LIBRARIES})
     add_subdirectory(tests)
 endif(BUILD_TESTS)
@@ -131,6 +141,7 @@ install(FILES
     kolabformat/errorhandler.h
     conversion/kcalconversion.h
     conversion/kabcconversion.h
+    freebusy/freebusy.h
     DESTINATION ${INCLUDE_INSTALL_DIR}
 )
 
diff --git a/calendaring/calendaring.cpp b/calendaring/calendaring.cpp
index 4579348..b7ad0e3 100644
--- a/calendaring/calendaring.cpp
+++ b/calendaring/calendaring.cpp
@@ -18,7 +18,7 @@
 #include "calendaring.h"
 
 #include <kcalcore/event.h>
-#include <KDE/KCalCore/Todo>
+#include <kcalcore/todo.h>
 #include <Qt/qdebug.h>
 #include <kolabevent.h>
 
diff --git a/cmake/modules/FindLibcalendaring.cmake b/cmake/modules/FindLibcalendaring.cmake
new file mode 100644
index 0000000..3c4c860
--- /dev/null
+++ b/cmake/modules/FindLibcalendaring.cmake
@@ -0,0 +1,20 @@
+find_package(PkgConfig)
+include(FindPackageHandleStandardArgs)
+
+find_library(CALENDARING_KDECORE NAMES calendaring-kdecore)
+find_library(CALENDARING_KCALCORE NAMES calendaring-kcalcore)
+find_library(CALENDARING_KMIME NAMES calendaring-kmime)
+find_library(CALENDARING_KIMAP NAMES calendaring-kimap)
+find_library(CALENDARING_KABC NAMES calendaring-kabc)
+find_library(CALENDARING_NOTES NAMES calendaring-akonadi-notes)
+find_library(CALENDARING_KCALUTILS NAMES calendaring-kcalutils)
+find_library(CALENDARING_KPIMUTILS NAMES calendaring-kpimutils)
+
+find_path(CALENDARING_INCLUDE_DIRS NAMES libcalendaring/kdatetime.h)
+
+set( Libcalendaring_INCLUDE_DIRS "${CALENDARING_INCLUDE_DIRS}/libcalendaring" )
+
+set( Libcalendaring_LIBRARIES ${CALENDARING_KDECORE} ${CALENDARING_KCALCORE} ${CALENDARING_KMIME} ${CALENDARING_KIMAP} ${CALENDARING_KABC} ${CALENDARING_NOTES} ${CALENDARING_KCALUTILS} ${CALENDARING_KPIMUTILS})
+
+find_package_handle_standard_args(Libcalendaring  DEFAULT_MSG
+                                  CALENDARING_KDECORE CALENDARING_KCALCORE CALENDARING_KMIME CALENDARING_KIMAP CALENDARING_KABC CALENDARING_NOTES CALENDARING_KCALUTILS CALENDARING_KPIMUTILS CALENDARING_INCLUDE_DIRS)
diff --git a/conversion/kabcconversion.cpp b/conversion/kabcconversion.cpp
index b710891..a418333 100644
--- a/conversion/kabcconversion.cpp
+++ b/conversion/kabcconversion.cpp
@@ -327,10 +327,10 @@ std::string fromPicture(const KABC::Picture &pic, std::string &mimetype)
         }
     } else if ( !pic.url().isEmpty() ) {
         QString tmpFile;
-        if ( KIO::NetAccess::download( pic.url(), tmpFile, 0 /*no widget known*/ ) ) {
-            img.load( tmpFile );
-            KIO::NetAccess::removeTempFile( tmpFile );
-        }
+//         if ( KIO::NetAccess::download( pic.url(), tmpFile, 0 /*no widget known*/ ) ) {
+//             img.load( tmpFile );
+//             KIO::NetAccess::removeTempFile( tmpFile );
+//         }
     }
     if (img.isNull()) {
         Error() << "invalid picture";
diff --git a/freebusy/freebusy.h b/freebusy/freebusy.h
index a61e1c4..edc3f58 100644
--- a/freebusy/freebusy.h
+++ b/freebusy/freebusy.h
@@ -22,7 +22,7 @@
 #include "kolab_export.h"
 #include <kolabevent.h>
 #include <kolabfreebusy.h>
-#include <KCalCore/Event>
+#include <kcalcore/event.h>
 
 namespace Kolab {
     namespace FreebusyUtils {
diff --git a/icalendar/icalendar.cpp b/icalendar/icalendar.cpp
index a8fdbeb..474b8e9 100644
--- a/icalendar/icalendar.cpp
+++ b/icalendar/icalendar.cpp
@@ -23,11 +23,11 @@
 #include <conversion/kcalconversion.h>
 #include <conversion/commonconversion.h>
 #include <mime/mimeutils.h>
-#include <KCalCore/Event>
+#include <kcalcore/event.h>
 #include <kcalcore/memorycalendar.h>
 #include <kcalcore/icalformat.h>
 #include <kmime/kmime_message.h>
-#include <klocalizedstring.h>
+// #include <klocalizedstring.h>
 #include <kdebug.h>
 #include <iostream>
 
@@ -137,7 +137,7 @@ std::string ITipHandler::toIMip(const Event &event , ITipHandler::ITipMethod m,
     } else {
         QString subject;
         if ( e && method == KCalCore::iTIPCounter ) {
-            subject = i18n( "Counter proposal: %1", e->summary() );
+            subject = QString( "Counter proposal: %1" ).arg(e->summary());
         }
         return QString(mailOrganizer( e, QString::fromStdString(from), bccMe, messageText, subject)).toStdString();
     }
diff --git a/icalendar/imip.cpp b/icalendar/imip.cpp
index a49aafa..0098bdb 100644
--- a/icalendar/imip.cpp
+++ b/icalendar/imip.cpp
@@ -21,10 +21,10 @@
 #include "imip.h"
 
 #include <kcalutils/incidenceformatter.h>
-#include <KPIMUtils/Email>
+#include <kpimutils/email.h>
 #include <kmime/kmime_message.h>
 #include <QDebug>
-#include <klocalizedstring.h>
+// #include <klocalizedstring.h>
 #include <ksystemtimezone.h>
 #include <kdebug.h>
 
@@ -203,7 +203,7 @@ QByteArray mailAttendees( const KCalCore::IncidenceBase::Ptr &incidence,
     KCalCore::Incidence::Ptr inc = incidence.staticCast<KCalCore::Incidence>();
     subject = inc->summary();
   } else {
-    subject = i18n( "Free Busy Object" );
+    subject = QString( "Free Busy Object" );
   }
 
   const QString body =
@@ -228,7 +228,7 @@ QByteArray mailOrganizer( const KCalCore::IncidenceBase::Ptr &incidence,
       subject = inc->summary();
     }
   } else {
-    subject = i18n( "Free Busy Message" );
+    subject = QString( "Free Busy Message" );
   }
 
   QString body = KCalUtils::IncidenceFormatter::mailBodyStr( incidence, KSystemTimeZones::local() );
diff --git a/kolabformatV2/contact.cpp b/kolabformatV2/contact.cpp
index 21d6fec..7e0e951 100644
--- a/kolabformatV2/contact.cpp
+++ b/kolabformatV2/contact.cpp
@@ -1179,10 +1179,10 @@ QImage Contact::loadPictureFromAddressee( const KABC::Picture& picture )
   QImage img;
   if ( !picture.isIntern() && !picture.url().isEmpty() ) {
     QString tmpFile;
-    if ( KIO::NetAccess::download( picture.url(), tmpFile, 0 /*no widget known*/ ) ) {
-      img.load( tmpFile );
-      KIO::NetAccess::removeTempFile( tmpFile );
-    }
+//     if ( KIO::NetAccess::download( picture.url(), tmpFile, 0 /*no widget known*/ ) ) {
+//       img.load( tmpFile );
+//       KIO::NetAccess::removeTempFile( tmpFile );
+//     }
   } else
     img = picture.data();
   return img;
@@ -1193,14 +1193,14 @@ QByteArray KolabV2::Contact::loadSoundFromAddressee( const KABC::Sound& sound )
   QByteArray data;
   if ( !sound.isIntern() && !sound.url().isEmpty() ) {
     QString tmpFile;
-    if ( KIO::NetAccess::download( sound.url(), tmpFile, 0 /*no widget known*/ ) ) {
-      QFile f( tmpFile );
-      if ( f.open( QIODevice::ReadOnly ) ) {
-        data = f.readAll();
-        f.close();
-      }
-      KIO::NetAccess::removeTempFile( tmpFile );
-    }
+//     if ( KIO::NetAccess::download( sound.url(), tmpFile, 0 /*no widget known*/ ) ) {
+//       QFile f( tmpFile );
+//       if ( f.open( QIODevice::ReadOnly ) ) {
+//         data = f.readAll();
+//         f.close();
+//       }
+//       KIO::NetAccess::removeTempFile( tmpFile );
+//     }
   } else
     data = sound.data();
   return data;
diff --git a/kolabformatV2/distributionlist.cpp b/kolabformatV2/distributionlist.cpp
index f011458..61605c6 100644
--- a/kolabformatV2/distributionlist.cpp
+++ b/kolabformatV2/distributionlist.cpp
@@ -31,8 +31,8 @@
 
 #include "distributionlist.h"
 
-#include <akonadi/itemfetchjob.h>
-#include <akonadi/itemfetchscope.h>
+// #include <akonadi/itemfetchjob.h>
+// #include <akonadi/itemfetchscope.h>
 #include <kabc/addressee.h>
 #include <kabc/contactgroup.h>
 #include <kdebug.h>
@@ -198,31 +198,32 @@ void DistributionList::setFields( const KABC::ContactGroup* contactGroup )
   // Hopefully all resources are available during saving, so we can look up
   // in the addressbook to get name+email from the UID.
   // TODO proxy should at least know the addressees it created
-  for ( uint index = 0; index < contactGroup->contactReferenceCount(); ++index ) {
-    const KABC::ContactGroup::ContactReference& reference = contactGroup->contactReference( index );
-
-    const Akonadi::Item item( reference.uid().toLongLong() );
-    Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( item );
-    job->fetchScope().fetchFullPayload();
-    if ( !job->exec() )
-      continue;
-
-    const Akonadi::Item::List items = job->items();
-    if ( items.count() != 1 )
-      continue;
-
-    const KABC::Addressee addressee = job->items().first().payload<KABC::Addressee>();
-
-    if ( !addressee.isEmpty() ) {
-      Member m;
-      m.displayName = addressee.formattedName();
-      m.email = reference.preferredEmail();
-      if ( m.email.isEmpty() )
-        m.email = addressee.preferredEmail();
-
-      mDistrListMembers.append( m );
-    }
-  }
+//   for ( uint index = 0; index < contactGroup->contactReferenceCount(); ++index ) {
+//     const KABC::ContactGroup::ContactReference& reference = contactGroup->contactReference( index );
+// 
+//     //FIXME this won't work on the server (wihtout akonadi), move this part to the akonadi resource
+//     const Akonadi::Item item( reference.uid().toLongLong() );
+//     Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( item );
+//     job->fetchScope().fetchFullPayload();
+//     if ( !job->exec() )
+//       continue;
+// 
+//     const Akonadi::Item::List items = job->items();
+//     if ( items.count() != 1 )
+//       continue;
+// 
+//     const KABC::Addressee addressee = job->items().first().payload<KABC::Addressee>();
+// 
+//     if ( !addressee.isEmpty() ) {
+//       Member m;
+//       m.displayName = addressee.formattedName();
+//       m.email = reference.preferredEmail();
+//       if ( m.email.isEmpty() )
+//         m.email = addressee.preferredEmail();
+// 
+//       mDistrListMembers.append( m );
+//     }
+//   }
 }
 
 // The loading is: xml -> DistributionList -> contactgroup, this is the second part


commit 9b386b6506e427efc25646c5ed2b86813bbde9ab
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Tue Jun 26 15:15:42 2012 +0200

    freebusy serializing, a couple of fixes for the generateFreeBusy code

diff --git a/freebusy/freebusy.cpp b/freebusy/freebusy.cpp
index ceb5bc2..c7f853e 100644
--- a/freebusy/freebusy.cpp
+++ b/freebusy/freebusy.cpp
@@ -24,6 +24,105 @@
 #include <quuid.h>
 
 
+// namespace KCalCore {
+//     struct KCalFreebusy
+// {
+//
+// void init( const Event::List &eventList, const KDateTime &start, const KDateTime &end )
+// {
+//     mDtStart = start.toUtc();
+//     mDtEnd = end.toUtc();
+//
+//   // Loops through every event in the calendar
+//   Event::List::ConstIterator it;
+//   for ( it = eventList.constBegin(); it != eventList.constEnd(); ++it ) {
+//     Event::Ptr event = *it;
+//
+//     // If this event is transparent it shouldn't be in the freebusy list.
+//     if ( event->transparency() == Event::Transparent ) {
+//       continue;
+//     }
+//
+//     if ( event->hasRecurrenceId() ) {
+//       continue; //TODO apply special period exception (duration could be different)
+//     }
+//
+//     const KDateTime eventStart = event->dtStart().toUtc();
+//     const KDateTime eventEnd = event->dtEnd().toUtc();
+//
+//     if ( event->recurs() ) {
+//         const KCalCore::Duration duration( eventStart, eventEnd );
+//         const KCalCore::DateTimeList list = event->recurrence()->timesInInterval(start, end);
+//         foreach (const KDateTime &dt, list) {
+//             const KDateTime utc = dt.toUtc();
+//             addLocalPeriod(utc, duration.end(utc) );
+//         }
+//     } else {
+//         addLocalPeriod( eventStart, eventEnd );
+//     }
+//   }
+//
+// //   q->sortList();
+// }
+//
+// bool addLocalPeriod(
+//                                         const KDateTime &eventStart,
+//                                         const KDateTime &eventEnd )
+// {
+//   KDateTime tmpStart;
+//   KDateTime tmpEnd;
+//
+//   //Check to see if the start *or* end of the event is
+//   //between the start and end of the freebusy dates.
+//   if ( !( ( ( mDtStart.secsTo( eventStart ) >= 0 ) &&
+//             ( eventStart.secsTo( mDtEnd ) >= 0 ) ) ||
+//           ( ( mDtStart.secsTo( eventEnd ) >= 0 ) &&
+//             ( eventEnd.secsTo( mDtEnd ) >= 0 ) ) ) ) {
+//       qDebug() << "out of scope";
+//     return false;
+//   }
+//
+// //   qDebug() << eventStart.date().toString() << eventStart.time().toString() << mDtStart.toString();
+//   if ( eventStart < mDtStart ) { //eventStart is before start
+// //       qDebug() << "use start";
+//     tmpStart = mDtStart;
+//   } else {
+//     tmpStart = eventStart;
+//   }
+//
+//   qDebug() << eventEnd.date().toString() << eventEnd.time().toString() << mDtEnd.toString();
+//   if ( eventEnd > mDtEnd ) { //event end is after dtEnd
+// //     qDebug() << "use end";
+//     tmpEnd = mDtEnd;
+//   } else {
+//     tmpEnd = eventEnd;
+//   }
+//
+// //   qDebug() << "########## " << tmpStart.isValid();
+//   Q_ASSERT(tmpStart.isValid());
+//   Q_ASSERT(tmpEnd.isValid());
+// //   qDebug() << tmpStart.date().toString() << tmpStart.time().toString() << tmpStart.toString();
+//
+//   FreeBusyPeriod p( tmpStart, tmpEnd );
+//   mBusyPeriods.append( p );
+//
+//   return true;
+// }
+//
+//     KDateTime mDtStart;
+//     KDateTime mDtEnd;                  // end datetime
+//     FreeBusyPeriod::List mBusyPeriods; // list of periods
+//
+// };
+//
+// } // Namespace
+
+
+
+
+
+
+
 namespace Kolab {
     namespace FreebusyUtils {
 
@@ -57,21 +156,43 @@ Kolab::Period addLocalPeriod(  const KDateTime &eventStart, const KDateTime &eve
   }
   Q_ASSERT(tmpStart.isValid());
   Q_ASSERT(tmpEnd.isValid());
+  if (tmpStart.isDateOnly()) {
+    tmpStart.setTime(QTime(0,0,0,0));
+  }
+  if (tmpEnd.isDateOnly()) {
+    tmpEnd.setTime(QTime(23,59,59,999)); //The window is inclusive
+  }
   return Kolab::Period(Kolab::Conversion::fromDate(tmpStart), Kolab::Conversion::fromDate(tmpEnd));
 }
 
-        
+Freebusy generateFreeBusy(const std::vector< Event >& events, const cDateTime& startDate, const cDateTime& endDate)
+{
+    QList<KCalCore::Event::Ptr> list;
+    foreach (const Kolab::Event &e, events) {
+        list.append(Kolab::Conversion::toKCalCore(e));
+    }
+    KCalCore::Person::Ptr person(new KCalCore::Person("dummyname", "dummyemail"));
+    return generateFreeBusy(list, Kolab::Conversion::toDate(startDate), Kolab::Conversion::toDate(endDate), person);
+}
 
-Freebusy generateFreeBusy(const std::vector< Event >& events, const cDateTime& startDate, const cDateTime& endDate, const Freebusy& existing)
+Freebusy generateFreeBusy(const QList<KCalCore::Event::Ptr>& events, const KDateTime& startDate, const KDateTime& endDate, const KCalCore::Person::Ptr &organizer)
 {
-    const KDateTime start = Kolab::Conversion::toDate(startDate).toUtc();
-    const KDateTime end = Kolab::Conversion::toDate(endDate).toUtc();
+    /*
+     * TODO the conversion of date-only values to date-time is only necessary because xCal doesn't allow date only. iCalendar doesn't seem to make this restriction so it looks like a bug.
+     */
+    KDateTime start = startDate.toUtc();
+    if (start.isDateOnly()) {
+        start.setTime(QTime(0,0,0,0));
+    }
+    KDateTime end = endDate.toUtc();
+    if (end.isDateOnly()) {
+        end.addDays(1);
+        end.setTime(QTime(0,0,0,0)); //The window is inclusive
+    }
 
     //TODO try to merge that with KCalCore::Freebusy
     std::vector<Kolab::FreebusyPeriod> freebusyPeriods;
-    foreach (const Kolab::Event &e, events) {
-        KCalCore::Event::Ptr event = Kolab::Conversion::toKCalCore(e);
-    
+    Q_FOREACH (KCalCore::Event::Ptr event, events) {    
         // If this event is transparent it shouldn't be in the freebusy list.
         if ( event->transparency() == KCalCore::Event::Transparent ) {
             continue;
@@ -88,7 +209,7 @@ Freebusy generateFreeBusy(const std::vector< Event >& events, const cDateTime& s
         if ( event->recurs() ) {
             const KCalCore::Duration duration( eventStart, eventEnd );
             const KCalCore::DateTimeList list = event->recurrence()->timesInInterval(start, end);
-            foreach (const KDateTime &dt, list) {
+            Q_FOREACH (const KDateTime &dt, list) {
                 const KDateTime utc = dt.toUtc();
                 const Kolab::Period &period = addLocalPeriod(utc, duration.end(utc), start, end);
                 if (period.isValid()) {
@@ -104,21 +225,21 @@ Freebusy generateFreeBusy(const std::vector< Event >& events, const cDateTime& s
         if (!periods.empty()) {
             Kolab::FreebusyPeriod period;
             period.setPeriods(periods);
-            //TODO get out of office from event
+            //TODO get busy type from event (out-of-office, tentative)
             period.setType(Kolab::FreebusyPeriod::Busy);
-    //         period.setEvent(event->summary().toStdString(), event->uid().toStdString(), event->location().toStdString());
-            //TODO event uid etc.
+            period.setEvent(event->uid().toStdString(), event->summary().toStdString(), event->location().toStdString());
             freebusyPeriods.push_back(period);
         }
     }
 
     Kolab::Freebusy freebusy;
-    freebusy.setStart(startDate);
-    freebusy.setEnd(endDate);
+    
+    freebusy.setStart(Kolab::Conversion::fromDate(start));
+    freebusy.setEnd(Kolab::Conversion::fromDate(end));
     freebusy.setPeriods(freebusyPeriods);
     freebusy.setUid(QUuid::createUuid().toString().toStdString());
     freebusy.setTimestamp(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime()));
-    freebusy.setOrganizer(ContactReference(Kolab::ContactReference::EmailReference, "email", "name"));
+    freebusy.setOrganizer(ContactReference(Kolab::ContactReference::EmailReference, organizer->email().toStdString(), organizer->name().toStdString()));
     
     return freebusy;
 }
diff --git a/freebusy/freebusy.h b/freebusy/freebusy.h
index fbea05f..a61e1c4 100644
--- a/freebusy/freebusy.h
+++ b/freebusy/freebusy.h
@@ -22,12 +22,15 @@
 #include "kolab_export.h"
 #include <kolabevent.h>
 #include <kolabfreebusy.h>
+#include <KCalCore/Event>
 
 namespace Kolab {
     namespace FreebusyUtils {
 
-Kolab::Freebusy generateFreeBusy(const std::vector<Kolab::Event> &events, const Kolab::cDateTime &startDate, const Kolab::cDateTime &endDate, const Kolab::Freebusy &existing = Kolab::Freebusy());
-std::string toIFB(const Kolab::Freebusy &);
+KOLAB_EXPORT Freebusy generateFreeBusy(const QList<KCalCore::Event::Ptr>& events, const KDateTime& startDate, const KDateTime& endDate, const KCalCore::Person::Ptr &organizer);
+KOLAB_EXPORT std::string toIFB(const Kolab::Freebusy &);
+
+Kolab::Freebusy generateFreeBusy(const std::vector<Kolab::Event> &events, const Kolab::cDateTime &startDate, const Kolab::cDateTime &endDate);
 
     }
 }
diff --git a/kolabformat/kolabdefinitions.h b/kolabformat/kolabdefinitions.h
index 2fdcf70..0d53c8e 100644
--- a/kolabformat/kolabdefinitions.h
+++ b/kolabformat/kolabdefinitions.h
@@ -28,7 +28,8 @@ namespace Kolab {
 #define KOLAB_FOLDER_TYPE_TASK    "task"
 #define KOLAB_FOLDER_TYPE_JOURNAL "journal"
 #define KOLAB_FOLDER_TYPE_NOTE    "note"
-#define KOLAB_FOLDER_TYPE_CONFIGURATION    "configuration"
+#define KOLAB_FOLDER_TYPE_CONFIGURATION "configuration"
+#define KOLAB_FOLDER_TYPE_FREEBUSY      "freebusy"
 
 #define KOLAB_FOLDER_TYPE_DEFAULT_SUFFIX ".default"
 
@@ -50,6 +51,7 @@ static QString distlistKolabTypeCompat() { return QString::fromLatin1("applicati
 static QString noteKolabType() { return QString::fromLatin1("application/x-vnd.kolab.note"); }
 static QString configurationKolabType() { return QString::fromLatin1("application/x-vnd.kolab.configuration"); }
 static QString dictKolabType() { return QString::fromLatin1("application/x-vnd.kolab.configuration.dictionary"); }
+static QString freebusyKolabType() { return QString::fromLatin1("application/x-vnd.kolab.freebusy"); }
 
 static QString xCalMimeType() { return QString::fromLatin1("application/calendar+xml"); };
 static QString xCardMimeType() { return QString::fromLatin1("application/vcard+xml"); };
diff --git a/kolabformat/kolabobject.cpp b/kolabformat/kolabobject.cpp
index 0af095d..4e76444 100644
--- a/kolabformat/kolabobject.cpp
+++ b/kolabformat/kolabobject.cpp
@@ -468,6 +468,16 @@ KMime::Message::Ptr KolabObjectWriter::writeDictionary(const QStringList &entrie
     return  Mime::createMessage(QString::fromStdString(configuration.uid()), kolabMimeType(), dictKolabType(), QString::fromStdString(v3String).toLocal8Bit(), true, getProductId(productId));
 }
 
+KMime::Message::Ptr KolabObjectWriter::writeFreebusy(const Freebusy &freebusy, Version v, const QString& productId)
+{
+    ErrorHandler::clearErrors();
+    if (v != KolabV3) {
+        Critical() << "only v3 implementation available";
+    }
+    const std::string &v3String = Kolab::writeFreebusy(freebusy, getProductId(productId).toStdString());
+    ErrorHandler::handleLibkolabxmlErrors();
+    return  Mime::createMessage(QString::fromStdString(freebusy.uid()), xCalMimeType(), freebusyKolabType(), QString::fromStdString(v3String).toLocal8Bit(), true, getProductId(productId));
+}
 
 
 
diff --git a/kolabformat/kolabobject.h b/kolabformat/kolabobject.h
index ecde1f1..7cea7bb 100644
--- a/kolabformat/kolabobject.h
+++ b/kolabformat/kolabobject.h
@@ -30,6 +30,8 @@
 
 namespace Kolab {
 
+class Freebusy;
+
 enum Version {
     KolabV2,
     KolabV3
@@ -43,7 +45,8 @@ enum ObjectType {
     ContactObject,
     DistlistObject,
     NoteObject,
-    DictionaryConfigurationObject
+    DictionaryConfigurationObject,
+    FreebusyObject
 };
 
 KOLAB_EXPORT KCalCore::Event::Ptr readV2EventXML(const QByteArray &xmlData, QStringList &attachments);
@@ -109,6 +112,8 @@ public:
     static KMime::Message::Ptr writeDistlist(const KABC::ContactGroup &, Version v = KolabV3, const QString &productId = QString());
     static KMime::Message::Ptr writeNote(const KMime::Message::Ptr &, Version v = KolabV3, const QString &productId = QString());
     static KMime::Message::Ptr writeDictionary(const QStringList &, const QString &lang, Version v = KolabV3, const QString &productId = QString());
+    static KMime::Message::Ptr writeFreebusy(const Kolab::Freebusy &, Version v = KolabV3, const QString &productId = QString());
+    
 };
 
 }; //Namespace


commit 1db58a28eeb95a2ade1299add76030ab23401ebb
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Tue Jun 26 15:14:47 2012 +0200

    better error messages

diff --git a/kolabformat/kolabobject.cpp b/kolabformat/kolabobject.cpp
index 27f7ef7..0af095d 100644
--- a/kolabformat/kolabobject.cpp
+++ b/kolabformat/kolabobject.cpp
@@ -121,6 +121,14 @@ QByteArray getMimeType(Kolab::ObjectType type)
     return QByteArray();
 }
 
+void printMessageDebugInfo(const KMime::Message::Ptr &msg)
+{
+    //TODO replace by Debug stream for Mimemessage
+    Debug() << "MessageId: " << msg->messageID()->asUnicodeString();
+    Debug() << "Subject: " << msg->subject()->asUnicodeString();
+//     Debug() << msg->encodedContent();
+}
+
 ObjectType KolabObjectReader::parseMimeMessage(const KMime::Message::Ptr &msg)
 {
     ErrorHandler::clearErrors();
@@ -128,6 +136,7 @@ ObjectType KolabObjectReader::parseMimeMessage(const KMime::Message::Ptr &msg)
     KMime::Headers::Base *xKolabHeader = msg->getHeaderByType(X_KOLAB_TYPE_HEADER);
     if (!xKolabHeader) {
         CRITICAL("could not find the X-Kolab-Type Header");
+        printMessageDebugInfo(msg);
         return InvalidObject;
     }
     const QString &kolabType = xKolabHeader->asUnicodeString(); //TODO we probably shouldn't use unicodeString
@@ -141,7 +150,7 @@ ObjectType KolabObjectReader::parseMimeMessage(const KMime::Message::Ptr &msg)
         d->mVersion = KolabV2;
     } else {
         if (xKolabVersion->asUnicodeString() != KOLAB_VERSION_V3) { //TODO version compatibility check?
-            WARNING("Kolab Version Header available but not on the same version as the implementation");
+            Warning() << "Kolab Version Header available but not on the same version as the implementation: " << xKolabVersion->asUnicodeString();
         }
         d->mVersion = KolabV3;
     }
@@ -150,7 +159,8 @@ ObjectType KolabObjectReader::parseMimeMessage(const KMime::Message::Ptr &msg)
         if (d->mObjectType == DictionaryConfigurationObject) {
             KMime::Content *xmlContent = Mime::findContentByType( msg, "application/xml" );
             if ( !xmlContent ) {
-                CRITICAL("no part found");
+                Critical() << "no application/xml part found";
+                printMessageDebugInfo(msg);
                 return InvalidObject;
             }
             const QByteArray &xmlData = xmlContent->decodedContent();
@@ -160,7 +170,8 @@ ObjectType KolabObjectReader::parseMimeMessage(const KMime::Message::Ptr &msg)
         }
         KMime::Content *xmlContent = Mime::findContentByType( msg, kolabType.toLocal8Bit() );
         if ( !xmlContent ) {
-            CRITICAL("no part found");
+            Critical() << "no part with type" << kolabType.toLocal8Bit() << " found";
+            printMessageDebugInfo(msg);
             return InvalidObject;
         }
         const QByteArray &xmlData = xmlContent->decodedContent();
@@ -199,7 +210,8 @@ ObjectType KolabObjectReader::parseMimeMessage(const KMime::Message::Ptr &msg)
     } else { //V3
         KMime::Content *xmlContent = Mime::findContentByType( msg, getMimeType(d->mObjectType) );
         if ( !xmlContent ) {
-            CRITICAL("no part found");
+            Critical() << "no " << getMimeType(d->mObjectType) << " part found";
+            printMessageDebugInfo(msg);
             return InvalidObject;
         }
         switch (d->mObjectType) {
@@ -244,7 +256,8 @@ ObjectType KolabObjectReader::parseMimeMessage(const KMime::Message::Ptr &msg)
             }
                 break;
             default:
-                CRITICAL("no kolab object found "+kolabType);
+                Critical() << "no kolab object found " << kolabType;
+                printMessageDebugInfo(msg);
                 break;
         }
 


commit 348048d35b5e41af909210fd1751bd04fe1c9405
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Tue Jun 26 15:14:29 2012 +0200

    uid in subject

diff --git a/kolabformat/kolabobject.cpp b/kolabformat/kolabobject.cpp
index 1f46d95..27f7ef7 100644
--- a/kolabformat/kolabobject.cpp
+++ b/kolabformat/kolabobject.cpp
@@ -417,7 +417,7 @@ KMime::Message::Ptr KolabObjectWriter::writeDistlist(const KABC::ContactGroup &d
         const Kolab::DistList &dist = Kolab::Conversion::fromKABC(distlist);
         const std::string &v3String = Kolab::writeDistlist(dist, getProductId(productId).toStdString());
         ErrorHandler::handleLibkolabxmlErrors();
-        return  Mime::createMessage(QString(), xCardMimeType(), contactKolabType(), QString::fromStdString(v3String).toLocal8Bit(), true, getProductId(productId));
+        return  Mime::createMessage(QString::fromStdString(dist.uid()), xCardMimeType(), contactKolabType(), QString::fromStdString(v3String).toLocal8Bit(), true, getProductId(productId));
     }
     KolabV2::DistributionList d(&distlist);
     return distListToKolabFormat(d, getProductId(productId));
@@ -431,7 +431,7 @@ KMime::Message::Ptr KolabObjectWriter::writeNote(const KMime::Message::Ptr &note
         const Kolab::Note &n = Kolab::Conversion::fromNote(note);
         const std::string &v3String = Kolab::writeNote(n, getProductId(productId).toStdString());
         ErrorHandler::handleLibkolabxmlErrors();
-        return  Mime::createMessage(QString::fromStdString(n.summary()), kolabMimeType(), noteKolabType(), QString::fromStdString(v3String).toLocal8Bit(), true, getProductId(productId));
+        return  Mime::createMessage(QString::fromStdString(n.uid()), kolabMimeType(), noteKolabType(), QString::fromStdString(v3String).toLocal8Bit(), true, getProductId(productId));
     }
     return noteToKolab(note, getProductId(productId));
 }
@@ -452,8 +452,7 @@ KMime::Message::Ptr KolabObjectWriter::writeDictionary(const QStringList &entrie
     Kolab::Configuration configuration(dictionary); //TODO preserve creation/lastModified date
     const std::string &v3String = Kolab::writeConfiguration(configuration, getProductId(productId).toStdString());
     ErrorHandler::handleLibkolabxmlErrors();
-    //TODO uid in subject?
-    return  Mime::createMessage(QString(), kolabMimeType(), dictKolabType(), QString::fromStdString(v3String).toLocal8Bit(), true, getProductId(productId));
+    return  Mime::createMessage(QString::fromStdString(configuration.uid()), kolabMimeType(), dictKolabType(), QString::fromStdString(v3String).toLocal8Bit(), true, getProductId(productId));
 }
 
 


commit fbe767a15225846b362f69f73a36ddd9f712fab9
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Tue Jun 26 15:12:47 2012 +0200

    make it easy to print an error.

diff --git a/kolabformat/errorhandler.cpp b/kolabformat/errorhandler.cpp
index 4fc5147..3b2f98a 100644
--- a/kolabformat/errorhandler.cpp
+++ b/kolabformat/errorhandler.cpp
@@ -40,6 +40,7 @@ void ErrorHandler::addError(ErrorHandler::Severity s, const QString& message, co
     }
     if (s > m_worstError) {
         m_worstError = s;
+        m_worstErrorMessage = message;
     }
     m_errorQueue.append(Err(s, message, location));
 }
@@ -49,6 +50,11 @@ ErrorHandler::Severity ErrorHandler::error() const
     return m_worstError;
 }
 
+QString ErrorHandler::errorMessage() const
+{
+    return m_worstErrorMessage;
+}
+
 const QList< ErrorHandler::Err >& ErrorHandler::getErrors() const
 {
     return m_errorQueue;
diff --git a/kolabformat/errorhandler.h b/kolabformat/errorhandler.h
index 73047cc..254a741 100644
--- a/kolabformat/errorhandler.h
+++ b/kolabformat/errorhandler.h
@@ -66,6 +66,7 @@ public:
     void addError(Severity s, const QString &message, const QString &location);
     const QList <Err> &getErrors() const;
     Severity error() const;
+    QString errorMessage() const;
     void clear();
     
     /**
@@ -84,6 +85,7 @@ private:
     ErrorHandler & operator= (const ErrorHandler &);
     
     Severity m_worstError;
+    QString m_worstErrorMessage;
     QList <Err> m_errorQueue;
 };
 


commit db746b474560dc4b50fdf3af480b09d9573195b6
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Thu Jun 21 17:16:10 2012 +0200

    Freebusy generation from events and ical file writing

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3f3186d..30c84a0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -73,6 +73,7 @@ add_subdirectory(kolabformatV2)
 add_subdirectory(conversion)
 add_subdirectory(calendaring)
 add_subdirectory(icalendar)
+add_subdirectory(freebusy)
 
 QT4_WRAP_CPP(CALENDARING_MOC calendaring/event.h)
 # QT4_WRAP_CPP(CONVERSION_MOC conversion/qtevent.h conversion/qtduration.h)
@@ -87,6 +88,7 @@ set(KOLAB_SRCS
     ${ICALENDAR_SRCS}
     ${CALENDARING_MOC}
     ${CONVERSION_MOC}
+    ${FREEBUSY_SRCS}
 )
 
 set(KOLAB_LINK_LIBRARIES
diff --git a/freebusy/CMakeLists.txt b/freebusy/CMakeLists.txt
new file mode 100644
index 0000000..f1f584e
--- /dev/null
+++ b/freebusy/CMakeLists.txt
@@ -0,0 +1,3 @@
+set (FREEBUSY_SRCS
+    ${CMAKE_CURRENT_SOURCE_DIR}/freebusy.cpp
+    PARENT_SCOPE)
diff --git a/freebusy/freebusy.cpp b/freebusy/freebusy.cpp
new file mode 100644
index 0000000..ceb5bc2
--- /dev/null
+++ b/freebusy/freebusy.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2012  Christian Mollekopf <mollekopf at kolabsys.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "freebusy.h"
+#include "conversion/kcalconversion.h"
+#include <kcalcore/freebusy.h>
+#include <kcalcore/icalformat.h>
+#include <kdebug.h>
+#include <quuid.h>
+
+
+namespace Kolab {
+    namespace FreebusyUtils {
+
+
+Kolab::Period addLocalPeriod(  const KDateTime &eventStart, const KDateTime &eventEnd, const KDateTime &mDtStart, const KDateTime &mDtEnd)
+{
+  KDateTime tmpStart;
+  KDateTime tmpEnd;
+
+  //Check to see if the start *or* end of the event is
+  //between the start and end of the freebusy dates.
+  if ( !( ( ( mDtStart <= eventStart) &&
+            ( eventStart <= mDtEnd ) ) ||
+          ( ( mDtStart <= eventEnd ) &&
+            ( eventEnd <= mDtEnd ) ) ) ) {
+    qDebug() << "out of scope";
+    return Kolab::Period();
+  }
+
+  if ( eventStart < mDtStart ) { //eventStart is before start
+    tmpStart = mDtStart;
+  } else {
+    tmpStart = eventStart;
+  }
+
+  qDebug() << eventEnd.date().toString() << eventEnd.time().toString() << mDtEnd.toString();
+  if ( eventEnd > mDtEnd ) { //event end is after dtEnd
+    tmpEnd = mDtEnd;
+  } else {
+    tmpEnd = eventEnd;
+  }
+  Q_ASSERT(tmpStart.isValid());
+  Q_ASSERT(tmpEnd.isValid());
+  return Kolab::Period(Kolab::Conversion::fromDate(tmpStart), Kolab::Conversion::fromDate(tmpEnd));
+}
+
+        
+
+Freebusy generateFreeBusy(const std::vector< Event >& events, const cDateTime& startDate, const cDateTime& endDate, const Freebusy& existing)
+{
+    const KDateTime start = Kolab::Conversion::toDate(startDate).toUtc();
+    const KDateTime end = Kolab::Conversion::toDate(endDate).toUtc();
+
+    //TODO try to merge that with KCalCore::Freebusy
+    std::vector<Kolab::FreebusyPeriod> freebusyPeriods;
+    foreach (const Kolab::Event &e, events) {
+        KCalCore::Event::Ptr event = Kolab::Conversion::toKCalCore(e);
+    
+        // If this event is transparent it shouldn't be in the freebusy list.
+        if ( event->transparency() == KCalCore::Event::Transparent ) {
+            continue;
+        }
+
+        if ( event->hasRecurrenceId() ) {
+            continue; //TODO apply special period exception (duration could be different)
+        }
+
+        const KDateTime eventStart = event->dtStart().toUtc();
+        const KDateTime eventEnd = event->dtEnd().toUtc();
+
+        std::vector <Kolab::Period> periods;
+        if ( event->recurs() ) {
+            const KCalCore::Duration duration( eventStart, eventEnd );
+            const KCalCore::DateTimeList list = event->recurrence()->timesInInterval(start, end);
+            foreach (const KDateTime &dt, list) {
+                const KDateTime utc = dt.toUtc();
+                const Kolab::Period &period = addLocalPeriod(utc, duration.end(utc), start, end);
+                if (period.isValid()) {
+                    periods.push_back(period);
+                }
+            }
+        } else {
+            const Kolab::Period &period = addLocalPeriod(eventStart, eventEnd, start, end);
+            if (period.isValid()) {
+                periods.push_back(period);
+            }
+        }
+        if (!periods.empty()) {
+            Kolab::FreebusyPeriod period;
+            period.setPeriods(periods);
+            //TODO get out of office from event
+            period.setType(Kolab::FreebusyPeriod::Busy);
+    //         period.setEvent(event->summary().toStdString(), event->uid().toStdString(), event->location().toStdString());
+            //TODO event uid etc.
+            freebusyPeriods.push_back(period);
+        }
+    }
+
+    Kolab::Freebusy freebusy;
+    freebusy.setStart(startDate);
+    freebusy.setEnd(endDate);
+    freebusy.setPeriods(freebusyPeriods);
+    freebusy.setUid(QUuid::createUuid().toString().toStdString());
+    freebusy.setTimestamp(Kolab::Conversion::fromDate(KDateTime::currentUtcDateTime()));
+    freebusy.setOrganizer(ContactReference(Kolab::ContactReference::EmailReference, "email", "name"));
+    
+    return freebusy;
+}
+
+std::string toIFB(const Kolab::Freebusy &freebusy)
+{
+    KCalCore::FreeBusy::Ptr fb(new KCalCore::FreeBusy(Kolab::Conversion::toDate(freebusy.start()), Kolab::Conversion::toDate(freebusy.end())));
+    KCalCore::FreeBusyPeriod::List list;
+    Q_FOREACH (const Kolab::FreebusyPeriod &fbPeriod, freebusy.periods()) {
+        Q_FOREACH (const Kolab::Period &p, fbPeriod.periods()) {
+            KCalCore::FreeBusyPeriod period(Kolab::Conversion::toDate(p.start), Kolab::Conversion::toDate(p.end));
+//             period.setSummary("summary"); Doesn't even work. X-SUMMARY is read though (just not written out)
+            //TODO
+            list.append(period);
+            
+        }
+    }
+    fb->addPeriods(list);
+
+    fb->setUid(QString::fromStdString(freebusy.uid()));
+    fb->setOrganizer(KCalCore::Person::Ptr(new KCalCore::Person(QString::fromStdString(freebusy.organizer().name()), QString::fromStdString(freebusy.organizer().email()))));
+    fb->setLastModified(Kolab::Conversion::toDate(freebusy.timestamp()));
+
+    KCalCore::ICalFormat format;
+    QString data = format.createScheduleMessage( fb, KCalCore::iTIPPublish );
+    return data.toStdString();
+}
+
+    }
+}
diff --git a/freebusy/freebusy.h b/freebusy/freebusy.h
new file mode 100644
index 0000000..fbea05f
--- /dev/null
+++ b/freebusy/freebusy.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012  Christian Mollekopf <mollekopf at kolabsys.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef FREEBUSY_H
+#define FREEBUSY_H
+
+#include "kolab_export.h"
+#include <kolabevent.h>
+#include <kolabfreebusy.h>
+
+namespace Kolab {
+    namespace FreebusyUtils {
+
+Kolab::Freebusy generateFreeBusy(const std::vector<Kolab::Event> &events, const Kolab::cDateTime &startDate, const Kolab::cDateTime &endDate, const Kolab::Freebusy &existing = Kolab::Freebusy());
+std::string toIFB(const Kolab::Freebusy &);
+
+    }
+}
+
+#endif // FREEBUSY_H
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 2f1f80e..a9df2b6 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -2,25 +2,29 @@
 include_directories(${CMAKE_CURRENT_BINARY_DIR})
 
 QT4_AUTOMOC(benchmark.cpp)
-add_executable(benchmarktest benchmark.cpp  ${CMAKE_CURRENT_BINARY_DIR}/${BINDINGSTEST_MOC})
+add_executable(benchmarktest benchmark.cpp)
 target_link_libraries(benchmarktest ${QT_QTTEST_LIBRARY} kolab_static)
 
 QT4_AUTOMOC(formattest.cpp)
-add_executable(formattest formattest.cpp  ${CMAKE_CURRENT_BINARY_DIR}/${BINDINGSTEST_MOC})
+add_executable(formattest formattest.cpp)
 target_link_libraries(formattest ${QT_QTTEST_LIBRARY} kolab_static)
 
 QT4_AUTOMOC(upgradetest.cpp)
-add_executable(upgradetest upgradetest.cpp  ${CMAKE_CURRENT_BINARY_DIR}/${BINDINGSTEST_MOC})
+add_executable(upgradetest upgradetest.cpp)
 target_link_libraries(upgradetest ${QT_QTTEST_LIBRARY} kolab_static)
 
 QT4_AUTOMOC(kcalconversiontest.cpp)
-add_executable(kcalconversiontest kcalconversiontest.cpp ${CMAKE_CURRENT_BINARY_DIR}/${BINDINGSTEST_MOC})
+add_executable(kcalconversiontest kcalconversiontest.cpp)
 target_link_libraries(kcalconversiontest ${QT_QTTEST_LIBRARY} kolab_static)
 
 QT4_AUTOMOC(calendaringtest.cpp)
-add_executable(calendaringtest calendaringtest.cpp ${CMAKE_CURRENT_BINARY_DIR}/${BINDINGSTEST_MOC})
+add_executable(calendaringtest calendaringtest.cpp)
 target_link_libraries(calendaringtest ${QT_QTTEST_LIBRARY} kolab_static)
 
 QT4_AUTOMOC(icalendartest.cpp)
-add_executable(icalendartest icalendartest.cpp ${CMAKE_CURRENT_BINARY_DIR}/${BINDINGSTEST_MOC})
-target_link_libraries(icalendartest ${QT_QTTEST_LIBRARY} kolab_static)
\ No newline at end of file
+add_executable(icalendartest icalendartest.cpp)
+target_link_libraries(icalendartest ${QT_QTTEST_LIBRARY} kolab_static)
+
+QT4_AUTOMOC(freebusytest.cpp)
+add_executable(freebusytest freebusytest.cpp)
+target_link_libraries(freebusytest ${QT_QTTEST_LIBRARY} kolab_static)
\ No newline at end of file
diff --git a/tests/calendaringtest.cpp b/tests/calendaringtest.cpp
index 3671ecb..9ad29bf 100644
--- a/tests/calendaringtest.cpp
+++ b/tests/calendaringtest.cpp
@@ -26,15 +26,7 @@
 #include <calendaring/event.h>
 
 #include "testhelpers.h"
-
-
-Kolab::Event createEvent(const Kolab::cDateTime &start, const Kolab::cDateTime &end)
-{
-    Kolab::Event event;
-    event.setStart(start);
-    event.setEnd(end);
-    return event;
-}
+#include "testutils.h"
 
 void compareEvents(const std::vector<Kolab::Event> &list1, const std::vector<Kolab::Event> &list2)
 {
diff --git a/tests/freebusytest.cpp b/tests/freebusytest.cpp
new file mode 100644
index 0000000..40adf6b
--- /dev/null
+++ b/tests/freebusytest.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2012  Christian Mollekopf <mollekopf at kolabsys.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "freebusytest.h"
+#include "testutils.h"
+#include "testhelpers.h"
+
+#include <QTest>
+#include "freebusy/freebusy.h"
+#include <kolabfreebusy.h>
+
+
+void FreebusyTest::testFB_data()
+{
+    QTest::addColumn<Kolab::cDateTime>( "start" );
+    QTest::addColumn<Kolab::cDateTime>( "end" );
+    QTest::addColumn< std::vector<Kolab::Event> >( "events" );
+    QTest::addColumn< std::vector<Kolab::FreebusyPeriod> >( "output" );
+
+
+    //UTC check
+    {
+        Kolab::Period p1(Kolab::cDateTime(2011,10,6,12,1,1,true), Kolab::cDateTime(2011,10,7,12,1,1,true));
+        Kolab::Period p2(Kolab::cDateTime(2011,10,8,12,1,1,true), Kolab::cDateTime(2011,10,9,12,1,1,true));
+        Kolab::Period p3(Kolab::cDateTime(2011,10,10,12,1,1,true), Kolab::cDateTime(2011,10,11,12,1,1,true));
+
+        std::vector<Kolab::Event> events;
+        events.push_back(createEvent(p1.start, p1.end));
+        events.push_back(createEvent(p2.start, p2.end));
+        events.push_back(createEvent(p3.start, p3.end));
+
+        Kolab::FreebusyPeriod period1;
+        period1.setType(Kolab::FreebusyPeriod::Busy);
+        period1.setPeriods(std::vector<Kolab::Period>() << p1);
+
+        Kolab::FreebusyPeriod period2;
+        period2.setType(Kolab::FreebusyPeriod::Busy);
+        period2.setPeriods(std::vector<Kolab::Period>() << p2);
+
+        Kolab::FreebusyPeriod period3;
+        period3.setType(Kolab::FreebusyPeriod::Busy);
+        period3.setPeriods(std::vector<Kolab::Period>() << p3);
+
+        {
+            std::vector<Kolab::FreebusyPeriod> output;
+            output.push_back(period1);
+            output.push_back(period2);
+            output.push_back(period3);
+
+            QTest::newRow( "simple utc" ) << Kolab::cDateTime(2010, 1, 1,1,1,1,true) << Kolab::cDateTime(2012, 1, 1,1,1,1,true) << events << output;
+        }
+
+        {
+            std::vector<Kolab::FreebusyPeriod> output;
+            output.push_back(period2);
+            output.push_back(period3);
+
+            QTest::newRow( "limit utc below" ) << Kolab::cDateTime(2011,10,8,12,1,1,true) << Kolab::cDateTime(2012, 1, 1,1,1,1,true) << events << output;
+        }
+        {
+            std::vector<Kolab::FreebusyPeriod> output;
+            output.push_back(period1);
+            output.push_back(period2);
+
+            QTest::newRow( "limit utc above" ) << Kolab::cDateTime(2010, 1, 1,1,1,1,true) << Kolab::cDateTime(2011,10,9,12,1,1,true) << events << output;
+        }
+    }
+    {
+        Kolab::Event event;
+        event.setStart(Kolab::cDateTime(2011,1,1,0,0,0,true));
+        event.setEnd(Kolab::cDateTime(2011,1,1,1,0,0,true));
+        Kolab::RecurrenceRule rrule;
+        rrule.setFrequency(Kolab::RecurrenceRule::Daily);
+        rrule.setInterval(1);
+        rrule.setCount(2);
+        event.setRecurrenceRule(rrule);
+        
+        std::vector<Kolab::Event> events;
+        events.push_back(event);
+
+        std::vector<Kolab::FreebusyPeriod> output;
+        Kolab::FreebusyPeriod period1;
+        period1.setType(Kolab::FreebusyPeriod::Busy);
+        period1.setPeriods(std::vector<Kolab::Period>() << Kolab::Period(Kolab::cDateTime(2011,1,1,0,0,0,true), Kolab::cDateTime(2011,1,1,1,0,0,true))
+                                                        << Kolab::Period(Kolab::cDateTime(2011,1,2,0,0,0,true), Kolab::cDateTime(2011,1,2,1,0,0,true))
+        );
+        output.push_back(period1);
+
+        QTest::newRow( "fullday recurrence" ) << Kolab::cDateTime(2010, 1, 1,1,1,1,true) << Kolab::cDateTime(2012,10,9,12,1,1,true) << events << output;
+    }
+}
+
+
+void FreebusyTest::testFB()
+{
+    QFETCH(Kolab::cDateTime, start);
+    QFETCH(Kolab::cDateTime, end);
+    QFETCH(std::vector<Kolab::Event>, events);
+    QFETCH(std::vector<Kolab::FreebusyPeriod>, output);
+
+    Kolab::Freebusy fb = Kolab::FreebusyUtils::generateFreeBusy(events, start, end);
+        
+    QCOMPARE((int)fb.periods().size(), (int)output.size());
+    for (int i = 0; i<output.size(); i++) {
+        QCOMPARE(fb.periods().at(i), output.at(i));
+    }
+
+    std::cout << Kolab::FreebusyUtils::toIFB(fb);
+}
+
+// void FreebusyTest::testHonorTimeFrame()
+// {
+// 
+//     Kolab::Period p1(Kolab::cDateTime(2011,10,6,12,1,1,true), Kolab::cDateTime(2011,10,8,12,1,1,true));
+//     Kolab::Period p2(Kolab::cDateTime(2011,10,7,12,1,1,true), Kolab::cDateTime(2011,10,10,12,1,1,true));
+//     Kolab::Period p3(Kolab::cDateTime(2011,10,9,12,1,1,true), Kolab::cDateTime(2011,10,11,12,1,1,true));
+// 
+//     std::vector<Kolab::Event> events;
+//     events.push_back(createEvent(p1.start, p1.end));
+//     events.push_back(createEvent(p2.start, p2.end));
+//     events.push_back(createEvent(p3.start, p3.end));
+// 
+//     Kolab::FreebusyPeriod period1;
+//     period1.setType(Kolab::FreebusyPeriod::Busy);
+//     period1.setPeriods(std::vector<Kolab::Period>() << p1);
+// 
+//     Kolab::FreebusyPeriod period2;
+//     period2.setType(Kolab::FreebusyPeriod::Busy);
+//     period2.setPeriods(std::vector<Kolab::Period>() << p2);
+// 
+//     Kolab::FreebusyPeriod period3;
+//     period3.setType(Kolab::FreebusyPeriod::Busy);
+//     period3.setPeriods(std::vector<Kolab::Period>() << p3);
+// 
+// 
+//     Kolab::Freebusy fb =  Kolab::FreebusyUtils::generateFreeBusy(events, Kolab::cDateTime(2010, 1, 1,1,1,1,true), Kolab::cDateTime(2012, 1, 1,1,1,1,true));
+//     QCOMPARE((int)fb.periods().size(), 3);
+//     QCOMPARE(fb.periods().at(0), period1);
+//     QCOMPARE(fb.periods().at(1), period2);
+//     QCOMPARE(fb.periods().at(2), period3);
+// }
+
+QTEST_MAIN( FreebusyTest )
+
+#include "freebusytest.moc"
\ No newline at end of file
diff --git a/tests/freebusytest.h b/tests/freebusytest.h
new file mode 100644
index 0000000..a27b9b5
--- /dev/null
+++ b/tests/freebusytest.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012  Christian Mollekopf <mollekopf at kolabsys.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef FREEBUSYTEST_H
+#define FREEBUSYTEST_H
+#include <QObject>
+
+class FreebusyTest: public QObject
+{
+    Q_OBJECT
+private slots:
+
+    void testFB_data();
+    void testFB();
+};
+
+#endif // FREEBUSYTEST_H
diff --git a/tests/testhelpers.h b/tests/testhelpers.h
index 614ddd2..02ef659 100644
--- a/tests/testhelpers.h
+++ b/tests/testhelpers.h
@@ -38,14 +38,16 @@ Q_DECLARE_METATYPE(std::vector<Kolab::Event>);
 Q_DECLARE_METATYPE(Kolab::Todo);
 Q_DECLARE_METATYPE(Kolab::Journal);
 Q_DECLARE_METATYPE(Kolab::Contact);
+Q_DECLARE_METATYPE(Kolab::Period);
+Q_DECLARE_METATYPE(std::vector<Kolab::FreebusyPeriod>);
+
 Q_DECLARE_METATYPE(KCalCore::Event);
 Q_DECLARE_METATYPE(KCalCore::Todo);
 Q_DECLARE_METATYPE(KCalCore::Journal);
 Q_DECLARE_METATYPE(KCalCore::Duration);
 
 namespace QTest {
-
-
+    
     template<>
     char *toString(const Kolab::cDateTime &dt)
     {
@@ -263,13 +265,42 @@ namespace QTest {
     {
         QByteArray ba = "vector<Kolab::CustomProperty>(";
         for (int i = 0; i < v.size(); i++) {
-                ba += QByteArray(toString(v.at(i)))+ "\n";
-            }
-            ba += ")";
-            return qstrdup(ba.data());
+            ba += QByteArray(toString(v.at(i)))+ "\n";
+        }
+        ba += ")";
+        return qstrdup(ba.data());
     }
 
+    template<>
+    char *toString(const Kolab::Period &p)
+    {
+        QByteArray ba = "Kolab::Period(";
+        ba += QByteArray(toString(p.start))+ "\n";
+        ba += QByteArray(toString(p.end))+ "\n";
+        ba += ")";
+        return qstrdup(ba.data());
+    }
 
+    template<>
+    char *toString(const std::vector<Kolab::Period> &v)
+    {
+        QByteArray ba = "vector<Kolab::Period>(";
+        for (int i = 0; i < v.size(); i++) {
+            ba += QByteArray(toString(v.at(i)))+ "\n";
+        }
+        ba += ")";
+        return qstrdup(ba.data());
+    }
+
+    template<>
+    char *toString(const Kolab::FreebusyPeriod &p)
+    {
+        QByteArray ba = "Kolab::FreebusyPeriod(";
+        ba += QString::number(p.type())+ "\n";
+        ba += QByteArray(toString(p.periods()))+ "\n";
+        ba += ")";
+        return qstrdup(ba.data());
+    }
 
 }
 
diff --git a/tests/testutils.h b/tests/testutils.h
index 82c4541..32842ae 100644
--- a/tests/testutils.h
+++ b/tests/testutils.h
@@ -23,6 +23,7 @@
 #include <qtemporaryfile.h>
 #include <qprocess.h>
 #include <kdebug.h>
+#include <kolabevent.h>
 #include <kmime/kmime_message.h>
 
 #include "kolabformat/kolabobject.h"
@@ -180,3 +181,11 @@ void normalizeContact(KABC::Addressee &addressee)
     addressee.removeCustom("KOLAB", "SoundAttachmentName");
     
 }
+
+Kolab::Event createEvent(const Kolab::cDateTime &start, const Kolab::cDateTime &end)
+{
+    Kolab::Event event;
+    event.setStart(start);
+    event.setEnd(end);
+    return event;
+}
\ No newline at end of file


commit 679b0effcec31cfb09e717c7a9f840434878b8bb
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Thu Jun 21 17:13:04 2012 +0200

    resolved merge conflict (something was messed up)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index f26b32d..3f3186d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -74,7 +74,21 @@ add_subdirectory(conversion)
 add_subdirectory(calendaring)
 add_subdirectory(icalendar)
 
-set(KOLAB_SRCS kolabformat/kolabobject.cpp kolabformat/errorhandler.cpp mime/mimeutils.cpp ${CONVERSION_SRCS} ${kolabformatv2_SRCS} ${CALENDARING_SRCS} ${ICALENDAR_SRCS})
+QT4_WRAP_CPP(CALENDARING_MOC calendaring/event.h)
+# QT4_WRAP_CPP(CONVERSION_MOC conversion/qtevent.h conversion/qtduration.h)
+
+set(KOLAB_SRCS
+    kolabformat/kolabobject.cpp
+    kolabformat/errorhandler.cpp
+    mime/mimeutils.cpp
+    ${CONVERSION_SRCS}
+    ${kolabformatv2_SRCS}
+    ${CALENDARING_SRCS}
+    ${ICALENDAR_SRCS}
+    ${CALENDARING_MOC}
+    ${CONVERSION_MOC}
+)
+
 set(KOLAB_LINK_LIBRARIES
     ${Libkolabxml_LIBRARIES}
     ${KDEPIMLIBS_KCALCORE_LIBS}


commit 4cb0873adc6bd79b8cf4266075faefcbf38681fc
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Tue Jun 19 23:38:33 2012 +0200

    Use UTC timestamp in mime-message.

diff --git a/mime/mimeutils.cpp b/mime/mimeutils.cpp
index 3a7ee6c..23fd9c1 100644
--- a/mime/mimeutils.cpp
+++ b/mime/mimeutils.cpp
@@ -192,7 +192,7 @@ KMime::Content* createExplanationPart(bool v3)
 KMime::Message::Ptr createMessage(const QString& xKolabType, bool v3, const QString &prodid)
 {
     KMime::Message::Ptr message( new KMime::Message );
-    message->date()->setDateTime( KDateTime::currentLocalDateTime() );
+    message->date()->setDateTime( KDateTime::currentUtcDateTime() );
     KMime::Headers::Generic *h = new KMime::Headers::Generic( X_KOLAB_TYPE_HEADER, message.get(), xKolabType, "utf-8" );
     message->appendHeader( h );
     if (v3) {





More information about the commits mailing list