From 1b621191deaf47abf05af1d6b7db1f34e3b81a66 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Mon, 3 Jul 2017 14:04:49 +0200 Subject: Going towards 0.4 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6690c4c..36bd0e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.0) cmake_policy(SET CMP0048 NEW) cmake_policy(SET CMP0028 NEW) -project(sink VERSION 0.3.0) +project(sink VERSION 0.4) option(BUILD_MAILDIR "BUILD_MAILDIR" ON) option(BUILD_DAV "BUILD_DAV" ON) -- cgit v1.2.3 From 938c519b026835daca93aee96a1766b4f68de62c Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Wed, 5 Jul 2017 22:40:11 +0200 Subject: Notification printing --- common/notification.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/notification.cpp b/common/notification.cpp index da31e20..20bc654 100644 --- a/common/notification.cpp +++ b/common/notification.cpp @@ -48,7 +48,7 @@ static QByteArray name(int type) QDebug operator<<(QDebug dbg, const Sink::Notification &n) { - dbg << "Notification(Type:" << name(n.type) << "Id, :" << n.id << ", Code:"; + dbg << "Notification(Type:" << name(n.type) << ", Id:" << n.id << ", Code:"; dbg << n.code; dbg << ", Message:" << n.message << ", Entities:" << n.entities << ")"; return dbg.space(); -- cgit v1.2.3 From 9d9f2f031cb96323fc089a516729c7979076187f Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Wed, 5 Jul 2017 22:40:47 +0200 Subject: We have no guarantee when the notification arrives --- tests/notificationtest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/notificationtest.cpp b/tests/notificationtest.cpp index f0d957e..3182d8e 100644 --- a/tests/notificationtest.cpp +++ b/tests/notificationtest.cpp @@ -128,7 +128,7 @@ private slots: VERIFYEXEC(Sink::Store::synchronize(newQuery)); VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "sink.dummy.instance1")); - QCOMPARE(status.size(), 3); + QTRY_COMPARE(status.size(), 3); //Sync progress of item QCOMPARE(status.at(0), static_cast(ApplicationDomain::SyncStatus::SyncInProgress)); QCOMPARE(status.at(1), static_cast(ApplicationDomain::SyncStatus::SyncSuccess)); -- cgit v1.2.3 From 691a11e8865c43a3cadf8e64df0612a81b08bf15 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Wed, 5 Jul 2017 23:12:47 +0200 Subject: New version in kube.spec --- dist/sink.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/sink.spec b/dist/sink.spec index f5132b7..5ce5484 100644 --- a/dist/sink.spec +++ b/dist/sink.spec @@ -1,7 +1,7 @@ Name: sink -Version: 0.3 -Release: 10%{?dist} +Version: 0.4 +Release: 0%{?dist} Summary: sink Group: Applications/Desktop -- cgit v1.2.3 From 09fba6f07c87aec84c80ce65136f0b7333b0b0bd Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Wed, 5 Jul 2017 23:40:34 +0200 Subject: Keep notifier alive for notifications of new resources. Necessary to get notifications for newly created resources. --- common/notifier.cpp | 4 ++++ tests/notificationtest.cpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/common/notifier.cpp b/common/notifier.cpp index 1af65e9..1b7cbdb 100644 --- a/common/notifier.cpp +++ b/common/notifier.cpp @@ -49,6 +49,7 @@ public: QList> resourceAccess; QList> handler; + QSharedPointer > > mResourceEmitter; QObject context; }; @@ -91,6 +92,9 @@ Notifier::Notifier(const Sink::Query &resourceQuery) : d(new Sink::Notifier::Pri SinkTraceCtx(resourceCtx) << "Resource query complete"; }); emitter->fetch({}); + if (resourceQuery.liveQuery()) { + d->mResourceEmitter = emitter; + } result.first.exec(); } diff --git a/tests/notificationtest.cpp b/tests/notificationtest.cpp index 3182d8e..2b54c26 100644 --- a/tests/notificationtest.cpp +++ b/tests/notificationtest.cpp @@ -135,6 +135,34 @@ private slots: //Modification triggered during sync QCOMPARE(status.at(2), static_cast(ApplicationDomain::SyncStatus::SyncSuccess)); } + + void testNotifier() + { + QList status; + Sink::Notifier notifier{Sink::Query{Sink::Query::LiveQuery}.resourceFilter("sink.dummy.instance2")}; + notifier.registerHandler([&] (const Sink::Notification ¬ification) { + if (notification.type == Notification::Info) { + status << notification.code; + } + }); + + auto query = Query().resourceFilter("sink.dummy.instance2"); + query.setType(); + query.setFlags(Query::LiveQuery | Query::UpdateStatus); + + auto resource = ApplicationDomain::ApplicationDomainType::createEntity("", "sink.dummy.instance2"); + resource.setResourceType("sink.dummy"); + VERIFYEXEC(Store::create(resource)); + + VERIFYEXEC(Sink::Store::synchronize(query)); + VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "sink.dummy.instance2")); + + QTRY_COMPARE(status.size(), 2); + //Sync progress of item + QCOMPARE(status.at(0), static_cast(ApplicationDomain::SyncStatus::SyncInProgress)); + QCOMPARE(status.at(1), static_cast(ApplicationDomain::SyncStatus::SyncSuccess)); + } + }; QTEST_MAIN(NotificationTest) -- cgit v1.2.3 From 0d5e1e431131558a04bf42c4850c8721414294d3 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 6 Jul 2017 03:57:20 +0200 Subject: Fixed test --- tests/notificationtest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/notificationtest.cpp b/tests/notificationtest.cpp index 2b54c26..c043f38 100644 --- a/tests/notificationtest.cpp +++ b/tests/notificationtest.cpp @@ -131,7 +131,7 @@ private slots: QTRY_COMPARE(status.size(), 3); //Sync progress of item QCOMPARE(status.at(0), static_cast(ApplicationDomain::SyncStatus::SyncInProgress)); - QCOMPARE(status.at(1), static_cast(ApplicationDomain::SyncStatus::SyncSuccess)); + QCOMPARE(status.at(1), static_cast(ApplicationDomain::SyncStatus::SyncInProgress)); //Modification triggered during sync QCOMPARE(status.at(2), static_cast(ApplicationDomain::SyncStatus::SyncSuccess)); } -- cgit v1.2.3 From a894efcaced8b1e2e330c13d4e8f2d07d3ae814b Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 6 Jul 2017 21:22:04 +0200 Subject: Avoid regenerating the messageId on every modfication --- common/mailpreprocessor.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/common/mailpreprocessor.cpp b/common/mailpreprocessor.cpp index 5c54fbc..253e8b4 100644 --- a/common/mailpreprocessor.cpp +++ b/common/mailpreprocessor.cpp @@ -104,9 +104,6 @@ static void updatedIndexedProperties(Sink::ApplicationDomain::Mail &mail, KMime: mail.setExtractedBcc(getContactList(msg->bcc(true))); mail.setExtractedDate(msg->date(true)->dateTime()); - //The rest should never change, unless we didn't have the headers available initially. - auto messageId = msg->messageID(true)->identifier(); - //Ensure the mssageId is unique. //If there already is one with the same id we'd have to assign a new message id, which probably doesn't make any sense. @@ -125,12 +122,21 @@ static void updatedIndexedProperties(Sink::ApplicationDomain::Mail &mail, KMime: parentMessageId = inReplyTo.first(); } } + + //The rest should never change, unless we didn't have the headers available initially. + auto messageId = msg->messageID(true)->identifier(); if (messageId.isEmpty()) { - auto tmp = KMime::Message::Ptr::create(); - auto header = tmp->messageID(true); - header->generate("kube.kde.org"); - messageId = header->as7BitString(); - SinkWarning() << "Message id is empty, generating one: " << messageId; + //reuse an existing messageis (on modification) + auto existing = mail.getMessageId(); + if (existing.isEmpty()) { + auto tmp = KMime::Message::Ptr::create(); + auto header = tmp->messageID(true); + header->generate("kube.kde.org"); + messageId = header->as7BitString(); + SinkWarning() << "Message id is empty, generating one: " << messageId; + } else { + messageId = existing; + } } mail.setExtractedMessageId(messageId); -- cgit v1.2.3 From 86c75f9d7747353045aae9b141da3f8fb08583f9 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sun, 16 Jul 2017 00:26:44 +0200 Subject: Filter resources for syncing by type. Otherwise we end up sending sync requests for contacts to imap resources. --- common/store.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/common/store.cpp b/common/store.cpp index 4735113..29e826a 100644 --- a/common/store.cpp +++ b/common/store.cpp @@ -311,9 +311,14 @@ KAsync::Job Store::synchronize(const Sink::Query &query) KAsync::Job Store::synchronize(const Sink::SyncScope &scope) { + auto resourceFilter = scope.getResourceFilter(); + //Filter resources by type by default + if (!resourceFilter.propertyFilter.contains(ApplicationDomain::SinkResource::Capabilities::name) && !scope.type().isEmpty()) { + resourceFilter.propertyFilter.insert(ApplicationDomain::SinkResource::Capabilities::name, Query::Comparator{scope.type(), Query::Comparator::Contains}); + } Sink::Query query; - query.setFilter(scope.getResourceFilter()); - SinkLog() << "Synchronizing: " << query; + query.setFilter(resourceFilter); + SinkLog() << "Synchronizing all resource matching: " << query; return fetchAll(query) .template each([scope](const ApplicationDomain::SinkResource::Ptr &resource) -> KAsync::Job { return synchronize(resource->identifier(), scope); -- cgit v1.2.3 From 27c731783a1b736cadf1f51062e6006ecd6eb8a0 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sun, 16 Jul 2017 02:48:57 +0200 Subject: Bumped release --- dist/sink.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/sink.spec b/dist/sink.spec index 5ce5484..397e6fc 100644 --- a/dist/sink.spec +++ b/dist/sink.spec @@ -1,7 +1,7 @@ Name: sink Version: 0.4 -Release: 0%{?dist} +Release: 1%{?dist} Summary: sink Group: Applications/Desktop -- cgit v1.2.3 From 9448988676c524e4080e18e861dbd7e1def84e44 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sun, 16 Jul 2017 19:18:59 +0200 Subject: No return value needed here. --- common/storage/entitystore.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/common/storage/entitystore.cpp b/common/storage/entitystore.cpp index 22e5ae3..1ac87b7 100644 --- a/common/storage/entitystore.cpp +++ b/common/storage/entitystore.cpp @@ -516,9 +516,8 @@ void EntityStore::readLatest(const QByteArray &type, const QByteArray &uid, cons { auto db = DataStore::mainDatabase(d->getTransaction(), type); db.findLatest(uid, - [=](const QByteArray &key, const QByteArray &value) -> bool { + [=](const QByteArray &key, const QByteArray &value) { callback(DataStore::uidFromKey(key), Sink::EntityBuffer(value.data(), value.size())); - return false; }, [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Error during query: " << error.message << uid; }); } @@ -653,7 +652,7 @@ bool EntityStore::exists(const QByteArray &type, const QByteArray &uid) bool alreadyRemoved = false; DataStore::mainDatabase(d->transaction, type) .findLatest(uid, - [&found, &alreadyRemoved](const QByteArray &key, const QByteArray &data) -> bool { + [&found, &alreadyRemoved](const QByteArray &key, const QByteArray &data) { auto entity = GetEntity(data.data()); if (entity && entity->metadata()) { auto metadata = GetMetadata(entity->metadata()->Data()); @@ -662,7 +661,6 @@ bool EntityStore::exists(const QByteArray &type, const QByteArray &uid) alreadyRemoved = true; } } - return false; }, [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Failed to read old revision from storage: " << error.message; }); if (!found) { -- cgit v1.2.3 From 8fe4eace598997c3ff4c74aa04f723e8ea444239 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sun, 16 Jul 2017 19:52:23 +0200 Subject: Better error messages --- common/storage_lmdb.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/common/storage_lmdb.cpp b/common/storage_lmdb.cpp index f7999d1..9fb2feb 100644 --- a/common/storage_lmdb.cpp +++ b/common/storage_lmdb.cpp @@ -406,7 +406,7 @@ int DataStore::NamedDatabase::scan(const QByteArray &k, const std::functionname.toLatin1() + d->db, getErrorCode(rc), QByteArray("Key: ") + k + " : " + QByteArray(mdb_strerror(rc))); + Error error(d->name.toLatin1() + d->db, getErrorCode(rc), QByteArray("Error during scan. Key: ") + k + " : " + QByteArray(mdb_strerror(rc))); errorHandler ? errorHandler(error) : d->defaultErrorHandler(error); } @@ -420,6 +420,11 @@ void DataStore::NamedDatabase::findLatest(const QByteArray &k, const std::functi // Not an error. We rely on this to read nothing from non-existing databases. return; } + if (k.isEmpty()) { + Error error(d->name.toLatin1() + d->db, GenericError, QByteArray("Can't use findLatest with empty key.")); + errorHandler ? errorHandler(error) : d->defaultErrorHandler(error); + return; + } int rc; MDB_val key; @@ -471,10 +476,10 @@ void DataStore::NamedDatabase::findLatest(const QByteArray &k, const std::functi mdb_cursor_close(cursor); if (rc) { - Error error(d->name.toLatin1(), getErrorCode(rc), QByteArray("Key: ") + k + " : " + QByteArray(mdb_strerror(rc))); + Error error(d->name.toLatin1(), getErrorCode(rc), QByteArray("Error during find latest. Key: ") + k + " : " + QByteArray(mdb_strerror(rc))); errorHandler ? errorHandler(error) : d->defaultErrorHandler(error); } else if (!foundValue) { - Error error(d->name.toLatin1(), 1, QByteArray("Key: ") + k + " : No value found"); + Error error(d->name.toLatin1(), 1, QByteArray("Error during find latest. Key: ") + k + " : No value found"); errorHandler ? errorHandler(error) : d->defaultErrorHandler(error); } -- cgit v1.2.3 From 942f5b11f2d91c030a4c87d13f8075538c21abc1 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sun, 16 Jul 2017 19:53:05 +0200 Subject: Simplified code The while loop is executed at least once, so advanced is always true. --- common/storage_lmdb.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/common/storage_lmdb.cpp b/common/storage_lmdb.cpp index 9fb2feb..58e3a9a 100644 --- a/common/storage_lmdb.cpp +++ b/common/storage_lmdb.cpp @@ -446,25 +446,23 @@ void DataStore::NamedDatabase::findLatest(const QByteArray &k, const std::functi if ((rc = mdb_cursor_get(cursor, &key, &data, op)) == 0) { // The first lookup will find a key that is equal or greather than our key if (QByteArray::fromRawData((char *)key.mv_data, key.mv_size).startsWith(k)) { - bool advanced = false; + //Read next value until we no longer match while (QByteArray::fromRawData((char *)key.mv_data, key.mv_size).startsWith(k)) { - advanced = true; MDB_cursor_op nextOp = MDB_NEXT; rc = mdb_cursor_get(cursor, &key, &data, nextOp); if (rc) { break; } } - if (advanced) { - MDB_cursor_op prefOp = MDB_PREV; - // We read past the end above, just take the last value - if (rc == MDB_NOTFOUND) { - prefOp = MDB_LAST; - } - rc = mdb_cursor_get(cursor, &key, &data, prefOp); - foundValue = true; - resultHandler(QByteArray::fromRawData((char *)key.mv_data, key.mv_size), QByteArray::fromRawData((char *)data.mv_data, data.mv_size)); + //Now read the previous value, and that's the latest one + MDB_cursor_op prefOp = MDB_PREV; + // We read past the end above, just take the last value + if (rc == MDB_NOTFOUND) { + prefOp = MDB_LAST; } + rc = mdb_cursor_get(cursor, &key, &data, prefOp); + foundValue = true; + resultHandler(QByteArray::fromRawData((char *)key.mv_data, key.mv_size), QByteArray::fromRawData((char *)data.mv_data, data.mv_size)); } } -- cgit v1.2.3 From 431f9a20c849fb438ca743d6989ad768d568e91d Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sun, 16 Jul 2017 19:53:43 +0200 Subject: Sanity check queries --- common/store.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/common/store.cpp b/common/store.cpp index 29e826a..392f9ce 100644 --- a/common/store.cpp +++ b/common/store.cpp @@ -40,6 +40,25 @@ Q_DECLARE_METATYPE(QSharedPointer); Q_DECLARE_METATYPE(std::shared_ptr); + +static bool sanityCheckQuery(const Sink::Query &query) +{ + for (const auto &id : query.ids()) { + if (id.isEmpty()) { + SinkError() << "Empty id in query."; + return false; + } + } + for (const auto &id : query.getResourceFilter().ids) { + if (id.isEmpty()) { + SinkError() << "Empty resourceid in query."; + return false; + } + } + return true; +} + + namespace Sink { QString Store::storageLocation() @@ -138,6 +157,7 @@ static Log::Context getQueryContext(const Sink::Query &query, const QByteArray & template QSharedPointer Store::loadModel(const Query &query) { + Q_ASSERT(sanityCheckQuery(query)); auto ctx = getQueryContext(query, ApplicationDomain::getTypeName()); auto model = QSharedPointer>::create(query, query.requestedProperties, ctx); @@ -342,6 +362,7 @@ KAsync::Job> Store::fetchAll(const Sink::Query & template KAsync::Job> Store::fetch(const Sink::Query &query, int minimumAmount) { + Q_ASSERT(sanityCheckQuery(query)); auto model = loadModel(query); auto list = QSharedPointer>::create(); auto context = QSharedPointer::create(); @@ -393,6 +414,7 @@ DomainType Store::readOne(const Sink::Query &query) template QList Store::read(const Sink::Query &query_) { + Q_ASSERT(sanityCheckQuery(query_)); auto query = query_; query.setFlags(Query::SynchronousQuery); -- cgit v1.2.3 From 71d0162843556c365444ae7b5da761d0795f349e Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Mon, 24 Jul 2017 04:58:29 +0200 Subject: Progress reporting for the DAV resource, and commit after 5 items. Otherwise seemingly nothing will happen in the UI, and then suddenly all items will appear. --- examples/davresource/davresource.cpp | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/examples/davresource/davresource.cpp b/examples/davresource/davresource.cpp index 465220f..4e94046 100644 --- a/examples/davresource/davresource.cpp +++ b/examples/davresource/davresource.cpp @@ -93,7 +93,7 @@ public: QVector ridList; for(const auto &f : addressbookList) { const auto &rid = getRid(f); - SinkTrace() << "Found addressbook:" << rid; + SinkLog() << "Found addressbook:" << rid << f.displayName(); ridList.append(rid); createAddressbook(f.displayName(), rid, ""); } @@ -138,19 +138,21 @@ public: if (error) { SinkWarningCtx(mLogCtx) << "Failed to synchronize addressbooks." << collectionsFetchJob->errorString(); } else { - synchronizeAddressbooks(collectionsFetchJob ->collections()); + synchronizeAddressbooks(collectionsFetchJob->collections()); } }); return job; } else if (query.type() == ApplicationDomain::getTypeName()) { SinkLogCtx(mLogCtx) << "Synchronizing contacts."; auto ridList = QSharedPointer::create(); + auto total = QSharedPointer::create(0); + auto progress = QSharedPointer::create(0); auto collectionsFetchJob = new KDAV2::DavCollectionsFetchJob(mResourceUrl); auto job = runJob(collectionsFetchJob).then([this, collectionsFetchJob] { synchronizeAddressbooks(collectionsFetchJob ->collections()); return collectionsFetchJob->collections(); }) - .serialEach([this, ridList](const KDAV2::DavCollection &collection) { + .serialEach([=](const KDAV2::DavCollection &collection) { auto collId = getRid(collection); const auto addressbookLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_ADDRESSBOOK, collId); auto ctag = collection.CTag().toLatin1(); @@ -158,10 +160,11 @@ public: SinkTraceCtx(mLogCtx) << "Syncing " << collId; auto cache = std::shared_ptr(new KDAV2::EtagCache()); auto davItemsListJob = new KDAV2::DavItemsListJob(collection.url(), cache); - const QByteArray bufferType = ENTITY_TYPE_CONTACT; QHash mergeCriteria; - auto colljob = runJob(davItemsListJob).then([davItemsListJob] { - return KAsync::value(davItemsListJob->items()); + auto colljob = runJob(davItemsListJob).then([=] { + const auto items = davItemsListJob->items(); + *total = items.size(); + return KAsync::value(items); }) .serialEach([=] (const KDAV2::DavItem &item) { QByteArray rid = getRid(item); @@ -175,13 +178,19 @@ public: Sink::ApplicationDomain::Contact contact; contact.setVcard(item.data()); contact.setAddressbook(addressbookLocalId); - createOrModify(bufferType, rid, contact, mergeCriteria); + createOrModify(ENTITY_TYPE_CONTACT, rid, contact, mergeCriteria); return item; }) - .then([this, ridList] (const KDAV2::DavItem &item) { + .then([=] (const KDAV2::DavItem &item) { const auto rid = getRid(item); syncStore().writeValue(rid + "_etag", item.etag().toLatin1()); ridList->append(rid); + *progress += 1; + reportProgress(*progress, *total, QByteArrayList{} << addressbookLocalId); + //commit every 5 contacts (so contacts start appearing in the UI) + if ((*progress % 5) == 0) { + commit(); + } return rid; }); return itemjob; @@ -190,7 +199,7 @@ public: return KAsync::value(rid); } }) - .then([this, collId, ctag] () { + .then([=] () { syncStore().writeValue(collId + "_ctag", ctag); }); return colljob; -- cgit v1.2.3 From 5d197dec9dc8f5c8ef4acd72555c32108404c4ae Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 27 Jul 2017 15:44:32 -0600 Subject: Only print modified properties if we have any. --- common/domain/applicationdomaintype.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/common/domain/applicationdomaintype.cpp b/common/domain/applicationdomaintype.cpp index 3718f77..2050fac 100644 --- a/common/domain/applicationdomaintype.cpp +++ b/common/domain/applicationdomaintype.cpp @@ -34,7 +34,13 @@ QDebug Sink::ApplicationDomain::operator<< (QDebug d, const Sink::ApplicationDom QDebug Sink::ApplicationDomain::operator<< (QDebug d, const Sink::ApplicationDomain::ApplicationDomainType &type) { d << "ApplicationDomainType(\n"; - auto properties = type.mAdaptor->availableProperties(); + auto properties = [&] { + if (!type.changedProperties().isEmpty()) { + return type.changedProperties(); + } else { + return type.mAdaptor->availableProperties(); + } + }(); std::sort(properties.begin(), properties.end()); d << " " << "Id: " << "\t" << type.identifier() << "\n"; d << " " << "Resource: " << "\t" << type.resourceInstanceIdentifier() << "\n"; -- cgit v1.2.3 From 63290ccce102495427a26e689725e565a03ae77a Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 27 Jul 2017 15:45:12 -0600 Subject: Skip modifications that do nothing. This allows us to i.e. blindly mark mails as read in kube, with the modification automatically being dropped if it doesn't do anything useful. --- common/domain/applicationdomaintype.cpp | 9 +++++++-- common/store.cpp | 8 ++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/common/domain/applicationdomaintype.cpp b/common/domain/applicationdomaintype.cpp index 2050fac..ee70c35 100644 --- a/common/domain/applicationdomaintype.cpp +++ b/common/domain/applicationdomaintype.cpp @@ -222,8 +222,13 @@ QVariant ApplicationDomainType::getProperty(const QByteArray &key) const void ApplicationDomainType::setProperty(const QByteArray &key, const QVariant &value) { Q_ASSERT(mAdaptor); - mChangeSet->insert(key); - mAdaptor->setProperty(key, value); + auto existing = mAdaptor->getProperty(key); + if (existing.isValid() && existing == value) { + SinkTrace() << "Tried to set property that is still the same: " << key << value; + } else { + mChangeSet->insert(key); + mAdaptor->setProperty(key, value); + } } void ApplicationDomainType::setResource(const QByteArray &identifier) diff --git a/common/store.cpp b/common/store.cpp index 392f9ce..33d7b51 100644 --- a/common/store.cpp +++ b/common/store.cpp @@ -209,6 +209,10 @@ KAsync::Job Store::create(const DomainType &domainObject) template KAsync::Job Store::modify(const DomainType &domainObject) { + if (domainObject.changedProperties().isEmpty()) { + SinkLog() << "Nothing to modify: " << domainObject.identifier(); + return KAsync::null(); + } SinkLog() << "Modify: " << domainObject; // Potentially move to separate thread as well auto facade = getFacade(domainObject.resourceInstanceIdentifier()); @@ -218,6 +222,10 @@ KAsync::Job Store::modify(const DomainType &domainObject) template KAsync::Job Store::modify(const Query &query, const DomainType &domainObject) { + if (domainObject.changedProperties().isEmpty()) { + SinkLog() << "Nothing to modify: " << domainObject.identifier(); + return KAsync::null(); + } SinkLog() << "Modify: " << query << domainObject; return fetchAll(query) .each([=] (const typename DomainType::Ptr &entity) { -- cgit v1.2.3 From 4333b8fe03d50ae9cfd5dfb5c656cc48302dc072 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 27 Jul 2017 15:54:46 -0600 Subject: Empty resource id's are valid when we search for resources. --- common/store.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/common/store.cpp b/common/store.cpp index 33d7b51..b0aac4c 100644 --- a/common/store.cpp +++ b/common/store.cpp @@ -49,12 +49,6 @@ static bool sanityCheckQuery(const Sink::Query &query) return false; } } - for (const auto &id : query.getResourceFilter().ids) { - if (id.isEmpty()) { - SinkError() << "Empty resourceid in query."; - return false; - } - } return true; } -- cgit v1.2.3 From 5275b0f173579162176e2340cbb9eaedafe8334a Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 27 Jul 2017 16:00:50 -0600 Subject: Adjusted docs and test. --- common/domain/applicationdomaintype.h | 10 ++++++++++ common/store.h | 3 +++ tests/clientapitest.cpp | 2 ++ 3 files changed, 15 insertions(+) diff --git a/common/domain/applicationdomaintype.h b/common/domain/applicationdomaintype.h index 602d54c..1250455 100644 --- a/common/domain/applicationdomaintype.h +++ b/common/domain/applicationdomaintype.h @@ -270,7 +270,17 @@ public: bool hasProperty(const QByteArray &key) const; QVariant getProperty(const QByteArray &key) const; + + /** + * Set a property and record a changed property + * + * If the propery is available and did not change the call will be ignored. + */ void setProperty(const QByteArray &key, const QVariant &value); + + /** + * Convenience method to set a reference property. + */ void setProperty(const QByteArray &key, const ApplicationDomainType &value); QByteArray getBlobProperty(const QByteArray &key) const; diff --git a/common/store.h b/common/store.h index 34e14df..3ad547e 100644 --- a/common/store.h +++ b/common/store.h @@ -75,12 +75,15 @@ KAsync::Job SINK_EXPORT create(const DomainType &domainObject); * Modify an entity. * * This includes moving etc. since these are also simple settings on a property. + * Note that the modification will be dropped if there is no changedProperty on the domain object. */ template KAsync::Job SINK_EXPORT modify(const DomainType &domainObject); /** * Modify a set of entities identified by @param query. + * + * Note that the modification will be dropped if there is no changedProperty on the domain object. */ template KAsync::Job SINK_EXPORT modify(const Query &query, const DomainType &domainObject); diff --git a/tests/clientapitest.cpp b/tests/clientapitest.cpp index 3955ebd..7e348c2 100644 --- a/tests/clientapitest.cpp +++ b/tests/clientapitest.cpp @@ -360,6 +360,8 @@ private slots: auto event = Sink::ApplicationDomain::Event::createEntity("dummyresource.instance1"); Sink::Store::create(event).exec().waitForFinished(); QCOMPARE(facade->creations.size(), 1); + //Modify something so the mdofication won't be dropped + event.setSummary("foobar"); Sink::Store::modify(event).exec().waitForFinished(); QCOMPARE(facade->modifications.size(), 1); Sink::Store::remove(event).exec().waitForFinished(); -- cgit v1.2.3 From 9e6952baf64b51fa7ddb6ac91d4ce79ebfd2b2df Mon Sep 17 00:00:00 2001 From: Heiko Becker Date: Sat, 13 May 2017 00:11:45 +0200 Subject: Use imported targets instead of qt5_use_modules From Qt's documentation: "This macro is obsolete. Use target_link_libraries with IMPORTED targets instead." It's only recommended with cmake >=2.8.9 & < 2.8.12. Sink already requires cmake 3.0. One advantage of using the imported targets is, that cmake complains if a target isn't found before it's used, like Qt5Concurrent missing from the find_package_call here. Reviewers: #sink, cmollekopf Reviewed By: #sink, cmollekopf Subscribers: #sink Tags: #sink Differential Revision: https://phabricator.kde.org/D6361 --- CMakeLists.txt | 2 +- common/CMakeLists.txt | 4 ++-- examples/davresource/CMakeLists.txt | 3 +-- examples/dummyresource/CMakeLists.txt | 3 +-- examples/imapresource/CMakeLists.txt | 3 +-- examples/maildirresource/CMakeLists.txt | 3 +-- examples/mailtransportresource/CMakeLists.txt | 18 ++++++++++++++---- synchronizer/CMakeLists.txt | 9 +++++++-- tests/CMakeLists.txt | 10 ++++++++-- tests/SinkTest.cmake | 19 +++++++++++++++---- tests/hawd/CMakeLists.txt | 6 ++---- 11 files changed, 53 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 36bd0e0..1d8aea2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ include(CMakePackageConfigHelpers) include(ECMSetupVersion) include(KDEInstallDirs) -find_package(Qt5 COMPONENTS REQUIRED Core Network Gui) +find_package(Qt5 COMPONENTS REQUIRED Core Concurrent Network Gui Test) find_package(KF5 COMPONENTS REQUIRED Mime Contacts) find_package(FlatBuffers REQUIRED 1.4.0) find_package(KAsync REQUIRED 0.1.2) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 001a412..8421fc2 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -116,13 +116,13 @@ SET_TARGET_PROPERTIES(${PROJECT_NAME} EXPORT_NAME ${PROJECT_NAME} ) -qt5_use_modules(${PROJECT_NAME} LINK_PUBLIC Network) -qt5_use_modules(${PROJECT_NAME} LINK_PRIVATE Gui) target_link_libraries(${PROJECT_NAME} PUBLIC KAsync + Qt5::Network PRIVATE ${storage_LIBS} + Qt5::Gui KF5::Mime KF5::Contacts ) diff --git a/examples/davresource/CMakeLists.txt b/examples/davresource/CMakeLists.txt index 7091edc..2351ecd 100644 --- a/examples/davresource/CMakeLists.txt +++ b/examples/davresource/CMakeLists.txt @@ -6,7 +6,6 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) find_package(KPimKDAV2 REQUIRED) add_library(${PROJECT_NAME} SHARED davresource.cpp) -qt5_use_modules(${PROJECT_NAME} Core Network) -target_link_libraries(${PROJECT_NAME} sink KPim::KDAV2) +target_link_libraries(${PROJECT_NAME} sink Qt5::Core Qt5::Network KPim::KDAV2) install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) diff --git a/examples/dummyresource/CMakeLists.txt b/examples/dummyresource/CMakeLists.txt index 2bbaa47..62e96f1 100644 --- a/examples/dummyresource/CMakeLists.txt +++ b/examples/dummyresource/CMakeLists.txt @@ -6,7 +6,6 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) add_library(${PROJECT_NAME} SHARED resourcefactory.cpp domainadaptor.cpp dummystore.cpp) generate_flatbuffers(${PROJECT_NAME} dummycalendar) -qt5_use_modules(${PROJECT_NAME} Core Network) -target_link_libraries(${PROJECT_NAME} sink) +target_link_libraries(${PROJECT_NAME} sink Qt5::Core Qt5::Network) install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) diff --git a/examples/imapresource/CMakeLists.txt b/examples/imapresource/CMakeLists.txt index 5d2d38b..f5f51f8 100644 --- a/examples/imapresource/CMakeLists.txt +++ b/examples/imapresource/CMakeLists.txt @@ -9,8 +9,7 @@ find_package(KIMAP2 0.2 REQUIRED) include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) add_library(${PROJECT_NAME} SHARED imapresource.cpp imapserverproxy.cpp) -qt5_use_modules(${PROJECT_NAME} Core Network) -target_link_libraries(${PROJECT_NAME} sink KF5::Mime KIMAP2) +target_link_libraries(${PROJECT_NAME} sink Qt5::Core Qt5::Network KF5::Mime KIMAP2) install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) diff --git a/examples/maildirresource/CMakeLists.txt b/examples/maildirresource/CMakeLists.txt index a8f0359..690817e 100644 --- a/examples/maildirresource/CMakeLists.txt +++ b/examples/maildirresource/CMakeLists.txt @@ -6,8 +6,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) find_package(KF5 COMPONENTS REQUIRED Mime) add_library(${PROJECT_NAME} SHARED facade.cpp maildirresource.cpp libmaildir/maildir.cpp libmaildir/keycache.cpp) -qt5_use_modules(${PROJECT_NAME} Core Network) -target_link_libraries(${PROJECT_NAME} sink KF5::Mime) +target_link_libraries(${PROJECT_NAME} sink Qt5::Core Qt5::Network KF5::Mime) install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) diff --git a/examples/mailtransportresource/CMakeLists.txt b/examples/mailtransportresource/CMakeLists.txt index 03b89db..1c34676 100644 --- a/examples/mailtransportresource/CMakeLists.txt +++ b/examples/mailtransportresource/CMakeLists.txt @@ -10,13 +10,23 @@ include_directories(${CURL_INCLUDE_DIRS}) add_library(${PROJECT_NAME} SHARED mailtransportresource.cpp mailtransport.cpp) -qt5_use_modules(${PROJECT_NAME} Core Network) -target_link_libraries(${PROJECT_NAME} sink KF5::Mime ${CURL_LIBRARIES}) +target_link_libraries(${PROJECT_NAME} + sink + Qt5::Core + Qt5::Network + KF5::Mime + ${CURL_LIBRARIES} +) install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) add_executable(sink_smtp_test smtptest.cpp mailtransport.cpp) -qt5_use_modules(sink_smtp_test Core Network) -target_link_libraries(sink_smtp_test sink KF5::Mime ${CURL_LIBRARIES}) +target_link_libraries(sink_smtp_test + sink + Qt5::Core + Qt5::Network + KF5::Mime + ${CURL_LIBRARIES} +) install(TARGETS sink_smtp_test ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) add_subdirectory(tests) diff --git a/synchronizer/CMakeLists.txt b/synchronizer/CMakeLists.txt index e049d64..2f8b128 100644 --- a/synchronizer/CMakeLists.txt +++ b/synchronizer/CMakeLists.txt @@ -7,6 +7,11 @@ set(sinksynchronizer_SRCS ) add_executable(${PROJECT_NAME} ${sinksynchronizer_SRCS}) -target_link_libraries(${PROJECT_NAME} sink KAsync ${CMAKE_DL_LIBS}) -qt5_use_modules(${PROJECT_NAME} Core Network) +target_link_libraries(${PROJECT_NAME} + sink + Qt5::Core + Qt5::Network + KAsync + ${CMAKE_DL_LIBS} +) install(TARGETS ${PROJECT_NAME} ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2b3e7b1..b0333a4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,8 +13,14 @@ add_definitions(-DTESTDATAPATH="${CMAKE_CURRENT_SOURCE_DIR}/data") find_package(KF5 COMPONENTS REQUIRED Mime) add_library(sink_test SHARED testimplementations.cpp getrssusage.cpp mailtest.cpp mailsynctest.cpp mailthreadtest.cpp) -qt5_use_modules(sink_test Core Test Concurrent) -target_link_libraries(sink_test sink libhawd KF5::Mime) +target_link_libraries(sink_test + sink + libhawd + Qt5::Core + Qt5::Concurrent + Qt5::Test + KF5::Mime +) add_executable(dbwriter dbwriter.cpp) target_link_libraries(dbwriter sink) diff --git a/tests/SinkTest.cmake b/tests/SinkTest.cmake index 03076e7..4eb8f43 100644 --- a/tests/SinkTest.cmake +++ b/tests/SinkTest.cmake @@ -17,8 +17,13 @@ macro(auto_tests) add_executable(${_testname} ${_testname}.cpp) add_test(${_testname} ${_testname}) add_memcheck_test(${_testname} ${_testname}) - qt5_use_modules(${_testname} Core Test Concurrent) - target_link_libraries(${_testname} sink libhawd sink_test) + target_link_libraries(${_testname} + sink libhawd + sink_test + Qt5::Core + Qt5::Concurrent + Qt5::Test + ) endforeach(_testname) endmacro(auto_tests) @@ -26,7 +31,13 @@ macro(manual_tests) foreach(_testname ${ARGN}) add_executable(${_testname} ${_testname}.cpp) add_memcheck_test(${_testname} ${_testname}) - qt5_use_modules(${_testname} Core Test Concurrent) - target_link_libraries(${_testname} sink libhawd sink_test) + target_link_libraries(${_testname} + sink + libhawd + sink_test + Qt5::Core + Qt5::Concurrent + Qt5::Test + ) endforeach(_testname) endmacro(manual_tests) diff --git a/tests/hawd/CMakeLists.txt b/tests/hawd/CMakeLists.txt index 6ae5f13..7546920 100644 --- a/tests/hawd/CMakeLists.txt +++ b/tests/hawd/CMakeLists.txt @@ -27,8 +27,7 @@ set(SRCS add_library(lib${PROJECT_NAME} SHARED ${lib_SRCS}) generate_export_header(lib${PROJECT_NAME} BASE_NAME HAWD EXPORT_FILE_NAME hawd_export.h) -qt5_use_modules(lib${PROJECT_NAME} Core) -target_link_libraries(lib${PROJECT_NAME} sink) +target_link_libraries(lib${PROJECT_NAME} sink Qt5::Core) if (LIBGIT2_FOUND) target_link_libraries(lib${PROJECT_NAME} ${LIBGIT2_LIBRARIES}) endif(LIBGIT2_FOUND) @@ -36,8 +35,7 @@ endif(LIBGIT2_FOUND) install(TARGETS lib${PROJECT_NAME} ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) add_executable(${PROJECT_NAME} ${SRCS}) -qt5_use_modules(${PROJECT_NAME} Core) -target_link_libraries(${PROJECT_NAME} lib${PROJECT_NAME}) +target_link_libraries(${PROJECT_NAME} lib${PROJECT_NAME} Qt5::Core) if (LIBGIT2_FOUND) target_link_libraries(${PROJECT_NAME} ${LIBGIT2_LIBRARIES}) endif(LIBGIT2_FOUND) -- cgit v1.2.3 From c206c1966e8e99d50ffbd08f45b01e99e140d498 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 28 Jul 2017 18:41:22 -0600 Subject: Ensure marking as unread works as well --- tests/mailtest.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/mailtest.cpp b/tests/mailtest.cpp index cbb56d5..93d3ce3 100644 --- a/tests/mailtest.cpp +++ b/tests/mailtest.cpp @@ -328,6 +328,15 @@ void MailTest::testMarkMailAsRead() return KAsync::null(); }); VERIFYEXEC(job2); + + //Verify we can mark the mail as unread again + { + auto readMail = Store::readOne(Query{mail}); + readMail.setUnread(true); + VERIFYEXEC(Store::modify(readMail)); + VERIFYEXEC(ResourceControl::flushReplayQueue(mResourceInstanceIdentifier)); + VERIFYEXEC(ResourceControl::inspect(ResourceControl::Inspection::PropertyInspection(readMail, Mail::Unread::name, true))); + } } void MailTest::testCreateDraft() -- cgit v1.2.3 From 685a16155504831c8b5fdb9a4d0a955b21c807bf Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Wed, 2 Aug 2017 12:12:07 -0600 Subject: Info command to print some default information --- sinksh/CMakeLists.txt | 1 + sinksh/syntax_modules/sink_info.cpp | 49 +++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 sinksh/syntax_modules/sink_info.cpp diff --git a/sinksh/CMakeLists.txt b/sinksh/CMakeLists.txt index bc487c1..cd12c16 100644 --- a/sinksh/CMakeLists.txt +++ b/sinksh/CMakeLists.txt @@ -19,6 +19,7 @@ set(sink_cli_SRCS syntax_modules/sink_inspect.cpp syntax_modules/sink_drop.cpp syntax_modules/sink_upgrade.cpp + syntax_modules/sink_info.cpp sinksh_utils.cpp repl/repl.cpp repl/replStates.cpp diff --git a/sinksh/syntax_modules/sink_info.cpp b/sinksh/syntax_modules/sink_info.cpp new file mode 100644 index 0000000..5f535eb --- /dev/null +++ b/sinksh/syntax_modules/sink_info.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2017 Christian Mollekopf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include // tr() + +#include "common/definitions.h" + +#include "sinksh_utils.h" +#include "state.h" +#include "syntaxtree.h" + +namespace SinkInfo +{ + +bool info(const QStringList &args, State &state) +{ + state.printLine(QString("Storage location: %1").arg(Sink::storageLocation())); + state.printLine(QString("Data location: %1").arg(Sink::dataLocation())); + state.printLine(QString("Config location: %1").arg(Sink::configLocation())); + state.printLine(QString("Temporary file location: %1").arg(Sink::temporaryFileLocation())); + state.printLine(QString("Resource storage location: %1").arg(Sink::resourceStorageLocation("$RESOURCE"))); + return false; +} + +Syntax::List syntax() +{ + return Syntax::List() << Syntax{"info", QObject::tr("Shows general system info"), &SinkInfo::info, Syntax::NotInteractive}; +} + +REGISTER_SYNTAX(SinkInfo) + +} -- cgit v1.2.3 From a7c40cd33ba99658ac0c8849622a2b3f3db16de2 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Wed, 2 Aug 2017 13:04:59 -0600 Subject: Print version --- CMakeLists.txt | 5 +++++ sinksh/syntax_modules/sink_info.cpp | 2 ++ 2 files changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d8aea2..f662234 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,11 @@ include(CMakePackageConfigHelpers) include(ECMSetupVersion) include(KDEInstallDirs) +ecm_setup_version(PROJECT + SOVERSION sink_VERSION_MAJOR + VERSION_HEADER sink_version.h + ) + find_package(Qt5 COMPONENTS REQUIRED Core Concurrent Network Gui Test) find_package(KF5 COMPONENTS REQUIRED Mime Contacts) find_package(FlatBuffers REQUIRED 1.4.0) diff --git a/sinksh/syntax_modules/sink_info.cpp b/sinksh/syntax_modules/sink_info.cpp index 5f535eb..aa515e6 100644 --- a/sinksh/syntax_modules/sink_info.cpp +++ b/sinksh/syntax_modules/sink_info.cpp @@ -25,12 +25,14 @@ #include "sinksh_utils.h" #include "state.h" #include "syntaxtree.h" +#include "sink_version.h" namespace SinkInfo { bool info(const QStringList &args, State &state) { + state.printLine(QString("Sink version: %1").arg(sink_VERSION_STRING)); state.printLine(QString("Storage location: %1").arg(Sink::storageLocation())); state.printLine(QString("Data location: %1").arg(Sink::dataLocation())); state.printLine(QString("Config location: %1").arg(Sink::configLocation())); -- cgit v1.2.3 From 1c2f876c83afcb6dbbf830b3fe368eab86838552 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Wed, 9 Aug 2017 15:59:31 -0600 Subject: Avoid warning setFuture can emit signals directly if the future is already stopped. This does not apply to our case but it fixes the warning. "QFutureWatcher::connect: connecting after calling setFuture() is likely to produce race" --- common/asyncutils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/asyncutils.h b/common/asyncutils.h index 67b5928..c80af30 100644 --- a/common/asyncutils.h +++ b/common/asyncutils.h @@ -31,12 +31,12 @@ KAsync::Job run(const std::function &f, bool runAsync = true) return KAsync::start([f](KAsync::Future &future) { auto result = QtConcurrent::run(f); auto watcher = new QFutureWatcher; - watcher->setFuture(result); QObject::connect(watcher, &QFutureWatcher::finished, watcher, [&future, watcher]() { future.setValue(watcher->future().result()); delete watcher; future.setFinished(); }); + watcher->setFuture(result); }); } else { return KAsync::start([f]() { -- cgit v1.2.3 From 2f38db2da3ccd93d21fa8326bfdc6bd8b115ef70 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 11 Aug 2017 20:08:49 -0600 Subject: Replaying a change without remoteid is not going to work. --- examples/imapresource/imapresource.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 81c808b..96055b4 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -619,6 +619,11 @@ public: KAsync::Job replay(const ApplicationDomain::Mail &mail, Sink::Operation operation, const QByteArray &oldRemoteId, const QList &changedProperties) Q_DECL_OVERRIDE { + if (operation != Sink::Operation_Creation) { + if(oldRemoteId.isEmpty()) { + return KAsync::error("Tried to replay modification without old remoteId."); + } + } auto imap = QSharedPointer::create(mServer, mPort, &mSessionCache); auto login = imap->login(mUser, mPassword); KAsync::Job job = KAsync::null(); -- cgit v1.2.3 From c22c91df4a35ce8fefad409f1ae265c74b8ede14 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 11 Aug 2017 20:16:20 -0600 Subject: Cleanup --- common/synchronizer.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/common/synchronizer.cpp b/common/synchronizer.cpp index 3b32e68..d6b1c1f 100644 --- a/common/synchronizer.cpp +++ b/common/synchronizer.cpp @@ -593,17 +593,13 @@ KAsync::Job Synchronizer::replay(const QByteArray &type, const QByteArray KAsync::Job job = KAsync::null(); //TODO This requires supporting every domain type here as well. Can we solve this better so we can do the dispatch somewhere centrally? if (type == ApplicationDomain::getTypeName()) { - auto folder = store().readEntity(key); - job = replay(folder, operation, oldRemoteId, modifiedProperties); + job = replay(store().readEntity(key), operation, oldRemoteId, modifiedProperties); } else if (type == ApplicationDomain::getTypeName()) { - auto mail = store().readEntity(key); - job = replay(mail, operation, oldRemoteId, modifiedProperties); + job = replay(store().readEntity(key), operation, oldRemoteId, modifiedProperties); } else if (type == ApplicationDomain::getTypeName()) { - auto mail = store().readEntity(key); - job = replay(mail, operation, oldRemoteId, modifiedProperties); + job = replay(store().readEntity(key), operation, oldRemoteId, modifiedProperties); } else if (type == ApplicationDomain::getTypeName()) { - auto mail = store().readEntity(key); - job = replay(mail, operation, oldRemoteId, modifiedProperties); + job = replay(store().readEntity(key), operation, oldRemoteId, modifiedProperties); } else { SinkErrorCtx(mLogCtx) << "Replayed unknown type: " << type; } -- cgit v1.2.3 From 1e9879479ea22017266de596db61d06d3950941b Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 11 Aug 2017 20:17:16 -0600 Subject: Silence the compiler warning --- common/domain/applicationdomaintype_p.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/domain/applicationdomaintype_p.h b/common/domain/applicationdomaintype_p.h index a5a6b1d..a60df38 100644 --- a/common/domain/applicationdomaintype_p.h +++ b/common/domain/applicationdomaintype_p.h @@ -45,5 +45,7 @@ struct TypeHelper { } else { Q_ASSERT(false); } + //Silence compiler warning + return Func{}(std::forward(args...)); } }; -- cgit v1.2.3 From b53881c6bd1aaf9841770120258a068a683b8bad Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 11 Aug 2017 20:16:38 -0600 Subject: Some metadata for inspect --- sinksh/syntax_modules/sink_inspect.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sinksh/syntax_modules/sink_inspect.cpp b/sinksh/syntax_modules/sink_inspect.cpp index a8a3805..848d576 100644 --- a/sinksh/syntax_modules/sink_inspect.cpp +++ b/sinksh/syntax_modules/sink_inspect.cpp @@ -19,8 +19,6 @@ #include #include // tr() -#include -#include #include "common/resource.h" #include "common/storage.h" @@ -30,6 +28,7 @@ #include "common/definitions.h" #include "common/entitybuffer.h" #include "common/metadata_generated.h" +#include "common/bufferutils.h" #include "sinksh_utils.h" #include "state.h" @@ -96,7 +95,10 @@ bool inspect(const QStringList &args, State &state) state.printError("Read invalid buffer from disk: " + key); } else { const auto metadata = flatbuffers::GetRoot(buffer.metadataBuffer()); - state.printLine("Key: " + key + " Operation: " + QString::number(metadata->operation())); + state.printLine("Key: " + key + + " Operation: " + QString::number(metadata->operation()) + + " Replay: " + (metadata->replayToSource() ? "true" : "false") + + ((metadata->modifiedProperties() && metadata->modifiedProperties()->size() != 0) ? (" Changeset: " + Sink::BufferUtils::fromVector(*metadata->modifiedProperties()).join(",")) : "")); } } else { state.printLine("Key: " + key + " Value: " + QString::fromUtf8(data)); -- cgit v1.2.3 From cfae1cca83739aef7cf185ee7d8fc63b271fed9f Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sun, 13 Aug 2017 13:44:58 -0600 Subject: Removed unnecessary message --- cmake/modules/FindLibgit2.cmake | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmake/modules/FindLibgit2.cmake b/cmake/modules/FindLibgit2.cmake index fbfb32f..3c0f78a 100644 --- a/cmake/modules/FindLibgit2.cmake +++ b/cmake/modules/FindLibgit2.cmake @@ -26,8 +26,6 @@ FIND_LIBRARY(LIBGIT2_LIBRARIES NAMES git2 ${PC_LIBGIT2_LIBRARY_DIRS} ) -message("foo: ${LIBGIT2_INCLUDE_DIR} : ${PC_LIBGIT2_INCLUDEDIR} : ${PC_LIBGIT2_INCLUDE_DIRS}") - # get version from header, should work on windows, too if(LIBGIT2_INCLUDE_DIR) file(STRINGS "${LIBGIT2_INCLUDE_DIR}/git2/version.h" LIBGIT2_H REGEX "^#define LIBGIT2_VERSION \"[^\"]*\"$") -- cgit v1.2.3 From 823d4170fc884d3707425c13198c2973b049c3b3 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sun, 13 Aug 2017 14:16:00 -0600 Subject: static members can apparently still lead to crashes... --- common/resource.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/resource.cpp b/common/resource.cpp index 32a92ca..804f0bf 100644 --- a/common/resource.cpp +++ b/common/resource.cpp @@ -56,10 +56,10 @@ class ResourceFactory::Private { public: QByteArrayList capabilities; - static QHash> s_loadedFactories; }; -QHash> ResourceFactory::Private::s_loadedFactories; +typedef QHash> FactoryRegistry; +Q_GLOBAL_STATIC(FactoryRegistry, s_loadedFactories); ResourceFactory::ResourceFactory(QObject *parent, const QByteArrayList &capabilities) : QObject(parent), d(new ResourceFactory::Private) { @@ -73,7 +73,7 @@ ResourceFactory::~ResourceFactory() ResourceFactory *ResourceFactory::load(const QByteArray &resourceName) { - ResourceFactory *factory = Private::s_loadedFactories.value(resourceName); + ResourceFactory *factory = s_loadedFactories->value(resourceName); if (factory) { return factory; } @@ -96,7 +96,7 @@ ResourceFactory *ResourceFactory::load(const QByteArray &resourceName) if (object) { factory = qobject_cast(object); if (factory) { - Private::s_loadedFactories.insert(resourceName, factory); + s_loadedFactories->insert(resourceName, factory); //TODO: Instead of always loading both facades and adaptorfactories into the respective singletons, we could also leave this up to the caller. (ResourceFactory::loadFacades(...)) factory->registerFacades(resourceName, FacadeFactory::instance()); factory->registerAdaptorFactories(resourceName, AdaptorFactoryRegistry::instance()); -- cgit v1.2.3 From 1e888175bbc94d0681d71feb4d12ba9354fd8224 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sun, 13 Aug 2017 14:38:04 -0600 Subject: Inspection to validate all rids --- sinksh/syntax_modules/sink_inspect.cpp | 59 +++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/sinksh/syntax_modules/sink_inspect.cpp b/sinksh/syntax_modules/sink_inspect.cpp index 848d576..d1f9791 100644 --- a/sinksh/syntax_modules/sink_inspect.cpp +++ b/sinksh/syntax_modules/sink_inspect.cpp @@ -40,7 +40,7 @@ namespace SinkInspect bool inspect(const QStringList &args, State &state) { if (args.isEmpty()) { - state.printError(QObject::tr("Options: $type [--resource $resource] [--db $db] [--filter $id] [--showinternal]")); + state.printError(QObject::tr("Options: [--resource $resource] ([--db $db] [--filter $id] [--showinternal] | [--validaterids $type])")); } auto options = SyntaxTree::parseOptions(args); auto resource = options.options.value("resource").value(0); @@ -48,6 +48,63 @@ bool inspect(const QStringList &args, State &state) Sink::Storage::DataStore storage(Sink::storageLocation(), resource, Sink::Storage::DataStore::ReadOnly); auto transaction = storage.createTransaction(Sink::Storage::DataStore::ReadOnly); + bool validateRids = options.options.contains("validaterids"); + if (validateRids) { + if (options.options.value("validaterids").isEmpty()) { + state.printError(QObject::tr("Specify a type to validate.")); + return false; + } + auto type = options.options.value("validaterids").first().toUtf8(); + /* + * Try to find all rid's for all uid's. + * If we have entities without rid's that either means we have only created it locally or that we have a problem. + */ + Sink::Storage::DataStore syncStore(Sink::storageLocation(), resource + ".synchronization", Sink::Storage::DataStore::ReadOnly); + auto syncTransaction = syncStore.createTransaction(Sink::Storage::DataStore::ReadOnly); + + auto db = transaction.openDatabase(type + ".main", + [&] (const Sink::Storage::DataStore::Error &e) { + Q_ASSERT(false); + state.printError(e.message); + }, false); + + auto ridMap = syncTransaction.openDatabase("localid.mapping." + type, + [&] (const Sink::Storage::DataStore::Error &e) { + Q_ASSERT(false); + state.printError(e.message); + }, false); + + QHash hash; + + ridMap.scan("", [&] (const QByteArray &key, const QByteArray &data) { + hash.insert(key, data); + return true; + }, + [&](const Sink::Storage::DataStore::Error &e) { + state.printError(e.message); + }, + false); + + db.scan("", [&] (const QByteArray &key, const QByteArray &data) { + if (!hash.remove(Sink::Storage::DataStore::uidFromKey(key))) { + qWarning() << "Failed to find RID for " << key; + } + return true; + }, + [&](const Sink::Storage::DataStore::Error &e) { + state.printError(e.message); + }, + false); + + //If we still have items in the hash it means we have rid mappings for entities + //that no longer exist. + if (!hash.isEmpty()) { + qWarning() << "Have rids left: " << hash.size(); + } + + return false; + } + auto dbs = options.options.value("db"); auto idFilter = options.options.value("filter"); bool showInternal = options.options.contains("showinternal"); -- cgit v1.2.3 From bfc3abb10f8827c5753a8a90a2010f0bfd3a4f10 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sun, 13 Aug 2017 14:38:19 -0600 Subject: More compact changeset --- sinksh/syntax_modules/sink_inspect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sinksh/syntax_modules/sink_inspect.cpp b/sinksh/syntax_modules/sink_inspect.cpp index d1f9791..b271b4f 100644 --- a/sinksh/syntax_modules/sink_inspect.cpp +++ b/sinksh/syntax_modules/sink_inspect.cpp @@ -155,7 +155,7 @@ bool inspect(const QStringList &args, State &state) state.printLine("Key: " + key + " Operation: " + QString::number(metadata->operation()) + " Replay: " + (metadata->replayToSource() ? "true" : "false") - + ((metadata->modifiedProperties() && metadata->modifiedProperties()->size() != 0) ? (" Changeset: " + Sink::BufferUtils::fromVector(*metadata->modifiedProperties()).join(",")) : "")); + + ((metadata->modifiedProperties() && metadata->modifiedProperties()->size() != 0) ? (" [" + Sink::BufferUtils::fromVector(*metadata->modifiedProperties()).join(", ")) + "]": "")); } } else { state.printLine("Key: " + key + " Value: " + QString::fromUtf8(data)); -- cgit v1.2.3 From 1c455b9a0b6d5a7abb0e8e9ab68e338c62811d24 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sun, 13 Aug 2017 14:58:34 -0600 Subject: sinksh show cleanup --- sinksh/syntax_modules/sink_show.cpp | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/sinksh/syntax_modules/sink_show.cpp b/sinksh/syntax_modules/sink_show.cpp index 391505a..7a4166f 100644 --- a/sinksh/syntax_modules/sink_show.cpp +++ b/sinksh/syntax_modules/sink_show.cpp @@ -18,18 +18,12 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include #include #include // tr() #include #include -#include "common/resource.h" #include "common/storage.h" -#include "common/resourceconfig.h" -#include "common/log.h" -#include "common/storage.h" -#include "common/definitions.h" #include "sinksh_utils.h" #include "state.h" @@ -41,25 +35,24 @@ namespace SinkShow bool show(const QStringList &args, State &state) { if (args.isEmpty()) { - state.printError(QObject::tr("Please provide at least one type to show (e.g. resource, ..")); + state.printError(QObject::tr("Options: $type --resource $resource --id $id")); return false; } - auto argList = args; - if (argList.size() < 2 || !SinkshUtils::isValidStoreType(argList.at(0))) { + auto options = SyntaxTree::parseOptions(args); + + auto type = options.positionalArguments.isEmpty() ? QString{} : options.positionalArguments.first(); + auto resource = options.options.value("resource"); + auto id = options.options.value("id"); + + if (id.isEmpty() || resource.isEmpty() || !SinkshUtils::isValidStoreType(type)) { state.printError(QObject::tr("Invalid command syntax. Supply type and resource at least.")); return false; } - auto type = argList.takeFirst(); - auto resource = argList.takeFirst(); - bool queryForResourceOrAgent = argList.isEmpty(); Sink::Query query; - if (queryForResourceOrAgent) { - query.filter(resource.toLatin1()); - } else { - query.resourceFilter(resource.toLatin1()); - } + query.resourceFilter(resource.first().toLatin1()); + query.filter(id.first().toLatin1()); QTime time; time.start(); -- cgit v1.2.3 From b63ae293c4f93d3bea9f1a7d96baf006cc459597 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Mon, 14 Aug 2017 08:30:06 -0600 Subject: Only count every uid once. The previous code would fail on the second revision with the same uid. --- sinksh/syntax_modules/sink_inspect.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/sinksh/syntax_modules/sink_inspect.cpp b/sinksh/syntax_modules/sink_inspect.cpp index b271b4f..9cc3b23 100644 --- a/sinksh/syntax_modules/sink_inspect.cpp +++ b/sinksh/syntax_modules/sink_inspect.cpp @@ -85,10 +85,9 @@ bool inspect(const QStringList &args, State &state) }, false); + QSet uids; db.scan("", [&] (const QByteArray &key, const QByteArray &data) { - if (!hash.remove(Sink::Storage::DataStore::uidFromKey(key))) { - qWarning() << "Failed to find RID for " << key; - } + uids.insert(Sink::Storage::DataStore::uidFromKey(key)); return true; }, [&](const Sink::Storage::DataStore::Error &e) { @@ -96,6 +95,17 @@ bool inspect(const QStringList &args, State &state) }, false); + int missing = 0; + for (const auto &uid : uids) { + if (!hash.remove(uid)) { + missing++; + qWarning() << "Failed to find RID for " << uid; + } + } + if (missing) { + qWarning() << "Found a total of " << missing << " missing rids"; + } + //If we still have items in the hash it means we have rid mappings for entities //that no longer exist. if (!hash.isEmpty()) { -- cgit v1.2.3 From d87c789f311b7727d2db687e3891319e98ad6535 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Mon, 14 Aug 2017 09:03:24 -0600 Subject: Skip over revisions that we can't replay. --- examples/imapresource/imapresource.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 96055b4..0c0c134 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -621,7 +621,11 @@ public: { if (operation != Sink::Operation_Creation) { if(oldRemoteId.isEmpty()) { - return KAsync::error("Tried to replay modification without old remoteId."); + // return KAsync::error("Tried to replay modification without old remoteId."); + qWarning() << "Tried to replay modification without old remoteId."; + // Since we can't recover from the situation we just skip over the revision. + // FIXME figure out how we can ever end up in this situation + return KAsync::null(); } } auto imap = QSharedPointer::create(mServer, mPort, &mSessionCache); -- cgit v1.2.3 From 3a7d2e81c7fdc8c2e4b9810065028f4906fc28b3 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 18 Aug 2017 19:04:54 -0600 Subject: Implemented thread merging It can happen that thread messages are not delivered in order, which means we will have to merge threads once all messages are available. --- common/mail/threadindexer.cpp | 30 ++++- tests/CMakeLists.txt | 1 + tests/mailthreadtest.cpp | 64 +++++++++ tests/mailthreadtest.h | 1 + tests/threaddata/thread1 | 228 ++++++++++++++++++++++++++++++++ tests/threaddata/thread2 | 129 ++++++++++++++++++ tests/threaddata/thread3 | 184 ++++++++++++++++++++++++++ tests/threaddata/thread4 | 187 ++++++++++++++++++++++++++ tests/threaddata/thread5 | 119 +++++++++++++++++ tests/threaddata/thread6 | 175 +++++++++++++++++++++++++ tests/threaddata/thread7 | 297 ++++++++++++++++++++++++++++++++++++++++++ tests/threaddata/thread8 | 253 +++++++++++++++++++++++++++++++++++ tests/threaddata/thread9 | 283 ++++++++++++++++++++++++++++++++++++++++ 13 files changed, 1950 insertions(+), 1 deletion(-) create mode 100644 tests/threaddata/thread1 create mode 100644 tests/threaddata/thread2 create mode 100644 tests/threaddata/thread3 create mode 100644 tests/threaddata/thread4 create mode 100644 tests/threaddata/thread5 create mode 100644 tests/threaddata/thread6 create mode 100644 tests/threaddata/thread7 create mode 100644 tests/threaddata/thread8 create mode 100644 tests/threaddata/thread9 diff --git a/common/mail/threadindexer.cpp b/common/mail/threadindexer.cpp index 4171d85..1401fc8 100644 --- a/common/mail/threadindexer.cpp +++ b/common/mail/threadindexer.cpp @@ -34,9 +34,37 @@ void ThreadIndexer::updateThreadingIndex(const QByteArray &identifier, const App QVector thread; - //a child already registered our thread. + //check if a child already registered our thread. thread = index().secondaryLookup(messageId); + if (!thread.isEmpty()) { + //A child already registered our thread so we merge the childs thread + //* check if we have a parent thread, if not just continue as usual + //* get all messages that have the same threadid as the child + //* switch all to the parents thread + auto parentThread = index().secondaryLookup(parentMessageId); + if (!parentThread.isEmpty()) { + auto childThreadId = thread.first(); + auto parentThreadId = parentThread.first(); + SinkTrace() << "Merging child thread: " << childThreadId << " into parent thread: " << parentThreadId; + + //Ensure this mail ends up in the correct thread + index().unindex(messageId, childThreadId, transaction); + //We have to copy the id here, otherwise it doesn't survive the subsequent writes + thread = QVector() << QByteArray{parentThreadId.data(), parentThreadId.size()}; + + //Merge all child messages into the correct thread + auto childThreadMessageIds = index().secondaryLookup(childThreadId); + for (const auto &msgId : childThreadMessageIds) { + SinkTrace() << "Merging child message: " << msgId; + index().unindex(msgId, childThreadId, transaction); + index().unindex(childThreadId, msgId, transaction); + index().index(msgId, parentThreadId, transaction); + index().index(parentThreadId, msgId, transaction); + } + } + } + //If parent is already available, add to thread of parent if (thread.isEmpty() && parentMessageId.isValid()) { thread = index().secondaryLookup(parentMessageId); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b0333a4..6a757ca 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,6 +9,7 @@ include_directories( ) add_definitions(-DTESTDATAPATH="${CMAKE_CURRENT_SOURCE_DIR}/data") +add_definitions(-DTHREADTESTDATAPATH="${CMAKE_CURRENT_SOURCE_DIR}/threaddata") find_package(KF5 COMPONENTS REQUIRED Mime) diff --git a/tests/mailthreadtest.cpp b/tests/mailthreadtest.cpp index 741eb78..9ed5d83 100644 --- a/tests/mailthreadtest.cpp +++ b/tests/mailthreadtest.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include "store.h" @@ -185,4 +186,67 @@ void MailThreadTest::testIndexInMixedOrder() /* VERIFYEXEC(ResourceControl::flushReplayQueue(QByteArrayList() << mResourceInstanceIdentifier)); */ } +static QByteArray readMailFromFile(const QString &mailFile) +{ + QFile file(QLatin1String(THREADTESTDATAPATH) + QLatin1Char('/') + mailFile); + file.open(QIODevice::ReadOnly); + Q_ASSERT(file.isOpen()); + return file.readAll(); +} + +static KMime::Message::Ptr readMail(const QString &mailFile) +{ + auto msg = KMime::Message::Ptr::create(); + msg->setContent(readMailFromFile(mailFile)); + msg->parse(); + return msg; +} + +void MailThreadTest::testRealWorldThread() +{ + auto folder = Folder::create(mResourceInstanceIdentifier); + folder.setName("folder"); + VERIFYEXEC(Store::create(folder)); + + auto createMail = [this, folder] (KMime::Message::Ptr msg) { + auto mail = Mail::create(mResourceInstanceIdentifier); + mail.setMimeMessage(msg->encodedContent(true)); + mail.setFolder(folder); + VERIFYEXEC(Store::create(mail)); + }; + + createMail(readMail("thread1")); + + VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); + + auto query = Sink::StandardQueries::threadLeaders(folder); + query.resourceFilter(mResourceInstanceIdentifier); + query.request().request().request().request(); + + //Ensure we find the thread leader + Mail threadLeader = [&] { + auto mails = Store::read(query); + Q_ASSERT(mails.size() == 1); + return mails.first(); + }(); + + createMail(readMail("thread2")); + createMail(readMail("thread3")); + createMail(readMail("thread4")); + createMail(readMail("thread5")); + createMail(readMail("thread6")); + createMail(readMail("thread7")); + createMail(readMail("thread8")); //This mail is breaking the thread + VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); + + //Ensure the thread is complete + { + auto query = Sink::StandardQueries::completeThread(threadLeader); + query.request().request().request().request(); + + auto mails = Store::read(query); + QCOMPARE(mails.size(), 8); + } +} + #include "mailthreadtest.moc" diff --git a/tests/mailthreadtest.h b/tests/mailthreadtest.h index 8730ec6..1c5c389 100644 --- a/tests/mailthreadtest.h +++ b/tests/mailthreadtest.h @@ -52,6 +52,7 @@ private slots: void testListThreadLeader(); void testIndexInMixedOrder(); + void testRealWorldThread(); }; } diff --git a/tests/threaddata/thread1 b/tests/threaddata/thread1 new file mode 100644 index 0000000..8b72901 --- /dev/null +++ b/tests/threaddata/thread1 @@ -0,0 +1,228 @@ +Return-Path: +Received: from imapb010.mykolab.com ([unix socket]) + by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; + Sun, 13 Aug 2017 11:50:30 +0200 +X-Sieve: CMU Sieve 2.4 +Received: from int-mx002.mykolab.com (unknown [10.9.13.2]) + by imapb010.mykolab.com (Postfix) with ESMTPS id E79C512C084C4 + for ; Sun, 13 Aug 2017 11:50:29 +0200 (CEST) +Received: from mx.kolabnow.com (unknown [10.9.4.1]) + by int-mx002.mykolab.com (Postfix) with ESMTPS id BE41F2329 + for ; Sun, 13 Aug 2017 11:50:29 +0200 (CEST) +X-Virus-Scanned: amavisd-new at mykolab.com +Authentication-Results: ext-mx-in001.mykolab.com (amavisd-new); + dkim=pass (1024-bit key) header.d=kde.org +X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 +Received: from forward2-smtp.messagingengine.com (forward2-smtp.messagingengine.com [66.111.4.226]) + by ext-mx-in001.mykolab.com (Postfix) with ESMTPS id 5614B11BB + for ; Sun, 13 Aug 2017 11:50:08 +0200 (CEST) +Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) + by mailforward.nyi.internal (Postfix) with ESMTP id E9026D1C6 + for ; Sun, 13 Aug 2017 05:50:06 -0400 (EDT) +Received: by mailredirect.nyi.internal (Postfix, from userid 501) + id D95328E3AC; Sun, 13 Aug 2017 05:50:06 -0400 (EDT) +Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) + by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; + Sun, 13 Aug 2017 05:50:06 -0400 +X-Cyrus-Session-Id: sloti36d2t28-2961984-1502617806-2-9300763073201928650 +X-Sieve: CMU Sieve 3.0 +X-Spam-known-sender: no +X-Orig-Spam-score: 0.0 +X-Spam-hits: BAYES_20 -0.001, RCVD_IN_DNSWL_MED -2.3, RP_MATCHES_RCVD -0.001, + SPF_PASS -0.001, LANGUAGES en, BAYES_USED global, SA_VERSION 3.4.0 +X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='org', + MailFrom='org' +X-Spam-charsets: plain='us-ascii' +X-Attached: signature.asc +X-Resolved-to: chrigi_1@fastmail.fm +X-Delivered-to: chrigi_1@fastmail.fm +X-Mail-from: kde-community-bounces@kde.org +Received: from mx4 ([10.202.2.203]) + by compute1.internal (LMTPProxy); Sun, 13 Aug 2017 05:50:06 -0400 +Authentication-Results: mx4.messagingengine.com; + dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=aAtxmD+3; + dmarc=none (p=none;has-list-id=yes) header.from=kde.org; + smime=temperror; + spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org +Received-SPF: pass + (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) + receiver=mx4.messagingengine.com; + identity=mailfrom; + envelope-from="kde-community-bounces@kde.org"; + helo=postbox.kde.org; + client-ip=46.4.96.248 +Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by mx4.messagingengine.com (Postfix) with ESMTPS + for ; Sun, 13 Aug 2017 05:50:05 -0400 (EDT) +DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; + t=1502617803; bh=IzJP1FRz6gX2xTBV2xMDBc2KfNLK284LvmfZvBQHRwU=; + h=From:To:Subject:Date:Reply-To:List-Id:List-Unsubscribe: + List-Archive:List-Post:List-Help:List-Subscribe:From; + b=aAtxmD+3cXY913YngN6okQjxPwOn+T9Cw1Hl1NpSZ2E4VbNDeuQ9IVj6zCqeAZE6y + elk2GquLeHlXeLnygo2n5LQL6epM83pkS+1AWSHQI11mBDT5byLUrXX64hOSZ579jG + L6+jAJT8vcqnXZcGg5EjBQqYmFp4HLedW/xduUVg= +X-Original-To: kde-community@kde.org +X-Remote-Delivered-To: kde-community@localhost.kde.org +Received-SPF: Neutral (access neither permitted nor denied) identity=mailfrom; + client-ip=85.214.75.115; helo=h2670809.stratoserver.net; + envelope-from=vkrause@kde.org; receiver=kde-community@kde.org +Received: from h2670809.stratoserver.net (deltatauchi.de [85.214.75.115]) + by postbox.kde.org (Postfix) with ESMTP id 61C21A308E + for ; Sun, 13 Aug 2017 09:49:38 +0000 (UTC) +Received: from deltatauchi.de (ip5b403802.dynamic.kabel-deutschland.de + [91.64.56.2]) + by h2670809.stratoserver.net (Postfix) with ESMTPSA id 521BBF1A0104 + for ; Sun, 13 Aug 2017 11:49:07 +0200 (CEST) +From: Volker Krause +To: kde-community@kde.org +Subject: Telemetry Policy +Date: Sun, 13 Aug 2017 11:47:28 +0200 +Message-ID: <2048912.XfIJe3ZSdj@vkpc5> +Organization: KDE +X-Face: rgzmh}R?iq +List-Id: informing about and discussing non-technical community topics + +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Errors-To: kde-community-bounces@kde.org +Sender: "kde-community" + +--nextPart1627232.ab0ruIHapE +Content-Transfer-Encoding: 7Bit +Content-Type: text/plain; charset="us-ascii" + +Hi, + +during the KUserFeedback BoF at Akademy there was quite some interest in +collecting telemetry data in KDE applications. But before actually +implementing that we agreed to define the rules under which we would want to +do that. I've tried to put the input we collected during Akademy into proper +wording below. What do you think? Did I miss anything? + +Regards, +Volker + + +# Telemetry Policy Draft + +Application telemetry data can be a valuable tool for tailoring our products +to the needs of our users. The following rules define how KDE collects and +uses such application telemetry data. As privacy is of utmost importance to +us, the general rule of thumb is to err on the side of caution here. Privacy +always trumps any need for telemetry data, no matter how legitimate. + +These rules apply to all products released by KDE. + +## Transparency + +We provide detailed information about the data that is going to be shared, in +a way that: +- is easy to understand +- is precise and complete +- is available locally without network connectivity + +Any changes or additions to the telemetry functionality of an application will +be highlighted in the corresponding release announcement. + +## Control + +We give the user full control over what data they want to share with KDE. In +particular: +- application telemetry is always opt-in, that is off by default +- application telemetry settings can be changed at any time, and are provided +as prominent in the application interface as other application settings +- applications honor system-wide telemetry settings where they exist (global +"kill switch") +- we provide detailed documentation about how to control the application +telemetry system + +In order to ensure control over the data after it has been shared with KDE, +applications will only transmit this data to KDE servers, that is servers +under the full control of the KDE sysadmin team. + +We will provide a designated contact point for users who have concerns about +the data they have shared with KDE. While we are willing to delete data a user +no longer wants to have shared, it should be understood that the below rules +are designed to make identification of data of a specific user impossible, and +thus a deletion request impractical. + +## Anonymity + +We do not transmit data that could be used to identify a specific user. In +particular: +- we will not use any unique device, installation or user id +- data is stripped of any unnecessary detail and downsampled appropriately +before sharing to avoid fingerprinting +- network addresses (which are exposed inevitably as part of the data +transmission) are not stored together with the telemetry data, and must only +be stored or used to the extend necessary for abuse counter-measures + +## Minimalism + +We only track the bare minimum of data necessary to answer specific questions, +we do not collect data preemptively or for exploratory research. In +particular, this means: +- collected data must have a clear purpose +- data is downsampled to the maximum extend possible at the source +- relevant correlations between individual bits of data should be computed at +the source whenever possible +- data collection is stopped once corresponding question has been answered + +## Privacy + +We will never transmit anything containing user content, or even just hints at +possible user content such as e.g. file names, URLs, etc. + +We will only ever track: +- system information that are specific to the installation/environment, but +independent of how the application/machine/installation is actually used +- statistical usage data of an installation/application + +## Compliance + +KDE only releases products capable of acquiring telemetry data if compliance +with these rules has been established by a public review on [kde-core-devel| +kde-community]@kde.org from at least two reviewers. The review has to be +repeated for every release if changes have been made to how/what data is +collected. + +Received data is regularly reviewed for violations of these rules, in +particular for data that is prone to fingerprinting. Should such violations be +found, the affected data will be deleted, and data recording will be suspended +until compliance with these rules has been established again. In order to +enable reviewing of the data, every KDE contributor with a developer account +will have access to all telemetry data gathered by any KDE product. + +--nextPart1627232.ab0ruIHapE +Content-Type: application/pgp-signature; name="signature.asc" +Content-Description: This is a digitally signed message part. +Content-Transfer-Encoding: 7Bit + +-----BEGIN PGP SIGNATURE----- + +iF0EABECAB0WIQQAnu3FVHA48KjZ07R/lszWTRLSRwUCWZAgMAAKCRB/lszWTRLS +Ry5WAJ9+8r8e7IFPh54YBsEkisE3+dNs8QCfY+0b0jcYPVP1HdpsTZVoh33JfhU= +=v6cZ +-----END PGP SIGNATURE----- + +--nextPart1627232.ab0ruIHapE-- + + diff --git a/tests/threaddata/thread2 b/tests/threaddata/thread2 new file mode 100644 index 0000000..4d90073 --- /dev/null +++ b/tests/threaddata/thread2 @@ -0,0 +1,129 @@ +Return-Path: +Received: from imapb010.mykolab.com ([unix socket]) + by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; + Wed, 16 Aug 2017 09:15:00 +0200 +X-Sieve: CMU Sieve 2.4 +Received: from int-mx002.mykolab.com (unknown [10.9.13.2]) + by imapb010.mykolab.com (Postfix) with ESMTPS id 1772014401C83 + for ; Wed, 16 Aug 2017 09:15:00 +0200 (CEST) +Received: from mx.kolabnow.com (unknown [10.9.4.1]) + by int-mx002.mykolab.com (Postfix) with ESMTPS id 01CCB2348 + for ; Wed, 16 Aug 2017 09:14:59 +0200 (CEST) +X-Virus-Scanned: amavisd-new at mykolab.com +Authentication-Results: ext-mx-in001.mykolab.com (amavisd-new); + dkim=pass (1024-bit key) header.d=kde.org +X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 +Received: from forward1-smtp.messagingengine.com (forward1-smtp.messagingengine.com [66.111.4.223]) + by ext-mx-in001.mykolab.com (Postfix) with ESMTPS id 3BC6B11AC + for ; Wed, 16 Aug 2017 09:14:42 +0200 (CEST) +Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) + by mailforward.nyi.internal (Postfix) with ESMTP id 9F77F12C6 + for ; Wed, 16 Aug 2017 03:14:41 -0400 (EDT) +Received: by mailredirect.nyi.internal (Postfix, from userid 501) + id 8EF798E597; Wed, 16 Aug 2017 03:14:41 -0400 (EDT) +Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) + by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; + Wed, 16 Aug 2017 03:14:41 -0400 +X-Cyrus-Session-Id: sloti36d2t28-476506-1502867681-2-17694110317903435823 +X-Sieve: CMU Sieve 3.0 +X-Spam-known-sender: no +X-Orig-Spam-score: 0.0 +X-Spam-hits: BAYES_20 -0.001, HEADER_FROM_DIFFERENT_DOMAINS 0.001, + RCVD_IN_DNSWL_MED -2.3, RP_MATCHES_RCVD -0.001, SPF_PASS -0.001, + LANGUAGES en, BAYES_USED global, SA_VERSION 3.4.0 +X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='ch', + MailFrom='org' +X-Spam-charsets: plain='us-ascii' +X-Resolved-to: chrigi_1@fastmail.fm +X-Delivered-to: chrigi_1@fastmail.fm +X-Mail-from: kde-community-bounces@kde.org +Received: from mx4 ([10.202.2.203]) + by compute1.internal (LMTPProxy); Wed, 16 Aug 2017 03:14:41 -0400 +Authentication-Results: mx4.messagingengine.com; + dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=cVfBDwjP; + dmarc=none (p=none;has-list-id=yes) header.from=fuchsnet.ch; + spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org +Received-SPF: pass + (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) + receiver=mx4.messagingengine.com; + identity=mailfrom; + envelope-from="kde-community-bounces@kde.org"; + helo=postbox.kde.org; + client-ip=46.4.96.248 +Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by mx4.messagingengine.com (Postfix) with ESMTPS + for ; Wed, 16 Aug 2017 03:14:40 -0400 (EDT) +DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; + t=1502867678; bh=70oyTvxfLkdYUd1D8WFhrBEneI7DP4MY5KH1tM/AxUI=; + h=From:To:Subject:Date:In-Reply-To:References:Reply-To:List-Id: + List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: + From; + b=cVfBDwjPyB0OrVy5jQaU1YBZtx/95ktf4lpQDQddz0Udb+QkxzLzv6S3He6EjQIRs + nnEfVM/Y6V/Q9IHj+AYQckxyZxbXNOmfb9jOgU/R5bhPMkpstCvw/gQTD+LMGsFuSl + fCKdwg+KmAWmvBhoe+8Oa6BMR3KKViYziJgMTuwI= +X-Original-To: kde-community@kde.org +X-Remote-Delivered-To: kde-community@localhost.kde.org +Received-SPF: None (no SPF record) identity=mailfrom; + client-ip=2a00:d70:0:e::317; helo=mxout017.mail.hostpoint.ch; + envelope-from=christian.loosli@fuchsnet.ch; receiver=kde-community@kde.org +Received: from mxout017.mail.hostpoint.ch (mxout017.mail.hostpoint.ch + [IPv6:2a00:d70:0:e::317]) + by postbox.kde.org (Postfix) with ESMTPS id AA196A3AC5 + for ; Sun, 13 Aug 2017 10:18:17 +0000 (UTC) +Received: from [10.0.2.45] (helo=asmtp012.mail.hostpoint.ch) + by mxout017.mail.hostpoint.ch with esmtp (Exim 4.89 (FreeBSD)) + (envelope-from ) id 1dgpyK-000DwH-Of + for kde-community@kde.org; Sun, 13 Aug 2017 12:18:16 +0200 +Received: from 77-56-19-119.dclient.hispeed.ch ([77.56.19.119] + helo=minixfox.localnet) by asmtp012.mail.hostpoint.ch with esmtpsa + (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.89 (FreeBSD)) + (envelope-from ) id 1dgpyK-000CRa-ML + for kde-community@kde.org; Sun, 13 Aug 2017 12:18:16 +0200 +X-Authenticated-Sender-Id: mail@fuchsnet.ch +From: Christian Loosli +To: kde-community@kde.org +Subject: Re: Telemetry Policy +Date: Sun, 13 Aug 2017 12:18:16 +0200 +Message-ID: <2990543.KVDkBByYO0@minixfox> +User-Agent: KMail/5.2.3 (Linux/4.6.2-040602-generic; KDE/5.35.0; x86_64; ; ) +In-Reply-To: <2048912.XfIJe3ZSdj@vkpc5> +References: <2048912.XfIJe3ZSdj@vkpc5> +MIME-Version: 1.0 +Content-Transfer-Encoding: 7Bit +Content-Type: text/plain; charset="us-ascii" +X-Mailman-Approved-At: Wed, 16 Aug 2017 07:14:22 +0000 +X-BeenThere: kde-community@kde.org +X-Mailman-Version: 2.1.16 +Precedence: list +Reply-To: informing about and discussing non-technical community topics + +List-Id: informing about and discussing non-technical community topics + +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Errors-To: kde-community-bounces@kde.org +Sender: "kde-community" + +Hi, + +thank you very much for this work, sounds great! + +Only point I have: maybe make sure that the opt-in / default settings are not +only mandatory for application developers, but also for packagers / +distributions. + +Some distributions have rather questionable views on privacy and by default +sent information to third parties, so I would feel much more safe if they +weren't allowed (in theory) to flick the switch in their package by default to +"on" either. + +Kind regards, + +Christian diff --git a/tests/threaddata/thread3 b/tests/threaddata/thread3 new file mode 100644 index 0000000..84db2b3 --- /dev/null +++ b/tests/threaddata/thread3 @@ -0,0 +1,184 @@ +Return-Path: +Received: from imapb010.mykolab.com ([unix socket]) + by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; + Wed, 16 Aug 2017 09:33:42 +0200 +X-Sieve: CMU Sieve 2.4 +Received: from int-mx001.mykolab.com (unknown [10.9.13.1]) + by imapb010.mykolab.com (Postfix) with ESMTPS id 5444D14414C34 + for ; Wed, 16 Aug 2017 09:33:42 +0200 (CEST) +Received: from mx.kolabnow.com (unknown [10.9.4.2]) + by int-mx001.mykolab.com (Postfix) with ESMTPS id 3DB4C114 + for ; Wed, 16 Aug 2017 09:33:42 +0200 (CEST) +X-Virus-Scanned: amavisd-new at mykolab.com +Authentication-Results: ext-mx-in002.mykolab.com (amavisd-new); + dkim=pass (1024-bit key) header.d=kde.org header.b=PXk+9Qyc; + dkim=pass (2048-bit key) header.d=gmail.com header.b=j1CN7DJ2 +X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 +Received: from forward1-smtp.messagingengine.com (forward1-smtp.messagingengine.com [66.111.4.223]) + by ext-mx-in002.mykolab.com (Postfix) with ESMTPS id DEAFCE9E + for ; Wed, 16 Aug 2017 09:33:36 +0200 (CEST) +Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) + by mailforward.nyi.internal (Postfix) with ESMTP id 6AD87108D + for ; Wed, 16 Aug 2017 03:33:35 -0400 (EDT) +Received: by mailredirect.nyi.internal (Postfix, from userid 501) + id 444F38E597; Wed, 16 Aug 2017 03:33:35 -0400 (EDT) +Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) + by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; + Wed, 16 Aug 2017 03:33:35 -0400 +X-Cyrus-Session-Id: sloti36d2t28-546055-1502868815-2-14217351451016405562 +X-Sieve: CMU Sieve 3.0 +X-Spam-known-sender: no +X-Orig-Spam-score: 0.0 +X-Spam-hits: BAYES_00 -1.9, FREEMAIL_FORGED_FROMDOMAIN 0.199, FREEMAIL_FROM 0.001, + HEADER_FROM_DIFFERENT_DOMAINS 0.001, RCVD_IN_DNSWL_MED -2.3, + RP_MATCHES_RCVD -0.001, SPF_PASS -0.001, LANGUAGES en, BAYES_USED global, + SA_VERSION 3.4.0 +X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='com', + MailFrom='org' +X-Spam-charsets: plain='UTF-8' +X-Resolved-to: chrigi_1@fastmail.fm +X-Delivered-to: chrigi_1@fastmail.fm +X-Mail-from: kde-community-bounces@kde.org +Received: from mx1 ([10.202.2.200]) + by compute1.internal (LMTPProxy); Wed, 16 Aug 2017 03:33:35 -0400 +Authentication-Results: mx1.messagingengine.com; + dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=PXk+9Qyc; + dkim=pass (2048-bit rsa key sha256) header.d=gmail.com header.i=@gmail.com header.b=j1CN7DJ2; + dmarc=pass header.from=gmail.com; + spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org; + x-google-dkim=pass (2048-bit rsa key) header.d=1e100.net header.i=@1e100.net header.b=nOWNMzab +Received-SPF: pass + (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) + receiver=mx1.messagingengine.com; + identity=mailfrom; + envelope-from="kde-community-bounces@kde.org"; + helo=postbox.kde.org; + client-ip=46.4.96.248 +Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by mx1.messagingengine.com (Postfix) with ESMTPS + for ; Wed, 16 Aug 2017 03:33:34 -0400 (EDT) +DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; + t=1502868810; bh=dVFv3mcZvqPFeac2frbs+zJpMjYutwuTUR/aZqUTbZY=; + h=In-Reply-To:References:From:Date:Subject:To:Reply-To:List-Id: + List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: + From; + b=PXk+9Qyc+iRxwLPIHod4loutgNXu9pHl4peiPK0rI8Bl+4b02Cw0SUrzyf2JPqyDn + zuoxSnetdDbzoPnV1ep3yyHX+MhXiWvvc+PTKk15kIuBJYB77t+EJq3I/awvqG++Fa + d4Um24yPg/LUw5fFTsMuJ+Ra5MtpmFOmVbXrHDt0= +X-Original-To: kde-community@kde.org +X-Remote-Delivered-To: kde-community@localhost.kde.org +Received-SPF: Pass (sender SPF authorized) identity=mailfrom; + client-ip=2607:f8b0:4001:c0b::22f; helo=mail-it0-x22f.google.com; + envelope-from=valorie.zimmerman@gmail.com; receiver=kde-community@kde.org +Authentication-Results: postbox.kde.org; dkim=pass + reason="2048-bit key; unprotected key" + header.d=gmail.com header.i=@gmail.com header.b=j1CN7DJ2; + dkim-adsp=pass; dkim-atps=neutral +Received: from mail-it0-x22f.google.com (mail-it0-x22f.google.com + [IPv6:2607:f8b0:4001:c0b::22f]) + by postbox.kde.org (Postfix) with ESMTPS id 06F4BA0243 + for ; Wed, 16 Aug 2017 07:33:19 +0000 (UTC) +Received: by mail-it0-x22f.google.com with SMTP id 76so14155500ith.0 + for ; Wed, 16 Aug 2017 00:33:19 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; + h=mime-version:in-reply-to:references:from:date:message-id:subject:to; + bh=FXMFEApKo547tDMnIu6insMVxFcMsw7/E/4fcI3MkkQ=; + b=j1CN7DJ2CYaCWqNWOR7Hpjah/U+OYATQhmN+zVkgRNbVJOMVW6B4hWmUihH5Nll4/G + YX5O5OQv6i2y1hAqT3R3iISGAz70o2gIWjq14Ea+zqM9ztCM/ZX4XGaBqdv4dHTAMyDh + mg556PB77JLPlwHtf2CsR9gTSAC2BAuY8lsTdBV7jVkLjCGdjaSPRxiyf2t4WbcVmiUt + yZzWB7QmtQA4JHQ8N/bJ2lEg8cTWSj8p9o4kSAF7HDZ4X7pXfQgAPEAs/DHf9LMNGiys + 1xgAuYNxywGvtLaArQ+NXfgYH6VfRcFf7HFbMLs6yLyn63G9GLyUPHlHIgqWVAJrdn65 + Nsow== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20161025; + h=x-gm-message-state:mime-version:in-reply-to:references:from:date + :message-id:subject:to; + bh=FXMFEApKo547tDMnIu6insMVxFcMsw7/E/4fcI3MkkQ=; + b=nOWNMzabDGsTEZISXzVD7236lDYmFHF2kAEUxMmDSvGYEcq1/FjZwj7w7SJT62S/pY + oS29tWyY7LE4I+Fq5E6D8H2sfMAfaCoYQ1J27ftPVClg/kmiTGRzxf2tcv6TR/v56+vD + pwgDEDwgZs1oM6IBFrJr65u2+0mlcmK3qsRHBdjoQLEbZMa+GugjcI2HILqtmpTS+NJi + HZcVfEgOwkyqgoZkgBsaBui+5OUpz/yqryOsYx7kQxCy6uZJIFCB0dsvk7COE8nG7LYa + 0H8aRhVFxXRW76MUR6E67EhGMS+MS9F3DiXiUsWTn4yEZnC8cy76YPcPHVBBmGQ7CH0a + ScwA== +X-Gm-Message-State: AHYfb5g0PFdyP1pw7TVZRMJqzU/nu12G3R2adj9OD2MzSxEew1QKnS99 + U5MlthDVsG6C1f9Ak0fXNCtdI5w4CaBJhbc= +X-Received: by 10.36.37.143 with SMTP id g137mr1056087itg.35.1502868798009; + Wed, 16 Aug 2017 00:33:18 -0700 (PDT) +MIME-Version: 1.0 +Received: by 10.107.6.142 with HTTP; Wed, 16 Aug 2017 00:33:02 -0700 (PDT) +In-Reply-To: <2990543.KVDkBByYO0@minixfox> +References: <2048912.XfIJe3ZSdj@vkpc5> <2990543.KVDkBByYO0@minixfox> +From: Valorie Zimmerman +Date: Wed, 16 Aug 2017 00:33:02 -0700 +Message-ID: +Subject: Re: Telemetry Policy +To: informing about and discussing non-technical community topics + +Content-Type: text/plain; charset="UTF-8" +X-BeenThere: kde-community@kde.org +X-Mailman-Version: 2.1.16 +Precedence: list +Reply-To: informing about and discussing non-technical community topics + +List-Id: informing about and discussing non-technical community topics + +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Errors-To: kde-community-bounces@kde.org +Sender: "kde-community" + +Hi all, Mozilla has done a lot of work on telemetry, and we might be +able to use some of their findings. On this page: +https://wiki.mozilla.org/Firefox/Data_Collection they break down the +data they might possibly collect into four buckets - technical (such +as crashes), user interaction, web activity, and sensitive (personal +data). + +This bit might be relevant to our discussion: "Categories 1 & 2 +(Technical & Interaction data) +Pre-Release & Release: Data may default on, provided the data is +exclusively in these categories (it cannot be in any other category). +In Release, an opt-out must be available for most types of Technical +and Interaction data. " + +I think the entire page might be enlightening to this discussion. I +believe our analysis of needs should be more fine-grained, and that +some parts of what we need can be "default on" especially for +pre-release testing. For releases, we can provide an opt-out. + +Other more sensitive data will need to be opt-in. I think it's a +mistake to treat all the data we might want all in the same way. + +Valorie + + +On Sun, Aug 13, 2017 at 3:18 AM, Christian Loosli + wrote: +> Hi, +> +> thank you very much for this work, sounds great! +> +> Only point I have: maybe make sure that the opt-in / default settings are not +> only mandatory for application developers, but also for packagers / +> distributions. +> +> Some distributions have rather questionable views on privacy and by default +> sent information to third parties, so I would feel much more safe if they +> weren't allowed (in theory) to flick the switch in their package by default to +> "on" either. +> +> Kind regards, +> +> Christian + + + +-- +http://about.me/valoriez diff --git a/tests/threaddata/thread4 b/tests/threaddata/thread4 new file mode 100644 index 0000000..492d64d --- /dev/null +++ b/tests/threaddata/thread4 @@ -0,0 +1,187 @@ +Return-Path: +Received: from imapb010.mykolab.com ([unix socket]) + by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; + Wed, 16 Aug 2017 14:15:52 +0200 +X-Sieve: CMU Sieve 2.4 +Received: from int-mx001.mykolab.com (unknown [10.9.13.1]) + by imapb010.mykolab.com (Postfix) with ESMTPS id B5DFE145C97EA + for ; Wed, 16 Aug 2017 14:15:52 +0200 (CEST) +Received: from mx.kolabnow.com (unknown [10.9.4.3]) + by int-mx001.mykolab.com (Postfix) with ESMTPS id 9430B114 + for ; Wed, 16 Aug 2017 14:15:52 +0200 (CEST) +X-Virus-Scanned: amavisd-new at mykolab.com +Authentication-Results: ext-mx-in003.mykolab.com (amavisd-new); + dkim=pass (1024-bit key) header.d=kde.org +X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 +Received: from forward1-smtp.messagingengine.com (forward1-smtp.messagingengine.com [66.111.4.223]) + by ext-mx-in003.mykolab.com (Postfix) with ESMTPS id 87ADC292C + for ; Wed, 16 Aug 2017 14:15:41 +0200 (CEST) +Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) + by mailforward.nyi.internal (Postfix) with ESMTP id 14E06F2B + for ; Wed, 16 Aug 2017 08:15:41 -0400 (EDT) +Received: by mailredirect.nyi.internal (Postfix, from userid 501) + id 02B668E597; Wed, 16 Aug 2017 08:15:40 -0400 (EDT) +Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) + by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; + Wed, 16 Aug 2017 08:15:40 -0400 +X-Cyrus-Session-Id: sloti36d2t28-920397-1502885740-5-10891205693403350257 +X-Sieve: CMU Sieve 3.0 +X-Spam-known-sender: no +X-Orig-Spam-score: 0.0 +X-Spam-hits: BAYES_00 -1.9, RCVD_IN_DNSWL_MED -2.3, RP_MATCHES_RCVD -0.001, + SPF_PASS -0.001, LANGUAGES en, BAYES_USED global, SA_VERSION 3.4.0 +X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='org', + MailFrom='org' +X-Spam-charsets: plain='utf-8' +X-Attached: signature.asc +X-Resolved-to: chrigi_1@fastmail.fm +X-Delivered-to: chrigi_1@fastmail.fm +X-Mail-from: kde-community-bounces@kde.org +Received: from mx1 ([10.202.2.200]) + by compute1.internal (LMTPProxy); Wed, 16 Aug 2017 08:15:40 -0400 +Authentication-Results: mx1.messagingengine.com; + dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=dcc9ZeF1; + dmarc=none (p=none;has-list-id=yes) header.from=kde.org; + smime=temperror; + spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org +Received-SPF: pass + (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) + receiver=mx1.messagingengine.com; + identity=mailfrom; + envelope-from="kde-community-bounces@kde.org"; + helo=postbox.kde.org; + client-ip=46.4.96.248 +Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by mx1.messagingengine.com (Postfix) with ESMTPS + for ; Wed, 16 Aug 2017 08:15:40 -0400 (EDT) +DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; + t=1502885735; bh=SH/qVWnJJ/KE8PqQNaOwBRNoy7rIm5VobJE4/TZFZ9g=; + h=From:To:Subject:Date:In-Reply-To:References:Reply-To:List-Id: + List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: + From; + b=dcc9ZeF1EO5Q0C8mVOjhOITKyPmrCB9KGB4gKdTSfuxo4OZGKHg/xi7VH0/UDLYxy + Ni1GHXrJiD50yXOLDYICYr0XsDpYQaHmRQXGs6O6g/hIYxR2BCdqH1/5/NgNzPyjLH + 5aKmEZt4LH8/JKYnv1UJCiKdhG2UQrs3fSg/ZMpM= +X-Original-To: kde-community@kde.org +X-Remote-Delivered-To: kde-community@localhost.kde.org +Received-SPF: Neutral (access neither permitted nor denied) identity=mailfrom; + client-ip=85.214.75.115; helo=h2670809.stratoserver.net; + envelope-from=vkrause@kde.org; receiver=kde-community@kde.org +Received: from h2670809.stratoserver.net (deltatauchi.de [85.214.75.115]) + by postbox.kde.org (Postfix) with ESMTP id 7F686A0160 + for ; Wed, 16 Aug 2017 12:15:15 +0000 (UTC) +Received: from vkpc19.localnet (unknown [185.28.184.2]) + by h2670809.stratoserver.net (Postfix) with ESMTPSA id 59DBAF1A0104 + for ; Wed, 16 Aug 2017 14:14:44 +0200 (CEST) +From: Volker Krause +To: kde-community@kde.org +Subject: Re: Telemetry Policy +Date: Wed, 16 Aug 2017 14:13:48 +0200 +Message-ID: <1942419.JquqIjZoWq@vkpc19> +Organization: KDE +In-Reply-To: +References: <2048912.XfIJe3ZSdj@vkpc5> <2990543.KVDkBByYO0@minixfox> + +MIME-Version: 1.0 +Content-Type: multipart/signed; boundary="nextPart3633370.DIlRsSa6NW"; + micalg="pgp-sha1"; protocol="application/pgp-signature" +X-BeenThere: kde-community@kde.org +X-Mailman-Version: 2.1.16 +Precedence: list +Reply-To: informing about and discussing non-technical community topics + +List-Id: informing about and discussing non-technical community topics + +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Errors-To: kde-community-bounces@kde.org +Sender: "kde-community" + +--nextPart3633370.DIlRsSa6NW +Content-Transfer-Encoding: 7Bit +Content-Type: text/plain; charset="utf-8" + +On Wednesday, 16 August 2017 09:33:02 CEST Valorie Zimmerman wrote: +> Hi all, Mozilla has done a lot of work on telemetry, and we might be +> able to use some of their findings. On this page: +> https://wiki.mozilla.org/Firefox/Data_Collection they break down the +> data they might possibly collect into four buckets - technical (such +> as crashes), user interaction, web activity, and sensitive (personal +> data). + +without making it that explicit, we basically have the same four categories of +data too, and explicitly exclude the use of category 3 and 4, ie user content/ +activity and personal data, only technical and interaction data are allowed to +be used (category 1 and 2). + +> This bit might be relevant to our discussion: "Categories 1 & 2 +> (Technical & Interaction data) +> Pre-Release & Release: Data may default on, provided the data is +> exclusively in these categories (it cannot be in any other category). +> In Release, an opt-out must be available for most types of Technical +> and Interaction data. " +> +> I think the entire page might be enlightening to this discussion. I +> believe our analysis of needs should be more fine-grained, and that +> some parts of what we need can be "default on" especially for +> pre-release testing. For releases, we can provide an opt-out. +> +> Other more sensitive data will need to be opt-in. I think it's a +> mistake to treat all the data we might want all in the same way. + +This again brings up opt-out, which so far doesn't seem to have a chance for +consensus. Can we defer this to when we have some more experience with the +opt-in approach and how much participation we get with that? Or are people +feeling this would too strongly limit what they are allowed to do in their +applications? + +Seeing yesterday's blog from the Krita team (https://akapust1n.github.io/ +2017-08-15-sixth-blog-gsoc-2017/), I'd particularly be interested in their +view on this. + +Regards, +Volker + +> On Sun, Aug 13, 2017 at 3:18 AM, Christian Loosli +> +> wrote: +> > Hi, +> > +> > thank you very much for this work, sounds great! +> > +> > Only point I have: maybe make sure that the opt-in / default settings are +> > not only mandatory for application developers, but also for packagers / +> > distributions. +> > +> > Some distributions have rather questionable views on privacy and by +> > default +> > sent information to third parties, so I would feel much more safe if they +> > weren't allowed (in theory) to flick the switch in their package by +> > default to "on" either. +> > +> > Kind regards, +> > +> > Christian + + + +--nextPart3633370.DIlRsSa6NW +Content-Type: application/pgp-signature; name="signature.asc" +Content-Description: This is a digitally signed message part. +Content-Transfer-Encoding: 7Bit + +-----BEGIN PGP SIGNATURE----- + +iF0EABECAB0WIQQAnu3FVHA48KjZ07R/lszWTRLSRwUCWZQ2/AAKCRB/lszWTRLS +R+niAKCpVjpRVPq455bnZlAVxpARkGWE/gCcCaBN1QAFz8Da6XIKJGY7iukaS3A= +=ZSiq +-----END PGP SIGNATURE----- + +--nextPart3633370.DIlRsSa6NW-- diff --git a/tests/threaddata/thread5 b/tests/threaddata/thread5 new file mode 100644 index 0000000..def438c --- /dev/null +++ b/tests/threaddata/thread5 @@ -0,0 +1,119 @@ +Return-Path: +Received: from imapb010.mykolab.com ([unix socket]) + by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; + Wed, 16 Aug 2017 15:30:55 +0200 +X-Sieve: CMU Sieve 2.4 +Received: from int-mx001.mykolab.com (unknown [10.9.13.1]) + by imapb010.mykolab.com (Postfix) with ESMTPS id 2C73C14646FD6 + for ; Wed, 16 Aug 2017 15:30:55 +0200 (CEST) +Received: from mx.kolabnow.com (unknown [10.9.4.2]) + by int-mx001.mykolab.com (Postfix) with ESMTPS id 0324D114 + for ; Wed, 16 Aug 2017 15:30:54 +0200 (CEST) +X-Virus-Scanned: amavisd-new at mykolab.com +Authentication-Results: ext-mx-in002.mykolab.com (amavisd-new); + dkim=pass (1024-bit key) header.d=kde.org +X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 +Received: from forward1-smtp.messagingengine.com (forward1-smtp.messagingengine.com [66.111.4.223]) + by ext-mx-in002.mykolab.com (Postfix) with ESMTPS id C91AA866 + for ; Wed, 16 Aug 2017 15:30:34 +0200 (CEST) +Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) + by mailforward.nyi.internal (Postfix) with ESMTP id 5C87A1858 + for ; Wed, 16 Aug 2017 09:30:33 -0400 (EDT) +Received: by mailredirect.nyi.internal (Postfix, from userid 501) + id 4CC8B8E597; Wed, 16 Aug 2017 09:30:33 -0400 (EDT) +Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) + by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; + Wed, 16 Aug 2017 09:30:33 -0400 +X-Cyrus-Session-Id: sloti36d2t28-1026013-1502890233-2-11003035487755983862 +X-Sieve: CMU Sieve 3.0 +X-Spam-known-sender: no +X-Orig-Spam-score: 0.0 +X-Spam-hits: BAYES_00 -1.9, HEADER_FROM_DIFFERENT_DOMAINS 0.001, RCVD_IN_DNSWL_MED -2.3, + RP_MATCHES_RCVD -0.001, SPF_PASS -0.001, LANGUAGES en, BAYES_USED global, + SA_VERSION 3.4.0 +X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='org', + MailFrom='org' +X-Spam-charsets: +X-Resolved-to: chrigi_1@fastmail.fm +X-Delivered-to: chrigi_1@fastmail.fm +X-Mail-from: kde-community-bounces@kde.org +Received: from mx5 ([10.202.2.204]) + by compute1.internal (LMTPProxy); Wed, 16 Aug 2017 09:30:33 -0400 +Authentication-Results: mx5.messagingengine.com; + dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=RolpJ4HJ; + dmarc=none (p=none;has-list-id=yes) header.from=valdyas.org; + spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org +Received-SPF: pass + (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) + receiver=mx5.messagingengine.com; + identity=mailfrom; + envelope-from="kde-community-bounces@kde.org"; + helo=postbox.kde.org; + client-ip=46.4.96.248 +Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by mx5.messagingengine.com (Postfix) with ESMTPS + for ; Wed, 16 Aug 2017 09:30:32 -0400 (EDT) +DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; + t=1502890227; bh=z989fztQpyrmqEjIXZUifZvjlTrbUJ38xgYnpo5TWHY=; + h=Date:From:To:Subject:In-Reply-To:References:Reply-To:List-Id: + List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: + From; + b=RolpJ4HJf2ZKKk0rJkqOuvP1Ed5rERJZdvt2+FMMsImGArH3hWTlgl1qQewN3B81n + Nq4o83kvWrlw2Y0i0n/fd+NjBLY9wtDBeRslr06KZSnZe4vL6N8p15wkQIs+oUAvCL + 01Uy2pFX/99m+u66rd5IH2Epkdj9iSn2S6U0S3Ew= +X-Original-To: kde-community@kde.org +X-Remote-Delivered-To: kde-community@localhost.kde.org +Received-SPF: None (no SPF record) identity=mailfrom; client-ip=80.100.45.33; + helo=calcifer.valdyas.org; envelope-from=boud@valdyas.org; + receiver=kde-community@kde.org +Received: from calcifer.valdyas.org (calcifer.xs4all.nl [80.100.45.33]) + by postbox.kde.org (Postfix) with ESMTP id 6A134A0178 + for ; Wed, 16 Aug 2017 13:30:15 +0000 (UTC) +Received: by calcifer.valdyas.org (Postfix, from userid 1001) + id D3C2BC283D; Wed, 16 Aug 2017 15:30:14 +0200 (CEST) +Date: Wed, 16 Aug 2017 15:30:14 +0200 (CEST) +From: Boudewijn Rempt +To: informing about and discussing non-technical community topics + +Subject: Re: Telemetry Policy +In-Reply-To: <1942419.JquqIjZoWq@vkpc19> +Message-ID: +References: <2048912.XfIJe3ZSdj@vkpc5> <2990543.KVDkBByYO0@minixfox> + + <1942419.JquqIjZoWq@vkpc19> +User-Agent: Alpine 2.00 (LNX 1167 2008-08-23) +MIME-Version: 1.0 +Content-Type: TEXT/PLAIN; charset=US-ASCII +X-BeenThere: kde-community@kde.org +X-Mailman-Version: 2.1.16 +Precedence: list +Reply-To: informing about and discussing non-technical community topics + +List-Id: informing about and discussing non-technical community topics + +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Errors-To: kde-community-bounces@kde.org +Sender: "kde-community" + +On Wed, 16 Aug 2017, Volker Krause wrote: + +> Seeing yesterday's blog from the Krita team (https://akapust1n.github.io/ +> 2017-08-15-sixth-blog-gsoc-2017/), I'd particularly be interested in their +> view on this. + +I've pointed alexey at this thread, but there's a huge language barrier: +he basically communicates through google translate. I've made it a firm +condition of merging and operating the telemetry that we adhere to the +KDE policy in every way. Even then, I still consider his work to be +an experimental research project. + +-- +Boudewijn Rempt | http://www.krita.org, http://www.valdyas.org diff --git a/tests/threaddata/thread6 b/tests/threaddata/thread6 new file mode 100644 index 0000000..5ff64ff --- /dev/null +++ b/tests/threaddata/thread6 @@ -0,0 +1,175 @@ +Return-Path: +Received: from imapb010.mykolab.com ([unix socket]) + by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; + Thu, 17 Aug 2017 01:47:27 +0200 +X-Sieve: CMU Sieve 2.4 +Received: from int-mx002.mykolab.com (unknown [10.9.13.2]) + by imapb010.mykolab.com (Postfix) with ESMTPS id 2CC5214A68D1A + for ; Thu, 17 Aug 2017 01:47:27 +0200 (CEST) +Received: from mx.kolabnow.com (unknown [10.9.4.2]) + by int-mx002.mykolab.com (Postfix) with ESMTPS id 13C82F44 + for ; Thu, 17 Aug 2017 01:47:27 +0200 (CEST) +X-Virus-Scanned: amavisd-new at mykolab.com +Authentication-Results: ext-mx-in002.mykolab.com (amavisd-new); + dkim=pass (1024-bit key) header.d=kde.org +X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 +Received: from forward1-smtp.messagingengine.com (forward1-smtp.messagingengine.com [66.111.4.223]) + by ext-mx-in002.mykolab.com (Postfix) with ESMTPS id DA7D7211 + for ; Thu, 17 Aug 2017 01:47:15 +0200 (CEST) +Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) + by mailforward.nyi.internal (Postfix) with ESMTP id F078A4C + for ; Wed, 16 Aug 2017 19:47:14 -0400 (EDT) +Received: by mailredirect.nyi.internal (Postfix, from userid 501) + id D2D7E8E231; Wed, 16 Aug 2017 19:47:14 -0400 (EDT) +Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) + by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; + Wed, 16 Aug 2017 19:47:14 -0400 +X-Cyrus-Session-Id: sloti36d2t28-1787481-1502927234-2-5475491779407099440 +X-Sieve: CMU Sieve 3.0 +X-Spam-known-sender: yes ("Address thomas.pfeiffer@kde.org in From header is in addressbook"); + in-addressbook +X-Orig-Spam-score: 0.0 +X-Spam-hits: BAYES_00 -1.9, RCVD_IN_DNSWL_MED -2.3, RCVD_IN_SORBS_SPAM 0.5, + RP_MATCHES_RCVD -0.001, SPF_PASS -0.001, LANGUAGES en, BAYES_USED global, + SA_VERSION 3.4.0 +X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='org', + MailFrom='org' +X-Spam-charsets: plain='us-ascii' +X-Resolved-to: chrigi_1@fastmail.fm +X-Delivered-to: chrigi_1@fastmail.fm +X-Mail-from: kde-community-bounces@kde.org +Received: from mx6 ([10.202.2.205]) + by compute1.internal (LMTPProxy); Wed, 16 Aug 2017 19:47:14 -0400 +Authentication-Results: mx6.messagingengine.com; + dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=jjcN/rDm; + dmarc=none (p=none;has-list-id=yes) header.from=kde.org; + spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org; + x-google-dkim=pass (2048-bit rsa key) header.d=1e100.net header.i=@1e100.net header.b=MDpKFUTu +Received-SPF: pass + (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) + receiver=mx6.messagingengine.com; + identity=mailfrom; + envelope-from="kde-community-bounces@kde.org"; + helo=postbox.kde.org; + client-ip=46.4.96.248 +Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by mx6.messagingengine.com (Postfix) with ESMTPS + for ; Wed, 16 Aug 2017 19:47:13 -0400 (EDT) +DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; + t=1502927232; bh=ZPaDxaRw15uQ6A7HkCF2KoV4m+FrAkqde8P/U1SNqY8=; + h=From:To:Subject:Date:In-Reply-To:References:Reply-To:List-Id: + List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: + From; + b=jjcN/rDm5jM+2ttx4iyMXexUXHMS9OAzt1cfA461VOjTfg9ZPg+Kt1qCqUVzJNoSj + tXrKk69VVjb7tr4GNWJMKc2FAb5P33ndx6UC08kFDADMECoxSgwbHeKWdKCLE0KqOH + sCtYBZp0heUQzEztcQtjwtPuExHqivuLyYqZRvyM= +X-Original-To: kde-community@kde.org +X-Remote-Delivered-To: kde-community@localhost.kde.org +Received-SPF: Pass (sender SPF authorized) identity=mailfrom; + client-ip=209.85.128.174; helo=mail-wr0-f174.google.com; + envelope-from=t.pfeiffer.ux@gmail.com; receiver=kde-community@kde.org +Received: from mail-wr0-f174.google.com (mail-wr0-f174.google.com + [209.85.128.174]) + by postbox.kde.org (Postfix) with ESMTPS id 6AB96A029E + for ; Wed, 16 Aug 2017 23:46:52 +0000 (UTC) +Received: by mail-wr0-f174.google.com with SMTP id b65so29404863wrd.0 + for ; Wed, 16 Aug 2017 16:46:52 -0700 (PDT) +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20161025; + h=x-gm-message-state:from:to:subject:date:message-id:organization + :in-reply-to:references:mime-version:content-transfer-encoding; + bh=vOHtuq150Bi0dtLwrlvhmLXneJGQN+nwYPMD7ClfMTY=; + b=MDpKFUTuVW39/V5tI6WXpiuZNRgPorWVPEILVo6uTCaSPIWU4FPwx/FYFqYRnwLLZ4 + JwLB2+R6USx5jpbjlgx7GDEuCAAGm+GI7GtyLRb0tZZMtXW7glpa2IuqLPTtIygXQSn4 + nsSRysSlT02zZ26qbDXYeoWUOpn2CK2fmQ9l9q29GdTmC/+Ud4vfJqdW/nvnczqZVyyF + zUsQuOalp0VORBdSgDxDrtEA50pR+8TrnBu48u4OSigb4d6QgqZvPEYSPp7UWHmuEoBe + F92VN6efXYqb4tRUthsfokDw7l1TFhRB0g0UOl7BxXrRT54MGceiJ4fY8jVD+7+DN3aT + pD3g== +X-Gm-Message-State: AHYfb5gfW1I+uGmtawofLSI0ZX4ZfkMah5Eyn73zmN/CEJ0d9ZDOFpsR + Y4FpRIYROX0uhR9L +X-Received: by 10.28.11.131 with SMTP id 125mr45861wml.82.1502927211295; + Wed, 16 Aug 2017 16:46:51 -0700 (PDT) +Received: from lenovo.localnet ([2a02:8071:31c0:f00:626c:66ff:fe3f:93eb]) + by smtp.gmail.com with ESMTPSA id r70sm3132823wmb.35.2017.08.16.16.46.48 + for + (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); + Wed, 16 Aug 2017 16:46:49 -0700 (PDT) +From: Thomas Pfeiffer +To: informing about and discussing non-technical community topics + +Subject: Re: Telemetry Policy +Date: Thu, 17 Aug 2017 01:46:48 +0200 +Message-ID: <5231282.Ch11jfsTMl@lenovo> +Organization: KDE +In-Reply-To: +References: <2048912.XfIJe3ZSdj@vkpc5> <2990543.KVDkBByYO0@minixfox> + +MIME-Version: 1.0 +Content-Transfer-Encoding: 7Bit +Content-Type: text/plain; charset="us-ascii" +X-BeenThere: kde-community@kde.org +X-Mailman-Version: 2.1.16 +Precedence: list +Reply-To: informing about and discussing non-technical community topics + +List-Id: informing about and discussing non-technical community topics + +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Errors-To: kde-community-bounces@kde.org +Sender: "kde-community" + +On Mittwoch, 16. August 2017 09:33:02 CEST Valorie Zimmerman wrote: +> Hi all, Mozilla has done a lot of work on telemetry, and we might be +> able to use some of their findings. On this page: +> https://wiki.mozilla.org/Firefox/Data_Collection they break down the +> data they might possibly collect into four buckets - technical (such +> as crashes), user interaction, web activity, and sensitive (personal +> data). +> +> This bit might be relevant to our discussion: "Categories 1 & 2 +> (Technical & Interaction data) +> Pre-Release & Release: Data may default on, provided the data is +> exclusively in these categories (it cannot be in any other category). +> In Release, an opt-out must be available for most types of Technical +> and Interaction data. " +> +> I think the entire page might be enlightening to this discussion. I +> believe our analysis of needs should be more fine-grained, and that +> some parts of what we need can be "default on" especially for +> pre-release testing. For releases, we can provide an opt-out. + +Hi Valorie, +Even if opt-out for some data is legally and even morally fine, it does not +align with the values we communicate to our users: +Unlike Mozilla's Mission, our Vision mentions privacy explicitly, and we're +striving to make privacy our USP. + +Therefore I agree with others who replied in this thread: We should respect +privacy unnecessarily much rather than too little. + +In the end, of course, it's a matter of how we present this opt-in. If it's an +option buried in some settings dialog, we might as well not do it at all. + +If we, however - like Firefox does -, pfominently present that choice to users +the first time they run one of our applications or desktop environment and try +to make clear why that data collection is important for us, I don't see why we +could not convince a relevant number of users to opt in. +Sure, we'll get less data than with an opt-out scheme, but let's try it out +first before we go for the option that carries a significant PR risk. + +> Other more sensitive data will need to be opt-in. I think it's a +> mistake to treat all the data we might want all in the same way. + +Content (web activity for Mozilla) and personal information should not be opt- +anything but not collected at all. + +Cheers, +Thomas diff --git a/tests/threaddata/thread7 b/tests/threaddata/thread7 new file mode 100644 index 0000000..b751d60 --- /dev/null +++ b/tests/threaddata/thread7 @@ -0,0 +1,297 @@ +Return-Path: +Received: from imapb010.mykolab.com ([unix socket]) + by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; + Thu, 17 Aug 2017 17:40:53 +0200 +X-Sieve: CMU Sieve 2.4 +Received: from int-mx003.mykolab.com (unknown [10.9.13.3]) + by imapb010.mykolab.com (Postfix) with ESMTPS id 467271505D03E + for ; Thu, 17 Aug 2017 17:40:53 +0200 (CEST) +Received: from mx.kolabnow.com (unknown [10.9.4.3]) + by int-mx003.mykolab.com (Postfix) with ESMTPS id 2CC4FF16 + for ; Thu, 17 Aug 2017 17:40:53 +0200 (CEST) +X-Virus-Scanned: amavisd-new at mykolab.com +Authentication-Results: ext-mx-in003.mykolab.com (amavisd-new); + dkim=pass (1024-bit key) header.d=kde.org header.b=rysq5aPx; + dkim=fail (2048-bit key) reason="fail (message has been altered)" + header.d=gmail.com header.b=WiuysEuO +X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 +Received: from forward1-smtp.messagingengine.com (forward1-smtp.messagingengine.com [66.111.4.223]) + by ext-mx-in003.mykolab.com (Postfix) with ESMTPS id 9C4BA2EB8 + for ; Thu, 17 Aug 2017 17:39:23 +0200 (CEST) +Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) + by mailforward.nyi.internal (Postfix) with ESMTP id 5138E1453 + for ; Thu, 17 Aug 2017 11:39:22 -0400 (EDT) +Received: by mailredirect.nyi.internal (Postfix, from userid 501) + id 48C918E9B6; Thu, 17 Aug 2017 11:39:22 -0400 (EDT) +Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) + by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; + Thu, 17 Aug 2017 11:39:22 -0400 +X-Cyrus-Session-Id: sloti36d2t28-3156705-1502984362-2-3811956415179411272 +X-Sieve: CMU Sieve 3.0 +X-Spam-known-sender: no +X-Orig-Spam-score: 0.0 +X-Spam-hits: BAYES_00 -1.9, HTML_MESSAGE 0.001, RCVD_IN_DNSWL_MED -2.3, + RP_MATCHES_RCVD -0.001, SPF_PASS -0.001, LANGUAGES en, BAYES_USED global, + SA_VERSION 3.4.0 +X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='org', + MailFrom='org' +X-Spam-charsets: plain='us-ascii', html='us-ascii' +X-Attached: signature.asc +X-Resolved-to: chrigi_1@fastmail.fm +X-Delivered-to: chrigi_1@fastmail.fm +X-Mail-from: kde-community-bounces@kde.org +Received: from mx3 ([10.202.2.202]) + by compute1.internal (LMTPProxy); Thu, 17 Aug 2017 11:39:22 -0400 +Authentication-Results: mx3.messagingengine.com; + dkim=fail (message has been altered; 2048-bit rsa key sha256) header.d=gmail.com header.i=@gmail.com header.b=WiuysEuO; + dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=rysq5aPx; + dmarc=none (p=none;has-list-id=yes) header.from=kde.org; + spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org; + x-google-dkim=fail (message has been altered; 2048-bit rsa key) header.d=1e100.net header.i=@1e100.net header.b=eS2FiZD3 +Received-SPF: pass + (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) + receiver=mx3.messagingengine.com; + identity=mailfrom; + envelope-from="kde-community-bounces@kde.org"; + helo=postbox.kde.org; + client-ip=46.4.96.248 +Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by mx3.messagingengine.com (Postfix) with ESMTPS + for ; Thu, 17 Aug 2017 11:39:21 -0400 (EDT) +DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; + t=1502984359; bh=g7hsgd71OQgeOpLvXEjz16cF2X/6f5pmr2ujAF633tY=; + h=From:Date:Subject:In-Reply-To:To:References:Reply-To:List-Id: + List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: + From; + b=rysq5aPxwhI8i+Fx0jQHMx7aHC9RRMfjzmZTplBHjuND6qLLgZgMg2Tqpwgp1PnTR + zbpE07c5O50AqjjN74AqtaWdN7xCtsPb1taF9XjBDScI3wVcmiRZ5d88Sp9YI8rAzy + cY5uS6QDZfPt/BmonQqnc0oKpuuIlSp78R482qck= +X-Original-To: kde-community@kde.org +X-Remote-Delivered-To: kde-community@localhost.kde.org +Received-SPF: Pass (sender SPF authorized) identity=mailfrom; + client-ip=2a00:1450:400c:c0c::22a; helo=mail-wr0-x22a.google.com; + envelope-from=mirko.mb.boehm@gmail.com; receiver=kde-community@kde.org +Authentication-Results: postbox.kde.org; dkim=pass + reason="2048-bit key; unprotected key" + header.d=gmail.com header.i=@gmail.com header.b=WiuysEuO; + dkim-adsp=pass; dkim-atps=neutral +Received: from mail-wr0-x22a.google.com (mail-wr0-x22a.google.com + [IPv6:2a00:1450:400c:c0c::22a]) + by postbox.kde.org (Postfix) with ESMTPS id 6622AA028C; + Thu, 17 Aug 2017 15:38:56 +0000 (UTC) +Received: by mail-wr0-x22a.google.com with SMTP id b65so47289023wrd.0; + Thu, 17 Aug 2017 08:38:56 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; + h=sender:from:message-id:mime-version:date:subject:in-reply-to:to + :references; bh=yh4e0FfFAXMmAqoicYQa52CLKXFU6SJTKLd0PdPDxRM=; + b=WiuysEuO59GFkLy+fKRSFayTM8LXWK3dVaVHDKfsw/XM8YKcLalwNWGVU0tsaDl+7P + r5MMLidc6O0gJKGftMdhWrjeFGY0aE5F5+2NKN1oEb2INbB/DrS9KaCVy1SWvHVu8zOo + t13omoGW6RIs5lgWrTLR1iwcwtfkWwO/+Ndy16U3/eYJSXeUPWHsVSXP0UgIS6IANt58 + lNQhTgWBAJNViCxH/p5nIZYvLY5tGJPL6J46GaM7jUK4Ev6HUx4pUwGBsPB4hBezPm7h + mzA74izFW7jE6JklTciMAb0q7wEG15exVQbTEG54nvWMASrWx6mMAc+CWLh/T8vokpvT + Kvrw== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20161025; + h=x-gm-message-state:sender:from:message-id:mime-version:date:subject + :in-reply-to:to:references; + bh=yh4e0FfFAXMmAqoicYQa52CLKXFU6SJTKLd0PdPDxRM=; + b=eS2FiZD3QQ7P0mT2qKkYWf91vVTGXnIHKKzNdIJq+8JXN8WoXQ8IXmvQqSQFJa/w16 + m9I0Yko7iv/JDAa7YTeJraBfImv9weknM3zpUNan8SltCFNXO8f4yylP1rGLn0RWbQ3Q + 9NEpmYbS5dYQ79PMwy3zHxZEkUbsIFk8OlVSohdzpzGgtyU6nOjnBDULL14uHnouaz8+ + TDss7L/vKlmrWOYdH+R8peCkFI6p3C69wpAEyNPGBaGyCRC+pebx6GGDBR63DFnyP464 + VFQCUS4hPPTFaBPriqOF6xcWToacU40DVy3s2S/3EwHpUGWi+WMqQpPgqZYJh81unCDH + Hc7g== +X-Gm-Message-State: AHYfb5hHmIopTFINsSS7+92/GpIh2jJhvpwp/cI1ajaDE2GLp/oZ6V7N + CCtnx8PQ3oXGOEKCRT4= +X-Received: by 10.80.212.133 with SMTP id s5mr2195642edi.95.1502984335423; + Thu, 17 Aug 2017 08:38:55 -0700 (PDT) +Received: from ?IPv6:2a02:8109:a4bf:e114:30bf:9873:2660:a4a8? + ([2a02:8109:a4bf:e114:30bf:9873:2660:a4a8]) + by smtp.gmail.com with ESMTPSA id r29sm1790792edi.85.2017.08.17.08.38.52 + (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); + Thu, 17 Aug 2017 08:38:52 -0700 (PDT) +From: Mirko Boehm - KDE +Message-Id: +Content-Type: multipart/signed; + boundary="Apple-Mail=_1637D59B-BBA3-401E-A7A5-3514665481AD"; + protocol="application/pgp-signature"; micalg=pgp-sha1 +Mime-Version: 1.0 (Mac OS X Mail 10.3 \(3273\)) +Date: Thu, 17 Aug 2017 17:38:52 +0200 +Subject: Re: Telemetry Policy +In-Reply-To: <5231282.Ch11jfsTMl@lenovo> +To: informing about and discussing non-technical community topics + +References: <2048912.XfIJe3ZSdj@vkpc5> <2990543.KVDkBByYO0@minixfox> + + <5231282.Ch11jfsTMl@lenovo> +X-Mailer: Apple Mail (2.3273) +X-BeenThere: kde-community@kde.org +X-Mailman-Version: 2.1.16 +Precedence: list +Reply-To: informing about and discussing non-technical community topics + +List-Id: informing about and discussing non-technical community topics + +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Errors-To: kde-community-bounces@kde.org +Sender: "kde-community" + + +--Apple-Mail=_1637D59B-BBA3-401E-A7A5-3514665481AD +Content-Type: multipart/alternative; + boundary="Apple-Mail=_F49D9C7A-5DFA-4D78-8758-C0DB8C98E040" + + +--Apple-Mail=_F49D9C7A-5DFA-4D78-8758-C0DB8C98E040 +Content-Transfer-Encoding: quoted-printable +Content-Type: text/plain; + charset=us-ascii + +Hi, + +> On 17. Aug 2017, at 01:46, Thomas Pfeiffer = +wrote: +>=20 +> Hi Valorie, +> Even if opt-out for some data is legally and even morally fine, it = +does not +> align with the values we communicate to our users: +> Unlike Mozilla's Mission, our Vision mentions privacy explicitly, and = +we're +> striving to make privacy our USP. + +We seem to assume a contradiction between telemetry and privacy. I = +believe this is a knee-jerk reaction. We can implement telemetry in a = +way that privacy is not violated. In fact, I would say that it follows = +from our vision that we should do this. + +Cheers, + +Mirko. +-- +Mirko Boehm | mirko@kde.org | KDE e.V. +FSFE Fellowship Representative, FSFE Team Germany +Qt Certified Specialist and Trainer +Request a meeting: https://doodle.com/mirkoboehm + + +--Apple-Mail=_F49D9C7A-5DFA-4D78-8758-C0DB8C98E040 +Content-Transfer-Encoding: quoted-printable +Content-Type: text/html; + charset=us-ascii + +Hi, 

On 17. Aug 2017, at 01:46, = +Thomas Pfeiffer <thomas.pfeiffer@kde.org> wrote:

Hi = +Valorie,
Even if opt-out for some data is legally = +and even morally fine, it does not 
align with the values we communicate to our = +users:
Unlike Mozilla's Mission, our Vision = +mentions privacy explicitly, and we're 
striving to make privacy our USP.

We seem to = +assume a contradiction between telemetry and privacy. I believe this is = +a knee-jerk reaction. We can implement telemetry in a way that privacy = +is not violated. In fact, I would say that it follows from our vision = +that we should do this.

Cheers,

Mirko.
+
-- 
Mirko Boehm | mirko@kde.org | KDE e.V.
FSFE Fellowship Representative, FSFE Team Germany
Qt Certified Specialist and Trainer
Request a = +meeting: https://doodle.com/mirkoboehm
+
+ +
= + +--Apple-Mail=_F49D9C7A-5DFA-4D78-8758-C0DB8C98E040-- + +--Apple-Mail=_1637D59B-BBA3-401E-A7A5-3514665481AD +Content-Transfer-Encoding: 7bit +Content-Disposition: attachment; + filename=signature.asc +Content-Type: application/pgp-signature; + name=signature.asc +Content-Description: Message signed with OpenPGP + +-----BEGIN PGP SIGNATURE----- +Comment: GPGTools - http://gpgtools.org + +iEYEARECAAYFAlmVuIwACgkQYSSaITCTnKX82QCgxjyaXNsffHG/42ioAQrxjdCN +D4kAn2Vv0q16buzjcRel1P144tLyqbr+ +=muZP +-----END PGP SIGNATURE----- + +--Apple-Mail=_1637D59B-BBA3-401E-A7A5-3514665481AD-- diff --git a/tests/threaddata/thread8 b/tests/threaddata/thread8 new file mode 100644 index 0000000..b57daee --- /dev/null +++ b/tests/threaddata/thread8 @@ -0,0 +1,253 @@ +Return-Path: +Received: from imapb010.mykolab.com ([unix socket]) + by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; + Thu, 17 Aug 2017 18:40:51 +0200 +X-Sieve: CMU Sieve 2.4 +Received: from int-mx001.mykolab.com (unknown [10.9.13.1]) + by imapb010.mykolab.com (Postfix) with ESMTPS id A9D23150D1CA9 + for ; Thu, 17 Aug 2017 18:40:51 +0200 (CEST) +Received: from mx.kolabnow.com (unknown [10.9.4.1]) + by int-mx001.mykolab.com (Postfix) with ESMTPS id 8FACC185 + for ; Thu, 17 Aug 2017 18:40:51 +0200 (CEST) +X-Virus-Scanned: amavisd-new at mykolab.com +Authentication-Results: ext-mx-in001.mykolab.com (amavisd-new); + dkim=pass (1024-bit key) header.d=kde.org +X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 +Received: from forward1-smtp.messagingengine.com (forward1-smtp.messagingengine.com [66.111.4.223]) + by ext-mx-in001.mykolab.com (Postfix) with ESMTPS id 1B005169D + for ; Thu, 17 Aug 2017 18:20:40 +0200 (CEST) +Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) + by mailforward.nyi.internal (Postfix) with ESMTP id B9C0FFD6 + for ; Thu, 17 Aug 2017 12:20:39 -0400 (EDT) +Received: by mailredirect.nyi.internal (Postfix, from userid 501) + id A9EF58E9B6; Thu, 17 Aug 2017 12:20:39 -0400 (EDT) +Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) + by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; + Thu, 17 Aug 2017 12:20:39 -0400 +X-Cyrus-Session-Id: sloti36d2t28-3239059-1502986839-5-11465270081887081630 +X-Sieve: CMU Sieve 3.0 +X-Spam-known-sender: yes ("Address thomas.pfeiffer@kde.org in From header is in addressbook"); + in-addressbook +X-Orig-Spam-score: 0.0 +X-Spam-hits: BAYES_00 -1.9, HTML_MESSAGE 0.001, RCVD_IN_DNSWL_MED -2.3, + RCVD_IN_SORBS_SPAM 0.5, RP_MATCHES_RCVD -0.001, SPF_PASS -0.001, + LANGUAGES en, BAYES_USED global, SA_VERSION 3.4.0 +X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='org', + MailFrom='org' +X-Spam-charsets: plain='utf-8', html='utf-8' +X-Resolved-to: chrigi_1@fastmail.fm +X-Delivered-to: chrigi_1@fastmail.fm +X-Mail-from: kde-community-bounces@kde.org +Received: from mx3 ([10.202.2.202]) + by compute1.internal (LMTPProxy); Thu, 17 Aug 2017 12:20:39 -0400 +Authentication-Results: mx3.messagingengine.com; + dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=iaOusBVL; + dmarc=none (p=none;has-list-id=yes) header.from=kde.org; + spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org; + x-google-dkim=pass (2048-bit rsa key) header.d=1e100.net header.i=@1e100.net header.b=J3ZGQfFP +Received-SPF: pass + (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) + receiver=mx3.messagingengine.com; + identity=mailfrom; + envelope-from="kde-community-bounces@kde.org"; + helo=postbox.kde.org; + client-ip=46.4.96.248 +Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by mx3.messagingengine.com (Postfix) with ESMTPS + for ; Thu, 17 Aug 2017 12:20:38 -0400 (EDT) +DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; + t=1502986836; bh=NN9eLPZMdRJe0stu0TDb+ROhjuNPhd/mDnhblsQ4F04=; + h=From:Subject:Date:References:To:In-Reply-To:Reply-To:List-Id: + List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: + From; + b=iaOusBVLSdEJElb2uoxf5ubKrt5iXH5zKZqAsGo/Ltor16eJ57YIP6QGSNn+L7fCO + QHgR+fL1/OCWmfEs80xz7ycwjVTdHSt8a9nP7EwwLfQFJ3b1bCs8hNFyLpwrlzH87p + 6I1z36M4x53j3Yq7OU5DIWw7TieU2TaHCCClC1Cg= +X-Original-To: kde-community@kde.org +X-Remote-Delivered-To: kde-community@localhost.kde.org +Received-SPF: Pass (sender SPF authorized) identity=mailfrom; + client-ip=209.85.128.181; helo=mail-wr0-f181.google.com; + envelope-from=t.pfeiffer.ux@gmail.com; receiver=kde-community@kde.org +Received: from mail-wr0-f181.google.com (mail-wr0-f181.google.com + [209.85.128.181]) + by postbox.kde.org (Postfix) with ESMTPS id A2098A0194 + for ; Thu, 17 Aug 2017 16:20:19 +0000 (UTC) +Received: by mail-wr0-f181.google.com with SMTP id f8so3729162wrf.3 + for ; Thu, 17 Aug 2017 09:20:19 -0700 (PDT) +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20161025; + h=x-gm-message-state:from:mime-version:subject:date:references:to + :in-reply-to:message-id; + bh=wicjkfxhAhrD+Lja6y+RkFl7BL7WSAOVLHUYZTaQM+E=; + b=J3ZGQfFPOcZSNOlqbFSZ/oBBPQSnoMN2pIBb5YlfFBYeCY2Rt6Xx0X0S/wET6IAcE6 + ZILrUjwPh9q3Bjhx0x+CAGscD/sNJBosuBoVrE1ZFX2d8prqRz9D8fNeeCtuPnRgkDmm + EBW3JP5ifajIMbUnHPevV1W8er5VY1uqWW/z6lZu7iH1zabPs+5wS+X0M1xx71xBxTb1 + Dx4jpLO/SRNSEIKZ0q1l0p6f9/9P9VScWbyDw7NeI1yj0GfRhNSP64dlQU3Z07vqaoKP + vfhpG0gFX/FEr0+MPz2r10v6LP1iACBlhOHwHZxYLTz/mNwvHvsLB6JWFoZ0FuwLRQFN + X47g== +X-Gm-Message-State: AHYfb5hGX37YHJwSkL5Gin7U/eRe+E5RLYqxnYErKBibvkrRhrJDArNX + VyIneA7/u3wUDC0Wvl8= +X-Received: by 10.223.176.5 with SMTP id f5mr3522751wra.194.1502986818721; + Thu, 17 Aug 2017 09:20:18 -0700 (PDT) +Received: from [172.16.5.187] ([109.109.206.114]) + by smtp.gmail.com with ESMTPSA id 5sm4544042wre.5.2017.08.17.09.20.17 + for + (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); + Thu, 17 Aug 2017 09:20:17 -0700 (PDT) +From: Thomas Pfeiffer +Content-Type: multipart/alternative; + boundary="Apple-Mail=_AF2C4455-1CF7-489B-98CD-6BFD8687BF81" +Mime-Version: 1.0 (Mac OS X Mail 10.3 \(3273\)) +Subject: Re: Telemetry Policy +Date: Thu, 17 Aug 2017 18:20:16 +0200 +References: <2048912.XfIJe3ZSdj@vkpc5> <2990543.KVDkBByYO0@minixfox> + + <5231282.Ch11jfsTMl@lenovo> +To: informing about and discussing non-technical community topics + +In-Reply-To: +Message-Id: <5A696707-744C-4035-A8FA-CA83EE8691D6@kde.org> +X-Mailer: Apple Mail (2.3273) +X-BeenThere: kde-community@kde.org +X-Mailman-Version: 2.1.16 +Precedence: list +Reply-To: informing about and discussing non-technical community topics + +List-Id: informing about and discussing non-technical community topics + +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Errors-To: kde-community-bounces@kde.org +Sender: "kde-community" + + +--Apple-Mail=_AF2C4455-1CF7-489B-98CD-6BFD8687BF81 +Content-Transfer-Encoding: quoted-printable +Content-Type: text/plain; + charset=utf-8 + + +> On 17. Aug 2017, at 17:38, Mirko Boehm - KDE wrote: +>=20 +> Hi,=20 +>=20 +>> On 17. Aug 2017, at 01:46, Thomas Pfeiffer > wrote: +>>=20 +>> Hi Valorie, +>> Even if opt-out for some data is legally and even morally fine, it = +does not=20 +>> align with the values we communicate to our users: +>> Unlike Mozilla's Mission, our Vision mentions privacy explicitly, and = +we're=20 +>> striving to make privacy our USP. +>=20 +> We seem to assume a contradiction between telemetry and privacy. I = +believe this is a knee-jerk reaction. We can implement telemetry in a = +way that privacy is not violated. In fact, I would say that it follows = +from our vision that we should do this. +>=20 + +The problem is: I expect users to have the same knee-jerk reaction. I = +don=E2=80=99t see us being able to explain to users that actually their = +privacy is perfectly safe before they freak out. +Privacy-minded Free Software users have freaked out in the past over = +things which objectively speaking were not a huge deal. +It=E2=80=99s emotion more than rational arguments + + +--Apple-Mail=_AF2C4455-1CF7-489B-98CD-6BFD8687BF81 +Content-Transfer-Encoding: quoted-printable +Content-Type: text/html; + charset=utf-8 + +
On 17. Aug 2017, at 17:38, Mirko Boehm - KDE <mirko@kde.org> = +wrote:

Hi, 

On 17. Aug 2017, at 01:46, Thomas Pfeiffer = +<thomas.pfeiffer@kde.org> wrote:

Hi = +Valorie,
Even if opt-out for some data is legally = +and even morally fine, it does not 
align with the values we communicate to our = +users:
Unlike Mozilla's Mission, our Vision = +mentions privacy explicitly, and we're 
striving to make privacy our USP.

We = +seem to assume a contradiction between telemetry and privacy. I believe = +this is a knee-jerk reaction. We can implement telemetry in a way that = +privacy is not violated. In fact, I would say that it follows from our = +vision that we should do this.


The problem is: I expect users to have the same = +knee-jerk reaction. I don=E2=80=99t see us being able to explain to = +users that actually their privacy is perfectly safe before they freak = +out.
Privacy-minded Free Software users have freaked out in = +the past over things which objectively speaking were not a huge = +deal.
It=E2=80=99s emotion more than rational = +arguments

= + +--Apple-Mail=_AF2C4455-1CF7-489B-98CD-6BFD8687BF81-- diff --git a/tests/threaddata/thread9 b/tests/threaddata/thread9 new file mode 100644 index 0000000..c17e7fd --- /dev/null +++ b/tests/threaddata/thread9 @@ -0,0 +1,283 @@ +Return-Path: +Received: from imapb010.mykolab.com ([unix socket]) + by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; + Thu, 17 Aug 2017 18:30:41 +0200 +X-Sieve: CMU Sieve 2.4 +Received: from int-mx001.mykolab.com (unknown [10.9.13.1]) + by imapb010.mykolab.com (Postfix) with ESMTPS id 92811150C3DE0 + for ; Thu, 17 Aug 2017 18:30:41 +0200 (CEST) +Received: from mx.kolabnow.com (unknown [10.9.4.3]) + by int-mx001.mykolab.com (Postfix) with ESMTPS id 7973B11D + for ; Thu, 17 Aug 2017 18:30:41 +0200 (CEST) +X-Virus-Scanned: amavisd-new at mykolab.com +Authentication-Results: ext-mx-in003.mykolab.com (amavisd-new); + dkim=pass (1024-bit key) header.d=kde.org header.b=q4j4OOKP; + dkim=fail (2048-bit key) reason="fail (message has been altered)" + header.d=gmail.com header.b=DJRXq7Se +X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 +Received: from forward1-smtp.messagingengine.com (forward1-smtp.messagingengine.com [66.111.4.223]) + by ext-mx-in003.mykolab.com (Postfix) with ESMTPS id 3E01E292D + for ; Thu, 17 Aug 2017 18:30:29 +0200 (CEST) +Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) + by mailforward.nyi.internal (Postfix) with ESMTP id 89BC31A23 + for ; Thu, 17 Aug 2017 12:30:28 -0400 (EDT) +Received: by mailredirect.nyi.internal (Postfix, from userid 501) + id 6EC348E9B6; Thu, 17 Aug 2017 12:30:28 -0400 (EDT) +Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) + by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; + Thu, 17 Aug 2017 12:30:28 -0400 +X-Cyrus-Session-Id: sloti36d2t28-3239059-1502987428-2-12164706007640762698 +X-Sieve: CMU Sieve 3.0 +X-Spam-known-sender: no +X-Orig-Spam-score: 0.0 +X-Spam-hits: BAYES_00 -1.9, HTML_MESSAGE 0.001, RCVD_IN_DNSWL_MED -2.3, + RP_MATCHES_RCVD -0.001, SPF_PASS -0.001, LANGUAGES en, BAYES_USED global, + SA_VERSION 3.4.0 +X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='org', + MailFrom='org' +X-Spam-charsets: plain='UTF-8', html='UTF-8' +X-Resolved-to: chrigi_1@fastmail.fm +X-Delivered-to: chrigi_1@fastmail.fm +X-Mail-from: kde-community-bounces@kde.org +Received: from mx1 ([10.202.2.200]) + by compute1.internal (LMTPProxy); Thu, 17 Aug 2017 12:30:28 -0400 +Authentication-Results: mx1.messagingengine.com; + dkim=fail (message has been altered; 2048-bit rsa key sha256) header.d=gmail.com header.i=@gmail.com header.b=DJRXq7Se; + dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=q4j4OOKP; + dmarc=none (p=none;has-list-id=yes) header.from=kde.org; + spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org; + x-google-dkim=fail (message has been altered; 2048-bit rsa key) header.d=1e100.net header.i=@1e100.net header.b=U7Pdj/LB +Received-SPF: pass + (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) + receiver=mx1.messagingengine.com; + identity=mailfrom; + envelope-from="kde-community-bounces@kde.org"; + helo=postbox.kde.org; + client-ip=46.4.96.248 +Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by mx1.messagingengine.com (Postfix) with ESMTPS + for ; Thu, 17 Aug 2017 12:30:27 -0400 (EDT) +DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; + t=1502987424; bh=P5C3gzzCdP/NQgV0POjgD3g9Hpun4leANxLktFzWpbo=; + h=In-Reply-To:References:From:Date:Subject:To:Reply-To:List-Id: + List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: + From; + b=q4j4OOKPbM6MLGfTlM1WlnmVrh2PfQSKPYcLEoHUjBwoiu+oacbJb5cxmPkadvddx + MIYmJyog8F4NCNZCIi5vzNkit8vaUJgHws3pk+0uIFo9SdOBkFBfTXSGsDBWB2AdL5 + wryEwxZKOqEDcECpTNEEmQykU3MYwLBw7sD+KJjY= +X-Original-To: kde-community@kde.org +X-Remote-Delivered-To: kde-community@localhost.kde.org +Received-SPF: Pass (sender SPF authorized) identity=mailfrom; + client-ip=2607:f8b0:4003:c06::232; helo=mail-oi0-x232.google.com; + envelope-from=kexipl@gmail.com; receiver=kde-community@kde.org +Authentication-Results: postbox.kde.org; dkim=pass + reason="2048-bit key; unprotected key" + header.d=gmail.com header.i=@gmail.com header.b=DJRXq7Se; + dkim-adsp=pass; dkim-atps=neutral +Received: from mail-oi0-x232.google.com (mail-oi0-x232.google.com + [IPv6:2607:f8b0:4003:c06::232]) + by postbox.kde.org (Postfix) with ESMTPS id A4F67A014D + for ; Thu, 17 Aug 2017 16:30:09 +0000 (UTC) +Received: by mail-oi0-x232.google.com with SMTP id f11so71799456oic.0 + for ; Thu, 17 Aug 2017 09:30:09 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; + h=mime-version:sender:in-reply-to:references:from:date:message-id + :subject:to; bh=P5C3gzzCdP/NQgV0POjgD3g9Hpun4leANxLktFzWpbo=; + b=DJRXq7SewhEpbavrA6kFk0TPbF9526gl1WpH2O4R7hpuM5tJVqLoT4b53UfmZyGeDw + pSdW599ZTY3WLsK29IZ5buua1TgJeSLgN+PWKfTJAFW7qAZaJo6pRIpqSgETEEk/BdMc + KtqYdBD/IkwUVx5LAuQikyNn1HrKbti/tbc/YiI23f5TRxfIQZb7DOvOaAi1bZO8jEFq + 5EHEVcrjvIR2S4HHWxen9rZvGIotVN3womdK8b0t+Wx+Kt0qv06px9jNF0mTqLKhCJAz + los9Tpv/7RI0JiQyfPzl7kMQjU3i/pyA1u6b6t69ALfUQcjv25NcwhSaQbWIi9DN8rLg + Lc7g== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20161025; + h=x-gm-message-state:mime-version:sender:in-reply-to:references:from + :date:message-id:subject:to; + bh=P5C3gzzCdP/NQgV0POjgD3g9Hpun4leANxLktFzWpbo=; + b=U7Pdj/LBlwGbtXVpnpJudVk938b0fKTIRhK+Lc9IfB9zZhXh3FGwX5kWSUObEOT3hX + BXRk0cWvJYHpuGUnLXx/Wjen3j6283GHvDvPhfagyTZbGJohkRMEkxLwFh4ZsJ87M71t + pqLLayDjqDHj5jVuko5TDPTtRL8mjzPM7r0DQKu1GYkYtiNLE5JlGR9OsqK8ZH78Wkf8 + PWUT2BD+mkOE03gFEYpTA0oQW1iwv+wN5xySzaUOlBVfxUUx69EOLnFuRthkQHXcnlGG + rchW44D/eiSVU7JWK1Tk2IKNK+ERiq2/zftSmKRzpbwfv6D8De0PZOJPyi89kS9t2I2L + ar9g== +X-Gm-Message-State: AHYfb5g28N+JHV5G6R5j0X0hpMFpCnu/TuLNw/idrsMKyvGOUXdbQiIn + whIAqO9js0sL5H92k3yqqJIGhuicWA== +X-Received: by 10.202.108.130 with SMTP id h124mr8149045oic.289.1502987407944; + Thu, 17 Aug 2017 09:30:07 -0700 (PDT) +MIME-Version: 1.0 +Received: by 10.182.45.227 with HTTP; Thu, 17 Aug 2017 09:29:27 -0700 (PDT) +In-Reply-To: <5A696707-744C-4035-A8FA-CA83EE8691D6@kde.org> +References: <2048912.XfIJe3ZSdj@vkpc5> <2990543.KVDkBByYO0@minixfox> + + <5231282.Ch11jfsTMl@lenovo> + <5A696707-744C-4035-A8FA-CA83EE8691D6@kde.org> +From: Jaroslaw Staniek +Date: Thu, 17 Aug 2017 18:29:27 +0200 +X-Google-Sender-Auth: LxL4QEJfN3UTITM2I0VbgyX7420 +Message-ID: +Subject: Re: Telemetry Policy +To: informing about and discussing non-technical community topics + +Content-Type: multipart/alternative; boundary="001a1142e7548d73010556f58604" +X-BeenThere: kde-community@kde.org +X-Mailman-Version: 2.1.16 +Precedence: list +Reply-To: informing about and discussing non-technical community topics + +List-Id: informing about and discussing non-technical community topics + +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Errors-To: kde-community-bounces@kde.org +Sender: "kde-community" + +--001a1142e7548d73010556f58604 +Content-Type: text/plain; charset="UTF-8" +Content-Transfer-Encoding: quoted-printable + +On 17 August 2017 at 18:20, Thomas Pfeiffer wrote= +: + +> +> On 17. Aug 2017, at 17:38, Mirko Boehm - KDE wrote: +> +> Hi, +> +> On 17. Aug 2017, at 01:46, Thomas Pfeiffer +> wrote: +> +> Hi Valorie, +> Even if opt-out for some data is legally and even morally fine, it does n= +ot +> +> align with the values we communicate to our users: +> Unlike Mozilla's Mission, our Vision mentions privacy explicitly, and we'= +re +> +> striving to make privacy our USP. +> +> +> We seem to assume a contradiction between telemetry and privacy. I believ= +e +> this is a knee-jerk reaction. We can implement telemetry in a way that +> privacy is not violated. In fact, I would say that it follows from our +> vision that we should do this. +> +> +> The problem is: I expect users to have the same knee-jerk reaction. I +> don=E2=80=99t see us being able to explain to users that actually their p= +rivacy is +> perfectly safe before they freak out. +> Privacy-minded Free Software users have freaked out in the past over +> things which objectively speaking were not a huge deal. +> It=E2=80=99s emotion more than rational arguments +> +> +=E2=80=8BIt's hard to argue here or generalize to all app's communities. Kr= +ita +community for example is different than gcc community in these aspects. + +--=20 +regards, Jaroslaw Staniek + +KDE: +: A world-wide network of software engineers, artists, writers, translators +: and facilitators committed to Free Software development - http://kde.org +Calligra Suite: +: A graphic art and office suite - http://calligra.org +Kexi: +: A visual database apps builder - http://calligra.org/kexi +Qt Certified Specialist: +: http://www.linkedin.com/in/jstaniek + +--001a1142e7548d73010556f58604 +Content-Type: text/html; charset="UTF-8" +Content-Transfer-Encoding: quoted-printable + +


On 17 August 2017 at 18:20, Thomas Pfeiffer <t= +homas.pfeiffer@kde.org> wrote:

On 17. Aug 2017, at 17:38, Mirko Boehm - KDE <mirko@kde.org> wrote:= +

Hi,=C2=A0

On 17. Aug 2017, at 01:46, Thomas Pfeiffer <thomas.pfeiffer@kde.org= +> wrote:

Hi Valorie,
Even if opt-out for some data is legal= +ly and even morally fine, it does not=C2=A0
align with the values we communicate to our users:
Unlike Mozilla's Mission, our Visi= +on mentions privacy explicitly, and we're=C2=A0
striving to make privacy our USP.

We seem to assume a contradiction between telemetry an= +d privacy. I believe this is a knee-jerk reaction. We can implement telemet= +ry in a way that privacy is not violated. In fact, I would say that it foll= +ows from our vision that we should do this.


The problem is: I expect users to= + have the same knee-jerk reaction. I don=E2=80=99t see us being able to exp= +lain to users that actually their privacy is perfectly safe before they fre= +ak out.
Privacy-minded Free Software users have freaked out in th= +e past over things which objectively speaking were not a huge deal.
It=E2=80=99s emotion more than rational arguments


=E2=80=8BIt's hard to argue here or general= +ize to all app's communities. Krita community for example is different = +than gcc community in these aspects.

--
regards, Jaroslaw S= +taniek

KDE:
: A world-wide network of software engineers, artists= +, writers, translators
: and facilitators committed to Free Software dev= +elopment - http://kde.org<= +br>Calligra Suite:
: A graphic art and office suite - http://calligra.org
Kexi:
: A vis= +ual database apps builder - http://calligra.org/kexi
Qt Certified Specialist:
: http://www.lin= +kedin.com/in/jstaniek
+ + +--001a1142e7548d73010556f58604-- -- cgit v1.2.3 From c917543f0e37d423186dd10ccd7b8b80beb0cd16 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 18 Aug 2017 19:09:56 -0600 Subject: Say something if things are okay --- sinksh/syntax_modules/sink_inspect.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sinksh/syntax_modules/sink_inspect.cpp b/sinksh/syntax_modules/sink_inspect.cpp index 9cc3b23..da62250 100644 --- a/sinksh/syntax_modules/sink_inspect.cpp +++ b/sinksh/syntax_modules/sink_inspect.cpp @@ -110,6 +110,8 @@ bool inspect(const QStringList &args, State &state) //that no longer exist. if (!hash.isEmpty()) { qWarning() << "Have rids left: " << hash.size(); + } else if (!missing) { + qWarning() << "Everything is in order."; } return false; -- cgit v1.2.3 From 5ddfe22ebf43763bdf49e639ca9a403e34e84c22 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Tue, 22 Aug 2017 11:06:17 -0600 Subject: Ensure the copied enum matches --- common/store.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/common/store.cpp b/common/store.cpp index b0aac4c..1701a43 100644 --- a/common/store.cpp +++ b/common/store.cpp @@ -36,6 +36,17 @@ #include "storage.h" #include "log.h" +#define ASSERT_ENUMS_MATCH(A, B) Q_STATIC_ASSERT_X(static_cast(A) == static_cast(B), "The enum values must match"); + +//Ensure the copied enum matches +typedef ModelResult MailModelResult; +ASSERT_ENUMS_MATCH(Sink::Store::DomainObjectBaseRole, MailModelResult::DomainObjectBaseRole) +ASSERT_ENUMS_MATCH(Sink::Store::ChildrenFetchedRole, MailModelResult::ChildrenFetchedRole) +ASSERT_ENUMS_MATCH(Sink::Store::DomainObjectRole, MailModelResult::DomainObjectRole) +ASSERT_ENUMS_MATCH(Sink::Store::StatusRole, MailModelResult::StatusRole) +ASSERT_ENUMS_MATCH(Sink::Store::WarningRole, MailModelResult::WarningRole) +ASSERT_ENUMS_MATCH(Sink::Store::ProgressRole, MailModelResult::ProgressRole) + Q_DECLARE_METATYPE(QSharedPointer>) Q_DECLARE_METATYPE(QSharedPointer); Q_DECLARE_METATYPE(std::shared_ptr); -- cgit v1.2.3 From 8e14799f43ea51a6d9f195c56ca4f0c0439d4039 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Wed, 23 Aug 2017 21:07:32 -0600 Subject: The davresource has the contact.storage capability --- examples/davresource/davresource.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/davresource/davresource.cpp b/examples/davresource/davresource.cpp index 4e94046..22c502f 100644 --- a/examples/davresource/davresource.cpp +++ b/examples/davresource/davresource.cpp @@ -260,6 +260,7 @@ DavResourceFactory::DavResourceFactory(QObject *parent) : Sink::ResourceFactory(parent, {Sink::ApplicationDomain::ResourceCapabilities::Contact::contact, Sink::ApplicationDomain::ResourceCapabilities::Contact::addressbook, + Sink::ApplicationDomain::ResourceCapabilities::Contact::storage } ) { -- cgit v1.2.3 From ea75d4bdba79d2a879c2ed31564928d4ef3cd9b1 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 25 Aug 2017 18:21:15 -0600 Subject: Default to NoStatus for resources until we know more. This allows the aggregation to ignore resources where we don't have any status information yet, so the account doesn't always end up being offline. --- common/domain/applicationdomaintype.h | 4 +++- common/resourceaccess.cpp | 2 +- common/synchronizer.cpp | 2 +- tests/accountstest.cpp | 2 +- tests/resourceconfigtest.cpp | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/common/domain/applicationdomaintype.h b/common/domain/applicationdomaintype.h index 1250455..518f6d5 100644 --- a/common/domain/applicationdomaintype.h +++ b/common/domain/applicationdomaintype.h @@ -118,12 +118,14 @@ enum SINK_EXPORT SyncStatus { * The status of an account or resource. * * It is set as follows: - * * By default the status is offline. + * * By default the status is no status. + * * If a connection to the server failed the status is Offline. * * If a connection to the server could be established the status is Connected. * * If an error occurred that keeps the resource from operating (so non transient), the resource enters the error state. * * If a long running operation is started the resource goes to the busy state (and return to the previous state after that). */ enum SINK_EXPORT Status { + NoStatus, OfflineStatus, ConnectedStatus, BusyStatus, diff --git a/common/resourceaccess.cpp b/common/resourceaccess.cpp index 808d892..35fa46c 100644 --- a/common/resourceaccess.cpp +++ b/common/resourceaccess.cpp @@ -232,7 +232,7 @@ KAsync::Job ResourceAccess::Private::initializeSocket() ResourceAccess::ResourceAccess(const QByteArray &resourceInstanceIdentifier, const QByteArray &resourceType) : ResourceAccessInterface(), d(new Private(resourceType, resourceInstanceIdentifier, this)) { - mResourceStatus = Sink::ApplicationDomain::OfflineStatus; + mResourceStatus = Sink::ApplicationDomain::NoStatus; SinkTrace() << "Starting access"; } diff --git a/common/synchronizer.cpp b/common/synchronizer.cpp index d6b1c1f..b6e33d5 100644 --- a/common/synchronizer.cpp +++ b/common/synchronizer.cpp @@ -40,7 +40,7 @@ Synchronizer::Synchronizer(const Sink::ResourceContext &context) mSyncStorage(Sink::storageLocation(), mResourceContext.instanceId() + ".synchronization", Sink::Storage::DataStore::DataStore::ReadWrite), mSyncInProgress(false) { - mCurrentState.push(ApplicationDomain::Status::OfflineStatus); + mCurrentState.push(ApplicationDomain::Status::NoStatus); SinkTraceCtx(mLogCtx) << "Starting synchronizer: " << mResourceContext.resourceType << mResourceContext.instanceId(); } diff --git a/tests/accountstest.cpp b/tests/accountstest.cpp index 0ab18ef..cc67645 100644 --- a/tests/accountstest.cpp +++ b/tests/accountstest.cpp @@ -139,7 +139,7 @@ private slots: auto model = Sink::Store::loadModel(query); QTRY_COMPARE(model->rowCount(QModelIndex()), 1); auto account = model->data(model->index(0, 0, QModelIndex()), Sink::Store::DomainObjectRole).value(); - QCOMPARE(account->getStatus(), static_cast(Sink::ApplicationDomain::OfflineStatus)); + QCOMPARE(account->getStatus(), static_cast(Sink::ApplicationDomain::NoStatus)); //Synchronize to connect VERIFYEXEC(Sink::Store::synchronize(Query().resourceFilter(res.identifier()))); diff --git a/tests/resourceconfigtest.cpp b/tests/resourceconfigtest.cpp index df98a61..78a0d4c 100644 --- a/tests/resourceconfigtest.cpp +++ b/tests/resourceconfigtest.cpp @@ -91,7 +91,7 @@ private slots: auto model = Sink::Store::loadModel(query); QTRY_COMPARE(model->rowCount(QModelIndex()), 1); auto resource = model->data(model->index(0, 0, QModelIndex()), Sink::Store::DomainObjectRole).value(); - QCOMPARE(resource->getStatus(), static_cast(OfflineStatus)); + QCOMPARE(resource->getStatus(), static_cast(NoStatus)); //Synchronize to connect VERIFYEXEC(Sink::Store::synchronize(query)); -- cgit v1.2.3 From 7669eeecdd394e1dd9ee8c2fa06edb948a410f6b Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sat, 26 Aug 2017 09:32:23 -0600 Subject: Only return connected if there is any resource connected. --- common/resourcefacade.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/common/resourcefacade.cpp b/common/resourcefacade.cpp index dab6aed..829375c 100644 --- a/common/resourcefacade.cpp +++ b/common/resourcefacade.cpp @@ -391,7 +391,10 @@ QPair, typename Sink::ResultEmitter Date: Mon, 28 Aug 2017 17:19:51 -0600 Subject: Detect connection lost so we can go to offline state kimap should really have better error codes... --- common/domain/applicationdomaintype.h | 1 + common/synchronizer.cpp | 5 ++++- examples/imapresource/imapresource.cpp | 2 ++ examples/imapresource/imapserverproxy.cpp | 32 ++++++++++++++++--------------- examples/imapresource/imapserverproxy.h | 4 +++- 5 files changed, 27 insertions(+), 17 deletions(-) diff --git a/common/domain/applicationdomaintype.h b/common/domain/applicationdomaintype.h index 518f6d5..f7fd07e 100644 --- a/common/domain/applicationdomaintype.h +++ b/common/domain/applicationdomaintype.h @@ -101,6 +101,7 @@ enum SINK_EXPORT ErrorCode { LoginError, ConfigurationError, TransmissionError, + ConnectionLostError, }; enum SINK_EXPORT SuccessCode { diff --git a/common/synchronizer.cpp b/common/synchronizer.cpp index b6e33d5..46d3980 100644 --- a/common/synchronizer.cpp +++ b/common/synchronizer.cpp @@ -344,8 +344,11 @@ void Synchronizer::setStatusFromResult(const KAsync::Error &error, const QString } else if (error.errorCode == ApplicationDomain::LoginError) { //If we failed to login altough we could connect that indicates a problem with our setup. setStatus(ApplicationDomain::ErrorStatus, s, requestId); + } else if (error.errorCode == ApplicationDomain::ConnectionLostError) { + //We've lost the connection so we assume the connection to the server broke. + setStatus(ApplicationDomain::OfflineStatus, s, requestId); } - //We don't know what kind of error this was, so we assume it's transient and don't change ou status. + //We don't know what kind of error this was, so we assume it's transient and don't change our status. } else { //An operation against the server worked, so we're probably online. setStatus(ApplicationDomain::ConnectedStatus, s, requestId); diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 0c0c134..3ae7fd7 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -511,6 +511,8 @@ public: return {ApplicationDomain::LoginError, error.errorMessage}; case Imap::HostNotFoundError: return {ApplicationDomain::NoServerError, error.errorMessage}; + case Imap::ConnectionLost: + return {ApplicationDomain::ConnectionLostError, error.errorMessage}; default: return {ApplicationDomain::UnknownError, error.errorMessage}; } diff --git a/examples/imapresource/imapserverproxy.cpp b/examples/imapresource/imapserverproxy.cpp index 538105c..a0f0970 100644 --- a/examples/imapresource/imapserverproxy.cpp +++ b/examples/imapresource/imapserverproxy.cpp @@ -80,6 +80,21 @@ static KAsync::Job runJob(KJob *job, const std::function &f) }); } +static int translateImapError(int error) +{ + switch (error) { + case KJob::UserDefinedError: + return Imap::ConnectionLost; + case KIMAP2::LoginJob::ErrorCode::ERR_HOST_NOT_FOUND: + return Imap::HostNotFoundError; + case KIMAP2::LoginJob::ErrorCode::ERR_COULD_NOT_CONNECT: + return Imap::CouldNotConnectError; + case KIMAP2::LoginJob::ErrorCode::ERR_SSL_HANDSHAKE_FAILED: + return Imap::SslHandshakeError; + } + return Imap::UnknownError; +} + static KAsync::Job runJob(KJob *job) { return KAsync::start([job](KAsync::Future &future) { @@ -87,7 +102,8 @@ static KAsync::Job runJob(KJob *job) SinkTrace() << "Job done: " << job->metaObject()->className(); if (job->error()) { SinkWarning() << "Job failed: " << job->errorString() << job->metaObject()->className(); - future.setError(job->error(), job->errorString()); + auto proxyError = translateImapError(job->error()); + future.setError(proxyError, job->errorString()); } else { future.setFinished(); } @@ -166,20 +182,6 @@ KAsync::Job ImapServerProxy::login(const QString &username, const QString // SinkTrace() << "Found personal namespaces: " << mNamespaces.personal; // SinkTrace() << "Found shared namespaces: " << mNamespaces.shared; // SinkTrace() << "Found user namespaces: " << mNamespaces.user; - }).then([=] (const KAsync::Error &error) { - if (error) { - switch (error.errorCode) { - case KIMAP2::LoginJob::ErrorCode::ERR_HOST_NOT_FOUND: - return KAsync::error(HostNotFoundError, "Host not found: " + error.errorMessage); - case KIMAP2::LoginJob::ErrorCode::ERR_COULD_NOT_CONNECT: - return KAsync::error(CouldNotConnectError, "Failed to connect: " + error.errorMessage); - case KIMAP2::LoginJob::ErrorCode::ERR_SSL_HANDSHAKE_FAILED: - return KAsync::error(SslHandshakeError, "Ssl handshake failed: " + error.errorMessage); - default: - return KAsync::error(error); - } - } - return KAsync::null(); }); } diff --git a/examples/imapresource/imapserverproxy.h b/examples/imapresource/imapserverproxy.h index 82f4f58..f9b854b 100644 --- a/examples/imapresource/imapserverproxy.h +++ b/examples/imapresource/imapserverproxy.h @@ -33,7 +33,9 @@ enum ErrorCode { NoError, HostNotFoundError, CouldNotConnectError, - SslHandshakeError + SslHandshakeError, + ConnectionLost, + UnknownError }; namespace Flags -- cgit v1.2.3 From dd2d4263459c12b9ca65a23711f5f77fe34fef1b Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Mon, 28 Aug 2017 21:19:51 -0600 Subject: use Q_GLOBAL_STATIC In an attempt to resolve T6890. --- common/log.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common/log.cpp b/common/log.cpp index 5dfb872..3edc89a 100644 --- a/common/log.cpp +++ b/common/log.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -267,7 +266,7 @@ public: QSet mDebugAreas; }; -static auto sDebugAreaCollector = std::unique_ptr(new DebugAreaCollector); +Q_GLOBAL_STATIC(DebugAreaCollector, sDebugAreaCollector); QSet Sink::Log::debugAreas() { -- cgit v1.2.3 From be19bfef2d04943aa17b3f719f50f34f647c4eeb Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Mon, 28 Aug 2017 21:21:44 -0600 Subject: Translate the error in both runJob overloads. --- examples/imapresource/imapserverproxy.cpp | 33 ++++++++++++++++--------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/examples/imapresource/imapserverproxy.cpp b/examples/imapresource/imapserverproxy.cpp index a0f0970..5c2e07c 100644 --- a/examples/imapresource/imapserverproxy.cpp +++ b/examples/imapresource/imapserverproxy.cpp @@ -61,6 +61,21 @@ const char* Imap::Capabilities::Namespace = "NAMESPACE"; const char* Imap::Capabilities::Uidplus = "UIDPLUS"; const char* Imap::Capabilities::Condstore = "CONDSTORE"; +static int translateImapError(int error) +{ + switch (error) { + case KJob::UserDefinedError: + return Imap::ConnectionLost; + case KIMAP2::LoginJob::ErrorCode::ERR_HOST_NOT_FOUND: + return Imap::HostNotFoundError; + case KIMAP2::LoginJob::ErrorCode::ERR_COULD_NOT_CONNECT: + return Imap::CouldNotConnectError; + case KIMAP2::LoginJob::ErrorCode::ERR_SSL_HANDSHAKE_FAILED: + return Imap::SslHandshakeError; + } + return Imap::UnknownError; +} + template static KAsync::Job runJob(KJob *job, const std::function &f) { @@ -69,7 +84,8 @@ static KAsync::Job runJob(KJob *job, const std::function &f) SinkTrace() << "Job done: " << job->metaObject()->className(); if (job->error()) { SinkWarning() << "Job failed: " << job->errorString() << job->metaObject()->className(); - future.setError(job->error(), job->errorString()); + auto proxyError = translateImapError(job->error()); + future.setError(proxyError, job->errorString()); } else { future.setValue(f(job)); future.setFinished(); @@ -80,21 +96,6 @@ static KAsync::Job runJob(KJob *job, const std::function &f) }); } -static int translateImapError(int error) -{ - switch (error) { - case KJob::UserDefinedError: - return Imap::ConnectionLost; - case KIMAP2::LoginJob::ErrorCode::ERR_HOST_NOT_FOUND: - return Imap::HostNotFoundError; - case KIMAP2::LoginJob::ErrorCode::ERR_COULD_NOT_CONNECT: - return Imap::CouldNotConnectError; - case KIMAP2::LoginJob::ErrorCode::ERR_SSL_HANDSHAKE_FAILED: - return Imap::SslHandshakeError; - } - return Imap::UnknownError; -} - static KAsync::Job runJob(KJob *job) { return KAsync::start([job](KAsync::Future &future) { -- cgit v1.2.3 From d05f3be54f619575769eaf7f00edff9f99feb6f6 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Mon, 28 Aug 2017 21:39:07 -0600 Subject: Avoid use after destruction --- common/log.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/common/log.cpp b/common/log.cpp index 3edc89a..ac87c84 100644 --- a/common/log.cpp +++ b/common/log.cpp @@ -270,12 +270,17 @@ Q_GLOBAL_STATIC(DebugAreaCollector, sDebugAreaCollector); QSet Sink::Log::debugAreas() { - return sDebugAreaCollector->debugAreas(); + if (!sDebugAreaCollector.isDestroyed()) { + return sDebugAreaCollector->debugAreas(); + } + return {}; } static void collectDebugArea(const QString &debugArea) { - sDebugAreaCollector->add(debugArea); + if (!sDebugAreaCollector.isDestroyed()) { + sDebugAreaCollector->add(debugArea); + } } static bool containsItemStartingWith(const QByteArray &pattern, const QByteArrayList &list) -- cgit v1.2.3 From bbf14304d1112882c20f4ad3818712cdfecdedaa Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Tue, 29 Aug 2017 14:46:52 -0600 Subject: Bumped release number. --- dist/sink.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/sink.spec b/dist/sink.spec index 397e6fc..442c815 100644 --- a/dist/sink.spec +++ b/dist/sink.spec @@ -1,7 +1,7 @@ Name: sink Version: 0.4 -Release: 1%{?dist} +Release: 2%{?dist} Summary: sink Group: Applications/Desktop -- cgit v1.2.3 From 4a1bcc63cd2919f74f29b41c7b000f80da7449f4 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 31 Aug 2017 13:57:25 -0600 Subject: Avoid non threadsafe initialization. local static initialization is only threadsafe if initialized on construction. The other codepath is not threadsafe, but is only used in testcode. --- common/definitions.cpp | 18 +++++++++++++----- common/definitions.h | 8 +++++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/common/definitions.cpp b/common/definitions.cpp index 17977bc..ee18d52 100644 --- a/common/definitions.cpp +++ b/common/definitions.cpp @@ -39,11 +39,17 @@ QString Sink::storageLocation() return dataLocation() + "/storage"; } +static QString sinkLocation(QStandardPaths::StandardLocation location) +{ + return QStandardPaths::writableLocation(location) + "/sink"; +} + QString Sink::dataLocation() { - static QString location; + static QString location = sinkLocation(QStandardPaths::GenericDataLocation); + //Warning: This is not threadsafe, but clearLocationCache is only ever used in testcode. The initialization above is required to make at least the initialization threadsafe (relies on C++11 threadsafe initialization). if (rereadDataLocation) { - location = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/sink"; + location = sinkLocation(QStandardPaths::GenericDataLocation); rereadDataLocation = false; } return location; @@ -51,9 +57,10 @@ QString Sink::dataLocation() QString Sink::configLocation() { - static QString location; + static QString location = sinkLocation(QStandardPaths::GenericConfigLocation); + //Warning: This is not threadsafe, but clearLocationCache is only ever used in testcode. The initialization above is required to make at least the initialization threadsafe (relies on C++11 threadsafe initialization). if (rereadConfigLocation) { - location = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/sink"; + location = sinkLocation(QStandardPaths::GenericConfigLocation); rereadConfigLocation = false; } return location; @@ -61,8 +68,9 @@ QString Sink::configLocation() QString Sink::temporaryFileLocation() { - static QString location; + static QString location = dataLocation() + "/temporaryFiles"; static bool dirCreated = false; + //Warning: This is not threadsafe, but clearLocationCache is only ever used in testcode. The initialization above is required to make at least the initialization threadsafe (relies on C++11 threadsafe initialization). if (rereadTemporaryFileLocation) { location = dataLocation() + "/temporaryFiles"; dirCreated = QDir{}.mkpath(location); diff --git a/common/definitions.h b/common/definitions.h index ce9e794..7ef215b 100644 --- a/common/definitions.h +++ b/common/definitions.h @@ -25,10 +25,16 @@ #include namespace Sink { -void SINK_EXPORT clearLocationCache(); QString SINK_EXPORT storageLocation(); QString SINK_EXPORT dataLocation(); QString SINK_EXPORT configLocation(); QString SINK_EXPORT temporaryFileLocation(); QString SINK_EXPORT resourceStorageLocation(const QByteArray &resourceInstanceIdentifier); + +/** + * Clear the location cache and lookup locations again. + * + * Warning: Calling this results in non-threadsafe initialization, only use it in test-code. + */ +void SINK_EXPORT clearLocationCache(); } -- cgit v1.2.3 From 6bfcc22e08aebbabeac3e2ccb61556439d9f4b56 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 31 Aug 2017 14:06:33 -0600 Subject: Use Q_GLOBAL_STATIC for threadsafety. This resolves the following warning on shutdown it seems: "QObject::connect: No such signal QObject::aboutToClose() in ../../include/QtCore/5.9.1/QtCore/private/../../../../../src/corelib/io/qtextstream_p.h:75" --- common/log.cpp | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/common/log.cpp b/common/log.cpp index ac87c84..bfc9d5e 100644 --- a/common/log.cpp +++ b/common/log.cpp @@ -26,10 +26,13 @@ static QSettings &config() return *sSettings.localData(); } -static QByteArray sPrimaryComponent; +Q_GLOBAL_STATIC(QByteArray, sPrimaryComponent); + void Sink::Log::setPrimaryComponent(const QString &component) { - sPrimaryComponent = component.toUtf8(); + if (!sPrimaryComponent.isDestroyed()) { + *sPrimaryComponent = component.toUtf8(); + } } class DebugStream : public QIODevice @@ -322,13 +325,17 @@ static QByteArray getFileName(const char *file) static QString assembleDebugArea(const char *debugArea, const char *debugComponent, const char *file) { - if (sPrimaryComponent.isEmpty()) { - sPrimaryComponent = getProgramName(); + if (!sPrimaryComponent.isDestroyed() && sPrimaryComponent->isEmpty()) { + *sPrimaryComponent = getProgramName(); + } + if (!sPrimaryComponent.isDestroyed()) { + //Using stringbuilder for fewer allocations + return QLatin1String{*sPrimaryComponent} % QLatin1String{"."} % + (debugComponent ? (QLatin1String{debugComponent} + QLatin1String{"."}) : QLatin1String{""}) % + (debugArea ? QLatin1String{debugArea} : QLatin1String{getFileName(file)}); + } else { + return {}; } - //Using stringbuilder for fewer allocations - return QLatin1String{sPrimaryComponent} % QLatin1String{"."} % - (debugComponent ? (QLatin1String{debugComponent} + QLatin1String{"."}) : QLatin1String{""}) % - (debugArea ? QLatin1String{debugArea} : QLatin1String{getFileName(file)}); } static bool isFiltered(DebugLevel debugLevel, const QByteArray &fullDebugArea) @@ -350,14 +357,19 @@ bool Sink::Log::isFiltered(DebugLevel debugLevel, const char *debugArea, const c return isFiltered(debugLevel, assembleDebugArea(debugArea, debugComponent, file).toLatin1()); } +Q_GLOBAL_STATIC(NullStream, sNullStream); +Q_GLOBAL_STATIC(DebugStream, sDebugStream); + QDebug Sink::Log::debugStream(DebugLevel debugLevel, int line, const char *file, const char *function, const char *debugArea, const char *debugComponent) { const auto fullDebugArea = assembleDebugArea(debugArea, debugComponent, file); collectDebugArea(fullDebugArea); - static NullStream nullstream; if (isFiltered(debugLevel, fullDebugArea.toLatin1())) { - return QDebug(&nullstream); + if (!sNullStream.isDestroyed()) { + return QDebug(sNullStream); + } + return QDebug{QtDebugMsg}; } QString prefix; @@ -422,8 +434,10 @@ QDebug Sink::Log::debugStream(DebugLevel debugLevel, int line, const char *file, } output += ":"; - static DebugStream stream; - QDebug debug(&stream); + if (sDebugStream.isDestroyed()) { + return QDebug{QtDebugMsg}; + } + QDebug debug(sDebugStream); debug.noquote().nospace() << output; -- cgit v1.2.3 From f3eb97b9b4aabef41d8bc6514c74d85600e60d7f Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sat, 2 Sep 2017 15:59:51 -0600 Subject: Ensure we monitor resources for status changes that have been created after the query. This fixes status monitoring when creating a new account. --- common/resourcefacade.cpp | 48 +++++++++++++++++++++++++++++++++++------------ common/resourcefacade.h | 1 + tests/accountstest.cpp | 34 +++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/common/resourcefacade.cpp b/common/resourcefacade.cpp index 829375c..0687bbc 100644 --- a/common/resourcefacade.cpp +++ b/common/resourcefacade.cpp @@ -24,6 +24,7 @@ #include "store.h" #include "resourceaccess.h" #include "resource.h" +#include "facadefactory.h" using namespace Sink; @@ -358,27 +359,50 @@ QPair, typename Sink::ResultEmitter(query, mIdentifier, mTypeName, sConfigNotifier, ctx); auto monitoredResources = QSharedPointer>::create(); - runner->setStatusUpdater([runner, monitoredResources, ctx](ApplicationDomain::SinkAccount &account) { - Query query; + auto monitorResource = [monitoredResources, runner, ctx] (const QByteArray &accountIdentifier, const ApplicationDomain::SinkResource &resource, const ResourceAccess::Ptr &resourceAccess) { + if (!monitoredResources->contains(resource.identifier())) { + auto ret = QObject::connect(resourceAccess.data(), &ResourceAccess::notification, runner->guard(), [resource, runner, resourceAccess, accountIdentifier, ctx](const Notification ¬ification) { + SinkTraceCtx(ctx) << "Received notification in facade: " << notification.type; + if (notification.type == Notification::Status) { + runner->statusChanged(accountIdentifier); + } + }); + Q_ASSERT(ret); + monitoredResources->insert(resource.identifier()); + } + }; + runner->setStatusUpdater([this, runner, monitoredResources, ctx, monitorResource](ApplicationDomain::SinkAccount &account) { + Query query{Query::LiveQuery}; query.filter(account.identifier()); query.request() .request(); const auto resources = Store::read(query); SinkTraceCtx(ctx) << "Found resource belonging to the account " << account.identifier() << " : " << resources; auto accountIdentifier = account.identifier(); + + //Monitor for new resources so they can be monitored as well + if (!runner->mResourceEmitter.contains(accountIdentifier)) { + auto facade = Sink::FacadeFactory::instance().getFacade(); + Q_ASSERT(facade); + + auto emitter = facade->load(query, ctx).second; + emitter->onAdded([=](const ApplicationDomain::SinkResource::Ptr &resource) { + auto resourceAccess = Sink::ResourceAccessFactory::instance().getAccess(resource->identifier(), ResourceConfig::getResourceType(resource->identifier())); + monitorResource(accountIdentifier, *resource, resourceAccess); + }); + emitter->onModified([](const ApplicationDomain::SinkResource::Ptr &) {}); + emitter->onRemoved([](const ApplicationDomain::SinkResource::Ptr &) {}); + emitter->onInitialResultSetComplete([](const ApplicationDomain::SinkResource::Ptr &, bool) {}); + emitter->onComplete([]() {}); + emitter->fetch({}); + runner->mResourceEmitter[accountIdentifier] = emitter; + } + QList states; + //Gather all resources and ensure they are monitored for (const auto &resource : resources) { auto resourceAccess = ResourceAccessFactory::instance().getAccess(resource.identifier(), ResourceConfig::getResourceType(resource.identifier())); - if (!monitoredResources->contains(resource.identifier())) { - auto ret = QObject::connect(resourceAccess.data(), &ResourceAccess::notification, runner->guard(), [resource, runner, resourceAccess, accountIdentifier, ctx](const Notification ¬ification) { - SinkTraceCtx(ctx) << "Received notification in facade: " << notification.type; - if (notification.type == Notification::Status) { - runner->statusChanged(accountIdentifier); - } - }); - Q_ASSERT(ret); - monitoredResources->insert(resource.identifier()); - } + monitorResource(accountIdentifier, resource, resourceAccess); states << resourceAccess->getResourceStatus(); } const auto status = [&] { diff --git a/common/resourcefacade.h b/common/resourcefacade.h index 76fadce..36049c4 100644 --- a/common/resourcefacade.h +++ b/common/resourcefacade.h @@ -65,6 +65,7 @@ public: void setStatusUpdater(const std::function &); void statusChanged(const QByteArray &identifier); QObject *guard() const; + QMap > > > mResourceEmitter; private: void updateStatus(DomainType &entity); diff --git a/tests/accountstest.cpp b/tests/accountstest.cpp index cc67645..2eee9f9 100644 --- a/tests/accountstest.cpp +++ b/tests/accountstest.cpp @@ -148,6 +148,40 @@ private slots: } } + void testLoadAccountStatusLive() + { + using namespace Sink; + using namespace Sink::ApplicationDomain; + + { + //Create a live query for all accounts + Sink::Query query; + query.setFlags(Query::LiveQuery); + query.request(); + + auto model = Sink::Store::loadModel(query); + + //Create the account + auto account = ApplicationDomainType::createEntity(); + account.setAccountType("dummy"); + account.setName("name"); + VERIFYEXEC(Store::create(account)); + + auto res = Sink::ApplicationDomain::DummyResource::create(account.identifier()); + VERIFYEXEC(Sink::Store::create(res)); + + //Ensure the account was created + QTRY_COMPARE(model->rowCount(QModelIndex()), 1); + auto retrievedAccount = model->data(model->index(0, 0, QModelIndex()), Sink::Store::DomainObjectRole).value(); + QCOMPARE(retrievedAccount->getStatus(), static_cast(Sink::ApplicationDomain::NoStatus)); + + //Synchronize to connect and ensure we receive the update + VERIFYEXEC(Sink::Store::synchronize(Query().resourceFilter(res.identifier()))); + + QTRY_COMPARE_WITH_TIMEOUT(model->data(model->index(0, 0, QModelIndex()), Sink::Store::DomainObjectRole).value()->getStatus(), static_cast(Sink::ApplicationDomain::ConnectedStatus), 1000); + } + } + }; QTEST_GUILESS_MAIN(AccountsTest) -- cgit v1.2.3 From 32c507fa0565547a187632db8a80c07babb95d9d Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sat, 2 Sep 2017 16:00:46 -0600 Subject: Avoid hiding the index() function --- common/modelresult.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/common/modelresult.cpp b/common/modelresult.cpp index 58703ab..95f4643 100644 --- a/common/modelresult.cpp +++ b/common/modelresult.cpp @@ -298,16 +298,16 @@ void ModelResult::add(const Ptr &value) auto parent = createIndexFromId(id); SinkTraceCtx(mLogCtx) << "Added entity " << childId << "id: " << value->identifier() << "parent: " << id; const auto keys = mTree[id]; - int index = 0; - for (; index < keys.size(); index++) { - if (childId < keys.at(index)) { + int idx = 0; + for (; idx < keys.size(); idx++) { + if (childId < keys.at(idx)) { break; } } // SinkTraceCtx(mLogCtx) << "Inserting rows " << index << parent; - beginInsertRows(parent, index, index); + beginInsertRows(parent, idx, idx); mEntities.insert(childId, value); - mTree[id].insert(index, childId); + mTree[id].insert(idx, childId); mParents.insert(childId, id); endInsertRows(); // SinkTraceCtx(mLogCtx) << "Inserted rows " << mTree[id].size(); -- cgit v1.2.3 From a98311fbc807b83ecfc65a17f98464e5f1f9b3f8 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 7 Sep 2017 02:34:10 +0200 Subject: Fixed getUids by type filtering. We used to simply return all uids. Requires "sinksh upgrade" --- common/storage.h | 6 +++--- common/storage/entitystore.cpp | 6 +++--- common/storage_common.cpp | 12 ++++++------ tests/storagetest.cpp | 29 +++++++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/common/storage.h b/common/storage.h index 8c129df..c39b904 100644 --- a/common/storage.h +++ b/common/storage.h @@ -198,9 +198,9 @@ public: static QByteArray getTypeFromRevision(const Transaction &, qint64 revision); static void recordRevision(Transaction &, qint64 revision, const QByteArray &uid, const QByteArray &type); static void removeRevision(Transaction &, qint64 revision); - static void recordUid(DataStore::Transaction &transaction, const QByteArray &uid); - static void removeUid(DataStore::Transaction &transaction, const QByteArray &uid); - static void getUids(const Transaction &, const std::function &); + static void recordUid(DataStore::Transaction &transaction, const QByteArray &uid, const QByteArray &type); + static void removeUid(DataStore::Transaction &transaction, const QByteArray &uid, const QByteArray &type); + static void getUids(const QByteArray &type, const Transaction &, const std::function &); bool exists() const; diff --git a/common/storage/entitystore.cpp b/common/storage/entitystore.cpp index 1ac87b7..5514e31 100644 --- a/common/storage/entitystore.cpp +++ b/common/storage/entitystore.cpp @@ -267,7 +267,7 @@ bool EntityStore::add(const QByteArray &type, ApplicationDomain::ApplicationDoma [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Failed to write entity" << entity.identifier() << newRevision; }); DataStore::setMaxRevision(d->transaction, newRevision); DataStore::recordRevision(d->transaction, newRevision, entity.identifier(), type); - DataStore::recordUid(d->transaction, entity.identifier()); + DataStore::recordUid(d->transaction, entity.identifier(), type); SinkTraceCtx(d->logCtx) << "Wrote entity: " << entity.identifier() << type << newRevision; return true; } @@ -379,7 +379,7 @@ bool EntityStore::remove(const QByteArray &type, const Sink::ApplicationDomain:: [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Failed to write entity" << uid << newRevision; }); DataStore::setMaxRevision(d->transaction, newRevision); DataStore::recordRevision(d->transaction, newRevision, uid, type); - DataStore::removeUid(d->transaction, uid); + DataStore::removeUid(d->transaction, uid, type); return true; } @@ -638,7 +638,7 @@ ApplicationDomain::ApplicationDomainType EntityStore::readPrevious(const QByteAr void EntityStore::readAllUids(const QByteArray &type, const std::function callback) { - DataStore::getUids(d->getTransaction(), callback); + DataStore::getUids(type, d->getTransaction(), callback); } bool EntityStore::contains(const QByteArray &type, const QByteArray &uid) diff --git a/common/storage_common.cpp b/common/storage_common.cpp index 8603787..630dae9 100644 --- a/common/storage_common.cpp +++ b/common/storage_common.cpp @@ -156,19 +156,19 @@ void DataStore::removeRevision(DataStore::Transaction &transaction, qint64 revis transaction.openDatabase("revisionType").remove(QByteArray::number(revision)); } -void DataStore::recordUid(DataStore::Transaction &transaction, const QByteArray &uid) +void DataStore::recordUid(DataStore::Transaction &transaction, const QByteArray &uid, const QByteArray &type) { - transaction.openDatabase("uids").write(uid, ""); + transaction.openDatabase(type + "uids").write(uid, ""); } -void DataStore::removeUid(DataStore::Transaction &transaction, const QByteArray &uid) +void DataStore::removeUid(DataStore::Transaction &transaction, const QByteArray &uid, const QByteArray &type) { - transaction.openDatabase("uids").remove(uid); + transaction.openDatabase(type + "uids").remove(uid); } -void DataStore::getUids(const Transaction &transaction, const std::function &callback) +void DataStore::getUids(const QByteArray &type, const Transaction &transaction, const std::function &callback) { - transaction.openDatabase("uids").scan("", [&] (const QByteArray &key, const QByteArray &) { + transaction.openDatabase(type + "uids").scan("", [&] (const QByteArray &key, const QByteArray &) { callback(key); return true; }); diff --git a/tests/storagetest.cpp b/tests/storagetest.cpp index 9e9bad9..3368549 100644 --- a/tests/storagetest.cpp +++ b/tests/storagetest.cpp @@ -542,6 +542,35 @@ private slots: } } + + void testRecordUid() + { + Sink::Storage::DataStore store(testDataPath, dbName, Sink::Storage::DataStore::ReadWrite); + auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); + Sink::Storage::DataStore::recordUid(transaction, "uid1", "type"); + Sink::Storage::DataStore::recordUid(transaction, "uid2", "type"); + Sink::Storage::DataStore::recordUid(transaction, "uid3", "type2"); + + { + QVector uids; + Sink::Storage::DataStore::getUids("type", transaction, [&](const QByteArray &r) { + uids << r; + }); + QVector expected{{"uid1"}, {"uid2"}}; + QCOMPARE(uids, expected); + } + + Sink::Storage::DataStore::removeUid(transaction, "uid2", "type"); + + { + QVector uids; + Sink::Storage::DataStore::getUids("type", transaction, [&](const QByteArray &r) { + uids << r; + }); + QVector expected{{"uid1"}}; + QCOMPARE(uids, expected); + } + } }; QTEST_MAIN(StorageTest) -- cgit v1.2.3 From ebdb89b8bb482bbb5ecd544c3d38bef35fc7d820 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 7 Sep 2017 14:39:31 +0200 Subject: Release of 0.4.0 --- CMakeLists.txt | 2 +- dist/sink.spec | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f662234..210774f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.0) cmake_policy(SET CMP0048 NEW) cmake_policy(SET CMP0028 NEW) -project(sink VERSION 0.4) +project(sink VERSION 0.4.0) option(BUILD_MAILDIR "BUILD_MAILDIR" ON) option(BUILD_DAV "BUILD_DAV" ON) diff --git a/dist/sink.spec b/dist/sink.spec index 442c815..4a4f50a 100644 --- a/dist/sink.spec +++ b/dist/sink.spec @@ -1,7 +1,7 @@ Name: sink -Version: 0.4 -Release: 2%{?dist} +Version: 0.4.0 +Release: 0%{?dist} Summary: sink Group: Applications/Desktop @@ -17,7 +17,7 @@ BuildRequires: kasync-devel BuildRequires: kf5-kcoreaddons-devel BuildRequires: kf5-kcontacts-devel BuildRequires: kf5-kmime-devel -BuildRequires: kimap2-devel +BuildRequires: kimap2-devel >= 0.2 BuildRequires: kdav2-devel BuildRequires: libcurl-devel BuildRequires: libgit2-devel -- cgit v1.2.3