=== modified file 'organizer/qorganizer-eds-engine.cpp'
--- organizer/qorganizer-eds-engine.cpp	2015-03-24 16:18:38 +0000
+++ organizer/qorganizer-eds-engine.cpp	2015-03-24 17:49:30 +0000
@@ -61,6 +61,7 @@
 #include <QtOrganizer/QOrganizerEventOccurrence>
 #include <QtOrganizer/QOrganizerTodoOccurrence>
 #include <QtOrganizer/QOrganizerItemParent>
+#include <QtOrganizer/QOrganizerItemExtendedDetail>
 
 #include <glib.h>
 #include <libecal/libecal.h>
@@ -1625,6 +1626,20 @@
     e_cal_component_free_attendee_list(attendeeList);
 }
 
+void QOrganizerEDSEngine::parseExtendedDetails(ECalComponent *comp, QOrganizerItem *item)
+{
+    icalcomponent *icalcomp = e_cal_component_get_icalcomponent(comp);
+    for (icalproperty *prop = icalcomponent_get_first_property(icalcomp, ICAL_X_PROPERTY);
+         prop != NULL;
+         prop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY)) {
+
+        QOrganizerItemExtendedDetail ex;
+        ex.setName(QString::fromUtf8(icalproperty_get_x_name(prop)));
+        ex.setData(QByteArray(icalproperty_get_x(prop)));
+        item->saveDetail(&ex);
+    }
+}
+
 QOrganizerItem *QOrganizerEDSEngine::parseEvent(ECalComponent *comp)
 {
     QOrganizerItem *event;
@@ -1847,6 +1862,7 @@
         parseTags(comp, item);
         parseReminders(comp, item);
         parseAttendeeList(comp, item);
+        parseExtendedDetails(comp, item);
 
         items << *item;
         delete item;
@@ -2166,6 +2182,25 @@
     e_cal_component_free_attendee_list(attendeeList);
 }
 
+void QOrganizerEDSEngine::parseExtendedDetails(const QOrganizerItem &item, ECalComponent *comp)
+{
+    icalcomponent *icalcomp = e_cal_component_get_icalcomponent(comp);
+    Q_FOREACH(const QOrganizerItemExtendedDetail &ex, item.details(QOrganizerItemDetail::TypeExtendedDetail)) {
+        // We only support QByteArray.
+        // We could use QStream serialization but it will make it impossible to read it from glib side, for example indicators.
+        QByteArray data = ex.data().toByteArray();
+        if (data.isEmpty()) {
+            qWarning() << "Invalid value for property" << ex.name()
+                       <<". EDS only supports QByteArray values for extended properties";
+            continue;
+        }
+
+        icalproperty *xProp = icalproperty_new_x(data.constData());
+        icalproperty_set_x_name(xProp, ex.name().toUtf8().constData());
+        icalcomponent_add_property(icalcomp, xProp);
+    }
+}
+
 bool QOrganizerEDSEngine::hasRecurrence(ECalComponent *comp)
 {
     char *rid = e_cal_component_get_recurid_as_string(comp);
@@ -2439,6 +2474,7 @@
         parseTags(item, comp);
         parseReminders(item, comp);
         parseAttendeeList(item, comp);
+        parseExtendedDetails(item, comp);
 
         if (!item.id().isNull()) {
             e_cal_component_commit_sequence(comp);

=== modified file 'organizer/qorganizer-eds-engine.h'
--- organizer/qorganizer-eds-engine.h	2015-03-24 16:06:33 +0000
+++ organizer/qorganizer-eds-engine.h	2015-03-24 17:49:30 +0000
@@ -168,6 +168,7 @@
     static void parseProgress(const QtOrganizer::QOrganizerItem &item, ECalComponent *comp);
     static void parseStatus(const QtOrganizer::QOrganizerItem &item, ECalComponent *comp);
     static void parseAttendeeList(const QtOrganizer::QOrganizerItem &item, ECalComponent *comp);
+    static void parseExtendedDetails(const QtOrganizer::QOrganizerItem &item, ECalComponent *comp);
 
     // ECalComponent -> QOrganizerItem
     static bool hasRecurrence(ECalComponent *comp);
@@ -193,6 +194,7 @@
     static void parseProgress(ECalComponent *comp, QtOrganizer::QOrganizerItem *item);
     static void parseStatus(ECalComponent *comp, QtOrganizer::QOrganizerItem *item);
     static void parseAttendeeList(ECalComponent *comp, QtOrganizer::QOrganizerItem *item);
+    static void parseExtendedDetails(ECalComponent *comp, QtOrganizer::QOrganizerItem *item);
 
     static QDateTime fromIcalTime(struct icaltimetype value, const char *tzId);
     static icaltimetype fromQDateTime(const QDateTime &dateTime, bool allDay, QByteArray *tzId);

=== modified file 'tests/unittest/event-test.cpp'
--- tests/unittest/event-test.cpp	2014-10-29 14:19:47 +0000
+++ tests/unittest/event-test.cpp	2015-03-24 17:49:30 +0000
@@ -806,7 +806,6 @@
         QList<QOrganizerItemId> ids;
         QOrganizerItemFetchHint hint;
         ids << items[0].id();
-        qDebug() << "Find for id" << ids;
         QList<QOrganizerItem> newItems = m_engine->items(ids, hint, &errorMap, &error);
         QCOMPARE(newItems.size(), 1);
 
@@ -819,6 +818,65 @@
         QCOMPARE(newAttendee.participationRole(), attendee.participationRole());
         QCOMPARE(newAttendee.participationStatus(), attendee.participationStatus());
     }
+
+    void testExtendedProperties()
+    {
+        static QString displayLabelValue = QStringLiteral("event with collection attendee");
+        static QString descriptionValue = QStringLiteral("event without collection");
+        QOrganizerItemId itemId;
+        QDateTime currentTime = QDateTime::currentDateTime();
+
+        {
+            // create a item with X-URL
+            QOrganizerEvent event;
+            event.setStartDateTime(currentTime);
+            event.setEndDateTime(currentTime.addSecs(60 * 30));
+            event.setDisplayLabel(displayLabelValue);
+            event.setDescription(descriptionValue);
+
+            QOrganizerItemExtendedDetail ex;
+            ex.setName(QStringLiteral("X-URL"));
+            ex.setData(QByteArray("http://canonical.com"));
+            event.saveDetail(&ex);
+
+            // save the new item
+            QtOrganizer::QOrganizerManager::Error error;
+            QMap<int, QtOrganizer::QOrganizerManager::Error> errorMap;
+            QList<QOrganizerItem> items;
+            QSignalSpy createdItem(m_engine, SIGNAL(itemsAdded(QList<QOrganizerItemId>)));
+            items << event;
+            bool saveResult = m_engine->saveItems(&items,
+                                                  QList<QtOrganizer::QOrganizerItemDetail::DetailType>(),
+                                                  &errorMap,
+                                                  &error);
+            QTRY_COMPARE(createdItem.count(), 1);
+            QVERIFY(saveResult);
+            QCOMPARE(error, QOrganizerManager::NoError);
+            QCOMPARE(items.size(), 1);
+            QVERIFY(errorMap.isEmpty());
+            QVERIFY(!items[0].id().isNull());
+            QCOMPARE(items[0].details(QOrganizerItemDetail::TypeExtendedDetail).size(), 1);
+            itemId = items[0].id();
+        }
+
+        // fetch for the item
+        {
+            QtOrganizer::QOrganizerManager::Error error;
+            QMap<int, QtOrganizer::QOrganizerManager::Error> errorMap;
+            QList<QOrganizerItemId> ids;
+            QOrganizerItemFetchHint hint;
+            ids << itemId;
+            QList<QOrganizerItem> items = m_engine->items(ids, hint, &errorMap, &error);
+            QCOMPARE(items.size(), 1);
+
+            QList<QOrganizerItemDetail> exs = items[0].details(QOrganizerItemDetail::TypeExtendedDetail);
+            QCOMPARE(exs.size(), 1);
+            QCOMPARE(exs[0].value(QOrganizerItemExtendedDetail::FieldName).toString(),
+                    QStringLiteral("X-URL"));
+            QCOMPARE(exs[0].value(QOrganizerItemExtendedDetail::FieldData).toByteArray(),
+                    QByteArray("http://canonical.com"));
+        }
+    }
 };
 
 const QString EventTest::collectionTypePropertyName = QStringLiteral("collection-type");

=== modified file 'tests/unittest/run-eds-test.sh'
--- tests/unittest/run-eds-test.sh	2014-10-28 20:54:11 +0000
+++ tests/unittest/run-eds-test.sh	2015-03-24 17:49:30 +0000
@@ -12,7 +12,7 @@
 export QT_QPA_PLATFORM=minimal
 export HOME=$TEST_TMP_DIR
 export XDG_RUNTIME_DIR=$TEST_TMP_DIR
-export XDG_CACHE_HOME=$TEST_TMP_DIR}/.cache
+export XDG_CACHE_HOME=$TEST_TMP_DIR/.cache
 export XDG_CONFIG_HOME=$TEST_TMP_DIR/.config
 export XDG_DATA_HOME=$TEST_TMP_DIR/.local/share
 export XDG_DESKTOP_DIR=$TEST_TMP_DIR

