kolabformat/kolabdefinitions.h kolabformat/kolabobject.cpp kolabformat/kolabobject.h tests/kolabobjecttest.cpp tests/kolabobjecttest.h

Christian Mollekopf mollekopf at kolabsys.com
Fri Aug 29 11:00:16 CEST 2014


 kolabformat/kolabdefinitions.h |    4 +
 kolabformat/kolabobject.cpp    |  112 +++++++++++++++++++++++++++++++++++++++++
 kolabformat/kolabobject.h      |   15 +++++
 tests/kolabobjecttest.cpp      |   28 ++++++++++
 tests/kolabobjecttest.h        |    1 
 5 files changed, 159 insertions(+), 1 deletion(-)

New commits:
commit 1173670e0716cdcb2d4fde6f80fc00f1a5d4ed38
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Wed Aug 27 10:26:26 2014 +0200

    Added tag support.
    
    Thanks to Kevin Krammer for the initial version of the patch.

diff --git a/kolabformat/kolabdefinitions.h b/kolabformat/kolabdefinitions.h
index 379648c..e1d8e93 100644
--- a/kolabformat/kolabdefinitions.h
+++ b/kolabformat/kolabdefinitions.h
@@ -63,6 +63,7 @@ namespace Kolab {
 #define KOLAB_TYPE_DICT    "application/x-vnd.kolab.configuration.dictionary"
 #define KOLAB_TYPE_FREEBUSY    "application/x-vnd.kolab.freebusy"
 #define KOLAB_TYPE_FILE    "application/x-vnd.kolab.file"
+#define KOLAB_TYPE_RELATION "application/x-vnd.kolab.configuration.relation"
 
 enum Version {
     KolabV2,
@@ -78,7 +79,8 @@ enum ObjectType {
     DistlistObject,
     NoteObject,
     DictionaryConfigurationObject,
-    FreebusyObject
+    FreebusyObject,
+    RelationConfigurationObject
 };
 
 }
diff --git a/kolabformat/kolabobject.cpp b/kolabformat/kolabobject.cpp
index b894818..90b4e78 100644
--- a/kolabformat/kolabobject.cpp
+++ b/kolabformat/kolabobject.cpp
@@ -51,6 +51,7 @@ static inline QString noteKolabType() { return QString::fromLatin1(KOLAB_TYPE_NO
 static inline QString configurationKolabType() { return QString::fromLatin1(KOLAB_TYPE_CONFIGURATION); }
 static inline QString dictKolabType() { return QString::fromLatin1(KOLAB_TYPE_DICT); }
 static inline QString freebusyKolabType() { return QString::fromLatin1(KOLAB_TYPE_FREEBUSY); }
+static inline QString relationKolabType() { return QString::fromLatin1(KOLAB_TYPE_RELATION); }
 
 static inline QString xCalMimeType() { return QString::fromLatin1(MIME_TYPE_XCAL); };
 static inline QString xCardMimeType() { return QString::fromLatin1(MIME_TYPE_XCARD); };
@@ -61,6 +62,62 @@ KCalCore::Event::Ptr readV2EventXML(const QByteArray& xmlData, QStringList& atta
     return fromXML<KCalCore::Event::Ptr, KolabV2::Event>(xmlData, attachments);
 }
 
+RelationMember parseMemberUrl(const QString &string)
+{
+    RelationMember member;
+    QUrl url(QUrl::fromPercentEncoding(string.toLatin1()));
+    QList<QByteArray> path = url.encodedPath().split('/');
+    // qDebug() << path;
+    int start = path.indexOf("user");
+    if (start < 0) {
+        kWarning() << "Couldn't find \"user\" in path: " << path;
+        return RelationMember();
+    }
+    path = path.mid(start + 1);
+    if (path.size() < 2) {
+        kWarning() << "Incomplete path: " << path;
+        return RelationMember();
+    }
+    // user-name
+    path.removeFirst();
+    member.uid = path.takeLast().toLong();
+    member.mailbox = path;
+    member.messageId = url.queryItemValue("message-id");
+    member.subject = url.queryItemValue("subject");
+    member.date = url.queryItemValue("date");
+    // qDebug() << member.uid << member.mailbox;
+    return member;
+}
+
+static QByteArray join(const QList<QByteArray> &list, const QByteArray &c)
+{
+    QByteArray result;
+    Q_FOREACH (const QByteArray &a, list) {
+        result += a + c;
+    }
+    result.chop(c.size());
+    return result;
+}
+
+KOLAB_EXPORT QString generateMemberUrl(const RelationMember &member)
+{
+    QUrl url;
+    url.setScheme("imap");
+    QList<QByteArray> path;
+    path << "user";
+    path << "localuser at localhost";
+    path << member.mailbox;
+    path << QByteArray::number(member.uid);
+    url.setPath("/" + join(path, "/"));
+
+    QList<QPair<QString, QString> > queryItems;
+    queryItems.append(qMakePair(QString::fromLatin1("message-id"), member.messageId));
+    queryItems.append(qMakePair(QString::fromLatin1("subject"), member.subject));
+    queryItems.append(qMakePair(QString::fromLatin1("date"), member.date));
+    url.setQueryItems(queryItems);
+
+    return QString::fromLatin1(url.toEncoded());
+}
 
 //@cond PRIVATE
 class KolabObjectReader::Private
@@ -87,6 +144,8 @@ public:
     ObjectType mObjectType;
     Version mVersion;
     Kolab::Freebusy mFreebusy;
+    Akonadi::Tag mTag;
+    QStringList mTagMembers;
     ObjectType mOverrideObjectType;
     Version mOverrideVersion;
     bool mDoOverrideVersion;
@@ -138,6 +197,8 @@ Kolab::ObjectType getObjectType(const QString &type)
         return FreebusyObject;
     } else if (type.contains(dictKolabType())) { //Previous versions appended the language to the type
         return DictionaryConfigurationObject;
+    } else if (type == relationKolabType()) {
+        return RelationConfigurationObject;
     }
     Warning() << "Unknown object type: " << type;
     return Kolab::InvalidObject;
@@ -162,6 +223,8 @@ QByteArray getTypeString(Kolab::ObjectType type)
             return KOLAB_TYPE_NOTE;
         case DictionaryConfigurationObject:
             return KOLAB_TYPE_CONFIGURATION;
+        case RelationConfigurationObject:
+            return KOLAB_TYPE_RELATION;
         default:
             Critical() << "unknown type "<< type;
     }
@@ -181,6 +244,7 @@ QByteArray getMimeType(Kolab::ObjectType type)
             return MIME_TYPE_XCARD;
         case NoteObject:
         case DictionaryConfigurationObject:
+        case RelationConfigurationObject:
             return MIME_TYPE_KOLAB;
         default:
             Critical() << "unknown type "<< type;
@@ -326,6 +390,22 @@ ObjectType KolabObjectReader::Private::readKolabV3(const KMime::Message::Ptr &ms
             mFreebusy = fb;
         }
             break;
+        case RelationConfigurationObject: {
+            const Kolab::Configuration &configuration = Kolab::readConfiguration(xml, false);
+            const Kolab::Relation &relation = configuration.relation();
+
+            mTag = Akonadi::Tag();
+            mTag.setName(Conversion::fromStdString(relation.name()));
+            mTag.setGid(Conversion::fromStdString(configuration.uid()).toLatin1());
+            mTag.setType(Akonadi::Tag::PLAIN);
+
+            mTagMembers.reserve(relation.members().size());
+            foreach (const std::string &member, relation.members()) {
+                mTagMembers << Conversion::fromStdString(member);
+            }
+
+        }
+            break;
         default:
             Critical() << "no kolab object found ";
             printMessageDebugInfo(msg);
@@ -452,6 +532,16 @@ Freebusy KolabObjectReader::getFreebusy() const
     return d->mFreebusy;
 }
 
+Akonadi::Tag KolabObjectReader::getTag() const
+{
+    return d->mTag;
+}
+
+QStringList KolabObjectReader::getTagMembers() const
+{
+    return d->mTagMembers;
+}
+
 
 //Normalize incidences before serializing them
 KCalCore::Incidence::Ptr normalizeIncidence(KCalCore::Incidence::Ptr original)
@@ -630,6 +720,28 @@ KMime::Message::Ptr KolabObjectWriter::writeFreebusy(const Freebusy &freebusy, V
     return  Mime::createMessage(Conversion::fromStdString(freebusy.uid()), xCalMimeType(), freebusyKolabType(), Conversion::fromStdString(v3String).toUtf8(), true, getProductId(productId));
 }
 
+KMime::Message::Ptr KolabObjectWriter::writeTag(const Akonadi::Tag &tag, const QStringList &members, Version v, const QString &productId)
+{
+    ErrorHandler::clearErrors();
+    if (v != KolabV3) {
+        Critical() << "only v3 implementation available";
+    }
+
+    Kolab::Relation relation(Conversion::toStdString(tag.name()), "tag");
+    std::vector<std::string> m;
+    m.reserve(members.count());
+    foreach (const QString &member, members) {
+        m.push_back(Conversion::toStdString(member));
+    }
+    relation.setMembers(m);
+
+    Kolab::Configuration configuration(relation); //TODO preserve creation/lastModified date
+    configuration.setUid(tag.gid().constData());
+    const std::string &v3String = Kolab::writeConfiguration(configuration, Conversion::toStdString(getProductId(productId)));
+    ErrorHandler::handleLibkolabxmlErrors();
+    return  Mime::createMessage(Conversion::fromStdString(configuration.uid()), kolabMimeType(), relationKolabType(), Conversion::fromStdString(v3String).toUtf8(), true, getProductId(productId));
+}
+
 
 
 
diff --git a/kolabformat/kolabobject.h b/kolabformat/kolabobject.h
index 1b39ad6..71a0e4b 100644
--- a/kolabformat/kolabobject.h
+++ b/kolabformat/kolabobject.h
@@ -20,6 +20,7 @@
 
 #include <kolab_export.h>
 
+#include <akonadi/tag.h>
 #include <kabc/addressee.h>
 #include <kabc/contactgroup.h>
 #include <kcalcore/incidence.h>
@@ -37,6 +38,17 @@ class Freebusy;
 
 KOLAB_EXPORT KCalCore::Event::Ptr readV2EventXML(const QByteArray &xmlData, QStringList &attachments);
 
+struct KOLAB_EXPORT RelationMember {
+    QString messageId;
+    QString subject;
+    QString date;
+    QList<QByteArray> mailbox;
+    QString user;
+    qint64 uid;
+};
+KOLAB_EXPORT RelationMember parseMemberUrl(const QString &url);
+KOLAB_EXPORT QString generateMemberUrl(const RelationMember &url);
+
 /**
  * Class to read Kolab Mime files
  * 
@@ -87,6 +99,8 @@ public:
     KMime::Message::Ptr getNote() const;
     QStringList getDictionary(QString &lang) const;
     Freebusy getFreebusy() const;
+    Akonadi::Tag getTag() const;
+    QStringList getTagMembers() const;
 
 private:
     //@cond PRIVATE
@@ -111,6 +125,7 @@ public:
     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());
+    static KMime::Message::Ptr writeTag(const Akonadi::Tag &, const QStringList &items, Version v = KolabV3, const QString &productId = QString());
     
 };
 
diff --git a/tests/kolabobjecttest.cpp b/tests/kolabobjecttest.cpp
index a90b39d..f57ce1d 100644
--- a/tests/kolabobjecttest.cpp
+++ b/tests/kolabobjecttest.cpp
@@ -80,6 +80,34 @@ void KolabObjectTest::dontCrashWithEmptyIncidence()
     QCOMPARE(Kolab::ErrorHandler::instance().error(), Kolab::ErrorHandler::Critical);
 }
 
+void KolabObjectTest::parseRelationMembers()
+{
+    {
+        // QString memberString("imap:///user/jan.aachen%40lhm.klab.cc/INBOX/20?message-id=%3Cf06aa3345a25005380b47547ad161d36%40lhm.klab.cc%3E&date=Tue%2C+12+Aug+2014+20%3A42%3A59+%2B0200&subject=Re%3A+test");
+        QString memberString("imap:///user/jan.aachen%40lhm.klab.cc/INBOX/20?message-id=%3Cf06aa3345a25005380b47547ad161d36%40lhm.klab.cc%3E&date=Tue%2C+12+Aug+2014+20%3A42%3A59+%2B0200&subject=Re%3A+test");
+        Kolab::RelationMember member = Kolab::parseMemberUrl(memberString);
+
+
+        const QString result = Kolab::generateMemberUrl(member);
+        qDebug() << result;
+    }
+
+    {
+
+        Kolab::RelationMember member;
+        member.uid = 20;
+        member.mailbox = QList<QByteArray>() << "INBOX";
+        member.user = "john.doe at example.org";
+        member.messageId = "messageid";
+        member.date = "date";
+        member.subject = "subject";
+        QString url = Kolab::generateMemberUrl(member);
+        qDebug() << url;
+        Kolab::RelationMember result = Kolab::parseMemberUrl(url);
+        QCOMPARE(result.uid, member.uid);
+        QCOMPARE(result.mailbox, member.mailbox);
+    }
+}
 
 
 
diff --git a/tests/kolabobjecttest.h b/tests/kolabobjecttest.h
index 9e0b760..7cf3298 100644
--- a/tests/kolabobjecttest.h
+++ b/tests/kolabobjecttest.h
@@ -27,6 +27,7 @@ private slots:
     void preserveUnicode();
     void dontCrashWithEmptyOrganizer();
     void dontCrashWithEmptyIncidence();
+    void parseRelationMembers();
 };
 
 #endif // KOLABOBJECTTEST_H




More information about the commits mailing list