2 commits - calendaring/event.cpp calendaring/event.h CMakeLists.txt icalendar/CMakeLists.txt icalendar/icalendar.cpp icalendar/icalendar.h icalendar/imip.cpp icalendar/imip.h tests/calendaringtest.cpp tests/calendaringtest.h tests/icalendartest.cpp tests/icalendartest.h

Christian Mollekopf mollekopf at kolabsys.com
Fri Jun 1 02:25:15 CEST 2012


 CMakeLists.txt            |   16 ++-
 calendaring/event.cpp     |   51 +++++++++
 calendaring/event.h       |   22 ++++
 icalendar/CMakeLists.txt  |    4 
 icalendar/icalendar.cpp   |  101 +++++++++++++++----
 icalendar/icalendar.h     |   22 +++-
 icalendar/imip.cpp        |  239 ++++++++++++++++++++++++++++++++++++++++++++++
 icalendar/imip.h          |   34 ++++++
 tests/calendaringtest.cpp |   43 ++++++++
 tests/calendaringtest.h   |    4 
 tests/icalendartest.cpp   |   44 ++++++++
 tests/icalendartest.h     |    3 
 12 files changed, 557 insertions(+), 26 deletions(-)

New commits:
commit 3189cdfcfa9f94db7f0396a49abdf19d0898b5d4
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Fri Jun 1 02:24:59 2012 +0200

    MIME / iMip handling for event.

diff --git a/calendaring/event.cpp b/calendaring/event.cpp
index 6efd1ec..b09ceeb 100644
--- a/calendaring/event.cpp
+++ b/calendaring/event.cpp
@@ -18,6 +18,8 @@
 
 #include "event.h"
 #include <icalendar/icalendar.h>
+#include <kolabformat/kolabobject.h>
+#include <conversion/kcalconversion.h>
 
 #include <iostream>
 #include <kolabformat.h>
@@ -53,6 +55,28 @@ std::string Event::write() const
     return Kolab::writeEvent(*this);
 }
 
+bool Event::fromMime(const std::string &input)
+{
+    KMime::Message::Ptr msg = KMime::Message::Ptr(new KMime::Message);
+    msg->setContent( QString::fromStdString(input).toLatin1() );
+    msg->parse();
+    msg->content(KMime::ContentIndex());
+    KolabObjectReader reader(msg);
+    if (reader.getType() != EventObject) {
+        std::cout << "not an event ";
+        return false;
+    }
+    const Kolab::Event &e = Kolab::Conversion::fromKCalCore(*reader.getEvent());
+    Kolab::Event::operator=(e);
+    return true;
+}
+
+std::string Event::toMime() const
+{
+    return QString(KolabObjectWriter::writeEvent(Kolab::Conversion::toKCalCore(*this))->encodedContent()).toStdString();
+}
+
+
 bool Event::fromICal(const std::string &input)
 {
     std::vector<Kolab::Event> list = fromICalEvents(input);
@@ -71,6 +95,33 @@ std::string Event::toICal() const
     return Kolab::toICal(list);
 }
 
+bool Event::fromIMip(const std::string &input)
+{
+    std::vector<Kolab::Event> list = mITipHandler.fromIMip(input);
+    if (list.size() != 1) {
+        std::cout << "invalid number of events: " << list.size();
+        return false;
+    }
+    Kolab::Event::operator=(list.at(0));
+    return true;
+}
+
+std::string Event::toIMip(ITipMethod method) const
+{
+    std::vector<Kolab::Event> list;
+    list.push_back(*this);
+    return mITipHandler.toIMip(*this, static_cast<ITipHandler::ITipMethod>(method), "from");
+}
+
+Calendaring::Event::ITipMethod Event::getSchedulingMethod() const
+{
+    Q_ASSERT(iTIPPublish == ITipHandler::iTIPPublish);
+    Q_ASSERT(iTIPNoMethod == ITipHandler::iTIPNoMethod);
+    return static_cast<ITipMethod>(mITipHandler.method());
+}
+
+
+
 bool contains(const Kolab::ContactReference &delegatorRef, const std::vector <Kolab::ContactReference > &list)
 {
     foreach (const Kolab::ContactReference &ref, list) {
diff --git a/calendaring/event.h b/calendaring/event.h
index afb8e1a..5775b84 100644
--- a/calendaring/event.h
+++ b/calendaring/event.h
@@ -22,6 +22,7 @@
 
 #ifndef SWIG
 #include "kolab_export.h"
+#include <icalendar/icalendar.h>
 #else
 /* No export/import SWIG interface files */
 #define KOLAB_EXPORT
@@ -39,9 +40,29 @@ public:
     bool read(const std::string &);
     std::string write() const;
 
+    bool fromMime(const std::string &);
+    std::string toMime() const;
+
+    enum ITipMethod {
+            iTIPPublish,       /**< Event, to-do, journal or freebusy posting */
+            iTIPRequest,       /**< Event, to-do or freebusy scheduling request */
+            iTIPReply,         /**< Event, to-do or freebusy reply to request */
+            iTIPAdd,           /**< Event, to-do or journal additional property request */
+            iTIPCancel,        /**< Event, to-do or journal cancellation notice */
+            iTIPRefresh,       /**< Event or to-do description update request */
+            iTIPCounter,       /**< Event or to-do submit counter proposal */
+            iTIPDeclineCounter,/**< Event or to-do decline a counter proposal */
+            iTIPNoMethod       /**< No method */
+        };
+    
     bool fromICal(const std::string &);
     std::string toICal() const;
 
+    bool fromIMip(const std::string &);
+    std::string toIMip(ITipMethod method) const;
+
+    ITipMethod getSchedulingMethod() const;
+
 
     /**
      * Updates the delegators and delegatees of the event.
@@ -59,6 +80,7 @@ public:
     Kolab::Attendee getAttendee(const std::string &);
 private:
     Kolab::Attendee *getAttendee(const ContactReference &);
+    Kolab::ITipHandler mITipHandler;
 };
 
     };
diff --git a/icalendar/icalendar.cpp b/icalendar/icalendar.cpp
index b3936b2..aca1c58 100644
--- a/icalendar/icalendar.cpp
+++ b/icalendar/icalendar.cpp
@@ -74,7 +74,7 @@ KCalCore::iTIPMethod mapToKCalCore(ITipHandler::ITipMethod method)
 }
 
 
-std::string ITipHandler::toITip(const Event &event, ITipHandler::ITipMethod method)
+std::string ITipHandler::toITip(const Event &event, ITipHandler::ITipMethod method) const
 {
     KCalCore::ICalFormat format;
     KCalCore::iTIPMethod m = mapToKCalCore(method);
@@ -115,7 +115,7 @@ ITipHandler::ITipMethod ITipHandler::method() const
 }
 
 
-std::string ITipHandler::toIMip(const Event &event , ITipHandler::ITipMethod m, std::string from, bool bccMe)
+std::string ITipHandler::toIMip(const Event &event , ITipHandler::ITipMethod m, std::string from, bool bccMe) const
 {
     KCalCore::Event::Ptr e = Conversion::toKCalCore(event);
 
diff --git a/icalendar/icalendar.h b/icalendar/icalendar.h
index 018ddea..11db800 100644
--- a/icalendar/icalendar.h
+++ b/icalendar/icalendar.h
@@ -56,13 +56,13 @@ namespace Kolab {
             iTIPNoMethod       /**< No method */
         };
         
-        std::string toIMip(const Kolab::Event &, ITipMethod, std::string from, bool bbcMe = false);
+        std::string toIMip(const Kolab::Event &, ITipMethod, std::string from, bool bbcMe = false) const;
         std::vector<Kolab::Event> fromIMip(const std::string &);
 
         /**
          * Create iTip message from single event
          */
-        std::string toITip(const Kolab::Event &, ITipMethod);
+        std::string toITip(const Kolab::Event &, ITipMethod) const;
 
         /**
          * Parse iTip message with a single event
diff --git a/tests/calendaringtest.cpp b/tests/calendaringtest.cpp
index 6d94178..3671ecb 100644
--- a/tests/calendaringtest.cpp
+++ b/tests/calendaringtest.cpp
@@ -43,6 +43,7 @@ void compareEvents(const std::vector<Kolab::Event> &list1, const std::vector<Kol
         const Kolab::Event &e1 = list1.at(i);
         const Kolab::Event &e2 = list2.at(i);
 //         qDebug() << i;
+//         QCOMPARE(e1.uid(), e2.uid());
         QCOMPARE(e1.start(), e2.start());
         QCOMPARE(e1.end(), e2.end());
     }
@@ -334,6 +335,48 @@ void CalendaringTest::delegationTest()
     //TODO write an actual test
 }
 
+void CalendaringTest::testICal()
+{
+    Kolab::Calendaring::Event event;
+    event.setStart(Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4));
+    const std::string &result = event.toICal();
+    //TODO write an actual test
+    event.setStart(Kolab::cDateTime(1,1,1));
+    event.fromICal(result);
+    QCOMPARE(event.start(), Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4));
+}
+
+void CalendaringTest::testMime()
+{
+    Kolab::Calendaring::Event event;
+    event.setStart(Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4));
+    std::cout << event.toMime();
+    const std::string &result = event.toMime();
+    event.setStart(Kolab::cDateTime(1,1,1));
+    event.fromMime(result);
+    QCOMPARE(event.start(), Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4));
+}
+
+void CalendaringTest::testIMip()
+{
+    Kolab::Calendaring::Event event;
+    Kolab::Attendee att1(Kolab::ContactReference("email1", "name1", "uid1"));
+
+    std::vector <Kolab::Attendee > attendees;
+    attendees.push_back(att1);
+    event.setAttendees(attendees);
+    event.setOrganizer(Kolab::ContactReference("organizer at test.org", "organizer", "uid3"));
+    event.setSummary("summary");
+    event.setStart(Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4));
+    const std::string &result = event.toIMip(Kolab::Calendaring::Event::iTIPRequest);
+    event.setStart(Kolab::cDateTime(1,1,1));
+    event.fromIMip(result);
+    QCOMPARE(event.start(), Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4));
+    QCOMPARE(event.getSchedulingMethod(), Kolab::Calendaring::Event::iTIPRequest);
+    //TODO returns UTC instead of local timezone
+}
+
+
 
 QTEST_MAIN( CalendaringTest )
 
diff --git a/tests/calendaringtest.h b/tests/calendaringtest.h
index 02c39bc..295dd90 100644
--- a/tests/calendaringtest.h
+++ b/tests/calendaringtest.h
@@ -39,6 +39,10 @@ private slots:
     void testCalendar();
 
     void delegationTest();
+
+    void testMime();
+    void testICal();
+    void testIMip();
 };
 
 #endif // CALENDARINGTEST_H
diff --git a/tests/icalendartest.cpp b/tests/icalendartest.cpp
index af0c000..d3273a7 100644
--- a/tests/icalendartest.cpp
+++ b/tests/icalendartest.cpp
@@ -68,7 +68,7 @@ void ICalendarTest::testToIMip()
     Kolab::ITipHandler handler;
     Kolab::Event ev1;
     ev1.setStart(Kolab::cDateTime(2011,10,10,12,1,1,true));
-    ev1.setEnd(Kolab::cDateTime(2011,10,11,12,1,1,true));
+    ev1.setEnd(Kolab::cDateTime("Europe/Zurich",2012,5,5,3,4,4));
     ev1.setLastModified(Kolab::cDateTime(2011,10,11,12,1,2,true));
     ev1.setCreated(Kolab::cDateTime(2011,10,11,12,1,3,true));
     
@@ -88,6 +88,8 @@ void ICalendarTest::testToIMip()
     qDebug() << QString::fromStdString(Kolab::toICal(eventResult));
 
     QCOMPARE((int)eventResult.size(), 1);
+    QCOMPARE(ev1.start(), eventResult.front().start());
+    QCOMPARE(ev1.end(), eventResult.front().end());
 }
 
 


commit f5183b4e23b97add769fdaf647b43500e1059024
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Fri Jun 1 01:44:40 2012 +0200

    First crude iMip implementation.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 567ba5d..b8ef17e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -68,7 +68,21 @@ 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})
-set(KOLAB_LINK_LIBRARIES ${Libkolabxml_LIBRARIES} ${KDEPIMLIBS_KCALCORE_LIBS} ${KDEPIMLIBS_KABC_LIBS} ${KDEPIMLIBS_KMIME_LIBS} ${KDEPIMLIBS_AKONADI_LIBS} ${KDEPIMLIBS_AKONADI_NOTES_LIBS} ${QT_QTCORE_LIBRARY} ${QT_QTXML_LIBRARY} ${QT_QTGUI_LIBRARY} ${KDE4_KDECORE_LIBRARY} ${KDE4_KIO_LIBRARY})
+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}
+)
 if(BUILD_TESTS)
     #for tests only
     kde4_add_library(kolab_static STATIC ${KOLAB_SRCS})
diff --git a/icalendar/CMakeLists.txt b/icalendar/CMakeLists.txt
index b82684f..7e0efd6 100644
--- a/icalendar/CMakeLists.txt
+++ b/icalendar/CMakeLists.txt
@@ -1,6 +1,8 @@
 
 set (ICALENDAR_SRCS
-    ${CMAKE_CURRENT_SOURCE_DIR}/icalendar.cpp PARENT_SCOPE)
+    ${CMAKE_CURRENT_SOURCE_DIR}/icalendar.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/imip.cpp
+    PARENT_SCOPE)
 
 if(PYTHON_BINDINGS)
     message("building python bindings")
diff --git a/icalendar/icalendar.cpp b/icalendar/icalendar.cpp
index 5e0f15a..b3936b2 100644
--- a/icalendar/icalendar.cpp
+++ b/icalendar/icalendar.cpp
@@ -19,13 +19,16 @@
 
 
 #include "icalendar.h"
+#include "imip.h"
 #include <conversion/kcalconversion.h>
 #include <conversion/commonconversion.h>
+#include <mime/mimeutils.h>
 #include <KCalCore/Event>
 #include <kcalcore/memorycalendar.h>
 #include <kcalcore/icalformat.h>
-
-#include <QDebug>
+#include <kmime/kmime_message.h>
+#include <klocalizedstring.h>
+#include <kdebug.h>
 
 namespace Kolab {
 
@@ -56,21 +59,45 @@ std::vector< Event > fromICalEvents(const std::string &input)
     return events;
 }
 
+ITipHandler::ITipMethod mapFromKCalCore(KCalCore::iTIPMethod method)
+{
+    Q_ASSERT(KCalCore::iTIPPublish == ITipHandler::iTIPPublish);
+    Q_ASSERT(KCalCore::iTIPNoMethod == ITipHandler::iTIPNoMethod);
+    return static_cast<ITipHandler::ITipMethod>(method);
+}
+
+KCalCore::iTIPMethod mapToKCalCore(ITipHandler::ITipMethod method)
+{
+    Q_ASSERT(KCalCore::iTIPPublish == ITipHandler::iTIPPublish);
+    Q_ASSERT(KCalCore::iTIPNoMethod == ITipHandler::iTIPNoMethod);
+    return static_cast<KCalCore::iTIPMethod>(method);
+}
+
 
 std::string ITipHandler::toITip(const Event &event, ITipHandler::ITipMethod method)
 {
     KCalCore::ICalFormat format;
-    KCalCore::iTIPMethod m;
-    switch  (method) {
-        case ITipHandler::iTIPRequest:
-            m = KCalCore::iTIPRequest;
-            break;
-        default:
-            qWarning() << "unsupported itip method";
+    KCalCore::iTIPMethod m = mapToKCalCore(method);
+    if (m == KCalCore::iTIPNoMethod) {
+        return std::string();
     }
-    return format.createScheduleMessage(Conversion::toKCalCore(event), m).toStdString();
+//     kDebug() << event.start().
+/* TODO
+ * DTSTAMP is created
+ * CREATED is current timestamp
+ * LASTMODIFIED is lastModified
+ * 
+ * Double check if that is correct.
+ *
+ * I think DTSTAMP should be the current timestamp, and CREATED should be the creation date.
+ */
+    KCalCore::Event::Ptr e = Conversion::toKCalCore(event);
+    return format.createScheduleMessage(e, m).toStdString();
 }
 
+
+
+
 std::vector< Event > ITipHandler::fromITip(const std::string &string)
 {
     KCalCore::Calendar::Ptr calendar(new KCalCore::MemoryCalendar(Kolab::Conversion::getTimeSpec(true, std::string())));
@@ -78,14 +105,7 @@ std::vector< Event > ITipHandler::fromITip(const std::string &string)
     KCalCore::ScheduleMessage::Ptr msg= format.parseScheduleMessage(calendar, QString::fromStdString(string));
     std::vector< Event > events;
     events.push_back(Conversion::fromKCalCore(*(msg->event().dynamicCast<KCalCore::Event>())));
-    switch  (msg->method()) {
-        case KCalCore::iTIPRequest:
-            mMethod = ITipHandler::iTIPRequest;
-            break;
-        default:
-            mMethod = ITipHandler::iTipUnknown;
-            qWarning() << "unsupported itip method";
-    }
+    mMethod = mapFromKCalCore(msg->method());
     return events;
 }
 
@@ -95,4 +115,47 @@ ITipHandler::ITipMethod ITipHandler::method() const
 }
 
 
+std::string ITipHandler::toIMip(const Event &event , ITipHandler::ITipMethod m, std::string from, bool bccMe)
+{
+    KCalCore::Event::Ptr e = Conversion::toKCalCore(event);
+
+    KCalCore::ICalFormat format;
+
+    KCalCore::iTIPMethod method = mapToKCalCore(m);
+    const QString &messageText = format.createScheduleMessage( e, method );
+    //This code is mostly from MailScheduler::performTransaction
+    bool status;
+    if ( method == KCalCore::iTIPRequest ||
+        method == KCalCore::iTIPCancel ||
+        method == KCalCore::iTIPAdd ||
+        method == KCalCore::iTIPDeclineCounter ) {
+        return QString(mailAttendees(e, bccMe, messageText)).toStdString();
+    } else {
+        QString subject;
+        if ( e && method == KCalCore::iTIPCounter ) {
+            subject = i18n( "Counter proposal: %1", e->summary() );
+        }
+        return QString(mailOrganizer( e, QString::fromStdString(from), bccMe, messageText, subject)).toStdString();
+    }
+    return std::string();
+}
+
+std::vector< Event > ITipHandler::fromIMip(const std::string &input)
+{
+    KMime::Message::Ptr msg = KMime::Message::Ptr(new KMime::Message);
+    msg->setContent( QString::fromStdString(input).toLatin1() );
+    msg->parse();
+    msg->content(KMime::ContentIndex());
+
+    KMime::Content *c = Kolab::Mime::findContentByType(msg, "text/calendar");
+    if (!c) {
+        qWarning() << "could not find text/calendar part";
+        return std::vector< Event >();
+    }
+    return fromITip(QString(c->decodedContent()).toStdString());
+}
+
+
+
+
 }
diff --git a/icalendar/icalendar.h b/icalendar/icalendar.h
index 395d673..018ddea 100644
--- a/icalendar/icalendar.h
+++ b/icalendar/icalendar.h
@@ -45,16 +45,27 @@ namespace Kolab {
     class KOLAB_EXPORT ITipHandler {
     public:
         enum ITipMethod {
-            iTipUnknown,
-            iTIPRequest
+            iTIPPublish,       /**< Event, to-do, journal or freebusy posting */
+            iTIPRequest,       /**< Event, to-do or freebusy scheduling request */
+            iTIPReply,         /**< Event, to-do or freebusy reply to request */
+            iTIPAdd,           /**< Event, to-do or journal additional property request */
+            iTIPCancel,        /**< Event, to-do or journal cancellation notice */
+            iTIPRefresh,       /**< Event or to-do description update request */
+            iTIPCounter,       /**< Event or to-do submit counter proposal */
+            iTIPDeclineCounter,/**< Event or to-do decline a counter proposal */
+            iTIPNoMethod       /**< No method */
         };
+        
+        std::string toIMip(const Kolab::Event &, ITipMethod, std::string from, bool bbcMe = false);
+        std::vector<Kolab::Event> fromIMip(const std::string &);
+
         /**
-         * Create iTip message from single event (only request supported so far)
+         * Create iTip message from single event
          */
         std::string toITip(const Kolab::Event &, ITipMethod);
 
         /**
-         * Parse iTip message with a single event (only request supported so far)
+         * Parse iTip message with a single event
          */
         std::vector<Kolab::Event> fromITip(const std::string &);
         ITipMethod method() const;
@@ -62,6 +73,7 @@ namespace Kolab {
         ITipMethod mMethod;
     };
 
+
 }
 
 #endif // ICALENDAR_H
diff --git a/icalendar/imip.cpp b/icalendar/imip.cpp
new file mode 100644
index 0000000..a49aafa
--- /dev/null
+++ b/icalendar/imip.cpp
@@ -0,0 +1,239 @@
+/*
+    <one line to give the library's name and an idea of what it does.>
+    Copyright (C) 2012  Christian Mollekopf <chrigi_1 at fastmail.fm>
+
+    This library 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 2.1 of the License, or (at your option) any later version.
+
+    This library 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 library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+
+#include "imip.h"
+
+#include <kcalutils/incidenceformatter.h>
+#include <KPIMUtils/Email>
+#include <kmime/kmime_message.h>
+#include <QDebug>
+#include <klocalizedstring.h>
+#include <ksystemtimezone.h>
+#include <kdebug.h>
+
+/*
+ * The code in here is copy paste work from kdepim/calendarsupport.
+ *
+ * We need to refactor the code there and move the relevant parts to kdepimlibs to make it reusable.
+ *
+ *
+ */
+
+//From MailClient::send
+KMime::Message::Ptr createMessage( const QString &from, const QString &_to,
+                       const QString &cc, const QString &subject,
+                       const QString &body, bool hidden, bool bccMe,
+                       const QString &attachment/*, const QString &mailTransport */)
+{
+  Q_UNUSED( hidden );
+
+  const bool outlookConformInvitation = false;
+  QString userAgent = "libkolab";
+
+  // We must have a recipients list for most MUAs. Thus, if the 'to' list
+  // is empty simply use the 'from' address as the recipient.
+  QString to = _to;
+  if ( to.isEmpty() ) {
+    to = from;
+  }
+  kDebug() << "\nFrom:" << from
+           << "\nTo:" << to
+           << "\nCC:" << cc
+           << "\nSubject:" << subject << "\nBody: \n" << body
+           << "\nAttachment:\n" << attachment
+           /*<< "\nmailTransport: " << mailTransport*/;
+
+  // Now build the message we like to send. The message KMime::Message::Ptr instance
+  // will be the root message that has 2 additional message. The body itself and
+  // the attached cal.ics calendar file.
+  KMime::Message::Ptr message = KMime::Message::Ptr( new KMime::Message );
+  message->contentTransferEncoding()->clear();  // 7Bit, decoded.
+
+  // Set the headers
+  message->userAgent()->fromUnicodeString(userAgent, "utf-8" );
+  message->from()->fromUnicodeString( from, "utf-8" );
+  message->to()->fromUnicodeString( to, "utf-8" );
+  message->cc()->fromUnicodeString( cc, "utf-8" );
+  if( bccMe ) {
+    message->bcc()->fromUnicodeString( from, "utf-8" ); //from==me, right?
+  }
+  message->date()->setDateTime( KDateTime::currentLocalDateTime() );
+  message->subject()->fromUnicodeString( subject, "utf-8" );
+
+  if ( outlookConformInvitation ) {
+    message->contentType()->setMimeType( "text/calendar" );
+    message->contentType()->setCharset( "utf-8" );
+    message->contentType()->setName( QLatin1String( "cal.ics" ), "utf-8" );
+    message->contentType()->setParameter( QLatin1String( "method" ), QLatin1String( "request" ) );
+
+    if ( !attachment.isEmpty() ) {
+      KMime::Headers::ContentDisposition *disposition =
+        new KMime::Headers::ContentDisposition( message.get() );
+      disposition->setDisposition( KMime::Headers::CDinline );
+      message->setHeader( disposition );
+      message->contentTransferEncoding()->setEncoding( KMime::Headers::CEquPr );
+      message->setBody( KMime::CRLFtoLF( attachment.toUtf8() ) );
+    }
+  } else {
+    // We need to set following 4 lines by hand else KMime::Content::addContent
+    // will create a new Content instance for us to attach the main message
+    // what we don't need cause we already have the main message instance where
+    // 2 additional messages are attached.
+    KMime::Headers::ContentType *ct = message->contentType();
+    ct->setMimeType( "multipart/mixed" );
+    ct->setBoundary( KMime::multiPartBoundary() );
+    ct->setCategory( KMime::Headers::CCcontainer );
+
+    // Set the first multipart, the body message.
+    KMime::Content *bodyMessage = new KMime::Content;
+    KMime::Headers::ContentDisposition *bodyDisposition =
+      new KMime::Headers::ContentDisposition( bodyMessage );
+    bodyDisposition->setDisposition( KMime::Headers::CDinline );
+    bodyMessage->contentType()->setMimeType( "text/plain" );
+    bodyMessage->contentType()->setCharset( "utf-8" );
+    bodyMessage->contentTransferEncoding()->setEncoding( KMime::Headers::CEquPr );
+    bodyMessage->setBody( KMime::CRLFtoLF( body.toUtf8() ) );
+    message->addContent( bodyMessage );
+
+    // Set the sedcond multipart, the attachment.
+    if ( !attachment.isEmpty() ) {
+      KMime::Content *attachMessage = new KMime::Content;
+      KMime::Headers::ContentDisposition *attachDisposition =
+        new KMime::Headers::ContentDisposition( attachMessage );
+      attachDisposition->setDisposition( KMime::Headers::CDattachment );
+      attachMessage->contentType()->setMimeType( "text/calendar" );
+      attachMessage->contentType()->setCharset( "utf-8" );
+      attachMessage->contentType()->setName( QLatin1String( "cal.ics" ), "utf-8" );
+      attachMessage->contentType()->setParameter( QLatin1String( "method" ),
+                                                  QLatin1String( "request" ) );
+      attachMessage->setHeader( attachDisposition );
+      attachMessage->contentTransferEncoding()->setEncoding( KMime::Headers::CEquPr );
+      attachMessage->setBody( KMime::CRLFtoLF( attachment.toUtf8() ) );
+      message->addContent( attachMessage );
+    }
+  }
+
+  // Job done, attach the both multiparts and assemble the message.
+  message->assemble();
+  return message;
+}
+
+//From MailClient::mailAttendees
+QByteArray mailAttendees( const KCalCore::IncidenceBase::Ptr &incidence,
+//                                 const KPIMIdentities::Identity &identity,
+                                bool bccMe, const QString &attachment
+                                /*const QString &mailTransport */)
+{
+  KCalCore::Attendee::List attendees = incidence->attendees();
+  if ( attendees.isEmpty() ) {
+    kWarning() << "There are no attendees to e-mail";
+    return false;
+  }
+
+  const QString from = incidence->organizer()->fullName();
+  const QString organizerEmail = incidence->organizer()->email();
+
+  QStringList toList;
+  QStringList ccList;
+  const int numberOfAttendees( attendees.count() );
+  for ( int i=0; i<numberOfAttendees; ++i ) {
+    KCalCore::Attendee::Ptr a = attendees.at(i);
+
+    const QString email = a->email();
+    if ( email.isEmpty() ) {
+      continue;
+    }
+
+    // In case we (as one of our identities) are the organizer we are sending
+    // this mail. We could also have added ourselves as an attendee, in which
+    // case we don't want to send ourselves a notification mail.
+    if ( organizerEmail == email ) {
+      continue;
+    }
+
+    // Build a nice address for this attendee including the CN.
+    QString tname, temail;
+    const QString username = KPIMUtils::quoteNameIfNecessary( a->name() );
+    // ignore the return value from extractEmailAddressAndName() because
+    // it will always be false since tusername does not contain "@domain".
+    KPIMUtils::extractEmailAddressAndName( username, temail/*byref*/, tname/*byref*/ );
+    tname += QLatin1String( " <" ) + email + QLatin1Char( '>' );
+
+    // Optional Participants and Non-Participants are copied on the email
+    if ( a->role() == KCalCore::Attendee::OptParticipant ||
+         a->role() == KCalCore::Attendee::NonParticipant ) {
+      ccList << tname;
+    } else {
+      toList << tname;
+    }
+  }
+  if( toList.isEmpty() && ccList.isEmpty() ) {
+    // Not really to be called a groupware meeting, eh
+    kWarning() << "There are really no attendees to e-mail";
+    return false;
+  }
+  QString to;
+  if ( !toList.isEmpty() ) {
+    to = toList.join( QLatin1String( ", " ) );
+  }
+  QString cc;
+  if ( !ccList.isEmpty() ) {
+    cc = ccList.join( QLatin1String( ", " ) );
+  }
+
+  QString subject;
+  if ( incidence->type() != KCalCore::Incidence::TypeFreeBusy ) {
+    KCalCore::Incidence::Ptr inc = incidence.staticCast<KCalCore::Incidence>();
+    subject = inc->summary();
+  } else {
+    subject = i18n( "Free Busy Object" );
+  }
+
+  const QString body =
+    KCalUtils::IncidenceFormatter::mailBodyStr( incidence, KSystemTimeZones::local() );
+
+  return createMessage(/* identity, */from, to, cc, subject, body, false,
+               bccMe, attachment/*, mailTransport */)->encodedContent();
+}
+
+QByteArray mailOrganizer( const KCalCore::IncidenceBase::Ptr &incidence,
+//                                 const KPIMIdentities::Identity &identity,
+                                const QString &from, bool bccMe,
+                                const QString &attachment,
+                                const QString &sub/*, const QString &mailTransport*/ )
+{
+  const QString to = incidence->organizer()->fullName();
+  QString subject = sub;
+
+  if ( incidence->type() != KCalCore::Incidence::TypeFreeBusy ) {
+    KCalCore::Incidence::Ptr inc = incidence.staticCast<KCalCore::Incidence>();
+    if ( subject.isEmpty() ) {
+      subject = inc->summary();
+    }
+  } else {
+    subject = i18n( "Free Busy Message" );
+  }
+
+  QString body = KCalUtils::IncidenceFormatter::mailBodyStr( incidence, KSystemTimeZones::local() );
+
+  return createMessage( /*identity, */from, to, QString(), subject, body, false,
+               bccMe, attachment/*, mailTransport */)->encodedContent();
+}
+
diff --git a/icalendar/imip.h b/icalendar/imip.h
new file mode 100644
index 0000000..2ee747e
--- /dev/null
+++ b/icalendar/imip.h
@@ -0,0 +1,34 @@
+/*
+    <one line to give the library's name and an idea of what it does.>
+    Copyright (C) 2012  Christian Mollekopf <chrigi_1 at fastmail.fm>
+
+    This library 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 2.1 of the License, or (at your option) any later version.
+
+    This library 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 library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+
+#ifndef IMIP_H
+#define IMIP_H
+#include <QByteArray>
+#include <kcalcore/incidencebase.h>
+
+QByteArray mailAttendees( const KCalCore::IncidenceBase::Ptr &incidence,
+                                bool bccMe, const QString &attachment );
+
+QByteArray mailOrganizer( const KCalCore::IncidenceBase::Ptr &incidence,
+                                const QString &from, bool bccMe,
+                                const QString &attachment,
+                                const QString &sub );
+
+#endif // IMIP_H
diff --git a/tests/icalendartest.cpp b/tests/icalendartest.cpp
index 8be697b..af0c000 100644
--- a/tests/icalendartest.cpp
+++ b/tests/icalendartest.cpp
@@ -50,6 +50,48 @@ void ICalendarTest::testToICal()
     qDebug() << QString::fromStdString(Kolab::toICal(events));
 }
 
+void ICalendarTest::testToITip()
+{
+    Kolab::ITipHandler handler;
+    Kolab::Event ev1;
+    ev1.setStart(Kolab::cDateTime(2011,10,10,12,1,1,true));
+    ev1.setEnd(Kolab::cDateTime(2011,10,11,12,1,1,true));
+    ev1.setLastModified(Kolab::cDateTime(2011,10,11,12,1,2,true));
+    ev1.setCreated(Kolab::cDateTime(2011,10,11,12,1,3,true));
+
+    qDebug() << QString::fromStdString(handler.toITip(ev1, Kolab::ITipHandler::iTIPRequest));
+    
+}
+
+void ICalendarTest::testToIMip()
+{
+    Kolab::ITipHandler handler;
+    Kolab::Event ev1;
+    ev1.setStart(Kolab::cDateTime(2011,10,10,12,1,1,true));
+    ev1.setEnd(Kolab::cDateTime(2011,10,11,12,1,1,true));
+    ev1.setLastModified(Kolab::cDateTime(2011,10,11,12,1,2,true));
+    ev1.setCreated(Kolab::cDateTime(2011,10,11,12,1,3,true));
+    
+    std::vector <Kolab::Attendee > attendees;
+    attendees.push_back(Kolab::Attendee(Kolab::ContactReference("email1 at test.org", "name1", "uid1")));
+    attendees.push_back(Kolab::Attendee (Kolab::ContactReference("email2 at test.org", "name2", "uid2")));
+    ev1.setAttendees(attendees);
+
+    ev1.setOrganizer(Kolab::ContactReference("organizer at test.org", "organizer", "uid3"));
+
+    const std::string mimeResult = handler.toIMip(ev1, Kolab::ITipHandler::iTIPRequest, "test at test.com");
+    qDebug() << QString::fromStdString(mimeResult);
+    qDebug() << QString::fromStdString(handler.toIMip(ev1, Kolab::ITipHandler::iTIPReply, "test at test.com"));
+
+    const std::vector<Kolab::Event> &eventResult = handler.fromIMip(mimeResult);
+
+    qDebug() << QString::fromStdString(Kolab::toICal(eventResult));
+
+    QCOMPARE((int)eventResult.size(), 1);
+}
+
+
+
 QTEST_MAIN( ICalendarTest )
 
 #include "icalendartest.moc"
diff --git a/tests/icalendartest.h b/tests/icalendartest.h
index b3e4166..d6f5acd 100644
--- a/tests/icalendartest.h
+++ b/tests/icalendartest.h
@@ -30,6 +30,9 @@ private slots:
 //     void testEventConflict_data();
     void testToICal();
     void testFromICalEvent();
+
+    void testToITip();
+    void testToIMip();
 };
 
 #endif // ICALENDARTEST_H





More information about the commits mailing list