diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-09-13 12:42:31 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-09-13 12:42:31 +0200 |
commit | c12a9a09da59b9e418316dba02e6215cb55e47ee (patch) | |
tree | 05498d9a42e399bcca787f40c1fc473fb09e680e | |
parent | 55fe06979ceebe67553135b43aa47e70d931304b (diff) | |
parent | ebdb89b8bb482bbb5ecd544c3d38bef35fc7d820 (diff) | |
download | sink-0.4.0.tar.gz sink-0.4.0.zip |
Merge commit 'ebdb89b8bb482bbb5ecd544c3d38bef35fc7d820'v0.4.0
61 files changed, 2547 insertions, 186 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 6690c4c..210774f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.0) | |||
3 | cmake_policy(SET CMP0048 NEW) | 3 | cmake_policy(SET CMP0048 NEW) |
4 | cmake_policy(SET CMP0028 NEW) | 4 | cmake_policy(SET CMP0028 NEW) |
5 | 5 | ||
6 | project(sink VERSION 0.3.0) | 6 | project(sink VERSION 0.4.0) |
7 | 7 | ||
8 | option(BUILD_MAILDIR "BUILD_MAILDIR" ON) | 8 | option(BUILD_MAILDIR "BUILD_MAILDIR" ON) |
9 | option(BUILD_DAV "BUILD_DAV" ON) | 9 | option(BUILD_DAV "BUILD_DAV" ON) |
@@ -25,7 +25,12 @@ include(CMakePackageConfigHelpers) | |||
25 | include(ECMSetupVersion) | 25 | include(ECMSetupVersion) |
26 | include(KDEInstallDirs) | 26 | include(KDEInstallDirs) |
27 | 27 | ||
28 | find_package(Qt5 COMPONENTS REQUIRED Core Network Gui) | 28 | ecm_setup_version(PROJECT |
29 | SOVERSION sink_VERSION_MAJOR | ||
30 | VERSION_HEADER sink_version.h | ||
31 | ) | ||
32 | |||
33 | find_package(Qt5 COMPONENTS REQUIRED Core Concurrent Network Gui Test) | ||
29 | find_package(KF5 COMPONENTS REQUIRED Mime Contacts) | 34 | find_package(KF5 COMPONENTS REQUIRED Mime Contacts) |
30 | find_package(FlatBuffers REQUIRED 1.4.0) | 35 | find_package(FlatBuffers REQUIRED 1.4.0) |
31 | find_package(KAsync REQUIRED 0.1.2) | 36 | find_package(KAsync REQUIRED 0.1.2) |
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 | |||
26 | ${PC_LIBGIT2_LIBRARY_DIRS} | 26 | ${PC_LIBGIT2_LIBRARY_DIRS} |
27 | ) | 27 | ) |
28 | 28 | ||
29 | message("foo: ${LIBGIT2_INCLUDE_DIR} : ${PC_LIBGIT2_INCLUDEDIR} : ${PC_LIBGIT2_INCLUDE_DIRS}") | ||
30 | |||
31 | # get version from header, should work on windows, too | 29 | # get version from header, should work on windows, too |
32 | if(LIBGIT2_INCLUDE_DIR) | 30 | if(LIBGIT2_INCLUDE_DIR) |
33 | file(STRINGS "${LIBGIT2_INCLUDE_DIR}/git2/version.h" LIBGIT2_H REGEX "^#define LIBGIT2_VERSION \"[^\"]*\"$") | 31 | file(STRINGS "${LIBGIT2_INCLUDE_DIR}/git2/version.h" LIBGIT2_H REGEX "^#define LIBGIT2_VERSION \"[^\"]*\"$") |
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} | |||
116 | EXPORT_NAME ${PROJECT_NAME} | 116 | EXPORT_NAME ${PROJECT_NAME} |
117 | ) | 117 | ) |
118 | 118 | ||
119 | qt5_use_modules(${PROJECT_NAME} LINK_PUBLIC Network) | ||
120 | qt5_use_modules(${PROJECT_NAME} LINK_PRIVATE Gui) | ||
121 | target_link_libraries(${PROJECT_NAME} | 119 | target_link_libraries(${PROJECT_NAME} |
122 | PUBLIC | 120 | PUBLIC |
123 | KAsync | 121 | KAsync |
122 | Qt5::Network | ||
124 | PRIVATE | 123 | PRIVATE |
125 | ${storage_LIBS} | 124 | ${storage_LIBS} |
125 | Qt5::Gui | ||
126 | KF5::Mime | 126 | KF5::Mime |
127 | KF5::Contacts | 127 | KF5::Contacts |
128 | ) | 128 | ) |
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<T> run(const std::function<T()> &f, bool runAsync = true) | |||
31 | return KAsync::start<T>([f](KAsync::Future<T> &future) { | 31 | return KAsync::start<T>([f](KAsync::Future<T> &future) { |
32 | auto result = QtConcurrent::run(f); | 32 | auto result = QtConcurrent::run(f); |
33 | auto watcher = new QFutureWatcher<T>; | 33 | auto watcher = new QFutureWatcher<T>; |
34 | watcher->setFuture(result); | ||
35 | QObject::connect(watcher, &QFutureWatcher<T>::finished, watcher, [&future, watcher]() { | 34 | QObject::connect(watcher, &QFutureWatcher<T>::finished, watcher, [&future, watcher]() { |
36 | future.setValue(watcher->future().result()); | 35 | future.setValue(watcher->future().result()); |
37 | delete watcher; | 36 | delete watcher; |
38 | future.setFinished(); | 37 | future.setFinished(); |
39 | }); | 38 | }); |
39 | watcher->setFuture(result); | ||
40 | }); | 40 | }); |
41 | } else { | 41 | } else { |
42 | return KAsync::start<T>([f]() { | 42 | return KAsync::start<T>([f]() { |
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() | |||
39 | return dataLocation() + "/storage"; | 39 | return dataLocation() + "/storage"; |
40 | } | 40 | } |
41 | 41 | ||
42 | static QString sinkLocation(QStandardPaths::StandardLocation location) | ||
43 | { | ||
44 | return QStandardPaths::writableLocation(location) + "/sink"; | ||
45 | } | ||
46 | |||
42 | QString Sink::dataLocation() | 47 | QString Sink::dataLocation() |
43 | { | 48 | { |
44 | static QString location; | 49 | static QString location = sinkLocation(QStandardPaths::GenericDataLocation); |
50 | //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). | ||
45 | if (rereadDataLocation) { | 51 | if (rereadDataLocation) { |
46 | location = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/sink"; | 52 | location = sinkLocation(QStandardPaths::GenericDataLocation); |
47 | rereadDataLocation = false; | 53 | rereadDataLocation = false; |
48 | } | 54 | } |
49 | return location; | 55 | return location; |
@@ -51,9 +57,10 @@ QString Sink::dataLocation() | |||
51 | 57 | ||
52 | QString Sink::configLocation() | 58 | QString Sink::configLocation() |
53 | { | 59 | { |
54 | static QString location; | 60 | static QString location = sinkLocation(QStandardPaths::GenericConfigLocation); |
61 | //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). | ||
55 | if (rereadConfigLocation) { | 62 | if (rereadConfigLocation) { |
56 | location = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/sink"; | 63 | location = sinkLocation(QStandardPaths::GenericConfigLocation); |
57 | rereadConfigLocation = false; | 64 | rereadConfigLocation = false; |
58 | } | 65 | } |
59 | return location; | 66 | return location; |
@@ -61,8 +68,9 @@ QString Sink::configLocation() | |||
61 | 68 | ||
62 | QString Sink::temporaryFileLocation() | 69 | QString Sink::temporaryFileLocation() |
63 | { | 70 | { |
64 | static QString location; | 71 | static QString location = dataLocation() + "/temporaryFiles"; |
65 | static bool dirCreated = false; | 72 | static bool dirCreated = false; |
73 | //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). | ||
66 | if (rereadTemporaryFileLocation) { | 74 | if (rereadTemporaryFileLocation) { |
67 | location = dataLocation() + "/temporaryFiles"; | 75 | location = dataLocation() + "/temporaryFiles"; |
68 | dirCreated = QDir{}.mkpath(location); | 76 | 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 @@ | |||
25 | #include <QByteArray> | 25 | #include <QByteArray> |
26 | 26 | ||
27 | namespace Sink { | 27 | namespace Sink { |
28 | void SINK_EXPORT clearLocationCache(); | ||
29 | QString SINK_EXPORT storageLocation(); | 28 | QString SINK_EXPORT storageLocation(); |
30 | QString SINK_EXPORT dataLocation(); | 29 | QString SINK_EXPORT dataLocation(); |
31 | QString SINK_EXPORT configLocation(); | 30 | QString SINK_EXPORT configLocation(); |
32 | QString SINK_EXPORT temporaryFileLocation(); | 31 | QString SINK_EXPORT temporaryFileLocation(); |
33 | QString SINK_EXPORT resourceStorageLocation(const QByteArray &resourceInstanceIdentifier); | 32 | QString SINK_EXPORT resourceStorageLocation(const QByteArray &resourceInstanceIdentifier); |
33 | |||
34 | /** | ||
35 | * Clear the location cache and lookup locations again. | ||
36 | * | ||
37 | * Warning: Calling this results in non-threadsafe initialization, only use it in test-code. | ||
38 | */ | ||
39 | void SINK_EXPORT clearLocationCache(); | ||
34 | } | 40 | } |
diff --git a/common/domain/applicationdomaintype.cpp b/common/domain/applicationdomaintype.cpp index 3718f77..ee70c35 100644 --- a/common/domain/applicationdomaintype.cpp +++ b/common/domain/applicationdomaintype.cpp | |||
@@ -34,7 +34,13 @@ QDebug Sink::ApplicationDomain::operator<< (QDebug d, const Sink::ApplicationDom | |||
34 | QDebug Sink::ApplicationDomain::operator<< (QDebug d, const Sink::ApplicationDomain::ApplicationDomainType &type) | 34 | QDebug Sink::ApplicationDomain::operator<< (QDebug d, const Sink::ApplicationDomain::ApplicationDomainType &type) |
35 | { | 35 | { |
36 | d << "ApplicationDomainType(\n"; | 36 | d << "ApplicationDomainType(\n"; |
37 | auto properties = type.mAdaptor->availableProperties(); | 37 | auto properties = [&] { |
38 | if (!type.changedProperties().isEmpty()) { | ||
39 | return type.changedProperties(); | ||
40 | } else { | ||
41 | return type.mAdaptor->availableProperties(); | ||
42 | } | ||
43 | }(); | ||
38 | std::sort(properties.begin(), properties.end()); | 44 | std::sort(properties.begin(), properties.end()); |
39 | d << " " << "Id: " << "\t" << type.identifier() << "\n"; | 45 | d << " " << "Id: " << "\t" << type.identifier() << "\n"; |
40 | d << " " << "Resource: " << "\t" << type.resourceInstanceIdentifier() << "\n"; | 46 | d << " " << "Resource: " << "\t" << type.resourceInstanceIdentifier() << "\n"; |
@@ -216,8 +222,13 @@ QVariant ApplicationDomainType::getProperty(const QByteArray &key) const | |||
216 | void ApplicationDomainType::setProperty(const QByteArray &key, const QVariant &value) | 222 | void ApplicationDomainType::setProperty(const QByteArray &key, const QVariant &value) |
217 | { | 223 | { |
218 | Q_ASSERT(mAdaptor); | 224 | Q_ASSERT(mAdaptor); |
219 | mChangeSet->insert(key); | 225 | auto existing = mAdaptor->getProperty(key); |
220 | mAdaptor->setProperty(key, value); | 226 | if (existing.isValid() && existing == value) { |
227 | SinkTrace() << "Tried to set property that is still the same: " << key << value; | ||
228 | } else { | ||
229 | mChangeSet->insert(key); | ||
230 | mAdaptor->setProperty(key, value); | ||
231 | } | ||
221 | } | 232 | } |
222 | 233 | ||
223 | void ApplicationDomainType::setResource(const QByteArray &identifier) | 234 | void ApplicationDomainType::setResource(const QByteArray &identifier) |
diff --git a/common/domain/applicationdomaintype.h b/common/domain/applicationdomaintype.h index 602d54c..f7fd07e 100644 --- a/common/domain/applicationdomaintype.h +++ b/common/domain/applicationdomaintype.h | |||
@@ -101,6 +101,7 @@ enum SINK_EXPORT ErrorCode { | |||
101 | LoginError, | 101 | LoginError, |
102 | ConfigurationError, | 102 | ConfigurationError, |
103 | TransmissionError, | 103 | TransmissionError, |
104 | ConnectionLostError, | ||
104 | }; | 105 | }; |
105 | 106 | ||
106 | enum SINK_EXPORT SuccessCode { | 107 | enum SINK_EXPORT SuccessCode { |
@@ -118,12 +119,14 @@ enum SINK_EXPORT SyncStatus { | |||
118 | * The status of an account or resource. | 119 | * The status of an account or resource. |
119 | * | 120 | * |
120 | * It is set as follows: | 121 | * It is set as follows: |
121 | * * By default the status is offline. | 122 | * * By default the status is no status. |
123 | * * If a connection to the server failed the status is Offline. | ||
122 | * * If a connection to the server could be established the status is Connected. | 124 | * * If a connection to the server could be established the status is Connected. |
123 | * * If an error occurred that keeps the resource from operating (so non transient), the resource enters the error state. | 125 | * * If an error occurred that keeps the resource from operating (so non transient), the resource enters the error state. |
124 | * * If a long running operation is started the resource goes to the busy state (and return to the previous state after that). | 126 | * * If a long running operation is started the resource goes to the busy state (and return to the previous state after that). |
125 | */ | 127 | */ |
126 | enum SINK_EXPORT Status { | 128 | enum SINK_EXPORT Status { |
129 | NoStatus, | ||
127 | OfflineStatus, | 130 | OfflineStatus, |
128 | ConnectedStatus, | 131 | ConnectedStatus, |
129 | BusyStatus, | 132 | BusyStatus, |
@@ -270,7 +273,17 @@ public: | |||
270 | bool hasProperty(const QByteArray &key) const; | 273 | bool hasProperty(const QByteArray &key) const; |
271 | 274 | ||
272 | QVariant getProperty(const QByteArray &key) const; | 275 | QVariant getProperty(const QByteArray &key) const; |
276 | |||
277 | /** | ||
278 | * Set a property and record a changed property | ||
279 | * | ||
280 | * If the propery is available and did not change the call will be ignored. | ||
281 | */ | ||
273 | void setProperty(const QByteArray &key, const QVariant &value); | 282 | void setProperty(const QByteArray &key, const QVariant &value); |
283 | |||
284 | /** | ||
285 | * Convenience method to set a reference property. | ||
286 | */ | ||
274 | void setProperty(const QByteArray &key, const ApplicationDomainType &value); | 287 | void setProperty(const QByteArray &key, const ApplicationDomainType &value); |
275 | 288 | ||
276 | QByteArray getBlobProperty(const QByteArray &key) const; | 289 | QByteArray getBlobProperty(const QByteArray &key) const; |
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 { | |||
45 | } else { | 45 | } else { |
46 | Q_ASSERT(false); | 46 | Q_ASSERT(false); |
47 | } | 47 | } |
48 | //Silence compiler warning | ||
49 | return Func<Sink::ApplicationDomain::Mail>{}(std::forward<Args...>(args...)); | ||
48 | } | 50 | } |
49 | }; | 51 | }; |
diff --git a/common/log.cpp b/common/log.cpp index 5dfb872..bfc9d5e 100644 --- a/common/log.cpp +++ b/common/log.cpp | |||
@@ -10,7 +10,6 @@ | |||
10 | #include <QMutexLocker> | 10 | #include <QMutexLocker> |
11 | #include <iostream> | 11 | #include <iostream> |
12 | #include <unistd.h> | 12 | #include <unistd.h> |
13 | #include <memory> | ||
14 | #include <atomic> | 13 | #include <atomic> |
15 | #include <definitions.h> | 14 | #include <definitions.h> |
16 | #include <QThreadStorage> | 15 | #include <QThreadStorage> |
@@ -27,10 +26,13 @@ static QSettings &config() | |||
27 | return *sSettings.localData(); | 26 | return *sSettings.localData(); |
28 | } | 27 | } |
29 | 28 | ||
30 | static QByteArray sPrimaryComponent; | 29 | Q_GLOBAL_STATIC(QByteArray, sPrimaryComponent); |
30 | |||
31 | void Sink::Log::setPrimaryComponent(const QString &component) | 31 | void Sink::Log::setPrimaryComponent(const QString &component) |
32 | { | 32 | { |
33 | sPrimaryComponent = component.toUtf8(); | 33 | if (!sPrimaryComponent.isDestroyed()) { |
34 | *sPrimaryComponent = component.toUtf8(); | ||
35 | } | ||
34 | } | 36 | } |
35 | 37 | ||
36 | class DebugStream : public QIODevice | 38 | class DebugStream : public QIODevice |
@@ -267,16 +269,21 @@ public: | |||
267 | QSet<QString> mDebugAreas; | 269 | QSet<QString> mDebugAreas; |
268 | }; | 270 | }; |
269 | 271 | ||
270 | static auto sDebugAreaCollector = std::unique_ptr<DebugAreaCollector>(new DebugAreaCollector); | 272 | Q_GLOBAL_STATIC(DebugAreaCollector, sDebugAreaCollector); |
271 | 273 | ||
272 | QSet<QString> Sink::Log::debugAreas() | 274 | QSet<QString> Sink::Log::debugAreas() |
273 | { | 275 | { |
274 | return sDebugAreaCollector->debugAreas(); | 276 | if (!sDebugAreaCollector.isDestroyed()) { |
277 | return sDebugAreaCollector->debugAreas(); | ||
278 | } | ||
279 | return {}; | ||
275 | } | 280 | } |
276 | 281 | ||
277 | static void collectDebugArea(const QString &debugArea) | 282 | static void collectDebugArea(const QString &debugArea) |
278 | { | 283 | { |
279 | sDebugAreaCollector->add(debugArea); | 284 | if (!sDebugAreaCollector.isDestroyed()) { |
285 | sDebugAreaCollector->add(debugArea); | ||
286 | } | ||
280 | } | 287 | } |
281 | 288 | ||
282 | static bool containsItemStartingWith(const QByteArray &pattern, const QByteArrayList &list) | 289 | static bool containsItemStartingWith(const QByteArray &pattern, const QByteArrayList &list) |
@@ -318,13 +325,17 @@ static QByteArray getFileName(const char *file) | |||
318 | 325 | ||
319 | static QString assembleDebugArea(const char *debugArea, const char *debugComponent, const char *file) | 326 | static QString assembleDebugArea(const char *debugArea, const char *debugComponent, const char *file) |
320 | { | 327 | { |
321 | if (sPrimaryComponent.isEmpty()) { | 328 | if (!sPrimaryComponent.isDestroyed() && sPrimaryComponent->isEmpty()) { |
322 | sPrimaryComponent = getProgramName(); | 329 | *sPrimaryComponent = getProgramName(); |
330 | } | ||
331 | if (!sPrimaryComponent.isDestroyed()) { | ||
332 | //Using stringbuilder for fewer allocations | ||
333 | return QLatin1String{*sPrimaryComponent} % QLatin1String{"."} % | ||
334 | (debugComponent ? (QLatin1String{debugComponent} + QLatin1String{"."}) : QLatin1String{""}) % | ||
335 | (debugArea ? QLatin1String{debugArea} : QLatin1String{getFileName(file)}); | ||
336 | } else { | ||
337 | return {}; | ||
323 | } | 338 | } |
324 | //Using stringbuilder for fewer allocations | ||
325 | return QLatin1String{sPrimaryComponent} % QLatin1String{"."} % | ||
326 | (debugComponent ? (QLatin1String{debugComponent} + QLatin1String{"."}) : QLatin1String{""}) % | ||
327 | (debugArea ? QLatin1String{debugArea} : QLatin1String{getFileName(file)}); | ||
328 | } | 339 | } |
329 | 340 | ||
330 | static bool isFiltered(DebugLevel debugLevel, const QByteArray &fullDebugArea) | 341 | static bool isFiltered(DebugLevel debugLevel, const QByteArray &fullDebugArea) |
@@ -346,14 +357,19 @@ bool Sink::Log::isFiltered(DebugLevel debugLevel, const char *debugArea, const c | |||
346 | return isFiltered(debugLevel, assembleDebugArea(debugArea, debugComponent, file).toLatin1()); | 357 | return isFiltered(debugLevel, assembleDebugArea(debugArea, debugComponent, file).toLatin1()); |
347 | } | 358 | } |
348 | 359 | ||
360 | Q_GLOBAL_STATIC(NullStream, sNullStream); | ||
361 | Q_GLOBAL_STATIC(DebugStream, sDebugStream); | ||
362 | |||
349 | QDebug Sink::Log::debugStream(DebugLevel debugLevel, int line, const char *file, const char *function, const char *debugArea, const char *debugComponent) | 363 | QDebug Sink::Log::debugStream(DebugLevel debugLevel, int line, const char *file, const char *function, const char *debugArea, const char *debugComponent) |
350 | { | 364 | { |
351 | const auto fullDebugArea = assembleDebugArea(debugArea, debugComponent, file); | 365 | const auto fullDebugArea = assembleDebugArea(debugArea, debugComponent, file); |
352 | collectDebugArea(fullDebugArea); | 366 | collectDebugArea(fullDebugArea); |
353 | 367 | ||
354 | static NullStream nullstream; | ||
355 | if (isFiltered(debugLevel, fullDebugArea.toLatin1())) { | 368 | if (isFiltered(debugLevel, fullDebugArea.toLatin1())) { |
356 | return QDebug(&nullstream); | 369 | if (!sNullStream.isDestroyed()) { |
370 | return QDebug(sNullStream); | ||
371 | } | ||
372 | return QDebug{QtDebugMsg}; | ||
357 | } | 373 | } |
358 | 374 | ||
359 | QString prefix; | 375 | QString prefix; |
@@ -418,8 +434,10 @@ QDebug Sink::Log::debugStream(DebugLevel debugLevel, int line, const char *file, | |||
418 | } | 434 | } |
419 | output += ":"; | 435 | output += ":"; |
420 | 436 | ||
421 | static DebugStream stream; | 437 | if (sDebugStream.isDestroyed()) { |
422 | QDebug debug(&stream); | 438 | return QDebug{QtDebugMsg}; |
439 | } | ||
440 | QDebug debug(sDebugStream); | ||
423 | 441 | ||
424 | debug.noquote().nospace() << output; | 442 | debug.noquote().nospace() << output; |
425 | 443 | ||
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 | |||
34 | 34 | ||
35 | QVector<QByteArray> thread; | 35 | QVector<QByteArray> thread; |
36 | 36 | ||
37 | //a child already registered our thread. | 37 | //check if a child already registered our thread. |
38 | thread = index().secondaryLookup<Mail::MessageId, Mail::ThreadId>(messageId); | 38 | thread = index().secondaryLookup<Mail::MessageId, Mail::ThreadId>(messageId); |
39 | 39 | ||
40 | if (!thread.isEmpty()) { | ||
41 | //A child already registered our thread so we merge the childs thread | ||
42 | //* check if we have a parent thread, if not just continue as usual | ||
43 | //* get all messages that have the same threadid as the child | ||
44 | //* switch all to the parents thread | ||
45 | auto parentThread = index().secondaryLookup<Mail::MessageId, Mail::ThreadId>(parentMessageId); | ||
46 | if (!parentThread.isEmpty()) { | ||
47 | auto childThreadId = thread.first(); | ||
48 | auto parentThreadId = parentThread.first(); | ||
49 | SinkTrace() << "Merging child thread: " << childThreadId << " into parent thread: " << parentThreadId; | ||
50 | |||
51 | //Ensure this mail ends up in the correct thread | ||
52 | index().unindex<Mail::MessageId, Mail::ThreadId>(messageId, childThreadId, transaction); | ||
53 | //We have to copy the id here, otherwise it doesn't survive the subsequent writes | ||
54 | thread = QVector<QByteArray>() << QByteArray{parentThreadId.data(), parentThreadId.size()}; | ||
55 | |||
56 | //Merge all child messages into the correct thread | ||
57 | auto childThreadMessageIds = index().secondaryLookup<Mail::ThreadId, Mail::MessageId>(childThreadId); | ||
58 | for (const auto &msgId : childThreadMessageIds) { | ||
59 | SinkTrace() << "Merging child message: " << msgId; | ||
60 | index().unindex<Mail::MessageId, Mail::ThreadId>(msgId, childThreadId, transaction); | ||
61 | index().unindex<Mail::ThreadId, Mail::MessageId>(childThreadId, msgId, transaction); | ||
62 | index().index<Mail::MessageId, Mail::ThreadId>(msgId, parentThreadId, transaction); | ||
63 | index().index<Mail::ThreadId, Mail::MessageId>(parentThreadId, msgId, transaction); | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | |||
40 | //If parent is already available, add to thread of parent | 68 | //If parent is already available, add to thread of parent |
41 | if (thread.isEmpty() && parentMessageId.isValid()) { | 69 | if (thread.isEmpty() && parentMessageId.isValid()) { |
42 | thread = index().secondaryLookup<Mail::MessageId, Mail::ThreadId>(parentMessageId); | 70 | thread = index().secondaryLookup<Mail::MessageId, Mail::ThreadId>(parentMessageId); |
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: | |||
104 | mail.setExtractedBcc(getContactList(msg->bcc(true))); | 104 | mail.setExtractedBcc(getContactList(msg->bcc(true))); |
105 | mail.setExtractedDate(msg->date(true)->dateTime()); | 105 | mail.setExtractedDate(msg->date(true)->dateTime()); |
106 | 106 | ||
107 | //The rest should never change, unless we didn't have the headers available initially. | ||
108 | auto messageId = msg->messageID(true)->identifier(); | ||
109 | |||
110 | //Ensure the mssageId is unique. | 107 | //Ensure the mssageId is unique. |
111 | //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. | 108 | //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. |
112 | 109 | ||
@@ -125,12 +122,21 @@ static void updatedIndexedProperties(Sink::ApplicationDomain::Mail &mail, KMime: | |||
125 | parentMessageId = inReplyTo.first(); | 122 | parentMessageId = inReplyTo.first(); |
126 | } | 123 | } |
127 | } | 124 | } |
125 | |||
126 | //The rest should never change, unless we didn't have the headers available initially. | ||
127 | auto messageId = msg->messageID(true)->identifier(); | ||
128 | if (messageId.isEmpty()) { | 128 | if (messageId.isEmpty()) { |
129 | auto tmp = KMime::Message::Ptr::create(); | 129 | //reuse an existing messageis (on modification) |
130 | auto header = tmp->messageID(true); | 130 | auto existing = mail.getMessageId(); |
131 | header->generate("kube.kde.org"); | 131 | if (existing.isEmpty()) { |
132 | messageId = header->as7BitString(); | 132 | auto tmp = KMime::Message::Ptr::create(); |
133 | SinkWarning() << "Message id is empty, generating one: " << messageId; | 133 | auto header = tmp->messageID(true); |
134 | header->generate("kube.kde.org"); | ||
135 | messageId = header->as7BitString(); | ||
136 | SinkWarning() << "Message id is empty, generating one: " << messageId; | ||
137 | } else { | ||
138 | messageId = existing; | ||
139 | } | ||
134 | } | 140 | } |
135 | 141 | ||
136 | mail.setExtractedMessageId(messageId); | 142 | mail.setExtractedMessageId(messageId); |
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<T, Ptr>::add(const Ptr &value) | |||
298 | auto parent = createIndexFromId(id); | 298 | auto parent = createIndexFromId(id); |
299 | SinkTraceCtx(mLogCtx) << "Added entity " << childId << "id: " << value->identifier() << "parent: " << id; | 299 | SinkTraceCtx(mLogCtx) << "Added entity " << childId << "id: " << value->identifier() << "parent: " << id; |
300 | const auto keys = mTree[id]; | 300 | const auto keys = mTree[id]; |
301 | int index = 0; | 301 | int idx = 0; |
302 | for (; index < keys.size(); index++) { | 302 | for (; idx < keys.size(); idx++) { |
303 | if (childId < keys.at(index)) { | 303 | if (childId < keys.at(idx)) { |
304 | break; | 304 | break; |
305 | } | 305 | } |
306 | } | 306 | } |
307 | // SinkTraceCtx(mLogCtx) << "Inserting rows " << index << parent; | 307 | // SinkTraceCtx(mLogCtx) << "Inserting rows " << index << parent; |
308 | beginInsertRows(parent, index, index); | 308 | beginInsertRows(parent, idx, idx); |
309 | mEntities.insert(childId, value); | 309 | mEntities.insert(childId, value); |
310 | mTree[id].insert(index, childId); | 310 | mTree[id].insert(idx, childId); |
311 | mParents.insert(childId, id); | 311 | mParents.insert(childId, id); |
312 | endInsertRows(); | 312 | endInsertRows(); |
313 | // SinkTraceCtx(mLogCtx) << "Inserted rows " << mTree[id].size(); | 313 | // SinkTraceCtx(mLogCtx) << "Inserted rows " << mTree[id].size(); |
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) | |||
48 | 48 | ||
49 | QDebug operator<<(QDebug dbg, const Sink::Notification &n) | 49 | QDebug operator<<(QDebug dbg, const Sink::Notification &n) |
50 | { | 50 | { |
51 | dbg << "Notification(Type:" << name(n.type) << "Id, :" << n.id << ", Code:"; | 51 | dbg << "Notification(Type:" << name(n.type) << ", Id:" << n.id << ", Code:"; |
52 | dbg << n.code; | 52 | dbg << n.code; |
53 | dbg << ", Message:" << n.message << ", Entities:" << n.entities << ")"; | 53 | dbg << ", Message:" << n.message << ", Entities:" << n.entities << ")"; |
54 | return dbg.space(); | 54 | return dbg.space(); |
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: | |||
49 | 49 | ||
50 | QList<QSharedPointer<ResourceAccess>> resourceAccess; | 50 | QList<QSharedPointer<ResourceAccess>> resourceAccess; |
51 | QList<std::function<void(const Notification &)>> handler; | 51 | QList<std::function<void(const Notification &)>> handler; |
52 | QSharedPointer<Sink::ResultEmitter<QSharedPointer<Sink::ApplicationDomain::SinkResource> > > mResourceEmitter; | ||
52 | QObject context; | 53 | QObject context; |
53 | }; | 54 | }; |
54 | 55 | ||
@@ -91,6 +92,9 @@ Notifier::Notifier(const Sink::Query &resourceQuery) : d(new Sink::Notifier::Pri | |||
91 | SinkTraceCtx(resourceCtx) << "Resource query complete"; | 92 | SinkTraceCtx(resourceCtx) << "Resource query complete"; |
92 | }); | 93 | }); |
93 | emitter->fetch({}); | 94 | emitter->fetch({}); |
95 | if (resourceQuery.liveQuery()) { | ||
96 | d->mResourceEmitter = emitter; | ||
97 | } | ||
94 | result.first.exec(); | 98 | result.first.exec(); |
95 | } | 99 | } |
96 | 100 | ||
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 | |||
56 | { | 56 | { |
57 | public: | 57 | public: |
58 | QByteArrayList capabilities; | 58 | QByteArrayList capabilities; |
59 | static QHash<QString, QPointer<ResourceFactory>> s_loadedFactories; | ||
60 | }; | 59 | }; |
61 | 60 | ||
62 | QHash<QString, QPointer<ResourceFactory>> ResourceFactory::Private::s_loadedFactories; | 61 | typedef QHash<QString, QPointer<ResourceFactory>> FactoryRegistry; |
62 | Q_GLOBAL_STATIC(FactoryRegistry, s_loadedFactories); | ||
63 | 63 | ||
64 | ResourceFactory::ResourceFactory(QObject *parent, const QByteArrayList &capabilities) : QObject(parent), d(new ResourceFactory::Private) | 64 | ResourceFactory::ResourceFactory(QObject *parent, const QByteArrayList &capabilities) : QObject(parent), d(new ResourceFactory::Private) |
65 | { | 65 | { |
@@ -73,7 +73,7 @@ ResourceFactory::~ResourceFactory() | |||
73 | 73 | ||
74 | ResourceFactory *ResourceFactory::load(const QByteArray &resourceName) | 74 | ResourceFactory *ResourceFactory::load(const QByteArray &resourceName) |
75 | { | 75 | { |
76 | ResourceFactory *factory = Private::s_loadedFactories.value(resourceName); | 76 | ResourceFactory *factory = s_loadedFactories->value(resourceName); |
77 | if (factory) { | 77 | if (factory) { |
78 | return factory; | 78 | return factory; |
79 | } | 79 | } |
@@ -96,7 +96,7 @@ ResourceFactory *ResourceFactory::load(const QByteArray &resourceName) | |||
96 | if (object) { | 96 | if (object) { |
97 | factory = qobject_cast<ResourceFactory *>(object); | 97 | factory = qobject_cast<ResourceFactory *>(object); |
98 | if (factory) { | 98 | if (factory) { |
99 | Private::s_loadedFactories.insert(resourceName, factory); | 99 | s_loadedFactories->insert(resourceName, factory); |
100 | //TODO: Instead of always loading both facades and adaptorfactories into the respective singletons, we could also leave this up to the caller. (ResourceFactory::loadFacades(...)) | 100 | //TODO: Instead of always loading both facades and adaptorfactories into the respective singletons, we could also leave this up to the caller. (ResourceFactory::loadFacades(...)) |
101 | factory->registerFacades(resourceName, FacadeFactory::instance()); | 101 | factory->registerFacades(resourceName, FacadeFactory::instance()); |
102 | factory->registerAdaptorFactories(resourceName, AdaptorFactoryRegistry::instance()); | 102 | factory->registerAdaptorFactories(resourceName, AdaptorFactoryRegistry::instance()); |
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<void> ResourceAccess::Private::initializeSocket() | |||
232 | ResourceAccess::ResourceAccess(const QByteArray &resourceInstanceIdentifier, const QByteArray &resourceType) | 232 | ResourceAccess::ResourceAccess(const QByteArray &resourceInstanceIdentifier, const QByteArray &resourceType) |
233 | : ResourceAccessInterface(), d(new Private(resourceType, resourceInstanceIdentifier, this)) | 233 | : ResourceAccessInterface(), d(new Private(resourceType, resourceInstanceIdentifier, this)) |
234 | { | 234 | { |
235 | mResourceStatus = Sink::ApplicationDomain::OfflineStatus; | 235 | mResourceStatus = Sink::ApplicationDomain::NoStatus; |
236 | SinkTrace() << "Starting access"; | 236 | SinkTrace() << "Starting access"; |
237 | } | 237 | } |
238 | 238 | ||
diff --git a/common/resourcefacade.cpp b/common/resourcefacade.cpp index dab6aed..0687bbc 100644 --- a/common/resourcefacade.cpp +++ b/common/resourcefacade.cpp | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "store.h" | 24 | #include "store.h" |
25 | #include "resourceaccess.h" | 25 | #include "resourceaccess.h" |
26 | #include "resource.h" | 26 | #include "resource.h" |
27 | #include "facadefactory.h" | ||
27 | 28 | ||
28 | using namespace Sink; | 29 | using namespace Sink; |
29 | 30 | ||
@@ -358,27 +359,50 @@ QPair<KAsync::Job<void>, typename Sink::ResultEmitter<typename ApplicationDomain | |||
358 | auto ctx = parentCtx.subContext("accounts"); | 359 | auto ctx = parentCtx.subContext("accounts"); |
359 | auto runner = new LocalStorageQueryRunner<ApplicationDomain::SinkAccount>(query, mIdentifier, mTypeName, sConfigNotifier, ctx); | 360 | auto runner = new LocalStorageQueryRunner<ApplicationDomain::SinkAccount>(query, mIdentifier, mTypeName, sConfigNotifier, ctx); |
360 | auto monitoredResources = QSharedPointer<QSet<QByteArray>>::create(); | 361 | auto monitoredResources = QSharedPointer<QSet<QByteArray>>::create(); |
361 | runner->setStatusUpdater([runner, monitoredResources, ctx](ApplicationDomain::SinkAccount &account) { | 362 | auto monitorResource = [monitoredResources, runner, ctx] (const QByteArray &accountIdentifier, const ApplicationDomain::SinkResource &resource, const ResourceAccess::Ptr &resourceAccess) { |
362 | Query query; | 363 | if (!monitoredResources->contains(resource.identifier())) { |
364 | auto ret = QObject::connect(resourceAccess.data(), &ResourceAccess::notification, runner->guard(), [resource, runner, resourceAccess, accountIdentifier, ctx](const Notification ¬ification) { | ||
365 | SinkTraceCtx(ctx) << "Received notification in facade: " << notification.type; | ||
366 | if (notification.type == Notification::Status) { | ||
367 | runner->statusChanged(accountIdentifier); | ||
368 | } | ||
369 | }); | ||
370 | Q_ASSERT(ret); | ||
371 | monitoredResources->insert(resource.identifier()); | ||
372 | } | ||
373 | }; | ||
374 | runner->setStatusUpdater([this, runner, monitoredResources, ctx, monitorResource](ApplicationDomain::SinkAccount &account) { | ||
375 | Query query{Query::LiveQuery}; | ||
363 | query.filter<ApplicationDomain::SinkResource::Account>(account.identifier()); | 376 | query.filter<ApplicationDomain::SinkResource::Account>(account.identifier()); |
364 | query.request<ApplicationDomain::SinkResource::Account>() | 377 | query.request<ApplicationDomain::SinkResource::Account>() |
365 | .request<ApplicationDomain::SinkResource::Capabilities>(); | 378 | .request<ApplicationDomain::SinkResource::Capabilities>(); |
366 | const auto resources = Store::read<ApplicationDomain::SinkResource>(query); | 379 | const auto resources = Store::read<ApplicationDomain::SinkResource>(query); |
367 | SinkTraceCtx(ctx) << "Found resource belonging to the account " << account.identifier() << " : " << resources; | 380 | SinkTraceCtx(ctx) << "Found resource belonging to the account " << account.identifier() << " : " << resources; |
368 | auto accountIdentifier = account.identifier(); | 381 | auto accountIdentifier = account.identifier(); |
382 | |||
383 | //Monitor for new resources so they can be monitored as well | ||
384 | if (!runner->mResourceEmitter.contains(accountIdentifier)) { | ||
385 | auto facade = Sink::FacadeFactory::instance().getFacade<ApplicationDomain::SinkResource>(); | ||
386 | Q_ASSERT(facade); | ||
387 | |||
388 | auto emitter = facade->load(query, ctx).second; | ||
389 | emitter->onAdded([=](const ApplicationDomain::SinkResource::Ptr &resource) { | ||
390 | auto resourceAccess = Sink::ResourceAccessFactory::instance().getAccess(resource->identifier(), ResourceConfig::getResourceType(resource->identifier())); | ||
391 | monitorResource(accountIdentifier, *resource, resourceAccess); | ||
392 | }); | ||
393 | emitter->onModified([](const ApplicationDomain::SinkResource::Ptr &) {}); | ||
394 | emitter->onRemoved([](const ApplicationDomain::SinkResource::Ptr &) {}); | ||
395 | emitter->onInitialResultSetComplete([](const ApplicationDomain::SinkResource::Ptr &, bool) {}); | ||
396 | emitter->onComplete([]() {}); | ||
397 | emitter->fetch({}); | ||
398 | runner->mResourceEmitter[accountIdentifier] = emitter; | ||
399 | } | ||
400 | |||
369 | QList<int> states; | 401 | QList<int> states; |
402 | //Gather all resources and ensure they are monitored | ||
370 | for (const auto &resource : resources) { | 403 | for (const auto &resource : resources) { |
371 | auto resourceAccess = ResourceAccessFactory::instance().getAccess(resource.identifier(), ResourceConfig::getResourceType(resource.identifier())); | 404 | auto resourceAccess = ResourceAccessFactory::instance().getAccess(resource.identifier(), ResourceConfig::getResourceType(resource.identifier())); |
372 | if (!monitoredResources->contains(resource.identifier())) { | 405 | monitorResource(accountIdentifier, resource, resourceAccess); |
373 | auto ret = QObject::connect(resourceAccess.data(), &ResourceAccess::notification, runner->guard(), [resource, runner, resourceAccess, accountIdentifier, ctx](const Notification ¬ification) { | ||
374 | SinkTraceCtx(ctx) << "Received notification in facade: " << notification.type; | ||
375 | if (notification.type == Notification::Status) { | ||
376 | runner->statusChanged(accountIdentifier); | ||
377 | } | ||
378 | }); | ||
379 | Q_ASSERT(ret); | ||
380 | monitoredResources->insert(resource.identifier()); | ||
381 | } | ||
382 | states << resourceAccess->getResourceStatus(); | 406 | states << resourceAccess->getResourceStatus(); |
383 | } | 407 | } |
384 | const auto status = [&] { | 408 | const auto status = [&] { |
@@ -391,7 +415,10 @@ QPair<KAsync::Job<void>, typename Sink::ResultEmitter<typename ApplicationDomain | |||
391 | if (states.contains(ApplicationDomain::OfflineStatus)) { | 415 | if (states.contains(ApplicationDomain::OfflineStatus)) { |
392 | return ApplicationDomain::OfflineStatus; | 416 | return ApplicationDomain::OfflineStatus; |
393 | } | 417 | } |
394 | return ApplicationDomain::ConnectedStatus; | 418 | if (states.contains(ApplicationDomain::ConnectedStatus)) { |
419 | return ApplicationDomain::ConnectedStatus; | ||
420 | } | ||
421 | return ApplicationDomain::NoStatus; | ||
395 | }(); | 422 | }(); |
396 | account.setStatusStatus(status); | 423 | account.setStatusStatus(status); |
397 | }); | 424 | }); |
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: | |||
65 | void setStatusUpdater(const std::function<void(DomainType &)> &); | 65 | void setStatusUpdater(const std::function<void(DomainType &)> &); |
66 | void statusChanged(const QByteArray &identifier); | 66 | void statusChanged(const QByteArray &identifier); |
67 | QObject *guard() const; | 67 | QObject *guard() const; |
68 | QMap<QByteArray, QSharedPointer<Sink::ResultEmitter<QSharedPointer<Sink::ApplicationDomain::SinkResource> > > > mResourceEmitter; | ||
68 | 69 | ||
69 | private: | 70 | private: |
70 | void updateStatus(DomainType &entity); | 71 | void updateStatus(DomainType &entity); |
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: | |||
198 | static QByteArray getTypeFromRevision(const Transaction &, qint64 revision); | 198 | static QByteArray getTypeFromRevision(const Transaction &, qint64 revision); |
199 | static void recordRevision(Transaction &, qint64 revision, const QByteArray &uid, const QByteArray &type); | 199 | static void recordRevision(Transaction &, qint64 revision, const QByteArray &uid, const QByteArray &type); |
200 | static void removeRevision(Transaction &, qint64 revision); | 200 | static void removeRevision(Transaction &, qint64 revision); |
201 | static void recordUid(DataStore::Transaction &transaction, const QByteArray &uid); | 201 | static void recordUid(DataStore::Transaction &transaction, const QByteArray &uid, const QByteArray &type); |
202 | static void removeUid(DataStore::Transaction &transaction, const QByteArray &uid); | 202 | static void removeUid(DataStore::Transaction &transaction, const QByteArray &uid, const QByteArray &type); |
203 | static void getUids(const Transaction &, const std::function<void(const QByteArray &uid)> &); | 203 | static void getUids(const QByteArray &type, const Transaction &, const std::function<void(const QByteArray &uid)> &); |
204 | 204 | ||
205 | bool exists() const; | 205 | bool exists() const; |
206 | 206 | ||
diff --git a/common/storage/entitystore.cpp b/common/storage/entitystore.cpp index 22e5ae3..5514e31 100644 --- a/common/storage/entitystore.cpp +++ b/common/storage/entitystore.cpp | |||
@@ -267,7 +267,7 @@ bool EntityStore::add(const QByteArray &type, ApplicationDomain::ApplicationDoma | |||
267 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Failed to write entity" << entity.identifier() << newRevision; }); | 267 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Failed to write entity" << entity.identifier() << newRevision; }); |
268 | DataStore::setMaxRevision(d->transaction, newRevision); | 268 | DataStore::setMaxRevision(d->transaction, newRevision); |
269 | DataStore::recordRevision(d->transaction, newRevision, entity.identifier(), type); | 269 | DataStore::recordRevision(d->transaction, newRevision, entity.identifier(), type); |
270 | DataStore::recordUid(d->transaction, entity.identifier()); | 270 | DataStore::recordUid(d->transaction, entity.identifier(), type); |
271 | SinkTraceCtx(d->logCtx) << "Wrote entity: " << entity.identifier() << type << newRevision; | 271 | SinkTraceCtx(d->logCtx) << "Wrote entity: " << entity.identifier() << type << newRevision; |
272 | return true; | 272 | return true; |
273 | } | 273 | } |
@@ -379,7 +379,7 @@ bool EntityStore::remove(const QByteArray &type, const Sink::ApplicationDomain:: | |||
379 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Failed to write entity" << uid << newRevision; }); | 379 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Failed to write entity" << uid << newRevision; }); |
380 | DataStore::setMaxRevision(d->transaction, newRevision); | 380 | DataStore::setMaxRevision(d->transaction, newRevision); |
381 | DataStore::recordRevision(d->transaction, newRevision, uid, type); | 381 | DataStore::recordRevision(d->transaction, newRevision, uid, type); |
382 | DataStore::removeUid(d->transaction, uid); | 382 | DataStore::removeUid(d->transaction, uid, type); |
383 | return true; | 383 | return true; |
384 | } | 384 | } |
385 | 385 | ||
@@ -516,9 +516,8 @@ void EntityStore::readLatest(const QByteArray &type, const QByteArray &uid, cons | |||
516 | { | 516 | { |
517 | auto db = DataStore::mainDatabase(d->getTransaction(), type); | 517 | auto db = DataStore::mainDatabase(d->getTransaction(), type); |
518 | db.findLatest(uid, | 518 | db.findLatest(uid, |
519 | [=](const QByteArray &key, const QByteArray &value) -> bool { | 519 | [=](const QByteArray &key, const QByteArray &value) { |
520 | callback(DataStore::uidFromKey(key), Sink::EntityBuffer(value.data(), value.size())); | 520 | callback(DataStore::uidFromKey(key), Sink::EntityBuffer(value.data(), value.size())); |
521 | return false; | ||
522 | }, | 521 | }, |
523 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Error during query: " << error.message << uid; }); | 522 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Error during query: " << error.message << uid; }); |
524 | } | 523 | } |
@@ -639,7 +638,7 @@ ApplicationDomain::ApplicationDomainType EntityStore::readPrevious(const QByteAr | |||
639 | 638 | ||
640 | void EntityStore::readAllUids(const QByteArray &type, const std::function<void(const QByteArray &uid)> callback) | 639 | void EntityStore::readAllUids(const QByteArray &type, const std::function<void(const QByteArray &uid)> callback) |
641 | { | 640 | { |
642 | DataStore::getUids(d->getTransaction(), callback); | 641 | DataStore::getUids(type, d->getTransaction(), callback); |
643 | } | 642 | } |
644 | 643 | ||
645 | bool EntityStore::contains(const QByteArray &type, const QByteArray &uid) | 644 | bool EntityStore::contains(const QByteArray &type, const QByteArray &uid) |
@@ -653,7 +652,7 @@ bool EntityStore::exists(const QByteArray &type, const QByteArray &uid) | |||
653 | bool alreadyRemoved = false; | 652 | bool alreadyRemoved = false; |
654 | DataStore::mainDatabase(d->transaction, type) | 653 | DataStore::mainDatabase(d->transaction, type) |
655 | .findLatest(uid, | 654 | .findLatest(uid, |
656 | [&found, &alreadyRemoved](const QByteArray &key, const QByteArray &data) -> bool { | 655 | [&found, &alreadyRemoved](const QByteArray &key, const QByteArray &data) { |
657 | auto entity = GetEntity(data.data()); | 656 | auto entity = GetEntity(data.data()); |
658 | if (entity && entity->metadata()) { | 657 | if (entity && entity->metadata()) { |
659 | auto metadata = GetMetadata(entity->metadata()->Data()); | 658 | auto metadata = GetMetadata(entity->metadata()->Data()); |
@@ -662,7 +661,6 @@ bool EntityStore::exists(const QByteArray &type, const QByteArray &uid) | |||
662 | alreadyRemoved = true; | 661 | alreadyRemoved = true; |
663 | } | 662 | } |
664 | } | 663 | } |
665 | return false; | ||
666 | }, | 664 | }, |
667 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Failed to read old revision from storage: " << error.message; }); | 665 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Failed to read old revision from storage: " << error.message; }); |
668 | if (!found) { | 666 | if (!found) { |
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 | |||
156 | transaction.openDatabase("revisionType").remove(QByteArray::number(revision)); | 156 | transaction.openDatabase("revisionType").remove(QByteArray::number(revision)); |
157 | } | 157 | } |
158 | 158 | ||
159 | void DataStore::recordUid(DataStore::Transaction &transaction, const QByteArray &uid) | 159 | void DataStore::recordUid(DataStore::Transaction &transaction, const QByteArray &uid, const QByteArray &type) |
160 | { | 160 | { |
161 | transaction.openDatabase("uids").write(uid, ""); | 161 | transaction.openDatabase(type + "uids").write(uid, ""); |
162 | } | 162 | } |
163 | 163 | ||
164 | void DataStore::removeUid(DataStore::Transaction &transaction, const QByteArray &uid) | 164 | void DataStore::removeUid(DataStore::Transaction &transaction, const QByteArray &uid, const QByteArray &type) |
165 | { | 165 | { |
166 | transaction.openDatabase("uids").remove(uid); | 166 | transaction.openDatabase(type + "uids").remove(uid); |
167 | } | 167 | } |
168 | 168 | ||
169 | void DataStore::getUids(const Transaction &transaction, const std::function<void(const QByteArray &uid)> &callback) | 169 | void DataStore::getUids(const QByteArray &type, const Transaction &transaction, const std::function<void(const QByteArray &uid)> &callback) |
170 | { | 170 | { |
171 | transaction.openDatabase("uids").scan("", [&] (const QByteArray &key, const QByteArray &) { | 171 | transaction.openDatabase(type + "uids").scan("", [&] (const QByteArray &key, const QByteArray &) { |
172 | callback(key); | 172 | callback(key); |
173 | return true; | 173 | return true; |
174 | }); | 174 | }); |
diff --git a/common/storage_lmdb.cpp b/common/storage_lmdb.cpp index f7999d1..58e3a9a 100644 --- a/common/storage_lmdb.cpp +++ b/common/storage_lmdb.cpp | |||
@@ -406,7 +406,7 @@ int DataStore::NamedDatabase::scan(const QByteArray &k, const std::function<bool | |||
406 | mdb_cursor_close(cursor); | 406 | mdb_cursor_close(cursor); |
407 | 407 | ||
408 | if (rc) { | 408 | if (rc) { |
409 | Error error(d->name.toLatin1() + d->db, getErrorCode(rc), QByteArray("Key: ") + k + " : " + QByteArray(mdb_strerror(rc))); | 409 | Error error(d->name.toLatin1() + d->db, getErrorCode(rc), QByteArray("Error during scan. Key: ") + k + " : " + QByteArray(mdb_strerror(rc))); |
410 | errorHandler ? errorHandler(error) : d->defaultErrorHandler(error); | 410 | errorHandler ? errorHandler(error) : d->defaultErrorHandler(error); |
411 | } | 411 | } |
412 | 412 | ||
@@ -420,6 +420,11 @@ void DataStore::NamedDatabase::findLatest(const QByteArray &k, const std::functi | |||
420 | // Not an error. We rely on this to read nothing from non-existing databases. | 420 | // Not an error. We rely on this to read nothing from non-existing databases. |
421 | return; | 421 | return; |
422 | } | 422 | } |
423 | if (k.isEmpty()) { | ||
424 | Error error(d->name.toLatin1() + d->db, GenericError, QByteArray("Can't use findLatest with empty key.")); | ||
425 | errorHandler ? errorHandler(error) : d->defaultErrorHandler(error); | ||
426 | return; | ||
427 | } | ||
423 | 428 | ||
424 | int rc; | 429 | int rc; |
425 | MDB_val key; | 430 | MDB_val key; |
@@ -441,25 +446,23 @@ void DataStore::NamedDatabase::findLatest(const QByteArray &k, const std::functi | |||
441 | if ((rc = mdb_cursor_get(cursor, &key, &data, op)) == 0) { | 446 | if ((rc = mdb_cursor_get(cursor, &key, &data, op)) == 0) { |
442 | // The first lookup will find a key that is equal or greather than our key | 447 | // The first lookup will find a key that is equal or greather than our key |
443 | if (QByteArray::fromRawData((char *)key.mv_data, key.mv_size).startsWith(k)) { | 448 | if (QByteArray::fromRawData((char *)key.mv_data, key.mv_size).startsWith(k)) { |
444 | bool advanced = false; | 449 | //Read next value until we no longer match |
445 | while (QByteArray::fromRawData((char *)key.mv_data, key.mv_size).startsWith(k)) { | 450 | while (QByteArray::fromRawData((char *)key.mv_data, key.mv_size).startsWith(k)) { |
446 | advanced = true; | ||
447 | MDB_cursor_op nextOp = MDB_NEXT; | 451 | MDB_cursor_op nextOp = MDB_NEXT; |
448 | rc = mdb_cursor_get(cursor, &key, &data, nextOp); | 452 | rc = mdb_cursor_get(cursor, &key, &data, nextOp); |
449 | if (rc) { | 453 | if (rc) { |
450 | break; | 454 | break; |
451 | } | 455 | } |
452 | } | 456 | } |
453 | if (advanced) { | 457 | //Now read the previous value, and that's the latest one |
454 | MDB_cursor_op prefOp = MDB_PREV; | 458 | MDB_cursor_op prefOp = MDB_PREV; |
455 | // We read past the end above, just take the last value | 459 | // We read past the end above, just take the last value |
456 | if (rc == MDB_NOTFOUND) { | 460 | if (rc == MDB_NOTFOUND) { |
457 | prefOp = MDB_LAST; | 461 | prefOp = MDB_LAST; |
458 | } | ||
459 | rc = mdb_cursor_get(cursor, &key, &data, prefOp); | ||
460 | foundValue = true; | ||
461 | resultHandler(QByteArray::fromRawData((char *)key.mv_data, key.mv_size), QByteArray::fromRawData((char *)data.mv_data, data.mv_size)); | ||
462 | } | 462 | } |
463 | rc = mdb_cursor_get(cursor, &key, &data, prefOp); | ||
464 | foundValue = true; | ||
465 | resultHandler(QByteArray::fromRawData((char *)key.mv_data, key.mv_size), QByteArray::fromRawData((char *)data.mv_data, data.mv_size)); | ||
463 | } | 466 | } |
464 | } | 467 | } |
465 | 468 | ||
@@ -471,10 +474,10 @@ void DataStore::NamedDatabase::findLatest(const QByteArray &k, const std::functi | |||
471 | mdb_cursor_close(cursor); | 474 | mdb_cursor_close(cursor); |
472 | 475 | ||
473 | if (rc) { | 476 | if (rc) { |
474 | Error error(d->name.toLatin1(), getErrorCode(rc), QByteArray("Key: ") + k + " : " + QByteArray(mdb_strerror(rc))); | 477 | Error error(d->name.toLatin1(), getErrorCode(rc), QByteArray("Error during find latest. Key: ") + k + " : " + QByteArray(mdb_strerror(rc))); |
475 | errorHandler ? errorHandler(error) : d->defaultErrorHandler(error); | 478 | errorHandler ? errorHandler(error) : d->defaultErrorHandler(error); |
476 | } else if (!foundValue) { | 479 | } else if (!foundValue) { |
477 | Error error(d->name.toLatin1(), 1, QByteArray("Key: ") + k + " : No value found"); | 480 | Error error(d->name.toLatin1(), 1, QByteArray("Error during find latest. Key: ") + k + " : No value found"); |
478 | errorHandler ? errorHandler(error) : d->defaultErrorHandler(error); | 481 | errorHandler ? errorHandler(error) : d->defaultErrorHandler(error); |
479 | } | 482 | } |
480 | 483 | ||
diff --git a/common/store.cpp b/common/store.cpp index 4735113..1701a43 100644 --- a/common/store.cpp +++ b/common/store.cpp | |||
@@ -36,10 +36,34 @@ | |||
36 | #include "storage.h" | 36 | #include "storage.h" |
37 | #include "log.h" | 37 | #include "log.h" |
38 | 38 | ||
39 | #define ASSERT_ENUMS_MATCH(A, B) Q_STATIC_ASSERT_X(static_cast<int>(A) == static_cast<int>(B), "The enum values must match"); | ||
40 | |||
41 | //Ensure the copied enum matches | ||
42 | typedef ModelResult<Sink::ApplicationDomain::Mail, Sink::ApplicationDomain::Mail::Ptr> MailModelResult; | ||
43 | ASSERT_ENUMS_MATCH(Sink::Store::DomainObjectBaseRole, MailModelResult::DomainObjectBaseRole) | ||
44 | ASSERT_ENUMS_MATCH(Sink::Store::ChildrenFetchedRole, MailModelResult::ChildrenFetchedRole) | ||
45 | ASSERT_ENUMS_MATCH(Sink::Store::DomainObjectRole, MailModelResult::DomainObjectRole) | ||
46 | ASSERT_ENUMS_MATCH(Sink::Store::StatusRole, MailModelResult::StatusRole) | ||
47 | ASSERT_ENUMS_MATCH(Sink::Store::WarningRole, MailModelResult::WarningRole) | ||
48 | ASSERT_ENUMS_MATCH(Sink::Store::ProgressRole, MailModelResult::ProgressRole) | ||
49 | |||
39 | Q_DECLARE_METATYPE(QSharedPointer<Sink::ResultEmitter<Sink::ApplicationDomain::SinkResource::Ptr>>) | 50 | Q_DECLARE_METATYPE(QSharedPointer<Sink::ResultEmitter<Sink::ApplicationDomain::SinkResource::Ptr>>) |
40 | Q_DECLARE_METATYPE(QSharedPointer<Sink::ResourceAccessInterface>); | 51 | Q_DECLARE_METATYPE(QSharedPointer<Sink::ResourceAccessInterface>); |
41 | Q_DECLARE_METATYPE(std::shared_ptr<void>); | 52 | Q_DECLARE_METATYPE(std::shared_ptr<void>); |
42 | 53 | ||
54 | |||
55 | static bool sanityCheckQuery(const Sink::Query &query) | ||
56 | { | ||
57 | for (const auto &id : query.ids()) { | ||
58 | if (id.isEmpty()) { | ||
59 | SinkError() << "Empty id in query."; | ||
60 | return false; | ||
61 | } | ||
62 | } | ||
63 | return true; | ||
64 | } | ||
65 | |||
66 | |||
43 | namespace Sink { | 67 | namespace Sink { |
44 | 68 | ||
45 | QString Store::storageLocation() | 69 | QString Store::storageLocation() |
@@ -138,6 +162,7 @@ static Log::Context getQueryContext(const Sink::Query &query, const QByteArray & | |||
138 | template <class DomainType> | 162 | template <class DomainType> |
139 | QSharedPointer<QAbstractItemModel> Store::loadModel(const Query &query) | 163 | QSharedPointer<QAbstractItemModel> Store::loadModel(const Query &query) |
140 | { | 164 | { |
165 | Q_ASSERT(sanityCheckQuery(query)); | ||
141 | auto ctx = getQueryContext(query, ApplicationDomain::getTypeName<DomainType>()); | 166 | auto ctx = getQueryContext(query, ApplicationDomain::getTypeName<DomainType>()); |
142 | auto model = QSharedPointer<ModelResult<DomainType, typename DomainType::Ptr>>::create(query, query.requestedProperties, ctx); | 167 | auto model = QSharedPointer<ModelResult<DomainType, typename DomainType::Ptr>>::create(query, query.requestedProperties, ctx); |
143 | 168 | ||
@@ -189,6 +214,10 @@ KAsync::Job<void> Store::create(const DomainType &domainObject) | |||
189 | template <class DomainType> | 214 | template <class DomainType> |
190 | KAsync::Job<void> Store::modify(const DomainType &domainObject) | 215 | KAsync::Job<void> Store::modify(const DomainType &domainObject) |
191 | { | 216 | { |
217 | if (domainObject.changedProperties().isEmpty()) { | ||
218 | SinkLog() << "Nothing to modify: " << domainObject.identifier(); | ||
219 | return KAsync::null(); | ||
220 | } | ||
192 | SinkLog() << "Modify: " << domainObject; | 221 | SinkLog() << "Modify: " << domainObject; |
193 | // Potentially move to separate thread as well | 222 | // Potentially move to separate thread as well |
194 | auto facade = getFacade<DomainType>(domainObject.resourceInstanceIdentifier()); | 223 | auto facade = getFacade<DomainType>(domainObject.resourceInstanceIdentifier()); |
@@ -198,6 +227,10 @@ KAsync::Job<void> Store::modify(const DomainType &domainObject) | |||
198 | template <class DomainType> | 227 | template <class DomainType> |
199 | KAsync::Job<void> Store::modify(const Query &query, const DomainType &domainObject) | 228 | KAsync::Job<void> Store::modify(const Query &query, const DomainType &domainObject) |
200 | { | 229 | { |
230 | if (domainObject.changedProperties().isEmpty()) { | ||
231 | SinkLog() << "Nothing to modify: " << domainObject.identifier(); | ||
232 | return KAsync::null(); | ||
233 | } | ||
201 | SinkLog() << "Modify: " << query << domainObject; | 234 | SinkLog() << "Modify: " << query << domainObject; |
202 | return fetchAll<DomainType>(query) | 235 | return fetchAll<DomainType>(query) |
203 | .each([=] (const typename DomainType::Ptr &entity) { | 236 | .each([=] (const typename DomainType::Ptr &entity) { |
@@ -311,9 +344,14 @@ KAsync::Job<void> Store::synchronize(const Sink::Query &query) | |||
311 | 344 | ||
312 | KAsync::Job<void> Store::synchronize(const Sink::SyncScope &scope) | 345 | KAsync::Job<void> Store::synchronize(const Sink::SyncScope &scope) |
313 | { | 346 | { |
347 | auto resourceFilter = scope.getResourceFilter(); | ||
348 | //Filter resources by type by default | ||
349 | if (!resourceFilter.propertyFilter.contains(ApplicationDomain::SinkResource::Capabilities::name) && !scope.type().isEmpty()) { | ||
350 | resourceFilter.propertyFilter.insert(ApplicationDomain::SinkResource::Capabilities::name, Query::Comparator{scope.type(), Query::Comparator::Contains}); | ||
351 | } | ||
314 | Sink::Query query; | 352 | Sink::Query query; |
315 | query.setFilter(scope.getResourceFilter()); | 353 | query.setFilter(resourceFilter); |
316 | SinkLog() << "Synchronizing: " << query; | 354 | SinkLog() << "Synchronizing all resource matching: " << query; |
317 | return fetchAll<ApplicationDomain::SinkResource>(query) | 355 | return fetchAll<ApplicationDomain::SinkResource>(query) |
318 | .template each([scope](const ApplicationDomain::SinkResource::Ptr &resource) -> KAsync::Job<void> { | 356 | .template each([scope](const ApplicationDomain::SinkResource::Ptr &resource) -> KAsync::Job<void> { |
319 | return synchronize(resource->identifier(), scope); | 357 | return synchronize(resource->identifier(), scope); |
@@ -337,6 +375,7 @@ KAsync::Job<QList<typename DomainType::Ptr>> Store::fetchAll(const Sink::Query & | |||
337 | template <class DomainType> | 375 | template <class DomainType> |
338 | KAsync::Job<QList<typename DomainType::Ptr>> Store::fetch(const Sink::Query &query, int minimumAmount) | 376 | KAsync::Job<QList<typename DomainType::Ptr>> Store::fetch(const Sink::Query &query, int minimumAmount) |
339 | { | 377 | { |
378 | Q_ASSERT(sanityCheckQuery(query)); | ||
340 | auto model = loadModel<DomainType>(query); | 379 | auto model = loadModel<DomainType>(query); |
341 | auto list = QSharedPointer<QList<typename DomainType::Ptr>>::create(); | 380 | auto list = QSharedPointer<QList<typename DomainType::Ptr>>::create(); |
342 | auto context = QSharedPointer<QObject>::create(); | 381 | auto context = QSharedPointer<QObject>::create(); |
@@ -388,6 +427,7 @@ DomainType Store::readOne(const Sink::Query &query) | |||
388 | template <class DomainType> | 427 | template <class DomainType> |
389 | QList<DomainType> Store::read(const Sink::Query &query_) | 428 | QList<DomainType> Store::read(const Sink::Query &query_) |
390 | { | 429 | { |
430 | Q_ASSERT(sanityCheckQuery(query_)); | ||
391 | auto query = query_; | 431 | auto query = query_; |
392 | query.setFlags(Query::SynchronousQuery); | 432 | query.setFlags(Query::SynchronousQuery); |
393 | 433 | ||
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<void> SINK_EXPORT create(const DomainType &domainObject); | |||
75 | * Modify an entity. | 75 | * Modify an entity. |
76 | * | 76 | * |
77 | * This includes moving etc. since these are also simple settings on a property. | 77 | * This includes moving etc. since these are also simple settings on a property. |
78 | * Note that the modification will be dropped if there is no changedProperty on the domain object. | ||
78 | */ | 79 | */ |
79 | template <class DomainType> | 80 | template <class DomainType> |
80 | KAsync::Job<void> SINK_EXPORT modify(const DomainType &domainObject); | 81 | KAsync::Job<void> SINK_EXPORT modify(const DomainType &domainObject); |
81 | 82 | ||
82 | /** | 83 | /** |
83 | * Modify a set of entities identified by @param query. | 84 | * Modify a set of entities identified by @param query. |
85 | * | ||
86 | * Note that the modification will be dropped if there is no changedProperty on the domain object. | ||
84 | */ | 87 | */ |
85 | template <class DomainType> | 88 | template <class DomainType> |
86 | KAsync::Job<void> SINK_EXPORT modify(const Query &query, const DomainType &domainObject); | 89 | KAsync::Job<void> SINK_EXPORT modify(const Query &query, const DomainType &domainObject); |
diff --git a/common/synchronizer.cpp b/common/synchronizer.cpp index 3b32e68..46d3980 100644 --- a/common/synchronizer.cpp +++ b/common/synchronizer.cpp | |||
@@ -40,7 +40,7 @@ Synchronizer::Synchronizer(const Sink::ResourceContext &context) | |||
40 | mSyncStorage(Sink::storageLocation(), mResourceContext.instanceId() + ".synchronization", Sink::Storage::DataStore::DataStore::ReadWrite), | 40 | mSyncStorage(Sink::storageLocation(), mResourceContext.instanceId() + ".synchronization", Sink::Storage::DataStore::DataStore::ReadWrite), |
41 | mSyncInProgress(false) | 41 | mSyncInProgress(false) |
42 | { | 42 | { |
43 | mCurrentState.push(ApplicationDomain::Status::OfflineStatus); | 43 | mCurrentState.push(ApplicationDomain::Status::NoStatus); |
44 | SinkTraceCtx(mLogCtx) << "Starting synchronizer: " << mResourceContext.resourceType << mResourceContext.instanceId(); | 44 | SinkTraceCtx(mLogCtx) << "Starting synchronizer: " << mResourceContext.resourceType << mResourceContext.instanceId(); |
45 | } | 45 | } |
46 | 46 | ||
@@ -344,8 +344,11 @@ void Synchronizer::setStatusFromResult(const KAsync::Error &error, const QString | |||
344 | } else if (error.errorCode == ApplicationDomain::LoginError) { | 344 | } else if (error.errorCode == ApplicationDomain::LoginError) { |
345 | //If we failed to login altough we could connect that indicates a problem with our setup. | 345 | //If we failed to login altough we could connect that indicates a problem with our setup. |
346 | setStatus(ApplicationDomain::ErrorStatus, s, requestId); | 346 | setStatus(ApplicationDomain::ErrorStatus, s, requestId); |
347 | } else if (error.errorCode == ApplicationDomain::ConnectionLostError) { | ||
348 | //We've lost the connection so we assume the connection to the server broke. | ||
349 | setStatus(ApplicationDomain::OfflineStatus, s, requestId); | ||
347 | } | 350 | } |
348 | //We don't know what kind of error this was, so we assume it's transient and don't change ou status. | 351 | //We don't know what kind of error this was, so we assume it's transient and don't change our status. |
349 | } else { | 352 | } else { |
350 | //An operation against the server worked, so we're probably online. | 353 | //An operation against the server worked, so we're probably online. |
351 | setStatus(ApplicationDomain::ConnectedStatus, s, requestId); | 354 | setStatus(ApplicationDomain::ConnectedStatus, s, requestId); |
@@ -593,17 +596,13 @@ KAsync::Job<void> Synchronizer::replay(const QByteArray &type, const QByteArray | |||
593 | KAsync::Job<QByteArray> job = KAsync::null<QByteArray>(); | 596 | KAsync::Job<QByteArray> job = KAsync::null<QByteArray>(); |
594 | //TODO This requires supporting every domain type here as well. Can we solve this better so we can do the dispatch somewhere centrally? | 597 | //TODO This requires supporting every domain type here as well. Can we solve this better so we can do the dispatch somewhere centrally? |
595 | if (type == ApplicationDomain::getTypeName<ApplicationDomain::Folder>()) { | 598 | if (type == ApplicationDomain::getTypeName<ApplicationDomain::Folder>()) { |
596 | auto folder = store().readEntity<ApplicationDomain::Folder>(key); | 599 | job = replay(store().readEntity<ApplicationDomain::Folder>(key), operation, oldRemoteId, modifiedProperties); |
597 | job = replay(folder, operation, oldRemoteId, modifiedProperties); | ||
598 | } else if (type == ApplicationDomain::getTypeName<ApplicationDomain::Mail>()) { | 600 | } else if (type == ApplicationDomain::getTypeName<ApplicationDomain::Mail>()) { |
599 | auto mail = store().readEntity<ApplicationDomain::Mail>(key); | 601 | job = replay(store().readEntity<ApplicationDomain::Mail>(key), operation, oldRemoteId, modifiedProperties); |
600 | job = replay(mail, operation, oldRemoteId, modifiedProperties); | ||
601 | } else if (type == ApplicationDomain::getTypeName<ApplicationDomain::Contact>()) { | 602 | } else if (type == ApplicationDomain::getTypeName<ApplicationDomain::Contact>()) { |
602 | auto mail = store().readEntity<ApplicationDomain::Contact>(key); | 603 | job = replay(store().readEntity<ApplicationDomain::Contact>(key), operation, oldRemoteId, modifiedProperties); |
603 | job = replay(mail, operation, oldRemoteId, modifiedProperties); | ||
604 | } else if (type == ApplicationDomain::getTypeName<ApplicationDomain::Addressbook>()) { | 604 | } else if (type == ApplicationDomain::getTypeName<ApplicationDomain::Addressbook>()) { |
605 | auto mail = store().readEntity<ApplicationDomain::Addressbook>(key); | 605 | job = replay(store().readEntity<ApplicationDomain::Addressbook>(key), operation, oldRemoteId, modifiedProperties); |
606 | job = replay(mail, operation, oldRemoteId, modifiedProperties); | ||
607 | } else { | 606 | } else { |
608 | SinkErrorCtx(mLogCtx) << "Replayed unknown type: " << type; | 607 | SinkErrorCtx(mLogCtx) << "Replayed unknown type: " << type; |
609 | } | 608 | } |
diff --git a/dist/sink.spec b/dist/sink.spec index f5132b7..4a4f50a 100644 --- a/dist/sink.spec +++ b/dist/sink.spec | |||
@@ -1,7 +1,7 @@ | |||
1 | 1 | ||
2 | Name: sink | 2 | Name: sink |
3 | Version: 0.3 | 3 | Version: 0.4.0 |
4 | Release: 10%{?dist} | 4 | Release: 0%{?dist} |
5 | Summary: sink | 5 | Summary: sink |
6 | 6 | ||
7 | Group: Applications/Desktop | 7 | Group: Applications/Desktop |
@@ -17,7 +17,7 @@ BuildRequires: kasync-devel | |||
17 | BuildRequires: kf5-kcoreaddons-devel | 17 | BuildRequires: kf5-kcoreaddons-devel |
18 | BuildRequires: kf5-kcontacts-devel | 18 | BuildRequires: kf5-kcontacts-devel |
19 | BuildRequires: kf5-kmime-devel | 19 | BuildRequires: kf5-kmime-devel |
20 | BuildRequires: kimap2-devel | 20 | BuildRequires: kimap2-devel >= 0.2 |
21 | BuildRequires: kdav2-devel | 21 | BuildRequires: kdav2-devel |
22 | BuildRequires: libcurl-devel | 22 | BuildRequires: libcurl-devel |
23 | BuildRequires: libgit2-devel | 23 | BuildRequires: libgit2-devel |
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}) | |||
6 | find_package(KPimKDAV2 REQUIRED) | 6 | find_package(KPimKDAV2 REQUIRED) |
7 | 7 | ||
8 | add_library(${PROJECT_NAME} SHARED davresource.cpp) | 8 | add_library(${PROJECT_NAME} SHARED davresource.cpp) |
9 | qt5_use_modules(${PROJECT_NAME} Core Network) | 9 | target_link_libraries(${PROJECT_NAME} sink Qt5::Core Qt5::Network KPim::KDAV2) |
10 | target_link_libraries(${PROJECT_NAME} sink KPim::KDAV2) | ||
11 | 10 | ||
12 | install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) | 11 | install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) |
diff --git a/examples/davresource/davresource.cpp b/examples/davresource/davresource.cpp index 465220f..22c502f 100644 --- a/examples/davresource/davresource.cpp +++ b/examples/davresource/davresource.cpp | |||
@@ -93,7 +93,7 @@ public: | |||
93 | QVector<QByteArray> ridList; | 93 | QVector<QByteArray> ridList; |
94 | for(const auto &f : addressbookList) { | 94 | for(const auto &f : addressbookList) { |
95 | const auto &rid = getRid(f); | 95 | const auto &rid = getRid(f); |
96 | SinkTrace() << "Found addressbook:" << rid; | 96 | SinkLog() << "Found addressbook:" << rid << f.displayName(); |
97 | ridList.append(rid); | 97 | ridList.append(rid); |
98 | createAddressbook(f.displayName(), rid, ""); | 98 | createAddressbook(f.displayName(), rid, ""); |
99 | } | 99 | } |
@@ -138,19 +138,21 @@ public: | |||
138 | if (error) { | 138 | if (error) { |
139 | SinkWarningCtx(mLogCtx) << "Failed to synchronize addressbooks." << collectionsFetchJob->errorString(); | 139 | SinkWarningCtx(mLogCtx) << "Failed to synchronize addressbooks." << collectionsFetchJob->errorString(); |
140 | } else { | 140 | } else { |
141 | synchronizeAddressbooks(collectionsFetchJob ->collections()); | 141 | synchronizeAddressbooks(collectionsFetchJob->collections()); |
142 | } | 142 | } |
143 | }); | 143 | }); |
144 | return job; | 144 | return job; |
145 | } else if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Contact>()) { | 145 | } else if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Contact>()) { |
146 | SinkLogCtx(mLogCtx) << "Synchronizing contacts."; | 146 | SinkLogCtx(mLogCtx) << "Synchronizing contacts."; |
147 | auto ridList = QSharedPointer<QByteArrayList>::create(); | 147 | auto ridList = QSharedPointer<QByteArrayList>::create(); |
148 | auto total = QSharedPointer<int>::create(0); | ||
149 | auto progress = QSharedPointer<int>::create(0); | ||
148 | auto collectionsFetchJob = new KDAV2::DavCollectionsFetchJob(mResourceUrl); | 150 | auto collectionsFetchJob = new KDAV2::DavCollectionsFetchJob(mResourceUrl); |
149 | auto job = runJob(collectionsFetchJob).then([this, collectionsFetchJob] { | 151 | auto job = runJob(collectionsFetchJob).then([this, collectionsFetchJob] { |
150 | synchronizeAddressbooks(collectionsFetchJob ->collections()); | 152 | synchronizeAddressbooks(collectionsFetchJob ->collections()); |
151 | return collectionsFetchJob->collections(); | 153 | return collectionsFetchJob->collections(); |
152 | }) | 154 | }) |
153 | .serialEach([this, ridList](const KDAV2::DavCollection &collection) { | 155 | .serialEach([=](const KDAV2::DavCollection &collection) { |
154 | auto collId = getRid(collection); | 156 | auto collId = getRid(collection); |
155 | const auto addressbookLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_ADDRESSBOOK, collId); | 157 | const auto addressbookLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_ADDRESSBOOK, collId); |
156 | auto ctag = collection.CTag().toLatin1(); | 158 | auto ctag = collection.CTag().toLatin1(); |
@@ -158,10 +160,11 @@ public: | |||
158 | SinkTraceCtx(mLogCtx) << "Syncing " << collId; | 160 | SinkTraceCtx(mLogCtx) << "Syncing " << collId; |
159 | auto cache = std::shared_ptr<KDAV2::EtagCache>(new KDAV2::EtagCache()); | 161 | auto cache = std::shared_ptr<KDAV2::EtagCache>(new KDAV2::EtagCache()); |
160 | auto davItemsListJob = new KDAV2::DavItemsListJob(collection.url(), cache); | 162 | auto davItemsListJob = new KDAV2::DavItemsListJob(collection.url(), cache); |
161 | const QByteArray bufferType = ENTITY_TYPE_CONTACT; | ||
162 | QHash<QByteArray, Query::Comparator> mergeCriteria; | 163 | QHash<QByteArray, Query::Comparator> mergeCriteria; |
163 | auto colljob = runJob(davItemsListJob).then([davItemsListJob] { | 164 | auto colljob = runJob(davItemsListJob).then([=] { |
164 | return KAsync::value(davItemsListJob->items()); | 165 | const auto items = davItemsListJob->items(); |
166 | *total = items.size(); | ||
167 | return KAsync::value(items); | ||
165 | }) | 168 | }) |
166 | .serialEach([=] (const KDAV2::DavItem &item) { | 169 | .serialEach([=] (const KDAV2::DavItem &item) { |
167 | QByteArray rid = getRid(item); | 170 | QByteArray rid = getRid(item); |
@@ -175,13 +178,19 @@ public: | |||
175 | Sink::ApplicationDomain::Contact contact; | 178 | Sink::ApplicationDomain::Contact contact; |
176 | contact.setVcard(item.data()); | 179 | contact.setVcard(item.data()); |
177 | contact.setAddressbook(addressbookLocalId); | 180 | contact.setAddressbook(addressbookLocalId); |
178 | createOrModify(bufferType, rid, contact, mergeCriteria); | 181 | createOrModify(ENTITY_TYPE_CONTACT, rid, contact, mergeCriteria); |
179 | return item; | 182 | return item; |
180 | }) | 183 | }) |
181 | .then([this, ridList] (const KDAV2::DavItem &item) { | 184 | .then([=] (const KDAV2::DavItem &item) { |
182 | const auto rid = getRid(item); | 185 | const auto rid = getRid(item); |
183 | syncStore().writeValue(rid + "_etag", item.etag().toLatin1()); | 186 | syncStore().writeValue(rid + "_etag", item.etag().toLatin1()); |
184 | ridList->append(rid); | 187 | ridList->append(rid); |
188 | *progress += 1; | ||
189 | reportProgress(*progress, *total, QByteArrayList{} << addressbookLocalId); | ||
190 | //commit every 5 contacts (so contacts start appearing in the UI) | ||
191 | if ((*progress % 5) == 0) { | ||
192 | commit(); | ||
193 | } | ||
185 | return rid; | 194 | return rid; |
186 | }); | 195 | }); |
187 | return itemjob; | 196 | return itemjob; |
@@ -190,7 +199,7 @@ public: | |||
190 | return KAsync::value(rid); | 199 | return KAsync::value(rid); |
191 | } | 200 | } |
192 | }) | 201 | }) |
193 | .then([this, collId, ctag] () { | 202 | .then([=] () { |
194 | syncStore().writeValue(collId + "_ctag", ctag); | 203 | syncStore().writeValue(collId + "_ctag", ctag); |
195 | }); | 204 | }); |
196 | return colljob; | 205 | return colljob; |
@@ -251,6 +260,7 @@ DavResourceFactory::DavResourceFactory(QObject *parent) | |||
251 | : Sink::ResourceFactory(parent, | 260 | : Sink::ResourceFactory(parent, |
252 | {Sink::ApplicationDomain::ResourceCapabilities::Contact::contact, | 261 | {Sink::ApplicationDomain::ResourceCapabilities::Contact::contact, |
253 | Sink::ApplicationDomain::ResourceCapabilities::Contact::addressbook, | 262 | Sink::ApplicationDomain::ResourceCapabilities::Contact::addressbook, |
263 | Sink::ApplicationDomain::ResourceCapabilities::Contact::storage | ||
254 | } | 264 | } |
255 | ) | 265 | ) |
256 | { | 266 | { |
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}) | |||
6 | 6 | ||
7 | add_library(${PROJECT_NAME} SHARED resourcefactory.cpp domainadaptor.cpp dummystore.cpp) | 7 | add_library(${PROJECT_NAME} SHARED resourcefactory.cpp domainadaptor.cpp dummystore.cpp) |
8 | generate_flatbuffers(${PROJECT_NAME} dummycalendar) | 8 | generate_flatbuffers(${PROJECT_NAME} dummycalendar) |
9 | qt5_use_modules(${PROJECT_NAME} Core Network) | 9 | target_link_libraries(${PROJECT_NAME} sink Qt5::Core Qt5::Network) |
10 | target_link_libraries(${PROJECT_NAME} sink) | ||
11 | 10 | ||
12 | install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) | 11 | 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) | |||
9 | include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) | 9 | include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) |
10 | 10 | ||
11 | add_library(${PROJECT_NAME} SHARED imapresource.cpp imapserverproxy.cpp) | 11 | add_library(${PROJECT_NAME} SHARED imapresource.cpp imapserverproxy.cpp) |
12 | qt5_use_modules(${PROJECT_NAME} Core Network) | 12 | target_link_libraries(${PROJECT_NAME} sink Qt5::Core Qt5::Network KF5::Mime KIMAP2) |
13 | target_link_libraries(${PROJECT_NAME} sink KF5::Mime KIMAP2) | ||
14 | 13 | ||
15 | install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) | 14 | install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) |
16 | 15 | ||
diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 81c808b..3ae7fd7 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp | |||
@@ -511,6 +511,8 @@ public: | |||
511 | return {ApplicationDomain::LoginError, error.errorMessage}; | 511 | return {ApplicationDomain::LoginError, error.errorMessage}; |
512 | case Imap::HostNotFoundError: | 512 | case Imap::HostNotFoundError: |
513 | return {ApplicationDomain::NoServerError, error.errorMessage}; | 513 | return {ApplicationDomain::NoServerError, error.errorMessage}; |
514 | case Imap::ConnectionLost: | ||
515 | return {ApplicationDomain::ConnectionLostError, error.errorMessage}; | ||
514 | default: | 516 | default: |
515 | return {ApplicationDomain::UnknownError, error.errorMessage}; | 517 | return {ApplicationDomain::UnknownError, error.errorMessage}; |
516 | } | 518 | } |
@@ -619,6 +621,15 @@ public: | |||
619 | 621 | ||
620 | KAsync::Job<QByteArray> replay(const ApplicationDomain::Mail &mail, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE | 622 | KAsync::Job<QByteArray> replay(const ApplicationDomain::Mail &mail, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE |
621 | { | 623 | { |
624 | if (operation != Sink::Operation_Creation) { | ||
625 | if(oldRemoteId.isEmpty()) { | ||
626 | // return KAsync::error<QByteArray>("Tried to replay modification without old remoteId."); | ||
627 | qWarning() << "Tried to replay modification without old remoteId."; | ||
628 | // Since we can't recover from the situation we just skip over the revision. | ||
629 | // FIXME figure out how we can ever end up in this situation | ||
630 | return KAsync::null<QByteArray>(); | ||
631 | } | ||
632 | } | ||
622 | auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort, &mSessionCache); | 633 | auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort, &mSessionCache); |
623 | auto login = imap->login(mUser, mPassword); | 634 | auto login = imap->login(mUser, mPassword); |
624 | KAsync::Job<QByteArray> job = KAsync::null<QByteArray>(); | 635 | KAsync::Job<QByteArray> job = KAsync::null<QByteArray>(); |
diff --git a/examples/imapresource/imapserverproxy.cpp b/examples/imapresource/imapserverproxy.cpp index 538105c..5c2e07c 100644 --- a/examples/imapresource/imapserverproxy.cpp +++ b/examples/imapresource/imapserverproxy.cpp | |||
@@ -61,6 +61,21 @@ const char* Imap::Capabilities::Namespace = "NAMESPACE"; | |||
61 | const char* Imap::Capabilities::Uidplus = "UIDPLUS"; | 61 | const char* Imap::Capabilities::Uidplus = "UIDPLUS"; |
62 | const char* Imap::Capabilities::Condstore = "CONDSTORE"; | 62 | const char* Imap::Capabilities::Condstore = "CONDSTORE"; |
63 | 63 | ||
64 | static int translateImapError(int error) | ||
65 | { | ||
66 | switch (error) { | ||
67 | case KJob::UserDefinedError: | ||
68 | return Imap::ConnectionLost; | ||
69 | case KIMAP2::LoginJob::ErrorCode::ERR_HOST_NOT_FOUND: | ||
70 | return Imap::HostNotFoundError; | ||
71 | case KIMAP2::LoginJob::ErrorCode::ERR_COULD_NOT_CONNECT: | ||
72 | return Imap::CouldNotConnectError; | ||
73 | case KIMAP2::LoginJob::ErrorCode::ERR_SSL_HANDSHAKE_FAILED: | ||
74 | return Imap::SslHandshakeError; | ||
75 | } | ||
76 | return Imap::UnknownError; | ||
77 | } | ||
78 | |||
64 | template <typename T> | 79 | template <typename T> |
65 | static KAsync::Job<T> runJob(KJob *job, const std::function<T(KJob*)> &f) | 80 | static KAsync::Job<T> runJob(KJob *job, const std::function<T(KJob*)> &f) |
66 | { | 81 | { |
@@ -69,7 +84,8 @@ static KAsync::Job<T> runJob(KJob *job, const std::function<T(KJob*)> &f) | |||
69 | SinkTrace() << "Job done: " << job->metaObject()->className(); | 84 | SinkTrace() << "Job done: " << job->metaObject()->className(); |
70 | if (job->error()) { | 85 | if (job->error()) { |
71 | SinkWarning() << "Job failed: " << job->errorString() << job->metaObject()->className(); | 86 | SinkWarning() << "Job failed: " << job->errorString() << job->metaObject()->className(); |
72 | future.setError(job->error(), job->errorString()); | 87 | auto proxyError = translateImapError(job->error()); |
88 | future.setError(proxyError, job->errorString()); | ||
73 | } else { | 89 | } else { |
74 | future.setValue(f(job)); | 90 | future.setValue(f(job)); |
75 | future.setFinished(); | 91 | future.setFinished(); |
@@ -87,7 +103,8 @@ static KAsync::Job<void> runJob(KJob *job) | |||
87 | SinkTrace() << "Job done: " << job->metaObject()->className(); | 103 | SinkTrace() << "Job done: " << job->metaObject()->className(); |
88 | if (job->error()) { | 104 | if (job->error()) { |
89 | SinkWarning() << "Job failed: " << job->errorString() << job->metaObject()->className(); | 105 | SinkWarning() << "Job failed: " << job->errorString() << job->metaObject()->className(); |
90 | future.setError(job->error(), job->errorString()); | 106 | auto proxyError = translateImapError(job->error()); |
107 | future.setError(proxyError, job->errorString()); | ||
91 | } else { | 108 | } else { |
92 | future.setFinished(); | 109 | future.setFinished(); |
93 | } | 110 | } |
@@ -166,20 +183,6 @@ KAsync::Job<void> ImapServerProxy::login(const QString &username, const QString | |||
166 | // SinkTrace() << "Found personal namespaces: " << mNamespaces.personal; | 183 | // SinkTrace() << "Found personal namespaces: " << mNamespaces.personal; |
167 | // SinkTrace() << "Found shared namespaces: " << mNamespaces.shared; | 184 | // SinkTrace() << "Found shared namespaces: " << mNamespaces.shared; |
168 | // SinkTrace() << "Found user namespaces: " << mNamespaces.user; | 185 | // SinkTrace() << "Found user namespaces: " << mNamespaces.user; |
169 | }).then([=] (const KAsync::Error &error) { | ||
170 | if (error) { | ||
171 | switch (error.errorCode) { | ||
172 | case KIMAP2::LoginJob::ErrorCode::ERR_HOST_NOT_FOUND: | ||
173 | return KAsync::error(HostNotFoundError, "Host not found: " + error.errorMessage); | ||
174 | case KIMAP2::LoginJob::ErrorCode::ERR_COULD_NOT_CONNECT: | ||
175 | return KAsync::error(CouldNotConnectError, "Failed to connect: " + error.errorMessage); | ||
176 | case KIMAP2::LoginJob::ErrorCode::ERR_SSL_HANDSHAKE_FAILED: | ||
177 | return KAsync::error(SslHandshakeError, "Ssl handshake failed: " + error.errorMessage); | ||
178 | default: | ||
179 | return KAsync::error(error); | ||
180 | } | ||
181 | } | ||
182 | return KAsync::null(); | ||
183 | }); | 186 | }); |
184 | } | 187 | } |
185 | 188 | ||
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 { | |||
33 | NoError, | 33 | NoError, |
34 | HostNotFoundError, | 34 | HostNotFoundError, |
35 | CouldNotConnectError, | 35 | CouldNotConnectError, |
36 | SslHandshakeError | 36 | SslHandshakeError, |
37 | ConnectionLost, | ||
38 | UnknownError | ||
37 | }; | 39 | }; |
38 | 40 | ||
39 | namespace Flags | 41 | namespace Flags |
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}) | |||
6 | find_package(KF5 COMPONENTS REQUIRED Mime) | 6 | find_package(KF5 COMPONENTS REQUIRED Mime) |
7 | 7 | ||
8 | add_library(${PROJECT_NAME} SHARED facade.cpp maildirresource.cpp libmaildir/maildir.cpp libmaildir/keycache.cpp) | 8 | add_library(${PROJECT_NAME} SHARED facade.cpp maildirresource.cpp libmaildir/maildir.cpp libmaildir/keycache.cpp) |
9 | qt5_use_modules(${PROJECT_NAME} Core Network) | 9 | target_link_libraries(${PROJECT_NAME} sink Qt5::Core Qt5::Network KF5::Mime) |
10 | target_link_libraries(${PROJECT_NAME} sink KF5::Mime) | ||
11 | 10 | ||
12 | install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) | 11 | install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) |
13 | 12 | ||
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}) | |||
10 | 10 | ||
11 | 11 | ||
12 | add_library(${PROJECT_NAME} SHARED mailtransportresource.cpp mailtransport.cpp) | 12 | add_library(${PROJECT_NAME} SHARED mailtransportresource.cpp mailtransport.cpp) |
13 | qt5_use_modules(${PROJECT_NAME} Core Network) | 13 | target_link_libraries(${PROJECT_NAME} |
14 | target_link_libraries(${PROJECT_NAME} sink KF5::Mime ${CURL_LIBRARIES}) | 14 | sink |
15 | Qt5::Core | ||
16 | Qt5::Network | ||
17 | KF5::Mime | ||
18 | ${CURL_LIBRARIES} | ||
19 | ) | ||
15 | install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) | 20 | install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${SINK_RESOURCE_PLUGINS_PATH}) |
16 | 21 | ||
17 | add_executable(sink_smtp_test smtptest.cpp mailtransport.cpp) | 22 | add_executable(sink_smtp_test smtptest.cpp mailtransport.cpp) |
18 | qt5_use_modules(sink_smtp_test Core Network) | 23 | target_link_libraries(sink_smtp_test |
19 | target_link_libraries(sink_smtp_test sink KF5::Mime ${CURL_LIBRARIES}) | 24 | sink |
25 | Qt5::Core | ||
26 | Qt5::Network | ||
27 | KF5::Mime | ||
28 | ${CURL_LIBRARIES} | ||
29 | ) | ||
20 | install(TARGETS sink_smtp_test ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) | 30 | install(TARGETS sink_smtp_test ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) |
21 | 31 | ||
22 | add_subdirectory(tests) | 32 | add_subdirectory(tests) |
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 | |||
19 | syntax_modules/sink_inspect.cpp | 19 | syntax_modules/sink_inspect.cpp |
20 | syntax_modules/sink_drop.cpp | 20 | syntax_modules/sink_drop.cpp |
21 | syntax_modules/sink_upgrade.cpp | 21 | syntax_modules/sink_upgrade.cpp |
22 | syntax_modules/sink_info.cpp | ||
22 | sinksh_utils.cpp | 23 | sinksh_utils.cpp |
23 | repl/repl.cpp | 24 | repl/repl.cpp |
24 | repl/replStates.cpp | 25 | 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..aa515e6 --- /dev/null +++ b/sinksh/syntax_modules/sink_info.cpp | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Christian Mollekopf <mollekopf@kolabsys.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | |||
20 | #include <QDebug> | ||
21 | #include <QObject> // tr() | ||
22 | |||
23 | #include "common/definitions.h" | ||
24 | |||
25 | #include "sinksh_utils.h" | ||
26 | #include "state.h" | ||
27 | #include "syntaxtree.h" | ||
28 | #include "sink_version.h" | ||
29 | |||
30 | namespace SinkInfo | ||
31 | { | ||
32 | |||
33 | bool info(const QStringList &args, State &state) | ||
34 | { | ||
35 | state.printLine(QString("Sink version: %1").arg(sink_VERSION_STRING)); | ||
36 | state.printLine(QString("Storage location: %1").arg(Sink::storageLocation())); | ||
37 | state.printLine(QString("Data location: %1").arg(Sink::dataLocation())); | ||
38 | state.printLine(QString("Config location: %1").arg(Sink::configLocation())); | ||
39 | state.printLine(QString("Temporary file location: %1").arg(Sink::temporaryFileLocation())); | ||
40 | state.printLine(QString("Resource storage location: %1").arg(Sink::resourceStorageLocation("$RESOURCE"))); | ||
41 | return false; | ||
42 | } | ||
43 | |||
44 | Syntax::List syntax() | ||
45 | { | ||
46 | return Syntax::List() << Syntax{"info", QObject::tr("Shows general system info"), &SinkInfo::info, Syntax::NotInteractive}; | ||
47 | } | ||
48 | |||
49 | REGISTER_SYNTAX(SinkInfo) | ||
50 | |||
51 | } | ||
diff --git a/sinksh/syntax_modules/sink_inspect.cpp b/sinksh/syntax_modules/sink_inspect.cpp index a8a3805..da62250 100644 --- a/sinksh/syntax_modules/sink_inspect.cpp +++ b/sinksh/syntax_modules/sink_inspect.cpp | |||
@@ -19,8 +19,6 @@ | |||
19 | 19 | ||
20 | #include <QDebug> | 20 | #include <QDebug> |
21 | #include <QObject> // tr() | 21 | #include <QObject> // tr() |
22 | #include <QTimer> | ||
23 | #include <QDir> | ||
24 | 22 | ||
25 | #include "common/resource.h" | 23 | #include "common/resource.h" |
26 | #include "common/storage.h" | 24 | #include "common/storage.h" |
@@ -30,6 +28,7 @@ | |||
30 | #include "common/definitions.h" | 28 | #include "common/definitions.h" |
31 | #include "common/entitybuffer.h" | 29 | #include "common/entitybuffer.h" |
32 | #include "common/metadata_generated.h" | 30 | #include "common/metadata_generated.h" |
31 | #include "common/bufferutils.h" | ||
33 | 32 | ||
34 | #include "sinksh_utils.h" | 33 | #include "sinksh_utils.h" |
35 | #include "state.h" | 34 | #include "state.h" |
@@ -41,7 +40,7 @@ namespace SinkInspect | |||
41 | bool inspect(const QStringList &args, State &state) | 40 | bool inspect(const QStringList &args, State &state) |
42 | { | 41 | { |
43 | if (args.isEmpty()) { | 42 | if (args.isEmpty()) { |
44 | state.printError(QObject::tr("Options: $type [--resource $resource] [--db $db] [--filter $id] [--showinternal]")); | 43 | state.printError(QObject::tr("Options: [--resource $resource] ([--db $db] [--filter $id] [--showinternal] | [--validaterids $type])")); |
45 | } | 44 | } |
46 | auto options = SyntaxTree::parseOptions(args); | 45 | auto options = SyntaxTree::parseOptions(args); |
47 | auto resource = options.options.value("resource").value(0); | 46 | auto resource = options.options.value("resource").value(0); |
@@ -49,6 +48,75 @@ bool inspect(const QStringList &args, State &state) | |||
49 | Sink::Storage::DataStore storage(Sink::storageLocation(), resource, Sink::Storage::DataStore::ReadOnly); | 48 | Sink::Storage::DataStore storage(Sink::storageLocation(), resource, Sink::Storage::DataStore::ReadOnly); |
50 | auto transaction = storage.createTransaction(Sink::Storage::DataStore::ReadOnly); | 49 | auto transaction = storage.createTransaction(Sink::Storage::DataStore::ReadOnly); |
51 | 50 | ||
51 | bool validateRids = options.options.contains("validaterids"); | ||
52 | if (validateRids) { | ||
53 | if (options.options.value("validaterids").isEmpty()) { | ||
54 | state.printError(QObject::tr("Specify a type to validate.")); | ||
55 | return false; | ||
56 | } | ||
57 | auto type = options.options.value("validaterids").first().toUtf8(); | ||
58 | /* | ||
59 | * Try to find all rid's for all uid's. | ||
60 | * If we have entities without rid's that either means we have only created it locally or that we have a problem. | ||
61 | */ | ||
62 | Sink::Storage::DataStore syncStore(Sink::storageLocation(), resource + ".synchronization", Sink::Storage::DataStore::ReadOnly); | ||
63 | auto syncTransaction = syncStore.createTransaction(Sink::Storage::DataStore::ReadOnly); | ||
64 | |||
65 | auto db = transaction.openDatabase(type + ".main", | ||
66 | [&] (const Sink::Storage::DataStore::Error &e) { | ||
67 | Q_ASSERT(false); | ||
68 | state.printError(e.message); | ||
69 | }, false); | ||
70 | |||
71 | auto ridMap = syncTransaction.openDatabase("localid.mapping." + type, | ||
72 | [&] (const Sink::Storage::DataStore::Error &e) { | ||
73 | Q_ASSERT(false); | ||
74 | state.printError(e.message); | ||
75 | }, false); | ||
76 | |||
77 | QHash<QByteArray, QByteArray> hash; | ||
78 | |||
79 | ridMap.scan("", [&] (const QByteArray &key, const QByteArray &data) { | ||
80 | hash.insert(key, data); | ||
81 | return true; | ||
82 | }, | ||
83 | [&](const Sink::Storage::DataStore::Error &e) { | ||
84 | state.printError(e.message); | ||
85 | }, | ||
86 | false); | ||
87 | |||
88 | QSet<QByteArray> uids; | ||
89 | db.scan("", [&] (const QByteArray &key, const QByteArray &data) { | ||
90 | uids.insert(Sink::Storage::DataStore::uidFromKey(key)); | ||
91 | return true; | ||
92 | }, | ||
93 | [&](const Sink::Storage::DataStore::Error &e) { | ||
94 | state.printError(e.message); | ||
95 | }, | ||
96 | false); | ||
97 | |||
98 | int missing = 0; | ||
99 | for (const auto &uid : uids) { | ||
100 | if (!hash.remove(uid)) { | ||
101 | missing++; | ||
102 | qWarning() << "Failed to find RID for " << uid; | ||
103 | } | ||
104 | } | ||
105 | if (missing) { | ||
106 | qWarning() << "Found a total of " << missing << " missing rids"; | ||
107 | } | ||
108 | |||
109 | //If we still have items in the hash it means we have rid mappings for entities | ||
110 | //that no longer exist. | ||
111 | if (!hash.isEmpty()) { | ||
112 | qWarning() << "Have rids left: " << hash.size(); | ||
113 | } else if (!missing) { | ||
114 | qWarning() << "Everything is in order."; | ||
115 | } | ||
116 | |||
117 | return false; | ||
118 | } | ||
119 | |||
52 | auto dbs = options.options.value("db"); | 120 | auto dbs = options.options.value("db"); |
53 | auto idFilter = options.options.value("filter"); | 121 | auto idFilter = options.options.value("filter"); |
54 | bool showInternal = options.options.contains("showinternal"); | 122 | bool showInternal = options.options.contains("showinternal"); |
@@ -96,7 +164,10 @@ bool inspect(const QStringList &args, State &state) | |||
96 | state.printError("Read invalid buffer from disk: " + key); | 164 | state.printError("Read invalid buffer from disk: " + key); |
97 | } else { | 165 | } else { |
98 | const auto metadata = flatbuffers::GetRoot<Sink::Metadata>(buffer.metadataBuffer()); | 166 | const auto metadata = flatbuffers::GetRoot<Sink::Metadata>(buffer.metadataBuffer()); |
99 | state.printLine("Key: " + key + " Operation: " + QString::number(metadata->operation())); | 167 | state.printLine("Key: " + key |
168 | + " Operation: " + QString::number(metadata->operation()) | ||
169 | + " Replay: " + (metadata->replayToSource() ? "true" : "false") | ||
170 | + ((metadata->modifiedProperties() && metadata->modifiedProperties()->size() != 0) ? (" [" + Sink::BufferUtils::fromVector(*metadata->modifiedProperties()).join(", ")) + "]": "")); | ||
100 | } | 171 | } |
101 | } else { | 172 | } else { |
102 | state.printLine("Key: " + key + " Value: " + QString::fromUtf8(data)); | 173 | state.printLine("Key: " + key + " Value: " + QString::fromUtf8(data)); |
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 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <QCoreApplication> | ||
22 | #include <QDebug> | 21 | #include <QDebug> |
23 | #include <QObject> // tr() | 22 | #include <QObject> // tr() |
24 | #include <QModelIndex> | 23 | #include <QModelIndex> |
25 | #include <QTime> | 24 | #include <QTime> |
26 | 25 | ||
27 | #include "common/resource.h" | ||
28 | #include "common/storage.h" | 26 | #include "common/storage.h" |
29 | #include "common/resourceconfig.h" | ||
30 | #include "common/log.h" | ||
31 | #include "common/storage.h" | ||
32 | #include "common/definitions.h" | ||
33 | 27 | ||
34 | #include "sinksh_utils.h" | 28 | #include "sinksh_utils.h" |
35 | #include "state.h" | 29 | #include "state.h" |
@@ -41,25 +35,24 @@ namespace SinkShow | |||
41 | bool show(const QStringList &args, State &state) | 35 | bool show(const QStringList &args, State &state) |
42 | { | 36 | { |
43 | if (args.isEmpty()) { | 37 | if (args.isEmpty()) { |
44 | state.printError(QObject::tr("Please provide at least one type to show (e.g. resource, ..")); | 38 | state.printError(QObject::tr("Options: $type --resource $resource --id $id")); |
45 | return false; | 39 | return false; |
46 | } | 40 | } |
47 | 41 | ||
48 | auto argList = args; | 42 | auto options = SyntaxTree::parseOptions(args); |
49 | if (argList.size() < 2 || !SinkshUtils::isValidStoreType(argList.at(0))) { | 43 | |
44 | auto type = options.positionalArguments.isEmpty() ? QString{} : options.positionalArguments.first(); | ||
45 | auto resource = options.options.value("resource"); | ||
46 | auto id = options.options.value("id"); | ||
47 | |||
48 | if (id.isEmpty() || resource.isEmpty() || !SinkshUtils::isValidStoreType(type)) { | ||
50 | state.printError(QObject::tr("Invalid command syntax. Supply type and resource at least.")); | 49 | state.printError(QObject::tr("Invalid command syntax. Supply type and resource at least.")); |
51 | return false; | 50 | return false; |
52 | } | 51 | } |
53 | auto type = argList.takeFirst(); | ||
54 | auto resource = argList.takeFirst(); | ||
55 | bool queryForResourceOrAgent = argList.isEmpty(); | ||
56 | 52 | ||
57 | Sink::Query query; | 53 | Sink::Query query; |
58 | if (queryForResourceOrAgent) { | 54 | query.resourceFilter(resource.first().toLatin1()); |
59 | query.filter(resource.toLatin1()); | 55 | query.filter(id.first().toLatin1()); |
60 | } else { | ||
61 | query.resourceFilter(resource.toLatin1()); | ||
62 | } | ||
63 | 56 | ||
64 | QTime time; | 57 | QTime time; |
65 | time.start(); | 58 | time.start(); |
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 | |||
7 | ) | 7 | ) |
8 | 8 | ||
9 | add_executable(${PROJECT_NAME} ${sinksynchronizer_SRCS}) | 9 | add_executable(${PROJECT_NAME} ${sinksynchronizer_SRCS}) |
10 | target_link_libraries(${PROJECT_NAME} sink KAsync ${CMAKE_DL_LIBS}) | 10 | target_link_libraries(${PROJECT_NAME} |
11 | qt5_use_modules(${PROJECT_NAME} Core Network) | 11 | sink |
12 | Qt5::Core | ||
13 | Qt5::Network | ||
14 | KAsync | ||
15 | ${CMAKE_DL_LIBS} | ||
16 | ) | ||
12 | install(TARGETS ${PROJECT_NAME} ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) | 17 | install(TARGETS ${PROJECT_NAME} ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) |
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2b3e7b1..6a757ca 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt | |||
@@ -9,12 +9,19 @@ include_directories( | |||
9 | ) | 9 | ) |
10 | 10 | ||
11 | add_definitions(-DTESTDATAPATH="${CMAKE_CURRENT_SOURCE_DIR}/data") | 11 | add_definitions(-DTESTDATAPATH="${CMAKE_CURRENT_SOURCE_DIR}/data") |
12 | add_definitions(-DTHREADTESTDATAPATH="${CMAKE_CURRENT_SOURCE_DIR}/threaddata") | ||
12 | 13 | ||
13 | find_package(KF5 COMPONENTS REQUIRED Mime) | 14 | find_package(KF5 COMPONENTS REQUIRED Mime) |
14 | 15 | ||
15 | add_library(sink_test SHARED testimplementations.cpp getrssusage.cpp mailtest.cpp mailsynctest.cpp mailthreadtest.cpp) | 16 | add_library(sink_test SHARED testimplementations.cpp getrssusage.cpp mailtest.cpp mailsynctest.cpp mailthreadtest.cpp) |
16 | qt5_use_modules(sink_test Core Test Concurrent) | 17 | target_link_libraries(sink_test |
17 | target_link_libraries(sink_test sink libhawd KF5::Mime) | 18 | sink |
19 | libhawd | ||
20 | Qt5::Core | ||
21 | Qt5::Concurrent | ||
22 | Qt5::Test | ||
23 | KF5::Mime | ||
24 | ) | ||
18 | 25 | ||
19 | add_executable(dbwriter dbwriter.cpp) | 26 | add_executable(dbwriter dbwriter.cpp) |
20 | target_link_libraries(dbwriter sink) | 27 | 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) | |||
17 | add_executable(${_testname} ${_testname}.cpp) | 17 | add_executable(${_testname} ${_testname}.cpp) |
18 | add_test(${_testname} ${_testname}) | 18 | add_test(${_testname} ${_testname}) |
19 | add_memcheck_test(${_testname} ${_testname}) | 19 | add_memcheck_test(${_testname} ${_testname}) |
20 | qt5_use_modules(${_testname} Core Test Concurrent) | 20 | target_link_libraries(${_testname} |
21 | target_link_libraries(${_testname} sink libhawd sink_test) | 21 | sink libhawd |
22 | sink_test | ||
23 | Qt5::Core | ||
24 | Qt5::Concurrent | ||
25 | Qt5::Test | ||
26 | ) | ||
22 | endforeach(_testname) | 27 | endforeach(_testname) |
23 | endmacro(auto_tests) | 28 | endmacro(auto_tests) |
24 | 29 | ||
@@ -26,7 +31,13 @@ macro(manual_tests) | |||
26 | foreach(_testname ${ARGN}) | 31 | foreach(_testname ${ARGN}) |
27 | add_executable(${_testname} ${_testname}.cpp) | 32 | add_executable(${_testname} ${_testname}.cpp) |
28 | add_memcheck_test(${_testname} ${_testname}) | 33 | add_memcheck_test(${_testname} ${_testname}) |
29 | qt5_use_modules(${_testname} Core Test Concurrent) | 34 | target_link_libraries(${_testname} |
30 | target_link_libraries(${_testname} sink libhawd sink_test) | 35 | sink |
36 | libhawd | ||
37 | sink_test | ||
38 | Qt5::Core | ||
39 | Qt5::Concurrent | ||
40 | Qt5::Test | ||
41 | ) | ||
31 | endforeach(_testname) | 42 | endforeach(_testname) |
32 | endmacro(manual_tests) | 43 | endmacro(manual_tests) |
diff --git a/tests/accountstest.cpp b/tests/accountstest.cpp index 0ab18ef..2eee9f9 100644 --- a/tests/accountstest.cpp +++ b/tests/accountstest.cpp | |||
@@ -139,7 +139,7 @@ private slots: | |||
139 | auto model = Sink::Store::loadModel<Sink::ApplicationDomain::SinkAccount>(query); | 139 | auto model = Sink::Store::loadModel<Sink::ApplicationDomain::SinkAccount>(query); |
140 | QTRY_COMPARE(model->rowCount(QModelIndex()), 1); | 140 | QTRY_COMPARE(model->rowCount(QModelIndex()), 1); |
141 | auto account = model->data(model->index(0, 0, QModelIndex()), Sink::Store::DomainObjectRole).value<Sink::ApplicationDomain::SinkAccount::Ptr>(); | 141 | auto account = model->data(model->index(0, 0, QModelIndex()), Sink::Store::DomainObjectRole).value<Sink::ApplicationDomain::SinkAccount::Ptr>(); |
142 | QCOMPARE(account->getStatus(), static_cast<int>(Sink::ApplicationDomain::OfflineStatus)); | 142 | QCOMPARE(account->getStatus(), static_cast<int>(Sink::ApplicationDomain::NoStatus)); |
143 | 143 | ||
144 | //Synchronize to connect | 144 | //Synchronize to connect |
145 | VERIFYEXEC(Sink::Store::synchronize(Query().resourceFilter(res.identifier()))); | 145 | VERIFYEXEC(Sink::Store::synchronize(Query().resourceFilter(res.identifier()))); |
@@ -148,6 +148,40 @@ private slots: | |||
148 | } | 148 | } |
149 | } | 149 | } |
150 | 150 | ||
151 | void testLoadAccountStatusLive() | ||
152 | { | ||
153 | using namespace Sink; | ||
154 | using namespace Sink::ApplicationDomain; | ||
155 | |||
156 | { | ||
157 | //Create a live query for all accounts | ||
158 | Sink::Query query; | ||
159 | query.setFlags(Query::LiveQuery); | ||
160 | query.request<Sink::ApplicationDomain::SinkAccount::Status>(); | ||
161 | |||
162 | auto model = Sink::Store::loadModel<Sink::ApplicationDomain::SinkAccount>(query); | ||
163 | |||
164 | //Create the account | ||
165 | auto account = ApplicationDomainType::createEntity<SinkAccount>(); | ||
166 | account.setAccountType("dummy"); | ||
167 | account.setName("name"); | ||
168 | VERIFYEXEC(Store::create(account)); | ||
169 | |||
170 | auto res = Sink::ApplicationDomain::DummyResource::create(account.identifier()); | ||
171 | VERIFYEXEC(Sink::Store::create(res)); | ||
172 | |||
173 | //Ensure the account was created | ||
174 | QTRY_COMPARE(model->rowCount(QModelIndex()), 1); | ||
175 | auto retrievedAccount = model->data(model->index(0, 0, QModelIndex()), Sink::Store::DomainObjectRole).value<Sink::ApplicationDomain::SinkAccount::Ptr>(); | ||
176 | QCOMPARE(retrievedAccount->getStatus(), static_cast<int>(Sink::ApplicationDomain::NoStatus)); | ||
177 | |||
178 | //Synchronize to connect and ensure we receive the update | ||
179 | VERIFYEXEC(Sink::Store::synchronize(Query().resourceFilter(res.identifier()))); | ||
180 | |||
181 | QTRY_COMPARE_WITH_TIMEOUT(model->data(model->index(0, 0, QModelIndex()), Sink::Store::DomainObjectRole).value<Sink::ApplicationDomain::SinkAccount::Ptr>()->getStatus(), static_cast<int>(Sink::ApplicationDomain::ConnectedStatus), 1000); | ||
182 | } | ||
183 | } | ||
184 | |||
151 | }; | 185 | }; |
152 | 186 | ||
153 | QTEST_GUILESS_MAIN(AccountsTest) | 187 | QTEST_GUILESS_MAIN(AccountsTest) |
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: | |||
360 | auto event = Sink::ApplicationDomain::Event::createEntity<Sink::ApplicationDomain::Event>("dummyresource.instance1"); | 360 | auto event = Sink::ApplicationDomain::Event::createEntity<Sink::ApplicationDomain::Event>("dummyresource.instance1"); |
361 | Sink::Store::create(event).exec().waitForFinished(); | 361 | Sink::Store::create(event).exec().waitForFinished(); |
362 | QCOMPARE(facade->creations.size(), 1); | 362 | QCOMPARE(facade->creations.size(), 1); |
363 | //Modify something so the mdofication won't be dropped | ||
364 | event.setSummary("foobar"); | ||
363 | Sink::Store::modify(event).exec().waitForFinished(); | 365 | Sink::Store::modify(event).exec().waitForFinished(); |
364 | QCOMPARE(facade->modifications.size(), 1); | 366 | QCOMPARE(facade->modifications.size(), 1); |
365 | Sink::Store::remove(event).exec().waitForFinished(); | 367 | Sink::Store::remove(event).exec().waitForFinished(); |
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 | |||
27 | 27 | ||
28 | add_library(lib${PROJECT_NAME} SHARED ${lib_SRCS}) | 28 | add_library(lib${PROJECT_NAME} SHARED ${lib_SRCS}) |
29 | generate_export_header(lib${PROJECT_NAME} BASE_NAME HAWD EXPORT_FILE_NAME hawd_export.h) | 29 | generate_export_header(lib${PROJECT_NAME} BASE_NAME HAWD EXPORT_FILE_NAME hawd_export.h) |
30 | qt5_use_modules(lib${PROJECT_NAME} Core) | 30 | target_link_libraries(lib${PROJECT_NAME} sink Qt5::Core) |
31 | target_link_libraries(lib${PROJECT_NAME} sink) | ||
32 | if (LIBGIT2_FOUND) | 31 | if (LIBGIT2_FOUND) |
33 | target_link_libraries(lib${PROJECT_NAME} ${LIBGIT2_LIBRARIES}) | 32 | target_link_libraries(lib${PROJECT_NAME} ${LIBGIT2_LIBRARIES}) |
34 | endif(LIBGIT2_FOUND) | 33 | endif(LIBGIT2_FOUND) |
@@ -36,8 +35,7 @@ endif(LIBGIT2_FOUND) | |||
36 | install(TARGETS lib${PROJECT_NAME} ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) | 35 | install(TARGETS lib${PROJECT_NAME} ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) |
37 | 36 | ||
38 | add_executable(${PROJECT_NAME} ${SRCS}) | 37 | add_executable(${PROJECT_NAME} ${SRCS}) |
39 | qt5_use_modules(${PROJECT_NAME} Core) | 38 | target_link_libraries(${PROJECT_NAME} lib${PROJECT_NAME} Qt5::Core) |
40 | target_link_libraries(${PROJECT_NAME} lib${PROJECT_NAME}) | ||
41 | if (LIBGIT2_FOUND) | 39 | if (LIBGIT2_FOUND) |
42 | target_link_libraries(${PROJECT_NAME} ${LIBGIT2_LIBRARIES}) | 40 | target_link_libraries(${PROJECT_NAME} ${LIBGIT2_LIBRARIES}) |
43 | endif(LIBGIT2_FOUND) | 41 | endif(LIBGIT2_FOUND) |
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() | |||
328 | return KAsync::null<void>(); | 328 | return KAsync::null<void>(); |
329 | }); | 329 | }); |
330 | VERIFYEXEC(job2); | 330 | VERIFYEXEC(job2); |
331 | |||
332 | //Verify we can mark the mail as unread again | ||
333 | { | ||
334 | auto readMail = Store::readOne<Mail>(Query{mail}); | ||
335 | readMail.setUnread(true); | ||
336 | VERIFYEXEC(Store::modify(readMail)); | ||
337 | VERIFYEXEC(ResourceControl::flushReplayQueue(mResourceInstanceIdentifier)); | ||
338 | VERIFYEXEC(ResourceControl::inspect<Mail>(ResourceControl::Inspection::PropertyInspection(readMail, Mail::Unread::name, true))); | ||
339 | } | ||
331 | } | 340 | } |
332 | 341 | ||
333 | void MailTest::testCreateDraft() | 342 | void MailTest::testCreateDraft() |
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 @@ | |||
21 | #include <QtTest> | 21 | #include <QtTest> |
22 | 22 | ||
23 | #include <QString> | 23 | #include <QString> |
24 | #include <QFile> | ||
24 | #include <KMime/Message> | 25 | #include <KMime/Message> |
25 | 26 | ||
26 | #include "store.h" | 27 | #include "store.h" |
@@ -185,4 +186,67 @@ void MailThreadTest::testIndexInMixedOrder() | |||
185 | /* VERIFYEXEC(ResourceControl::flushReplayQueue(QByteArrayList() << mResourceInstanceIdentifier)); */ | 186 | /* VERIFYEXEC(ResourceControl::flushReplayQueue(QByteArrayList() << mResourceInstanceIdentifier)); */ |
186 | } | 187 | } |
187 | 188 | ||
189 | static QByteArray readMailFromFile(const QString &mailFile) | ||
190 | { | ||
191 | QFile file(QLatin1String(THREADTESTDATAPATH) + QLatin1Char('/') + mailFile); | ||
192 | file.open(QIODevice::ReadOnly); | ||
193 | Q_ASSERT(file.isOpen()); | ||
194 | return file.readAll(); | ||
195 | } | ||
196 | |||
197 | static KMime::Message::Ptr readMail(const QString &mailFile) | ||
198 | { | ||
199 | auto msg = KMime::Message::Ptr::create(); | ||
200 | msg->setContent(readMailFromFile(mailFile)); | ||
201 | msg->parse(); | ||
202 | return msg; | ||
203 | } | ||
204 | |||
205 | void MailThreadTest::testRealWorldThread() | ||
206 | { | ||
207 | auto folder = Folder::create(mResourceInstanceIdentifier); | ||
208 | folder.setName("folder"); | ||
209 | VERIFYEXEC(Store::create(folder)); | ||
210 | |||
211 | auto createMail = [this, folder] (KMime::Message::Ptr msg) { | ||
212 | auto mail = Mail::create(mResourceInstanceIdentifier); | ||
213 | mail.setMimeMessage(msg->encodedContent(true)); | ||
214 | mail.setFolder(folder); | ||
215 | VERIFYEXEC(Store::create(mail)); | ||
216 | }; | ||
217 | |||
218 | createMail(readMail("thread1")); | ||
219 | |||
220 | VERIFYEXEC(ResourceControl::flushMessageQueue(QByteArrayList() << mResourceInstanceIdentifier)); | ||
221 | |||
222 | auto query = Sink::StandardQueries::threadLeaders(folder); | ||
223 | query.resourceFilter(mResourceInstanceIdentifier); | ||
224 | query.request<Mail::Subject>().request<Mail::MimeMessage>().request<Mail::Folder>().request<Mail::Date>(); | ||
225 | |||
226 | //Ensure we find the thread leader | ||
227 | Mail threadLeader = [&] { | ||
228 | auto mails = Store::read<Mail>(query); | ||
229 | Q_ASSERT(mails.size() == 1); | ||
230 | return mails.first(); | ||
231 | }(); | ||
232 | |||
233 | createMail(readMail("thread2")); | ||
234 | createMail(readMail("thread3")); | ||
235 | createMail(readMail("thread4")); | ||
236 | createMail(readMail("thread5")); | ||
237 | createMail(readMail("thread6")); | ||
238 | createMail(readMail("thread7")); | ||
239 | createMail(readMail("thread8")); //This mail is breaking the thread | ||
240 | VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); | ||
241 | |||
242 | //Ensure the thread is complete | ||
243 | { | ||
244 | auto query = Sink::StandardQueries::completeThread(threadLeader); | ||
245 | query.request<Mail::Subject>().request<Mail::MimeMessage>().request<Mail::Folder>().request<Mail::Date>(); | ||
246 | |||
247 | auto mails = Store::read<Mail>(query); | ||
248 | QCOMPARE(mails.size(), 8); | ||
249 | } | ||
250 | } | ||
251 | |||
188 | #include "mailthreadtest.moc" | 252 | #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: | |||
52 | 52 | ||
53 | void testListThreadLeader(); | 53 | void testListThreadLeader(); |
54 | void testIndexInMixedOrder(); | 54 | void testIndexInMixedOrder(); |
55 | void testRealWorldThread(); | ||
55 | }; | 56 | }; |
56 | 57 | ||
57 | } | 58 | } |
diff --git a/tests/notificationtest.cpp b/tests/notificationtest.cpp index f0d957e..c043f38 100644 --- a/tests/notificationtest.cpp +++ b/tests/notificationtest.cpp | |||
@@ -128,13 +128,41 @@ private slots: | |||
128 | VERIFYEXEC(Sink::Store::synchronize(newQuery)); | 128 | VERIFYEXEC(Sink::Store::synchronize(newQuery)); |
129 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "sink.dummy.instance1")); | 129 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "sink.dummy.instance1")); |
130 | 130 | ||
131 | QCOMPARE(status.size(), 3); | 131 | QTRY_COMPARE(status.size(), 3); |
132 | //Sync progress of item | 132 | //Sync progress of item |
133 | QCOMPARE(status.at(0), static_cast<int>(ApplicationDomain::SyncStatus::SyncInProgress)); | 133 | QCOMPARE(status.at(0), static_cast<int>(ApplicationDomain::SyncStatus::SyncInProgress)); |
134 | QCOMPARE(status.at(1), static_cast<int>(ApplicationDomain::SyncStatus::SyncSuccess)); | 134 | QCOMPARE(status.at(1), static_cast<int>(ApplicationDomain::SyncStatus::SyncInProgress)); |
135 | //Modification triggered during sync | 135 | //Modification triggered during sync |
136 | QCOMPARE(status.at(2), static_cast<int>(ApplicationDomain::SyncStatus::SyncSuccess)); | 136 | QCOMPARE(status.at(2), static_cast<int>(ApplicationDomain::SyncStatus::SyncSuccess)); |
137 | } | 137 | } |
138 | |||
139 | void testNotifier() | ||
140 | { | ||
141 | QList<int> status; | ||
142 | Sink::Notifier notifier{Sink::Query{Sink::Query::LiveQuery}.resourceFilter("sink.dummy.instance2")}; | ||
143 | notifier.registerHandler([&] (const Sink::Notification ¬ification) { | ||
144 | if (notification.type == Notification::Info) { | ||
145 | status << notification.code; | ||
146 | } | ||
147 | }); | ||
148 | |||
149 | auto query = Query().resourceFilter("sink.dummy.instance2"); | ||
150 | query.setType<ApplicationDomain::Mail>(); | ||
151 | query.setFlags(Query::LiveQuery | Query::UpdateStatus); | ||
152 | |||
153 | auto resource = ApplicationDomain::ApplicationDomainType::createEntity<ApplicationDomain::SinkResource>("", "sink.dummy.instance2"); | ||
154 | resource.setResourceType("sink.dummy"); | ||
155 | VERIFYEXEC(Store::create(resource)); | ||
156 | |||
157 | VERIFYEXEC(Sink::Store::synchronize(query)); | ||
158 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "sink.dummy.instance2")); | ||
159 | |||
160 | QTRY_COMPARE(status.size(), 2); | ||
161 | //Sync progress of item | ||
162 | QCOMPARE(status.at(0), static_cast<int>(ApplicationDomain::SyncStatus::SyncInProgress)); | ||
163 | QCOMPARE(status.at(1), static_cast<int>(ApplicationDomain::SyncStatus::SyncSuccess)); | ||
164 | } | ||
165 | |||
138 | }; | 166 | }; |
139 | 167 | ||
140 | QTEST_MAIN(NotificationTest) | 168 | QTEST_MAIN(NotificationTest) |
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: | |||
91 | auto model = Sink::Store::loadModel<SinkResource>(query); | 91 | auto model = Sink::Store::loadModel<SinkResource>(query); |
92 | QTRY_COMPARE(model->rowCount(QModelIndex()), 1); | 92 | QTRY_COMPARE(model->rowCount(QModelIndex()), 1); |
93 | auto resource = model->data(model->index(0, 0, QModelIndex()), Sink::Store::DomainObjectRole).value<SinkResource::Ptr>(); | 93 | auto resource = model->data(model->index(0, 0, QModelIndex()), Sink::Store::DomainObjectRole).value<SinkResource::Ptr>(); |
94 | QCOMPARE(resource->getStatus(), static_cast<int>(OfflineStatus)); | 94 | QCOMPARE(resource->getStatus(), static_cast<int>(NoStatus)); |
95 | 95 | ||
96 | //Synchronize to connect | 96 | //Synchronize to connect |
97 | VERIFYEXEC(Sink::Store::synchronize(query)); | 97 | VERIFYEXEC(Sink::Store::synchronize(query)); |
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: | |||
542 | } | 542 | } |
543 | 543 | ||
544 | } | 544 | } |
545 | |||
546 | void testRecordUid() | ||
547 | { | ||
548 | Sink::Storage::DataStore store(testDataPath, dbName, Sink::Storage::DataStore::ReadWrite); | ||
549 | auto transaction = store.createTransaction(Sink::Storage::DataStore::ReadWrite); | ||
550 | Sink::Storage::DataStore::recordUid(transaction, "uid1", "type"); | ||
551 | Sink::Storage::DataStore::recordUid(transaction, "uid2", "type"); | ||
552 | Sink::Storage::DataStore::recordUid(transaction, "uid3", "type2"); | ||
553 | |||
554 | { | ||
555 | QVector<QByteArray> uids; | ||
556 | Sink::Storage::DataStore::getUids("type", transaction, [&](const QByteArray &r) { | ||
557 | uids << r; | ||
558 | }); | ||
559 | QVector<QByteArray> expected{{"uid1"}, {"uid2"}}; | ||
560 | QCOMPARE(uids, expected); | ||
561 | } | ||
562 | |||
563 | Sink::Storage::DataStore::removeUid(transaction, "uid2", "type"); | ||
564 | |||
565 | { | ||
566 | QVector<QByteArray> uids; | ||
567 | Sink::Storage::DataStore::getUids("type", transaction, [&](const QByteArray &r) { | ||
568 | uids << r; | ||
569 | }); | ||
570 | QVector<QByteArray> expected{{"uid1"}}; | ||
571 | QCOMPARE(uids, expected); | ||
572 | } | ||
573 | } | ||
545 | }; | 574 | }; |
546 | 575 | ||
547 | QTEST_MAIN(StorageTest) | 576 | QTEST_MAIN(StorageTest) |
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 @@ | |||
1 | Return-Path: <kde-community-bounces@kde.org> | ||
2 | Received: from imapb010.mykolab.com ([unix socket]) | ||
3 | by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; | ||
4 | Sun, 13 Aug 2017 11:50:30 +0200 | ||
5 | X-Sieve: CMU Sieve 2.4 | ||
6 | Received: from int-mx002.mykolab.com (unknown [10.9.13.2]) | ||
7 | by imapb010.mykolab.com (Postfix) with ESMTPS id E79C512C084C4 | ||
8 | for <christian@mailqueue.ch>; Sun, 13 Aug 2017 11:50:29 +0200 (CEST) | ||
9 | Received: from mx.kolabnow.com (unknown [10.9.4.1]) | ||
10 | by int-mx002.mykolab.com (Postfix) with ESMTPS id BE41F2329 | ||
11 | for <christian@mailqueue.ch>; Sun, 13 Aug 2017 11:50:29 +0200 (CEST) | ||
12 | X-Virus-Scanned: amavisd-new at mykolab.com | ||
13 | Authentication-Results: ext-mx-in001.mykolab.com (amavisd-new); | ||
14 | dkim=pass (1024-bit key) header.d=kde.org | ||
15 | X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 | ||
16 | Received: from forward2-smtp.messagingengine.com (forward2-smtp.messagingengine.com [66.111.4.226]) | ||
17 | by ext-mx-in001.mykolab.com (Postfix) with ESMTPS id 5614B11BB | ||
18 | for <christian@mailqueue.ch>; Sun, 13 Aug 2017 11:50:08 +0200 (CEST) | ||
19 | Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) | ||
20 | by mailforward.nyi.internal (Postfix) with ESMTP id E9026D1C6 | ||
21 | for <christian@mailqueue.ch>; Sun, 13 Aug 2017 05:50:06 -0400 (EDT) | ||
22 | Received: by mailredirect.nyi.internal (Postfix, from userid 501) | ||
23 | id D95328E3AC; Sun, 13 Aug 2017 05:50:06 -0400 (EDT) | ||
24 | Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) | ||
25 | by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; | ||
26 | Sun, 13 Aug 2017 05:50:06 -0400 | ||
27 | X-Cyrus-Session-Id: sloti36d2t28-2961984-1502617806-2-9300763073201928650 | ||
28 | X-Sieve: CMU Sieve 3.0 | ||
29 | X-Spam-known-sender: no | ||
30 | X-Orig-Spam-score: 0.0 | ||
31 | X-Spam-hits: BAYES_20 -0.001, RCVD_IN_DNSWL_MED -2.3, RP_MATCHES_RCVD -0.001, | ||
32 | SPF_PASS -0.001, LANGUAGES en, BAYES_USED global, SA_VERSION 3.4.0 | ||
33 | X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='org', | ||
34 | MailFrom='org' | ||
35 | X-Spam-charsets: plain='us-ascii' | ||
36 | X-Attached: signature.asc | ||
37 | X-Resolved-to: chrigi_1@fastmail.fm | ||
38 | X-Delivered-to: chrigi_1@fastmail.fm | ||
39 | X-Mail-from: kde-community-bounces@kde.org | ||
40 | Received: from mx4 ([10.202.2.203]) | ||
41 | by compute1.internal (LMTPProxy); Sun, 13 Aug 2017 05:50:06 -0400 | ||
42 | Authentication-Results: mx4.messagingengine.com; | ||
43 | dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=aAtxmD+3; | ||
44 | dmarc=none (p=none;has-list-id=yes) header.from=kde.org; | ||
45 | smime=temperror; | ||
46 | spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org | ||
47 | Received-SPF: pass | ||
48 | (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) | ||
49 | receiver=mx4.messagingengine.com; | ||
50 | identity=mailfrom; | ||
51 | envelope-from="kde-community-bounces@kde.org"; | ||
52 | helo=postbox.kde.org; | ||
53 | client-ip=46.4.96.248 | ||
54 | Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) | ||
55 | (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) | ||
56 | (No client certificate requested) | ||
57 | by mx4.messagingengine.com (Postfix) with ESMTPS | ||
58 | for <chrigi_1@fastmail.fm>; Sun, 13 Aug 2017 05:50:05 -0400 (EDT) | ||
59 | DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; | ||
60 | t=1502617803; bh=IzJP1FRz6gX2xTBV2xMDBc2KfNLK284LvmfZvBQHRwU=; | ||
61 | h=From:To:Subject:Date:Reply-To:List-Id:List-Unsubscribe: | ||
62 | List-Archive:List-Post:List-Help:List-Subscribe:From; | ||
63 | b=aAtxmD+3cXY913YngN6okQjxPwOn+T9Cw1Hl1NpSZ2E4VbNDeuQ9IVj6zCqeAZE6y | ||
64 | elk2GquLeHlXeLnygo2n5LQL6epM83pkS+1AWSHQI11mBDT5byLUrXX64hOSZ579jG | ||
65 | L6+jAJT8vcqnXZcGg5EjBQqYmFp4HLedW/xduUVg= | ||
66 | X-Original-To: kde-community@kde.org | ||
67 | X-Remote-Delivered-To: kde-community@localhost.kde.org | ||
68 | Received-SPF: Neutral (access neither permitted nor denied) identity=mailfrom; | ||
69 | client-ip=85.214.75.115; helo=h2670809.stratoserver.net; | ||
70 | envelope-from=vkrause@kde.org; receiver=kde-community@kde.org | ||
71 | Received: from h2670809.stratoserver.net (deltatauchi.de [85.214.75.115]) | ||
72 | by postbox.kde.org (Postfix) with ESMTP id 61C21A308E | ||
73 | for <kde-community@kde.org>; Sun, 13 Aug 2017 09:49:38 +0000 (UTC) | ||
74 | Received: from deltatauchi.de (ip5b403802.dynamic.kabel-deutschland.de | ||
75 | [91.64.56.2]) | ||
76 | by h2670809.stratoserver.net (Postfix) with ESMTPSA id 521BBF1A0104 | ||
77 | for <kde-community@kde.org>; Sun, 13 Aug 2017 11:49:07 +0200 (CEST) | ||
78 | From: Volker Krause <vkrause@kde.org> | ||
79 | To: kde-community@kde.org | ||
80 | Subject: Telemetry Policy | ||
81 | Date: Sun, 13 Aug 2017 11:47:28 +0200 | ||
82 | Message-ID: <2048912.XfIJe3ZSdj@vkpc5> | ||
83 | Organization: KDE | ||
84 | X-Face: rgzmh}R?iq<z7H#sc'l86vzjJ"{\d6`}N5x*9!HFBn`A^tnU?<Q%ruT(jt5PG1$td=GDXe | ||
85 | XsXW(lVZ%Z0.2|w-)y[+@HI})\pNZEMi/UY_D"; | ||
86 | tt:5C'5&O9_xAqO!$HA8Ks-5}uMz%`D "2{s`Mt$}N]I`0UI=0; | ||
87 | '4v"!]XgBET9Q%cB?\vr#1=5X3,[a3k@083{n9H0m~Ey5_5xOb; @06MoJe"3/Rfe[eki | ||
88 | MIME-Version: 1.0 | ||
89 | Content-Type: multipart/signed; boundary="nextPart1627232.ab0ruIHapE"; | ||
90 | micalg="pgp-sha1"; protocol="application/pgp-signature" | ||
91 | X-BeenThere: kde-community@kde.org | ||
92 | X-Mailman-Version: 2.1.16 | ||
93 | Precedence: list | ||
94 | Reply-To: informing about and discussing non-technical community topics | ||
95 | <kde-community@kde.org> | ||
96 | List-Id: informing about and discussing non-technical community topics | ||
97 | <kde-community.kde.org> | ||
98 | List-Unsubscribe: <https://mail.kde.org/mailman/options/kde-community>, | ||
99 | <mailto:kde-community-request@kde.org?subject=unsubscribe> | ||
100 | List-Archive: <http://mail.kde.org/pipermail/kde-community/> | ||
101 | List-Post: <mailto:kde-community@kde.org> | ||
102 | List-Help: <mailto:kde-community-request@kde.org?subject=help> | ||
103 | List-Subscribe: <https://mail.kde.org/mailman/listinfo/kde-community>, | ||
104 | <mailto:kde-community-request@kde.org?subject=subscribe> | ||
105 | Errors-To: kde-community-bounces@kde.org | ||
106 | Sender: "kde-community" <kde-community-bounces@kde.org> | ||
107 | |||
108 | --nextPart1627232.ab0ruIHapE | ||
109 | Content-Transfer-Encoding: 7Bit | ||
110 | Content-Type: text/plain; charset="us-ascii" | ||
111 | |||
112 | Hi, | ||
113 | |||
114 | during the KUserFeedback BoF at Akademy there was quite some interest in | ||
115 | collecting telemetry data in KDE applications. But before actually | ||
116 | implementing that we agreed to define the rules under which we would want to | ||
117 | do that. I've tried to put the input we collected during Akademy into proper | ||
118 | wording below. What do you think? Did I miss anything? | ||
119 | |||
120 | Regards, | ||
121 | Volker | ||
122 | |||
123 | |||
124 | # Telemetry Policy Draft | ||
125 | |||
126 | Application telemetry data can be a valuable tool for tailoring our products | ||
127 | to the needs of our users. The following rules define how KDE collects and | ||
128 | uses such application telemetry data. As privacy is of utmost importance to | ||
129 | us, the general rule of thumb is to err on the side of caution here. Privacy | ||
130 | always trumps any need for telemetry data, no matter how legitimate. | ||
131 | |||
132 | These rules apply to all products released by KDE. | ||
133 | |||
134 | ## Transparency | ||
135 | |||
136 | We provide detailed information about the data that is going to be shared, in | ||
137 | a way that: | ||
138 | - is easy to understand | ||
139 | - is precise and complete | ||
140 | - is available locally without network connectivity | ||
141 | |||
142 | Any changes or additions to the telemetry functionality of an application will | ||
143 | be highlighted in the corresponding release announcement. | ||
144 | |||
145 | ## Control | ||
146 | |||
147 | We give the user full control over what data they want to share with KDE. In | ||
148 | particular: | ||
149 | - application telemetry is always opt-in, that is off by default | ||
150 | - application telemetry settings can be changed at any time, and are provided | ||
151 | as prominent in the application interface as other application settings | ||
152 | - applications honor system-wide telemetry settings where they exist (global | ||
153 | "kill switch") | ||
154 | - we provide detailed documentation about how to control the application | ||
155 | telemetry system | ||
156 | |||
157 | In order to ensure control over the data after it has been shared with KDE, | ||
158 | applications will only transmit this data to KDE servers, that is servers | ||
159 | under the full control of the KDE sysadmin team. | ||
160 | |||
161 | We will provide a designated contact point for users who have concerns about | ||
162 | the data they have shared with KDE. While we are willing to delete data a user | ||
163 | no longer wants to have shared, it should be understood that the below rules | ||
164 | are designed to make identification of data of a specific user impossible, and | ||
165 | thus a deletion request impractical. | ||
166 | |||
167 | ## Anonymity | ||
168 | |||
169 | We do not transmit data that could be used to identify a specific user. In | ||
170 | particular: | ||
171 | - we will not use any unique device, installation or user id | ||
172 | - data is stripped of any unnecessary detail and downsampled appropriately | ||
173 | before sharing to avoid fingerprinting | ||
174 | - network addresses (which are exposed inevitably as part of the data | ||
175 | transmission) are not stored together with the telemetry data, and must only | ||
176 | be stored or used to the extend necessary for abuse counter-measures | ||
177 | |||
178 | ## Minimalism | ||
179 | |||
180 | We only track the bare minimum of data necessary to answer specific questions, | ||
181 | we do not collect data preemptively or for exploratory research. In | ||
182 | particular, this means: | ||
183 | - collected data must have a clear purpose | ||
184 | - data is downsampled to the maximum extend possible at the source | ||
185 | - relevant correlations between individual bits of data should be computed at | ||
186 | the source whenever possible | ||
187 | - data collection is stopped once corresponding question has been answered | ||
188 | |||
189 | ## Privacy | ||
190 | |||
191 | We will never transmit anything containing user content, or even just hints at | ||
192 | possible user content such as e.g. file names, URLs, etc. | ||
193 | |||
194 | We will only ever track: | ||
195 | - system information that are specific to the installation/environment, but | ||
196 | independent of how the application/machine/installation is actually used | ||
197 | - statistical usage data of an installation/application | ||
198 | |||
199 | ## Compliance | ||
200 | |||
201 | KDE only releases products capable of acquiring telemetry data if compliance | ||
202 | with these rules has been established by a public review on [kde-core-devel| | ||
203 | kde-community]@kde.org from at least two reviewers. The review has to be | ||
204 | repeated for every release if changes have been made to how/what data is | ||
205 | collected. | ||
206 | |||
207 | Received data is regularly reviewed for violations of these rules, in | ||
208 | particular for data that is prone to fingerprinting. Should such violations be | ||
209 | found, the affected data will be deleted, and data recording will be suspended | ||
210 | until compliance with these rules has been established again. In order to | ||
211 | enable reviewing of the data, every KDE contributor with a developer account | ||
212 | will have access to all telemetry data gathered by any KDE product. | ||
213 | |||
214 | --nextPart1627232.ab0ruIHapE | ||
215 | Content-Type: application/pgp-signature; name="signature.asc" | ||
216 | Content-Description: This is a digitally signed message part. | ||
217 | Content-Transfer-Encoding: 7Bit | ||
218 | |||
219 | -----BEGIN PGP SIGNATURE----- | ||
220 | |||
221 | iF0EABECAB0WIQQAnu3FVHA48KjZ07R/lszWTRLSRwUCWZAgMAAKCRB/lszWTRLS | ||
222 | Ry5WAJ9+8r8e7IFPh54YBsEkisE3+dNs8QCfY+0b0jcYPVP1HdpsTZVoh33JfhU= | ||
223 | =v6cZ | ||
224 | -----END PGP SIGNATURE----- | ||
225 | |||
226 | --nextPart1627232.ab0ruIHapE-- | ||
227 | |||
228 | |||
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 @@ | |||
1 | Return-Path: <kde-community-bounces@kde.org> | ||
2 | Received: from imapb010.mykolab.com ([unix socket]) | ||
3 | by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; | ||
4 | Wed, 16 Aug 2017 09:15:00 +0200 | ||
5 | X-Sieve: CMU Sieve 2.4 | ||
6 | Received: from int-mx002.mykolab.com (unknown [10.9.13.2]) | ||
7 | by imapb010.mykolab.com (Postfix) with ESMTPS id 1772014401C83 | ||
8 | for <christian@mailqueue.ch>; Wed, 16 Aug 2017 09:15:00 +0200 (CEST) | ||
9 | Received: from mx.kolabnow.com (unknown [10.9.4.1]) | ||
10 | by int-mx002.mykolab.com (Postfix) with ESMTPS id 01CCB2348 | ||
11 | for <christian@mailqueue.ch>; Wed, 16 Aug 2017 09:14:59 +0200 (CEST) | ||
12 | X-Virus-Scanned: amavisd-new at mykolab.com | ||
13 | Authentication-Results: ext-mx-in001.mykolab.com (amavisd-new); | ||
14 | dkim=pass (1024-bit key) header.d=kde.org | ||
15 | X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 | ||
16 | Received: from forward1-smtp.messagingengine.com (forward1-smtp.messagingengine.com [66.111.4.223]) | ||
17 | by ext-mx-in001.mykolab.com (Postfix) with ESMTPS id 3BC6B11AC | ||
18 | for <christian@mailqueue.ch>; Wed, 16 Aug 2017 09:14:42 +0200 (CEST) | ||
19 | Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) | ||
20 | by mailforward.nyi.internal (Postfix) with ESMTP id 9F77F12C6 | ||
21 | for <christian@mailqueue.ch>; Wed, 16 Aug 2017 03:14:41 -0400 (EDT) | ||
22 | Received: by mailredirect.nyi.internal (Postfix, from userid 501) | ||
23 | id 8EF798E597; Wed, 16 Aug 2017 03:14:41 -0400 (EDT) | ||
24 | Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) | ||
25 | by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; | ||
26 | Wed, 16 Aug 2017 03:14:41 -0400 | ||
27 | X-Cyrus-Session-Id: sloti36d2t28-476506-1502867681-2-17694110317903435823 | ||
28 | X-Sieve: CMU Sieve 3.0 | ||
29 | X-Spam-known-sender: no | ||
30 | X-Orig-Spam-score: 0.0 | ||
31 | X-Spam-hits: BAYES_20 -0.001, HEADER_FROM_DIFFERENT_DOMAINS 0.001, | ||
32 | RCVD_IN_DNSWL_MED -2.3, RP_MATCHES_RCVD -0.001, SPF_PASS -0.001, | ||
33 | LANGUAGES en, BAYES_USED global, SA_VERSION 3.4.0 | ||
34 | X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='ch', | ||
35 | MailFrom='org' | ||
36 | X-Spam-charsets: plain='us-ascii' | ||
37 | X-Resolved-to: chrigi_1@fastmail.fm | ||
38 | X-Delivered-to: chrigi_1@fastmail.fm | ||
39 | X-Mail-from: kde-community-bounces@kde.org | ||
40 | Received: from mx4 ([10.202.2.203]) | ||
41 | by compute1.internal (LMTPProxy); Wed, 16 Aug 2017 03:14:41 -0400 | ||
42 | Authentication-Results: mx4.messagingengine.com; | ||
43 | dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=cVfBDwjP; | ||
44 | dmarc=none (p=none;has-list-id=yes) header.from=fuchsnet.ch; | ||
45 | spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org | ||
46 | Received-SPF: pass | ||
47 | (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) | ||
48 | receiver=mx4.messagingengine.com; | ||
49 | identity=mailfrom; | ||
50 | envelope-from="kde-community-bounces@kde.org"; | ||
51 | helo=postbox.kde.org; | ||
52 | client-ip=46.4.96.248 | ||
53 | Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) | ||
54 | (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) | ||
55 | (No client certificate requested) | ||
56 | by mx4.messagingengine.com (Postfix) with ESMTPS | ||
57 | for <chrigi_1@fastmail.fm>; Wed, 16 Aug 2017 03:14:40 -0400 (EDT) | ||
58 | DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; | ||
59 | t=1502867678; bh=70oyTvxfLkdYUd1D8WFhrBEneI7DP4MY5KH1tM/AxUI=; | ||
60 | h=From:To:Subject:Date:In-Reply-To:References:Reply-To:List-Id: | ||
61 | List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: | ||
62 | From; | ||
63 | b=cVfBDwjPyB0OrVy5jQaU1YBZtx/95ktf4lpQDQddz0Udb+QkxzLzv6S3He6EjQIRs | ||
64 | nnEfVM/Y6V/Q9IHj+AYQckxyZxbXNOmfb9jOgU/R5bhPMkpstCvw/gQTD+LMGsFuSl | ||
65 | fCKdwg+KmAWmvBhoe+8Oa6BMR3KKViYziJgMTuwI= | ||
66 | X-Original-To: kde-community@kde.org | ||
67 | X-Remote-Delivered-To: kde-community@localhost.kde.org | ||
68 | Received-SPF: None (no SPF record) identity=mailfrom; | ||
69 | client-ip=2a00:d70:0:e::317; helo=mxout017.mail.hostpoint.ch; | ||
70 | envelope-from=christian.loosli@fuchsnet.ch; receiver=kde-community@kde.org | ||
71 | Received: from mxout017.mail.hostpoint.ch (mxout017.mail.hostpoint.ch | ||
72 | [IPv6:2a00:d70:0:e::317]) | ||
73 | by postbox.kde.org (Postfix) with ESMTPS id AA196A3AC5 | ||
74 | for <kde-community@kde.org>; Sun, 13 Aug 2017 10:18:17 +0000 (UTC) | ||
75 | Received: from [10.0.2.45] (helo=asmtp012.mail.hostpoint.ch) | ||
76 | by mxout017.mail.hostpoint.ch with esmtp (Exim 4.89 (FreeBSD)) | ||
77 | (envelope-from <christian.loosli@fuchsnet.ch>) id 1dgpyK-000DwH-Of | ||
78 | for kde-community@kde.org; Sun, 13 Aug 2017 12:18:16 +0200 | ||
79 | Received: from 77-56-19-119.dclient.hispeed.ch ([77.56.19.119] | ||
80 | helo=minixfox.localnet) by asmtp012.mail.hostpoint.ch with esmtpsa | ||
81 | (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.89 (FreeBSD)) | ||
82 | (envelope-from <christian.loosli@fuchsnet.ch>) id 1dgpyK-000CRa-ML | ||
83 | for kde-community@kde.org; Sun, 13 Aug 2017 12:18:16 +0200 | ||
84 | X-Authenticated-Sender-Id: mail@fuchsnet.ch | ||
85 | From: Christian Loosli <christian.loosli@fuchsnet.ch> | ||
86 | To: kde-community@kde.org | ||
87 | Subject: Re: Telemetry Policy | ||
88 | Date: Sun, 13 Aug 2017 12:18:16 +0200 | ||
89 | Message-ID: <2990543.KVDkBByYO0@minixfox> | ||
90 | User-Agent: KMail/5.2.3 (Linux/4.6.2-040602-generic; KDE/5.35.0; x86_64; ; ) | ||
91 | In-Reply-To: <2048912.XfIJe3ZSdj@vkpc5> | ||
92 | References: <2048912.XfIJe3ZSdj@vkpc5> | ||
93 | MIME-Version: 1.0 | ||
94 | Content-Transfer-Encoding: 7Bit | ||
95 | Content-Type: text/plain; charset="us-ascii" | ||
96 | X-Mailman-Approved-At: Wed, 16 Aug 2017 07:14:22 +0000 | ||
97 | X-BeenThere: kde-community@kde.org | ||
98 | X-Mailman-Version: 2.1.16 | ||
99 | Precedence: list | ||
100 | Reply-To: informing about and discussing non-technical community topics | ||
101 | <kde-community@kde.org> | ||
102 | List-Id: informing about and discussing non-technical community topics | ||
103 | <kde-community.kde.org> | ||
104 | List-Unsubscribe: <https://mail.kde.org/mailman/options/kde-community>, | ||
105 | <mailto:kde-community-request@kde.org?subject=unsubscribe> | ||
106 | List-Archive: <http://mail.kde.org/pipermail/kde-community/> | ||
107 | List-Post: <mailto:kde-community@kde.org> | ||
108 | List-Help: <mailto:kde-community-request@kde.org?subject=help> | ||
109 | List-Subscribe: <https://mail.kde.org/mailman/listinfo/kde-community>, | ||
110 | <mailto:kde-community-request@kde.org?subject=subscribe> | ||
111 | Errors-To: kde-community-bounces@kde.org | ||
112 | Sender: "kde-community" <kde-community-bounces@kde.org> | ||
113 | |||
114 | Hi, | ||
115 | |||
116 | thank you very much for this work, sounds great! | ||
117 | |||
118 | Only point I have: maybe make sure that the opt-in / default settings are not | ||
119 | only mandatory for application developers, but also for packagers / | ||
120 | distributions. | ||
121 | |||
122 | Some distributions have rather questionable views on privacy and by default | ||
123 | sent information to third parties, so I would feel much more safe if they | ||
124 | weren't allowed (in theory) to flick the switch in their package by default to | ||
125 | "on" either. | ||
126 | |||
127 | Kind regards, | ||
128 | |||
129 | 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 @@ | |||
1 | Return-Path: <kde-community-bounces@kde.org> | ||
2 | Received: from imapb010.mykolab.com ([unix socket]) | ||
3 | by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; | ||
4 | Wed, 16 Aug 2017 09:33:42 +0200 | ||
5 | X-Sieve: CMU Sieve 2.4 | ||
6 | Received: from int-mx001.mykolab.com (unknown [10.9.13.1]) | ||
7 | by imapb010.mykolab.com (Postfix) with ESMTPS id 5444D14414C34 | ||
8 | for <christian@mailqueue.ch>; Wed, 16 Aug 2017 09:33:42 +0200 (CEST) | ||
9 | Received: from mx.kolabnow.com (unknown [10.9.4.2]) | ||
10 | by int-mx001.mykolab.com (Postfix) with ESMTPS id 3DB4C114 | ||
11 | for <christian@mailqueue.ch>; Wed, 16 Aug 2017 09:33:42 +0200 (CEST) | ||
12 | X-Virus-Scanned: amavisd-new at mykolab.com | ||
13 | Authentication-Results: ext-mx-in002.mykolab.com (amavisd-new); | ||
14 | dkim=pass (1024-bit key) header.d=kde.org header.b=PXk+9Qyc; | ||
15 | dkim=pass (2048-bit key) header.d=gmail.com header.b=j1CN7DJ2 | ||
16 | X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 | ||
17 | Received: from forward1-smtp.messagingengine.com (forward1-smtp.messagingengine.com [66.111.4.223]) | ||
18 | by ext-mx-in002.mykolab.com (Postfix) with ESMTPS id DEAFCE9E | ||
19 | for <christian@mailqueue.ch>; Wed, 16 Aug 2017 09:33:36 +0200 (CEST) | ||
20 | Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) | ||
21 | by mailforward.nyi.internal (Postfix) with ESMTP id 6AD87108D | ||
22 | for <christian@mailqueue.ch>; Wed, 16 Aug 2017 03:33:35 -0400 (EDT) | ||
23 | Received: by mailredirect.nyi.internal (Postfix, from userid 501) | ||
24 | id 444F38E597; Wed, 16 Aug 2017 03:33:35 -0400 (EDT) | ||
25 | Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) | ||
26 | by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; | ||
27 | Wed, 16 Aug 2017 03:33:35 -0400 | ||
28 | X-Cyrus-Session-Id: sloti36d2t28-546055-1502868815-2-14217351451016405562 | ||
29 | X-Sieve: CMU Sieve 3.0 | ||
30 | X-Spam-known-sender: no | ||
31 | X-Orig-Spam-score: 0.0 | ||
32 | X-Spam-hits: BAYES_00 -1.9, FREEMAIL_FORGED_FROMDOMAIN 0.199, FREEMAIL_FROM 0.001, | ||
33 | HEADER_FROM_DIFFERENT_DOMAINS 0.001, RCVD_IN_DNSWL_MED -2.3, | ||
34 | RP_MATCHES_RCVD -0.001, SPF_PASS -0.001, LANGUAGES en, BAYES_USED global, | ||
35 | SA_VERSION 3.4.0 | ||
36 | X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='com', | ||
37 | MailFrom='org' | ||
38 | X-Spam-charsets: plain='UTF-8' | ||
39 | X-Resolved-to: chrigi_1@fastmail.fm | ||
40 | X-Delivered-to: chrigi_1@fastmail.fm | ||
41 | X-Mail-from: kde-community-bounces@kde.org | ||
42 | Received: from mx1 ([10.202.2.200]) | ||
43 | by compute1.internal (LMTPProxy); Wed, 16 Aug 2017 03:33:35 -0400 | ||
44 | Authentication-Results: mx1.messagingengine.com; | ||
45 | dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=PXk+9Qyc; | ||
46 | dkim=pass (2048-bit rsa key sha256) header.d=gmail.com header.i=@gmail.com header.b=j1CN7DJ2; | ||
47 | dmarc=pass header.from=gmail.com; | ||
48 | spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org; | ||
49 | x-google-dkim=pass (2048-bit rsa key) header.d=1e100.net header.i=@1e100.net header.b=nOWNMzab | ||
50 | Received-SPF: pass | ||
51 | (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) | ||
52 | receiver=mx1.messagingengine.com; | ||
53 | identity=mailfrom; | ||
54 | envelope-from="kde-community-bounces@kde.org"; | ||
55 | helo=postbox.kde.org; | ||
56 | client-ip=46.4.96.248 | ||
57 | Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) | ||
58 | (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) | ||
59 | (No client certificate requested) | ||
60 | by mx1.messagingengine.com (Postfix) with ESMTPS | ||
61 | for <chrigi_1@fastmail.fm>; Wed, 16 Aug 2017 03:33:34 -0400 (EDT) | ||
62 | DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; | ||
63 | t=1502868810; bh=dVFv3mcZvqPFeac2frbs+zJpMjYutwuTUR/aZqUTbZY=; | ||
64 | h=In-Reply-To:References:From:Date:Subject:To:Reply-To:List-Id: | ||
65 | List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: | ||
66 | From; | ||
67 | b=PXk+9Qyc+iRxwLPIHod4loutgNXu9pHl4peiPK0rI8Bl+4b02Cw0SUrzyf2JPqyDn | ||
68 | zuoxSnetdDbzoPnV1ep3yyHX+MhXiWvvc+PTKk15kIuBJYB77t+EJq3I/awvqG++Fa | ||
69 | d4Um24yPg/LUw5fFTsMuJ+Ra5MtpmFOmVbXrHDt0= | ||
70 | X-Original-To: kde-community@kde.org | ||
71 | X-Remote-Delivered-To: kde-community@localhost.kde.org | ||
72 | Received-SPF: Pass (sender SPF authorized) identity=mailfrom; | ||
73 | client-ip=2607:f8b0:4001:c0b::22f; helo=mail-it0-x22f.google.com; | ||
74 | envelope-from=valorie.zimmerman@gmail.com; receiver=kde-community@kde.org | ||
75 | Authentication-Results: postbox.kde.org; dkim=pass | ||
76 | reason="2048-bit key; unprotected key" | ||
77 | header.d=gmail.com header.i=@gmail.com header.b=j1CN7DJ2; | ||
78 | dkim-adsp=pass; dkim-atps=neutral | ||
79 | Received: from mail-it0-x22f.google.com (mail-it0-x22f.google.com | ||
80 | [IPv6:2607:f8b0:4001:c0b::22f]) | ||
81 | by postbox.kde.org (Postfix) with ESMTPS id 06F4BA0243 | ||
82 | for <kde-community@kde.org>; Wed, 16 Aug 2017 07:33:19 +0000 (UTC) | ||
83 | Received: by mail-it0-x22f.google.com with SMTP id 76so14155500ith.0 | ||
84 | for <kde-community@kde.org>; Wed, 16 Aug 2017 00:33:19 -0700 (PDT) | ||
85 | DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; | ||
86 | h=mime-version:in-reply-to:references:from:date:message-id:subject:to; | ||
87 | bh=FXMFEApKo547tDMnIu6insMVxFcMsw7/E/4fcI3MkkQ=; | ||
88 | b=j1CN7DJ2CYaCWqNWOR7Hpjah/U+OYATQhmN+zVkgRNbVJOMVW6B4hWmUihH5Nll4/G | ||
89 | YX5O5OQv6i2y1hAqT3R3iISGAz70o2gIWjq14Ea+zqM9ztCM/ZX4XGaBqdv4dHTAMyDh | ||
90 | mg556PB77JLPlwHtf2CsR9gTSAC2BAuY8lsTdBV7jVkLjCGdjaSPRxiyf2t4WbcVmiUt | ||
91 | yZzWB7QmtQA4JHQ8N/bJ2lEg8cTWSj8p9o4kSAF7HDZ4X7pXfQgAPEAs/DHf9LMNGiys | ||
92 | 1xgAuYNxywGvtLaArQ+NXfgYH6VfRcFf7HFbMLs6yLyn63G9GLyUPHlHIgqWVAJrdn65 | ||
93 | Nsow== | ||
94 | X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; | ||
95 | d=1e100.net; s=20161025; | ||
96 | h=x-gm-message-state:mime-version:in-reply-to:references:from:date | ||
97 | :message-id:subject:to; | ||
98 | bh=FXMFEApKo547tDMnIu6insMVxFcMsw7/E/4fcI3MkkQ=; | ||
99 | b=nOWNMzabDGsTEZISXzVD7236lDYmFHF2kAEUxMmDSvGYEcq1/FjZwj7w7SJT62S/pY | ||
100 | oS29tWyY7LE4I+Fq5E6D8H2sfMAfaCoYQ1J27ftPVClg/kmiTGRzxf2tcv6TR/v56+vD | ||
101 | pwgDEDwgZs1oM6IBFrJr65u2+0mlcmK3qsRHBdjoQLEbZMa+GugjcI2HILqtmpTS+NJi | ||
102 | HZcVfEgOwkyqgoZkgBsaBui+5OUpz/yqryOsYx7kQxCy6uZJIFCB0dsvk7COE8nG7LYa | ||
103 | 0H8aRhVFxXRW76MUR6E67EhGMS+MS9F3DiXiUsWTn4yEZnC8cy76YPcPHVBBmGQ7CH0a | ||
104 | ScwA== | ||
105 | X-Gm-Message-State: AHYfb5g0PFdyP1pw7TVZRMJqzU/nu12G3R2adj9OD2MzSxEew1QKnS99 | ||
106 | U5MlthDVsG6C1f9Ak0fXNCtdI5w4CaBJhbc= | ||
107 | X-Received: by 10.36.37.143 with SMTP id g137mr1056087itg.35.1502868798009; | ||
108 | Wed, 16 Aug 2017 00:33:18 -0700 (PDT) | ||
109 | MIME-Version: 1.0 | ||
110 | Received: by 10.107.6.142 with HTTP; Wed, 16 Aug 2017 00:33:02 -0700 (PDT) | ||
111 | In-Reply-To: <2990543.KVDkBByYO0@minixfox> | ||
112 | References: <2048912.XfIJe3ZSdj@vkpc5> <2990543.KVDkBByYO0@minixfox> | ||
113 | From: Valorie Zimmerman <valorie.zimmerman@gmail.com> | ||
114 | Date: Wed, 16 Aug 2017 00:33:02 -0700 | ||
115 | Message-ID: <CACpu024EH1OeDqwL94QK33eq4sCGjKjwedcQDR_PWjprBevzfg@mail.gmail.com> | ||
116 | Subject: Re: Telemetry Policy | ||
117 | To: informing about and discussing non-technical community topics | ||
118 | <kde-community@kde.org> | ||
119 | Content-Type: text/plain; charset="UTF-8" | ||
120 | X-BeenThere: kde-community@kde.org | ||
121 | X-Mailman-Version: 2.1.16 | ||
122 | Precedence: list | ||
123 | Reply-To: informing about and discussing non-technical community topics | ||
124 | <kde-community@kde.org> | ||
125 | List-Id: informing about and discussing non-technical community topics | ||
126 | <kde-community.kde.org> | ||
127 | List-Unsubscribe: <https://mail.kde.org/mailman/options/kde-community>, | ||
128 | <mailto:kde-community-request@kde.org?subject=unsubscribe> | ||
129 | List-Archive: <http://mail.kde.org/pipermail/kde-community/> | ||
130 | List-Post: <mailto:kde-community@kde.org> | ||
131 | List-Help: <mailto:kde-community-request@kde.org?subject=help> | ||
132 | List-Subscribe: <https://mail.kde.org/mailman/listinfo/kde-community>, | ||
133 | <mailto:kde-community-request@kde.org?subject=subscribe> | ||
134 | Errors-To: kde-community-bounces@kde.org | ||
135 | Sender: "kde-community" <kde-community-bounces@kde.org> | ||
136 | |||
137 | Hi all, Mozilla has done a lot of work on telemetry, and we might be | ||
138 | able to use some of their findings. On this page: | ||
139 | https://wiki.mozilla.org/Firefox/Data_Collection they break down the | ||
140 | data they might possibly collect into four buckets - technical (such | ||
141 | as crashes), user interaction, web activity, and sensitive (personal | ||
142 | data). | ||
143 | |||
144 | This bit might be relevant to our discussion: "Categories 1 & 2 | ||
145 | (Technical & Interaction data) | ||
146 | Pre-Release & Release: Data may default on, provided the data is | ||
147 | exclusively in these categories (it cannot be in any other category). | ||
148 | In Release, an opt-out must be available for most types of Technical | ||
149 | and Interaction data. " | ||
150 | |||
151 | I think the entire page might be enlightening to this discussion. I | ||
152 | believe our analysis of needs should be more fine-grained, and that | ||
153 | some parts of what we need can be "default on" especially for | ||
154 | pre-release testing. For releases, we can provide an opt-out. | ||
155 | |||
156 | Other more sensitive data will need to be opt-in. I think it's a | ||
157 | mistake to treat all the data we might want all in the same way. | ||
158 | |||
159 | Valorie | ||
160 | |||
161 | |||
162 | On Sun, Aug 13, 2017 at 3:18 AM, Christian Loosli | ||
163 | <christian.loosli@fuchsnet.ch> wrote: | ||
164 | > Hi, | ||
165 | > | ||
166 | > thank you very much for this work, sounds great! | ||
167 | > | ||
168 | > Only point I have: maybe make sure that the opt-in / default settings are not | ||
169 | > only mandatory for application developers, but also for packagers / | ||
170 | > distributions. | ||
171 | > | ||
172 | > Some distributions have rather questionable views on privacy and by default | ||
173 | > sent information to third parties, so I would feel much more safe if they | ||
174 | > weren't allowed (in theory) to flick the switch in their package by default to | ||
175 | > "on" either. | ||
176 | > | ||
177 | > Kind regards, | ||
178 | > | ||
179 | > Christian | ||
180 | |||
181 | |||
182 | |||
183 | -- | ||
184 | 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 @@ | |||
1 | Return-Path: <kde-community-bounces@kde.org> | ||
2 | Received: from imapb010.mykolab.com ([unix socket]) | ||
3 | by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; | ||
4 | Wed, 16 Aug 2017 14:15:52 +0200 | ||
5 | X-Sieve: CMU Sieve 2.4 | ||
6 | Received: from int-mx001.mykolab.com (unknown [10.9.13.1]) | ||
7 | by imapb010.mykolab.com (Postfix) with ESMTPS id B5DFE145C97EA | ||
8 | for <christian@mailqueue.ch>; Wed, 16 Aug 2017 14:15:52 +0200 (CEST) | ||
9 | Received: from mx.kolabnow.com (unknown [10.9.4.3]) | ||
10 | by int-mx001.mykolab.com (Postfix) with ESMTPS id 9430B114 | ||
11 | for <christian@mailqueue.ch>; Wed, 16 Aug 2017 14:15:52 +0200 (CEST) | ||
12 | X-Virus-Scanned: amavisd-new at mykolab.com | ||
13 | Authentication-Results: ext-mx-in003.mykolab.com (amavisd-new); | ||
14 | dkim=pass (1024-bit key) header.d=kde.org | ||
15 | X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 | ||
16 | Received: from forward1-smtp.messagingengine.com (forward1-smtp.messagingengine.com [66.111.4.223]) | ||
17 | by ext-mx-in003.mykolab.com (Postfix) with ESMTPS id 87ADC292C | ||
18 | for <christian@mailqueue.ch>; Wed, 16 Aug 2017 14:15:41 +0200 (CEST) | ||
19 | Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) | ||
20 | by mailforward.nyi.internal (Postfix) with ESMTP id 14E06F2B | ||
21 | for <christian@mailqueue.ch>; Wed, 16 Aug 2017 08:15:41 -0400 (EDT) | ||
22 | Received: by mailredirect.nyi.internal (Postfix, from userid 501) | ||
23 | id 02B668E597; Wed, 16 Aug 2017 08:15:40 -0400 (EDT) | ||
24 | Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) | ||
25 | by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; | ||
26 | Wed, 16 Aug 2017 08:15:40 -0400 | ||
27 | X-Cyrus-Session-Id: sloti36d2t28-920397-1502885740-5-10891205693403350257 | ||
28 | X-Sieve: CMU Sieve 3.0 | ||
29 | X-Spam-known-sender: no | ||
30 | X-Orig-Spam-score: 0.0 | ||
31 | X-Spam-hits: BAYES_00 -1.9, RCVD_IN_DNSWL_MED -2.3, RP_MATCHES_RCVD -0.001, | ||
32 | SPF_PASS -0.001, LANGUAGES en, BAYES_USED global, SA_VERSION 3.4.0 | ||
33 | X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='org', | ||
34 | MailFrom='org' | ||
35 | X-Spam-charsets: plain='utf-8' | ||
36 | X-Attached: signature.asc | ||
37 | X-Resolved-to: chrigi_1@fastmail.fm | ||
38 | X-Delivered-to: chrigi_1@fastmail.fm | ||
39 | X-Mail-from: kde-community-bounces@kde.org | ||
40 | Received: from mx1 ([10.202.2.200]) | ||
41 | by compute1.internal (LMTPProxy); Wed, 16 Aug 2017 08:15:40 -0400 | ||
42 | Authentication-Results: mx1.messagingengine.com; | ||
43 | dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=dcc9ZeF1; | ||
44 | dmarc=none (p=none;has-list-id=yes) header.from=kde.org; | ||
45 | smime=temperror; | ||
46 | spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org | ||
47 | Received-SPF: pass | ||
48 | (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) | ||
49 | receiver=mx1.messagingengine.com; | ||
50 | identity=mailfrom; | ||
51 | envelope-from="kde-community-bounces@kde.org"; | ||
52 | helo=postbox.kde.org; | ||
53 | client-ip=46.4.96.248 | ||
54 | Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) | ||
55 | (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) | ||
56 | (No client certificate requested) | ||
57 | by mx1.messagingengine.com (Postfix) with ESMTPS | ||
58 | for <chrigi_1@fastmail.fm>; Wed, 16 Aug 2017 08:15:40 -0400 (EDT) | ||
59 | DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; | ||
60 | t=1502885735; bh=SH/qVWnJJ/KE8PqQNaOwBRNoy7rIm5VobJE4/TZFZ9g=; | ||
61 | h=From:To:Subject:Date:In-Reply-To:References:Reply-To:List-Id: | ||
62 | List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: | ||
63 | From; | ||
64 | b=dcc9ZeF1EO5Q0C8mVOjhOITKyPmrCB9KGB4gKdTSfuxo4OZGKHg/xi7VH0/UDLYxy | ||
65 | Ni1GHXrJiD50yXOLDYICYr0XsDpYQaHmRQXGs6O6g/hIYxR2BCdqH1/5/NgNzPyjLH | ||
66 | 5aKmEZt4LH8/JKYnv1UJCiKdhG2UQrs3fSg/ZMpM= | ||
67 | X-Original-To: kde-community@kde.org | ||
68 | X-Remote-Delivered-To: kde-community@localhost.kde.org | ||
69 | Received-SPF: Neutral (access neither permitted nor denied) identity=mailfrom; | ||
70 | client-ip=85.214.75.115; helo=h2670809.stratoserver.net; | ||
71 | envelope-from=vkrause@kde.org; receiver=kde-community@kde.org | ||
72 | Received: from h2670809.stratoserver.net (deltatauchi.de [85.214.75.115]) | ||
73 | by postbox.kde.org (Postfix) with ESMTP id 7F686A0160 | ||
74 | for <kde-community@kde.org>; Wed, 16 Aug 2017 12:15:15 +0000 (UTC) | ||
75 | Received: from vkpc19.localnet (unknown [185.28.184.2]) | ||
76 | by h2670809.stratoserver.net (Postfix) with ESMTPSA id 59DBAF1A0104 | ||
77 | for <kde-community@kde.org>; Wed, 16 Aug 2017 14:14:44 +0200 (CEST) | ||
78 | From: Volker Krause <vkrause@kde.org> | ||
79 | To: kde-community@kde.org | ||
80 | Subject: Re: Telemetry Policy | ||
81 | Date: Wed, 16 Aug 2017 14:13:48 +0200 | ||
82 | Message-ID: <1942419.JquqIjZoWq@vkpc19> | ||
83 | Organization: KDE | ||
84 | In-Reply-To: <CACpu024EH1OeDqwL94QK33eq4sCGjKjwedcQDR_PWjprBevzfg@mail.gmail.com> | ||
85 | References: <2048912.XfIJe3ZSdj@vkpc5> <2990543.KVDkBByYO0@minixfox> | ||
86 | <CACpu024EH1OeDqwL94QK33eq4sCGjKjwedcQDR_PWjprBevzfg@mail.gmail.com> | ||
87 | MIME-Version: 1.0 | ||
88 | Content-Type: multipart/signed; boundary="nextPart3633370.DIlRsSa6NW"; | ||
89 | micalg="pgp-sha1"; protocol="application/pgp-signature" | ||
90 | X-BeenThere: kde-community@kde.org | ||
91 | X-Mailman-Version: 2.1.16 | ||
92 | Precedence: list | ||
93 | Reply-To: informing about and discussing non-technical community topics | ||
94 | <kde-community@kde.org> | ||
95 | List-Id: informing about and discussing non-technical community topics | ||
96 | <kde-community.kde.org> | ||
97 | List-Unsubscribe: <https://mail.kde.org/mailman/options/kde-community>, | ||
98 | <mailto:kde-community-request@kde.org?subject=unsubscribe> | ||
99 | List-Archive: <http://mail.kde.org/pipermail/kde-community/> | ||
100 | List-Post: <mailto:kde-community@kde.org> | ||
101 | List-Help: <mailto:kde-community-request@kde.org?subject=help> | ||
102 | List-Subscribe: <https://mail.kde.org/mailman/listinfo/kde-community>, | ||
103 | <mailto:kde-community-request@kde.org?subject=subscribe> | ||
104 | Errors-To: kde-community-bounces@kde.org | ||
105 | Sender: "kde-community" <kde-community-bounces@kde.org> | ||
106 | |||
107 | --nextPart3633370.DIlRsSa6NW | ||
108 | Content-Transfer-Encoding: 7Bit | ||
109 | Content-Type: text/plain; charset="utf-8" | ||
110 | |||
111 | On Wednesday, 16 August 2017 09:33:02 CEST Valorie Zimmerman wrote: | ||
112 | > Hi all, Mozilla has done a lot of work on telemetry, and we might be | ||
113 | > able to use some of their findings. On this page: | ||
114 | > https://wiki.mozilla.org/Firefox/Data_Collection they break down the | ||
115 | > data they might possibly collect into four buckets - technical (such | ||
116 | > as crashes), user interaction, web activity, and sensitive (personal | ||
117 | > data). | ||
118 | |||
119 | without making it that explicit, we basically have the same four categories of | ||
120 | data too, and explicitly exclude the use of category 3 and 4, ie user content/ | ||
121 | activity and personal data, only technical and interaction data are allowed to | ||
122 | be used (category 1 and 2). | ||
123 | |||
124 | > This bit might be relevant to our discussion: "Categories 1 & 2 | ||
125 | > (Technical & Interaction data) | ||
126 | > Pre-Release & Release: Data may default on, provided the data is | ||
127 | > exclusively in these categories (it cannot be in any other category). | ||
128 | > In Release, an opt-out must be available for most types of Technical | ||
129 | > and Interaction data. " | ||
130 | > | ||
131 | > I think the entire page might be enlightening to this discussion. I | ||
132 | > believe our analysis of needs should be more fine-grained, and that | ||
133 | > some parts of what we need can be "default on" especially for | ||
134 | > pre-release testing. For releases, we can provide an opt-out. | ||
135 | > | ||
136 | > Other more sensitive data will need to be opt-in. I think it's a | ||
137 | > mistake to treat all the data we might want all in the same way. | ||
138 | |||
139 | This again brings up opt-out, which so far doesn't seem to have a chance for | ||
140 | consensus. Can we defer this to when we have some more experience with the | ||
141 | opt-in approach and how much participation we get with that? Or are people | ||
142 | feeling this would too strongly limit what they are allowed to do in their | ||
143 | applications? | ||
144 | |||
145 | Seeing yesterday's blog from the Krita team (https://akapust1n.github.io/ | ||
146 | 2017-08-15-sixth-blog-gsoc-2017/), I'd particularly be interested in their | ||
147 | view on this. | ||
148 | |||
149 | Regards, | ||
150 | Volker | ||
151 | |||
152 | > On Sun, Aug 13, 2017 at 3:18 AM, Christian Loosli | ||
153 | > | ||
154 | > <christian.loosli@fuchsnet.ch> wrote: | ||
155 | > > Hi, | ||
156 | > > | ||
157 | > > thank you very much for this work, sounds great! | ||
158 | > > | ||
159 | > > Only point I have: maybe make sure that the opt-in / default settings are | ||
160 | > > not only mandatory for application developers, but also for packagers / | ||
161 | > > distributions. | ||
162 | > > | ||
163 | > > Some distributions have rather questionable views on privacy and by | ||
164 | > > default | ||
165 | > > sent information to third parties, so I would feel much more safe if they | ||
166 | > > weren't allowed (in theory) to flick the switch in their package by | ||
167 | > > default to "on" either. | ||
168 | > > | ||
169 | > > Kind regards, | ||
170 | > > | ||
171 | > > Christian | ||
172 | |||
173 | |||
174 | |||
175 | --nextPart3633370.DIlRsSa6NW | ||
176 | Content-Type: application/pgp-signature; name="signature.asc" | ||
177 | Content-Description: This is a digitally signed message part. | ||
178 | Content-Transfer-Encoding: 7Bit | ||
179 | |||
180 | -----BEGIN PGP SIGNATURE----- | ||
181 | |||
182 | iF0EABECAB0WIQQAnu3FVHA48KjZ07R/lszWTRLSRwUCWZQ2/AAKCRB/lszWTRLS | ||
183 | R+niAKCpVjpRVPq455bnZlAVxpARkGWE/gCcCaBN1QAFz8Da6XIKJGY7iukaS3A= | ||
184 | =ZSiq | ||
185 | -----END PGP SIGNATURE----- | ||
186 | |||
187 | --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 @@ | |||
1 | Return-Path: <kde-community-bounces@kde.org> | ||
2 | Received: from imapb010.mykolab.com ([unix socket]) | ||
3 | by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; | ||
4 | Wed, 16 Aug 2017 15:30:55 +0200 | ||
5 | X-Sieve: CMU Sieve 2.4 | ||
6 | Received: from int-mx001.mykolab.com (unknown [10.9.13.1]) | ||
7 | by imapb010.mykolab.com (Postfix) with ESMTPS id 2C73C14646FD6 | ||
8 | for <christian@mailqueue.ch>; Wed, 16 Aug 2017 15:30:55 +0200 (CEST) | ||
9 | Received: from mx.kolabnow.com (unknown [10.9.4.2]) | ||
10 | by int-mx001.mykolab.com (Postfix) with ESMTPS id 0324D114 | ||
11 | for <christian@mailqueue.ch>; Wed, 16 Aug 2017 15:30:54 +0200 (CEST) | ||
12 | X-Virus-Scanned: amavisd-new at mykolab.com | ||
13 | Authentication-Results: ext-mx-in002.mykolab.com (amavisd-new); | ||
14 | dkim=pass (1024-bit key) header.d=kde.org | ||
15 | X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 | ||
16 | Received: from forward1-smtp.messagingengine.com (forward1-smtp.messagingengine.com [66.111.4.223]) | ||
17 | by ext-mx-in002.mykolab.com (Postfix) with ESMTPS id C91AA866 | ||
18 | for <christian@mailqueue.ch>; Wed, 16 Aug 2017 15:30:34 +0200 (CEST) | ||
19 | Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) | ||
20 | by mailforward.nyi.internal (Postfix) with ESMTP id 5C87A1858 | ||
21 | for <christian@mailqueue.ch>; Wed, 16 Aug 2017 09:30:33 -0400 (EDT) | ||
22 | Received: by mailredirect.nyi.internal (Postfix, from userid 501) | ||
23 | id 4CC8B8E597; Wed, 16 Aug 2017 09:30:33 -0400 (EDT) | ||
24 | Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) | ||
25 | by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; | ||
26 | Wed, 16 Aug 2017 09:30:33 -0400 | ||
27 | X-Cyrus-Session-Id: sloti36d2t28-1026013-1502890233-2-11003035487755983862 | ||
28 | X-Sieve: CMU Sieve 3.0 | ||
29 | X-Spam-known-sender: no | ||
30 | X-Orig-Spam-score: 0.0 | ||
31 | X-Spam-hits: BAYES_00 -1.9, HEADER_FROM_DIFFERENT_DOMAINS 0.001, RCVD_IN_DNSWL_MED -2.3, | ||
32 | RP_MATCHES_RCVD -0.001, SPF_PASS -0.001, LANGUAGES en, BAYES_USED global, | ||
33 | SA_VERSION 3.4.0 | ||
34 | X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='org', | ||
35 | MailFrom='org' | ||
36 | X-Spam-charsets: | ||
37 | X-Resolved-to: chrigi_1@fastmail.fm | ||
38 | X-Delivered-to: chrigi_1@fastmail.fm | ||
39 | X-Mail-from: kde-community-bounces@kde.org | ||
40 | Received: from mx5 ([10.202.2.204]) | ||
41 | by compute1.internal (LMTPProxy); Wed, 16 Aug 2017 09:30:33 -0400 | ||
42 | Authentication-Results: mx5.messagingengine.com; | ||
43 | dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=RolpJ4HJ; | ||
44 | dmarc=none (p=none;has-list-id=yes) header.from=valdyas.org; | ||
45 | spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org | ||
46 | Received-SPF: pass | ||
47 | (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) | ||
48 | receiver=mx5.messagingengine.com; | ||
49 | identity=mailfrom; | ||
50 | envelope-from="kde-community-bounces@kde.org"; | ||
51 | helo=postbox.kde.org; | ||
52 | client-ip=46.4.96.248 | ||
53 | Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) | ||
54 | (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) | ||
55 | (No client certificate requested) | ||
56 | by mx5.messagingengine.com (Postfix) with ESMTPS | ||
57 | for <chrigi_1@fastmail.fm>; Wed, 16 Aug 2017 09:30:32 -0400 (EDT) | ||
58 | DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; | ||
59 | t=1502890227; bh=z989fztQpyrmqEjIXZUifZvjlTrbUJ38xgYnpo5TWHY=; | ||
60 | h=Date:From:To:Subject:In-Reply-To:References:Reply-To:List-Id: | ||
61 | List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: | ||
62 | From; | ||
63 | b=RolpJ4HJf2ZKKk0rJkqOuvP1Ed5rERJZdvt2+FMMsImGArH3hWTlgl1qQewN3B81n | ||
64 | Nq4o83kvWrlw2Y0i0n/fd+NjBLY9wtDBeRslr06KZSnZe4vL6N8p15wkQIs+oUAvCL | ||
65 | 01Uy2pFX/99m+u66rd5IH2Epkdj9iSn2S6U0S3Ew= | ||
66 | X-Original-To: kde-community@kde.org | ||
67 | X-Remote-Delivered-To: kde-community@localhost.kde.org | ||
68 | Received-SPF: None (no SPF record) identity=mailfrom; client-ip=80.100.45.33; | ||
69 | helo=calcifer.valdyas.org; envelope-from=boud@valdyas.org; | ||
70 | receiver=kde-community@kde.org | ||
71 | Received: from calcifer.valdyas.org (calcifer.xs4all.nl [80.100.45.33]) | ||
72 | by postbox.kde.org (Postfix) with ESMTP id 6A134A0178 | ||
73 | for <kde-community@kde.org>; Wed, 16 Aug 2017 13:30:15 +0000 (UTC) | ||
74 | Received: by calcifer.valdyas.org (Postfix, from userid 1001) | ||
75 | id D3C2BC283D; Wed, 16 Aug 2017 15:30:14 +0200 (CEST) | ||
76 | Date: Wed, 16 Aug 2017 15:30:14 +0200 (CEST) | ||
77 | From: Boudewijn Rempt <boud@valdyas.org> | ||
78 | To: informing about and discussing non-technical community topics | ||
79 | <kde-community@kde.org> | ||
80 | Subject: Re: Telemetry Policy | ||
81 | In-Reply-To: <1942419.JquqIjZoWq@vkpc19> | ||
82 | Message-ID: <alpine.LNX.2.00.1708161528260.1363@calcifer.valdyas.org> | ||
83 | References: <2048912.XfIJe3ZSdj@vkpc5> <2990543.KVDkBByYO0@minixfox> | ||
84 | <CACpu024EH1OeDqwL94QK33eq4sCGjKjwedcQDR_PWjprBevzfg@mail.gmail.com> | ||
85 | <1942419.JquqIjZoWq@vkpc19> | ||
86 | User-Agent: Alpine 2.00 (LNX 1167 2008-08-23) | ||
87 | MIME-Version: 1.0 | ||
88 | Content-Type: TEXT/PLAIN; charset=US-ASCII | ||
89 | X-BeenThere: kde-community@kde.org | ||
90 | X-Mailman-Version: 2.1.16 | ||
91 | Precedence: list | ||
92 | Reply-To: informing about and discussing non-technical community topics | ||
93 | <kde-community@kde.org> | ||
94 | List-Id: informing about and discussing non-technical community topics | ||
95 | <kde-community.kde.org> | ||
96 | List-Unsubscribe: <https://mail.kde.org/mailman/options/kde-community>, | ||
97 | <mailto:kde-community-request@kde.org?subject=unsubscribe> | ||
98 | List-Archive: <http://mail.kde.org/pipermail/kde-community/> | ||
99 | List-Post: <mailto:kde-community@kde.org> | ||
100 | List-Help: <mailto:kde-community-request@kde.org?subject=help> | ||
101 | List-Subscribe: <https://mail.kde.org/mailman/listinfo/kde-community>, | ||
102 | <mailto:kde-community-request@kde.org?subject=subscribe> | ||
103 | Errors-To: kde-community-bounces@kde.org | ||
104 | Sender: "kde-community" <kde-community-bounces@kde.org> | ||
105 | |||
106 | On Wed, 16 Aug 2017, Volker Krause wrote: | ||
107 | |||
108 | > Seeing yesterday's blog from the Krita team (https://akapust1n.github.io/ | ||
109 | > 2017-08-15-sixth-blog-gsoc-2017/), I'd particularly be interested in their | ||
110 | > view on this. | ||
111 | |||
112 | I've pointed alexey at this thread, but there's a huge language barrier: | ||
113 | he basically communicates through google translate. I've made it a firm | ||
114 | condition of merging and operating the telemetry that we adhere to the | ||
115 | KDE policy in every way. Even then, I still consider his work to be | ||
116 | an experimental research project. | ||
117 | |||
118 | -- | ||
119 | 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 @@ | |||
1 | Return-Path: <kde-community-bounces@kde.org> | ||
2 | Received: from imapb010.mykolab.com ([unix socket]) | ||
3 | by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; | ||
4 | Thu, 17 Aug 2017 01:47:27 +0200 | ||
5 | X-Sieve: CMU Sieve 2.4 | ||
6 | Received: from int-mx002.mykolab.com (unknown [10.9.13.2]) | ||
7 | by imapb010.mykolab.com (Postfix) with ESMTPS id 2CC5214A68D1A | ||
8 | for <christian@mailqueue.ch>; Thu, 17 Aug 2017 01:47:27 +0200 (CEST) | ||
9 | Received: from mx.kolabnow.com (unknown [10.9.4.2]) | ||
10 | by int-mx002.mykolab.com (Postfix) with ESMTPS id 13C82F44 | ||
11 | for <christian@mailqueue.ch>; Thu, 17 Aug 2017 01:47:27 +0200 (CEST) | ||
12 | X-Virus-Scanned: amavisd-new at mykolab.com | ||
13 | Authentication-Results: ext-mx-in002.mykolab.com (amavisd-new); | ||
14 | dkim=pass (1024-bit key) header.d=kde.org | ||
15 | X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 | ||
16 | Received: from forward1-smtp.messagingengine.com (forward1-smtp.messagingengine.com [66.111.4.223]) | ||
17 | by ext-mx-in002.mykolab.com (Postfix) with ESMTPS id DA7D7211 | ||
18 | for <christian@mailqueue.ch>; Thu, 17 Aug 2017 01:47:15 +0200 (CEST) | ||
19 | Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) | ||
20 | by mailforward.nyi.internal (Postfix) with ESMTP id F078A4C | ||
21 | for <christian@mailqueue.ch>; Wed, 16 Aug 2017 19:47:14 -0400 (EDT) | ||
22 | Received: by mailredirect.nyi.internal (Postfix, from userid 501) | ||
23 | id D2D7E8E231; Wed, 16 Aug 2017 19:47:14 -0400 (EDT) | ||
24 | Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) | ||
25 | by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; | ||
26 | Wed, 16 Aug 2017 19:47:14 -0400 | ||
27 | X-Cyrus-Session-Id: sloti36d2t28-1787481-1502927234-2-5475491779407099440 | ||
28 | X-Sieve: CMU Sieve 3.0 | ||
29 | X-Spam-known-sender: yes ("Address thomas.pfeiffer@kde.org in From header is in addressbook"); | ||
30 | in-addressbook | ||
31 | X-Orig-Spam-score: 0.0 | ||
32 | X-Spam-hits: BAYES_00 -1.9, RCVD_IN_DNSWL_MED -2.3, RCVD_IN_SORBS_SPAM 0.5, | ||
33 | RP_MATCHES_RCVD -0.001, SPF_PASS -0.001, LANGUAGES en, BAYES_USED global, | ||
34 | SA_VERSION 3.4.0 | ||
35 | X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='org', | ||
36 | MailFrom='org' | ||
37 | X-Spam-charsets: plain='us-ascii' | ||
38 | X-Resolved-to: chrigi_1@fastmail.fm | ||
39 | X-Delivered-to: chrigi_1@fastmail.fm | ||
40 | X-Mail-from: kde-community-bounces@kde.org | ||
41 | Received: from mx6 ([10.202.2.205]) | ||
42 | by compute1.internal (LMTPProxy); Wed, 16 Aug 2017 19:47:14 -0400 | ||
43 | Authentication-Results: mx6.messagingengine.com; | ||
44 | dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=jjcN/rDm; | ||
45 | dmarc=none (p=none;has-list-id=yes) header.from=kde.org; | ||
46 | spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org; | ||
47 | x-google-dkim=pass (2048-bit rsa key) header.d=1e100.net header.i=@1e100.net header.b=MDpKFUTu | ||
48 | Received-SPF: pass | ||
49 | (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) | ||
50 | receiver=mx6.messagingengine.com; | ||
51 | identity=mailfrom; | ||
52 | envelope-from="kde-community-bounces@kde.org"; | ||
53 | helo=postbox.kde.org; | ||
54 | client-ip=46.4.96.248 | ||
55 | Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) | ||
56 | (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) | ||
57 | (No client certificate requested) | ||
58 | by mx6.messagingengine.com (Postfix) with ESMTPS | ||
59 | for <chrigi_1@fastmail.fm>; Wed, 16 Aug 2017 19:47:13 -0400 (EDT) | ||
60 | DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; | ||
61 | t=1502927232; bh=ZPaDxaRw15uQ6A7HkCF2KoV4m+FrAkqde8P/U1SNqY8=; | ||
62 | h=From:To:Subject:Date:In-Reply-To:References:Reply-To:List-Id: | ||
63 | List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: | ||
64 | From; | ||
65 | b=jjcN/rDm5jM+2ttx4iyMXexUXHMS9OAzt1cfA461VOjTfg9ZPg+Kt1qCqUVzJNoSj | ||
66 | tXrKk69VVjb7tr4GNWJMKc2FAb5P33ndx6UC08kFDADMECoxSgwbHeKWdKCLE0KqOH | ||
67 | sCtYBZp0heUQzEztcQtjwtPuExHqivuLyYqZRvyM= | ||
68 | X-Original-To: kde-community@kde.org | ||
69 | X-Remote-Delivered-To: kde-community@localhost.kde.org | ||
70 | Received-SPF: Pass (sender SPF authorized) identity=mailfrom; | ||
71 | client-ip=209.85.128.174; helo=mail-wr0-f174.google.com; | ||
72 | envelope-from=t.pfeiffer.ux@gmail.com; receiver=kde-community@kde.org | ||
73 | Received: from mail-wr0-f174.google.com (mail-wr0-f174.google.com | ||
74 | [209.85.128.174]) | ||
75 | by postbox.kde.org (Postfix) with ESMTPS id 6AB96A029E | ||
76 | for <kde-community@kde.org>; Wed, 16 Aug 2017 23:46:52 +0000 (UTC) | ||
77 | Received: by mail-wr0-f174.google.com with SMTP id b65so29404863wrd.0 | ||
78 | for <kde-community@kde.org>; Wed, 16 Aug 2017 16:46:52 -0700 (PDT) | ||
79 | X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; | ||
80 | d=1e100.net; s=20161025; | ||
81 | h=x-gm-message-state:from:to:subject:date:message-id:organization | ||
82 | :in-reply-to:references:mime-version:content-transfer-encoding; | ||
83 | bh=vOHtuq150Bi0dtLwrlvhmLXneJGQN+nwYPMD7ClfMTY=; | ||
84 | b=MDpKFUTuVW39/V5tI6WXpiuZNRgPorWVPEILVo6uTCaSPIWU4FPwx/FYFqYRnwLLZ4 | ||
85 | JwLB2+R6USx5jpbjlgx7GDEuCAAGm+GI7GtyLRb0tZZMtXW7glpa2IuqLPTtIygXQSn4 | ||
86 | nsSRysSlT02zZ26qbDXYeoWUOpn2CK2fmQ9l9q29GdTmC/+Ud4vfJqdW/nvnczqZVyyF | ||
87 | zUsQuOalp0VORBdSgDxDrtEA50pR+8TrnBu48u4OSigb4d6QgqZvPEYSPp7UWHmuEoBe | ||
88 | F92VN6efXYqb4tRUthsfokDw7l1TFhRB0g0UOl7BxXrRT54MGceiJ4fY8jVD+7+DN3aT | ||
89 | pD3g== | ||
90 | X-Gm-Message-State: AHYfb5gfW1I+uGmtawofLSI0ZX4ZfkMah5Eyn73zmN/CEJ0d9ZDOFpsR | ||
91 | Y4FpRIYROX0uhR9L | ||
92 | X-Received: by 10.28.11.131 with SMTP id 125mr45861wml.82.1502927211295; | ||
93 | Wed, 16 Aug 2017 16:46:51 -0700 (PDT) | ||
94 | Received: from lenovo.localnet ([2a02:8071:31c0:f00:626c:66ff:fe3f:93eb]) | ||
95 | by smtp.gmail.com with ESMTPSA id r70sm3132823wmb.35.2017.08.16.16.46.48 | ||
96 | for <kde-community@kde.org> | ||
97 | (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); | ||
98 | Wed, 16 Aug 2017 16:46:49 -0700 (PDT) | ||
99 | From: Thomas Pfeiffer <thomas.pfeiffer@kde.org> | ||
100 | To: informing about and discussing non-technical community topics | ||
101 | <kde-community@kde.org> | ||
102 | Subject: Re: Telemetry Policy | ||
103 | Date: Thu, 17 Aug 2017 01:46:48 +0200 | ||
104 | Message-ID: <5231282.Ch11jfsTMl@lenovo> | ||
105 | Organization: KDE | ||
106 | In-Reply-To: <CACpu024EH1OeDqwL94QK33eq4sCGjKjwedcQDR_PWjprBevzfg@mail.gmail.com> | ||
107 | References: <2048912.XfIJe3ZSdj@vkpc5> <2990543.KVDkBByYO0@minixfox> | ||
108 | <CACpu024EH1OeDqwL94QK33eq4sCGjKjwedcQDR_PWjprBevzfg@mail.gmail.com> | ||
109 | MIME-Version: 1.0 | ||
110 | Content-Transfer-Encoding: 7Bit | ||
111 | Content-Type: text/plain; charset="us-ascii" | ||
112 | X-BeenThere: kde-community@kde.org | ||
113 | X-Mailman-Version: 2.1.16 | ||
114 | Precedence: list | ||
115 | Reply-To: informing about and discussing non-technical community topics | ||
116 | <kde-community@kde.org> | ||
117 | List-Id: informing about and discussing non-technical community topics | ||
118 | <kde-community.kde.org> | ||
119 | List-Unsubscribe: <https://mail.kde.org/mailman/options/kde-community>, | ||
120 | <mailto:kde-community-request@kde.org?subject=unsubscribe> | ||
121 | List-Archive: <http://mail.kde.org/pipermail/kde-community/> | ||
122 | List-Post: <mailto:kde-community@kde.org> | ||
123 | List-Help: <mailto:kde-community-request@kde.org?subject=help> | ||
124 | List-Subscribe: <https://mail.kde.org/mailman/listinfo/kde-community>, | ||
125 | <mailto:kde-community-request@kde.org?subject=subscribe> | ||
126 | Errors-To: kde-community-bounces@kde.org | ||
127 | Sender: "kde-community" <kde-community-bounces@kde.org> | ||
128 | |||
129 | On Mittwoch, 16. August 2017 09:33:02 CEST Valorie Zimmerman wrote: | ||
130 | > Hi all, Mozilla has done a lot of work on telemetry, and we might be | ||
131 | > able to use some of their findings. On this page: | ||
132 | > https://wiki.mozilla.org/Firefox/Data_Collection they break down the | ||
133 | > data they might possibly collect into four buckets - technical (such | ||
134 | > as crashes), user interaction, web activity, and sensitive (personal | ||
135 | > data). | ||
136 | > | ||
137 | > This bit might be relevant to our discussion: "Categories 1 & 2 | ||
138 | > (Technical & Interaction data) | ||
139 | > Pre-Release & Release: Data may default on, provided the data is | ||
140 | > exclusively in these categories (it cannot be in any other category). | ||
141 | > In Release, an opt-out must be available for most types of Technical | ||
142 | > and Interaction data. " | ||
143 | > | ||
144 | > I think the entire page might be enlightening to this discussion. I | ||
145 | > believe our analysis of needs should be more fine-grained, and that | ||
146 | > some parts of what we need can be "default on" especially for | ||
147 | > pre-release testing. For releases, we can provide an opt-out. | ||
148 | |||
149 | Hi Valorie, | ||
150 | Even if opt-out for some data is legally and even morally fine, it does not | ||
151 | align with the values we communicate to our users: | ||
152 | Unlike Mozilla's Mission, our Vision mentions privacy explicitly, and we're | ||
153 | striving to make privacy our USP. | ||
154 | |||
155 | Therefore I agree with others who replied in this thread: We should respect | ||
156 | privacy unnecessarily much rather than too little. | ||
157 | |||
158 | In the end, of course, it's a matter of how we present this opt-in. If it's an | ||
159 | option buried in some settings dialog, we might as well not do it at all. | ||
160 | |||
161 | If we, however - like Firefox does -, pfominently present that choice to users | ||
162 | the first time they run one of our applications or desktop environment and try | ||
163 | to make clear why that data collection is important for us, I don't see why we | ||
164 | could not convince a relevant number of users to opt in. | ||
165 | Sure, we'll get less data than with an opt-out scheme, but let's try it out | ||
166 | first before we go for the option that carries a significant PR risk. | ||
167 | |||
168 | > Other more sensitive data will need to be opt-in. I think it's a | ||
169 | > mistake to treat all the data we might want all in the same way. | ||
170 | |||
171 | Content (web activity for Mozilla) and personal information should not be opt- | ||
172 | anything but not collected at all. | ||
173 | |||
174 | Cheers, | ||
175 | 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 @@ | |||
1 | Return-Path: <kde-community-bounces@kde.org> | ||
2 | Received: from imapb010.mykolab.com ([unix socket]) | ||
3 | by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; | ||
4 | Thu, 17 Aug 2017 17:40:53 +0200 | ||
5 | X-Sieve: CMU Sieve 2.4 | ||
6 | Received: from int-mx003.mykolab.com (unknown [10.9.13.3]) | ||
7 | by imapb010.mykolab.com (Postfix) with ESMTPS id 467271505D03E | ||
8 | for <christian@mailqueue.ch>; Thu, 17 Aug 2017 17:40:53 +0200 (CEST) | ||
9 | Received: from mx.kolabnow.com (unknown [10.9.4.3]) | ||
10 | by int-mx003.mykolab.com (Postfix) with ESMTPS id 2CC4FF16 | ||
11 | for <christian@mailqueue.ch>; Thu, 17 Aug 2017 17:40:53 +0200 (CEST) | ||
12 | X-Virus-Scanned: amavisd-new at mykolab.com | ||
13 | Authentication-Results: ext-mx-in003.mykolab.com (amavisd-new); | ||
14 | dkim=pass (1024-bit key) header.d=kde.org header.b=rysq5aPx; | ||
15 | dkim=fail (2048-bit key) reason="fail (message has been altered)" | ||
16 | header.d=gmail.com header.b=WiuysEuO | ||
17 | X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 | ||
18 | Received: from forward1-smtp.messagingengine.com (forward1-smtp.messagingengine.com [66.111.4.223]) | ||
19 | by ext-mx-in003.mykolab.com (Postfix) with ESMTPS id 9C4BA2EB8 | ||
20 | for <christian@mailqueue.ch>; Thu, 17 Aug 2017 17:39:23 +0200 (CEST) | ||
21 | Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) | ||
22 | by mailforward.nyi.internal (Postfix) with ESMTP id 5138E1453 | ||
23 | for <christian@mailqueue.ch>; Thu, 17 Aug 2017 11:39:22 -0400 (EDT) | ||
24 | Received: by mailredirect.nyi.internal (Postfix, from userid 501) | ||
25 | id 48C918E9B6; Thu, 17 Aug 2017 11:39:22 -0400 (EDT) | ||
26 | Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) | ||
27 | by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; | ||
28 | Thu, 17 Aug 2017 11:39:22 -0400 | ||
29 | X-Cyrus-Session-Id: sloti36d2t28-3156705-1502984362-2-3811956415179411272 | ||
30 | X-Sieve: CMU Sieve 3.0 | ||
31 | X-Spam-known-sender: no | ||
32 | X-Orig-Spam-score: 0.0 | ||
33 | X-Spam-hits: BAYES_00 -1.9, HTML_MESSAGE 0.001, RCVD_IN_DNSWL_MED -2.3, | ||
34 | RP_MATCHES_RCVD -0.001, SPF_PASS -0.001, LANGUAGES en, BAYES_USED global, | ||
35 | SA_VERSION 3.4.0 | ||
36 | X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='org', | ||
37 | MailFrom='org' | ||
38 | X-Spam-charsets: plain='us-ascii', html='us-ascii' | ||
39 | X-Attached: signature.asc | ||
40 | X-Resolved-to: chrigi_1@fastmail.fm | ||
41 | X-Delivered-to: chrigi_1@fastmail.fm | ||
42 | X-Mail-from: kde-community-bounces@kde.org | ||
43 | Received: from mx3 ([10.202.2.202]) | ||
44 | by compute1.internal (LMTPProxy); Thu, 17 Aug 2017 11:39:22 -0400 | ||
45 | Authentication-Results: mx3.messagingengine.com; | ||
46 | dkim=fail (message has been altered; 2048-bit rsa key sha256) header.d=gmail.com header.i=@gmail.com header.b=WiuysEuO; | ||
47 | dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=rysq5aPx; | ||
48 | dmarc=none (p=none;has-list-id=yes) header.from=kde.org; | ||
49 | spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org; | ||
50 | x-google-dkim=fail (message has been altered; 2048-bit rsa key) header.d=1e100.net header.i=@1e100.net header.b=eS2FiZD3 | ||
51 | Received-SPF: pass | ||
52 | (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) | ||
53 | receiver=mx3.messagingengine.com; | ||
54 | identity=mailfrom; | ||
55 | envelope-from="kde-community-bounces@kde.org"; | ||
56 | helo=postbox.kde.org; | ||
57 | client-ip=46.4.96.248 | ||
58 | Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) | ||
59 | (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) | ||
60 | (No client certificate requested) | ||
61 | by mx3.messagingengine.com (Postfix) with ESMTPS | ||
62 | for <chrigi_1@fastmail.fm>; Thu, 17 Aug 2017 11:39:21 -0400 (EDT) | ||
63 | DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; | ||
64 | t=1502984359; bh=g7hsgd71OQgeOpLvXEjz16cF2X/6f5pmr2ujAF633tY=; | ||
65 | h=From:Date:Subject:In-Reply-To:To:References:Reply-To:List-Id: | ||
66 | List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: | ||
67 | From; | ||
68 | b=rysq5aPxwhI8i+Fx0jQHMx7aHC9RRMfjzmZTplBHjuND6qLLgZgMg2Tqpwgp1PnTR | ||
69 | zbpE07c5O50AqjjN74AqtaWdN7xCtsPb1taF9XjBDScI3wVcmiRZ5d88Sp9YI8rAzy | ||
70 | cY5uS6QDZfPt/BmonQqnc0oKpuuIlSp78R482qck= | ||
71 | X-Original-To: kde-community@kde.org | ||
72 | X-Remote-Delivered-To: kde-community@localhost.kde.org | ||
73 | Received-SPF: Pass (sender SPF authorized) identity=mailfrom; | ||
74 | client-ip=2a00:1450:400c:c0c::22a; helo=mail-wr0-x22a.google.com; | ||
75 | envelope-from=mirko.mb.boehm@gmail.com; receiver=kde-community@kde.org | ||
76 | Authentication-Results: postbox.kde.org; dkim=pass | ||
77 | reason="2048-bit key; unprotected key" | ||
78 | header.d=gmail.com header.i=@gmail.com header.b=WiuysEuO; | ||
79 | dkim-adsp=pass; dkim-atps=neutral | ||
80 | Received: from mail-wr0-x22a.google.com (mail-wr0-x22a.google.com | ||
81 | [IPv6:2a00:1450:400c:c0c::22a]) | ||
82 | by postbox.kde.org (Postfix) with ESMTPS id 6622AA028C; | ||
83 | Thu, 17 Aug 2017 15:38:56 +0000 (UTC) | ||
84 | Received: by mail-wr0-x22a.google.com with SMTP id b65so47289023wrd.0; | ||
85 | Thu, 17 Aug 2017 08:38:56 -0700 (PDT) | ||
86 | DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; | ||
87 | h=sender:from:message-id:mime-version:date:subject:in-reply-to:to | ||
88 | :references; bh=yh4e0FfFAXMmAqoicYQa52CLKXFU6SJTKLd0PdPDxRM=; | ||
89 | b=WiuysEuO59GFkLy+fKRSFayTM8LXWK3dVaVHDKfsw/XM8YKcLalwNWGVU0tsaDl+7P | ||
90 | r5MMLidc6O0gJKGftMdhWrjeFGY0aE5F5+2NKN1oEb2INbB/DrS9KaCVy1SWvHVu8zOo | ||
91 | t13omoGW6RIs5lgWrTLR1iwcwtfkWwO/+Ndy16U3/eYJSXeUPWHsVSXP0UgIS6IANt58 | ||
92 | lNQhTgWBAJNViCxH/p5nIZYvLY5tGJPL6J46GaM7jUK4Ev6HUx4pUwGBsPB4hBezPm7h | ||
93 | mzA74izFW7jE6JklTciMAb0q7wEG15exVQbTEG54nvWMASrWx6mMAc+CWLh/T8vokpvT | ||
94 | Kvrw== | ||
95 | X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; | ||
96 | d=1e100.net; s=20161025; | ||
97 | h=x-gm-message-state:sender:from:message-id:mime-version:date:subject | ||
98 | :in-reply-to:to:references; | ||
99 | bh=yh4e0FfFAXMmAqoicYQa52CLKXFU6SJTKLd0PdPDxRM=; | ||
100 | b=eS2FiZD3QQ7P0mT2qKkYWf91vVTGXnIHKKzNdIJq+8JXN8WoXQ8IXmvQqSQFJa/w16 | ||
101 | m9I0Yko7iv/JDAa7YTeJraBfImv9weknM3zpUNan8SltCFNXO8f4yylP1rGLn0RWbQ3Q | ||
102 | 9NEpmYbS5dYQ79PMwy3zHxZEkUbsIFk8OlVSohdzpzGgtyU6nOjnBDULL14uHnouaz8+ | ||
103 | TDss7L/vKlmrWOYdH+R8peCkFI6p3C69wpAEyNPGBaGyCRC+pebx6GGDBR63DFnyP464 | ||
104 | VFQCUS4hPPTFaBPriqOF6xcWToacU40DVy3s2S/3EwHpUGWi+WMqQpPgqZYJh81unCDH | ||
105 | Hc7g== | ||
106 | X-Gm-Message-State: AHYfb5hHmIopTFINsSS7+92/GpIh2jJhvpwp/cI1ajaDE2GLp/oZ6V7N | ||
107 | CCtnx8PQ3oXGOEKCRT4= | ||
108 | X-Received: by 10.80.212.133 with SMTP id s5mr2195642edi.95.1502984335423; | ||
109 | Thu, 17 Aug 2017 08:38:55 -0700 (PDT) | ||
110 | Received: from ?IPv6:2a02:8109:a4bf:e114:30bf:9873:2660:a4a8? | ||
111 | ([2a02:8109:a4bf:e114:30bf:9873:2660:a4a8]) | ||
112 | by smtp.gmail.com with ESMTPSA id r29sm1790792edi.85.2017.08.17.08.38.52 | ||
113 | (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); | ||
114 | Thu, 17 Aug 2017 08:38:52 -0700 (PDT) | ||
115 | From: Mirko Boehm - KDE <mirko@kde.org> | ||
116 | Message-Id: <B95D7D2A-23A9-4245-AAC0-8A3FAE330090@kde.org> | ||
117 | Content-Type: multipart/signed; | ||
118 | boundary="Apple-Mail=_1637D59B-BBA3-401E-A7A5-3514665481AD"; | ||
119 | protocol="application/pgp-signature"; micalg=pgp-sha1 | ||
120 | Mime-Version: 1.0 (Mac OS X Mail 10.3 \(3273\)) | ||
121 | Date: Thu, 17 Aug 2017 17:38:52 +0200 | ||
122 | Subject: Re: Telemetry Policy | ||
123 | In-Reply-To: <5231282.Ch11jfsTMl@lenovo> | ||
124 | To: informing about and discussing non-technical community topics | ||
125 | <kde-community@kde.org> | ||
126 | References: <2048912.XfIJe3ZSdj@vkpc5> <2990543.KVDkBByYO0@minixfox> | ||
127 | <CACpu024EH1OeDqwL94QK33eq4sCGjKjwedcQDR_PWjprBevzfg@mail.gmail.com> | ||
128 | <5231282.Ch11jfsTMl@lenovo> | ||
129 | X-Mailer: Apple Mail (2.3273) | ||
130 | X-BeenThere: kde-community@kde.org | ||
131 | X-Mailman-Version: 2.1.16 | ||
132 | Precedence: list | ||
133 | Reply-To: informing about and discussing non-technical community topics | ||
134 | <kde-community@kde.org> | ||
135 | List-Id: informing about and discussing non-technical community topics | ||
136 | <kde-community.kde.org> | ||
137 | List-Unsubscribe: <https://mail.kde.org/mailman/options/kde-community>, | ||
138 | <mailto:kde-community-request@kde.org?subject=unsubscribe> | ||
139 | List-Archive: <http://mail.kde.org/pipermail/kde-community/> | ||
140 | List-Post: <mailto:kde-community@kde.org> | ||
141 | List-Help: <mailto:kde-community-request@kde.org?subject=help> | ||
142 | List-Subscribe: <https://mail.kde.org/mailman/listinfo/kde-community>, | ||
143 | <mailto:kde-community-request@kde.org?subject=subscribe> | ||
144 | Errors-To: kde-community-bounces@kde.org | ||
145 | Sender: "kde-community" <kde-community-bounces@kde.org> | ||
146 | |||
147 | |||
148 | --Apple-Mail=_1637D59B-BBA3-401E-A7A5-3514665481AD | ||
149 | Content-Type: multipart/alternative; | ||
150 | boundary="Apple-Mail=_F49D9C7A-5DFA-4D78-8758-C0DB8C98E040" | ||
151 | |||
152 | |||
153 | --Apple-Mail=_F49D9C7A-5DFA-4D78-8758-C0DB8C98E040 | ||
154 | Content-Transfer-Encoding: quoted-printable | ||
155 | Content-Type: text/plain; | ||
156 | charset=us-ascii | ||
157 | |||
158 | Hi, | ||
159 | |||
160 | > On 17. Aug 2017, at 01:46, Thomas Pfeiffer <thomas.pfeiffer@kde.org> = | ||
161 | wrote: | ||
162 | >=20 | ||
163 | > Hi Valorie, | ||
164 | > Even if opt-out for some data is legally and even morally fine, it = | ||
165 | does not | ||
166 | > align with the values we communicate to our users: | ||
167 | > Unlike Mozilla's Mission, our Vision mentions privacy explicitly, and = | ||
168 | we're | ||
169 | > striving to make privacy our USP. | ||
170 | |||
171 | We seem to assume a contradiction between telemetry and privacy. I = | ||
172 | believe this is a knee-jerk reaction. We can implement telemetry in a = | ||
173 | way that privacy is not violated. In fact, I would say that it follows = | ||
174 | from our vision that we should do this. | ||
175 | |||
176 | Cheers, | ||
177 | |||
178 | Mirko. | ||
179 | -- | ||
180 | Mirko Boehm | mirko@kde.org | KDE e.V. | ||
181 | FSFE Fellowship Representative, FSFE Team Germany | ||
182 | Qt Certified Specialist and Trainer | ||
183 | Request a meeting: https://doodle.com/mirkoboehm | ||
184 | |||
185 | |||
186 | --Apple-Mail=_F49D9C7A-5DFA-4D78-8758-C0DB8C98E040 | ||
187 | Content-Transfer-Encoding: quoted-printable | ||
188 | Content-Type: text/html; | ||
189 | charset=us-ascii | ||
190 | |||
191 | <html><head><meta http-equiv=3D"Content-Type" content=3D"text/html = | ||
192 | charset=3Dus-ascii"></head><body style=3D"word-wrap: break-word; = | ||
193 | -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" = | ||
194 | class=3D"">Hi, <div class=3D""><br class=3D""><div><blockquote = | ||
195 | type=3D"cite" class=3D""><div class=3D"">On 17. Aug 2017, at 01:46, = | ||
196 | Thomas Pfeiffer <<a href=3D"mailto:thomas.pfeiffer@kde.org" = | ||
197 | class=3D"">thomas.pfeiffer@kde.org</a>> wrote:</div><br = | ||
198 | class=3D"Apple-interchange-newline"><div class=3D""><span = | ||
199 | style=3D"font-family: Menlo-Regular; font-size: 11px; font-style: = | ||
200 | normal; font-variant-caps: normal; font-weight: normal; letter-spacing: = | ||
201 | normal; text-align: start; text-indent: 0px; text-transform: none; = | ||
202 | white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; = | ||
203 | float: none; display: inline !important;" class=3D"">Hi = | ||
204 | Valorie,</span><br style=3D"font-family: Menlo-Regular; font-size: 11px; = | ||
205 | font-style: normal; font-variant-caps: normal; font-weight: normal; = | ||
206 | letter-spacing: normal; text-align: start; text-indent: 0px; = | ||
207 | text-transform: none; white-space: normal; word-spacing: 0px; = | ||
208 | -webkit-text-stroke-width: 0px;" class=3D""><span style=3D"font-family: = | ||
209 | Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: = | ||
210 | normal; font-weight: normal; letter-spacing: normal; text-align: start; = | ||
211 | text-indent: 0px; text-transform: none; white-space: normal; = | ||
212 | word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: = | ||
213 | inline !important;" class=3D"">Even if opt-out for some data is legally = | ||
214 | and even morally fine, it does not<span = | ||
215 | class=3D"Apple-converted-space"> </span></span><br = | ||
216 | style=3D"font-family: Menlo-Regular; font-size: 11px; font-style: = | ||
217 | normal; font-variant-caps: normal; font-weight: normal; letter-spacing: = | ||
218 | normal; text-align: start; text-indent: 0px; text-transform: none; = | ||
219 | white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" = | ||
220 | class=3D""><span style=3D"font-family: Menlo-Regular; font-size: 11px; = | ||
221 | font-style: normal; font-variant-caps: normal; font-weight: normal; = | ||
222 | letter-spacing: normal; text-align: start; text-indent: 0px; = | ||
223 | text-transform: none; white-space: normal; word-spacing: 0px; = | ||
224 | -webkit-text-stroke-width: 0px; float: none; display: inline = | ||
225 | !important;" class=3D"">align with the values we communicate to our = | ||
226 | users:</span><br style=3D"font-family: Menlo-Regular; font-size: 11px; = | ||
227 | font-style: normal; font-variant-caps: normal; font-weight: normal; = | ||
228 | letter-spacing: normal; text-align: start; text-indent: 0px; = | ||
229 | text-transform: none; white-space: normal; word-spacing: 0px; = | ||
230 | -webkit-text-stroke-width: 0px;" class=3D""><span style=3D"font-family: = | ||
231 | Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: = | ||
232 | normal; font-weight: normal; letter-spacing: normal; text-align: start; = | ||
233 | text-indent: 0px; text-transform: none; white-space: normal; = | ||
234 | word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: = | ||
235 | inline !important;" class=3D"">Unlike Mozilla's Mission, our Vision = | ||
236 | mentions privacy explicitly, and we're<span = | ||
237 | class=3D"Apple-converted-space"> </span></span><br = | ||
238 | style=3D"font-family: Menlo-Regular; font-size: 11px; font-style: = | ||
239 | normal; font-variant-caps: normal; font-weight: normal; letter-spacing: = | ||
240 | normal; text-align: start; text-indent: 0px; text-transform: none; = | ||
241 | white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" = | ||
242 | class=3D""><span style=3D"font-family: Menlo-Regular; font-size: 11px; = | ||
243 | font-style: normal; font-variant-caps: normal; font-weight: normal; = | ||
244 | letter-spacing: normal; text-align: start; text-indent: 0px; = | ||
245 | text-transform: none; white-space: normal; word-spacing: 0px; = | ||
246 | -webkit-text-stroke-width: 0px; float: none; display: inline = | ||
247 | !important;" class=3D"">striving to make privacy our USP.</span><br = | ||
248 | style=3D"font-family: Menlo-Regular; font-size: 11px; font-style: = | ||
249 | normal; font-variant-caps: normal; font-weight: normal; letter-spacing: = | ||
250 | normal; text-align: start; text-indent: 0px; text-transform: none; = | ||
251 | white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" = | ||
252 | class=3D""></div></blockquote><br class=3D""></div><div>We seem to = | ||
253 | assume a contradiction between telemetry and privacy. I believe this is = | ||
254 | a knee-jerk reaction. We can implement telemetry in a way that privacy = | ||
255 | is not violated. In fact, I would say that it follows from our vision = | ||
256 | that we should do this.</div><div><br = | ||
257 | class=3D""></div><div>Cheers,</div><div><br = | ||
258 | class=3D""></div><div>Mirko.</div><div class=3D""> | ||
259 | <div style=3D"orphans: auto; text-align: start; text-indent: 0px; = | ||
260 | widows: auto; word-wrap: break-word; -webkit-nbsp-mode: space; = | ||
261 | -webkit-line-break: after-white-space;" class=3D""><div style=3D"color: = | ||
262 | rgb(0, 0, 0); letter-spacing: normal; text-transform: none; white-space: = | ||
263 | normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; orphans: = | ||
264 | auto; text-align: start; text-indent: 0px; widows: auto; word-wrap: = | ||
265 | break-word; -webkit-nbsp-mode: space; -webkit-line-break: = | ||
266 | after-white-space;" class=3D"">-- <br class=3D""></div><div = | ||
267 | style=3D"orphans: auto; text-align: start; text-indent: 0px; widows: = | ||
268 | auto; word-wrap: break-word; -webkit-nbsp-mode: space; = | ||
269 | -webkit-line-break: after-white-space;" class=3D"">Mirko Boehm | <a = | ||
270 | href=3D"mailto:mirko@kde.org" class=3D"">mirko@kde.org</a> | KDE e.V.<br = | ||
271 | class=3D"">FSFE Fellowship Representative, FSFE Team Germany<br = | ||
272 | class=3D"">Qt Certified Specialist and Trainer<br class=3D"">Request a = | ||
273 | meeting: <a href=3D"https://doodle.com/mirkoboehm" = | ||
274 | class=3D"">https://doodle.com/mirkoboehm</a><br class=3D""></div></div> | ||
275 | </div> | ||
276 | |||
277 | <br class=3D""></div></body></html>= | ||
278 | |||
279 | --Apple-Mail=_F49D9C7A-5DFA-4D78-8758-C0DB8C98E040-- | ||
280 | |||
281 | --Apple-Mail=_1637D59B-BBA3-401E-A7A5-3514665481AD | ||
282 | Content-Transfer-Encoding: 7bit | ||
283 | Content-Disposition: attachment; | ||
284 | filename=signature.asc | ||
285 | Content-Type: application/pgp-signature; | ||
286 | name=signature.asc | ||
287 | Content-Description: Message signed with OpenPGP | ||
288 | |||
289 | -----BEGIN PGP SIGNATURE----- | ||
290 | Comment: GPGTools - http://gpgtools.org | ||
291 | |||
292 | iEYEARECAAYFAlmVuIwACgkQYSSaITCTnKX82QCgxjyaXNsffHG/42ioAQrxjdCN | ||
293 | D4kAn2Vv0q16buzjcRel1P144tLyqbr+ | ||
294 | =muZP | ||
295 | -----END PGP SIGNATURE----- | ||
296 | |||
297 | --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 @@ | |||
1 | Return-Path: <kde-community-bounces@kde.org> | ||
2 | Received: from imapb010.mykolab.com ([unix socket]) | ||
3 | by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; | ||
4 | Thu, 17 Aug 2017 18:40:51 +0200 | ||
5 | X-Sieve: CMU Sieve 2.4 | ||
6 | Received: from int-mx001.mykolab.com (unknown [10.9.13.1]) | ||
7 | by imapb010.mykolab.com (Postfix) with ESMTPS id A9D23150D1CA9 | ||
8 | for <christian@mailqueue.ch>; Thu, 17 Aug 2017 18:40:51 +0200 (CEST) | ||
9 | Received: from mx.kolabnow.com (unknown [10.9.4.1]) | ||
10 | by int-mx001.mykolab.com (Postfix) with ESMTPS id 8FACC185 | ||
11 | for <christian@mailqueue.ch>; Thu, 17 Aug 2017 18:40:51 +0200 (CEST) | ||
12 | X-Virus-Scanned: amavisd-new at mykolab.com | ||
13 | Authentication-Results: ext-mx-in001.mykolab.com (amavisd-new); | ||
14 | dkim=pass (1024-bit key) header.d=kde.org | ||
15 | X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 | ||
16 | Received: from forward1-smtp.messagingengine.com (forward1-smtp.messagingengine.com [66.111.4.223]) | ||
17 | by ext-mx-in001.mykolab.com (Postfix) with ESMTPS id 1B005169D | ||
18 | for <christian@mailqueue.ch>; Thu, 17 Aug 2017 18:20:40 +0200 (CEST) | ||
19 | Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) | ||
20 | by mailforward.nyi.internal (Postfix) with ESMTP id B9C0FFD6 | ||
21 | for <christian@mailqueue.ch>; Thu, 17 Aug 2017 12:20:39 -0400 (EDT) | ||
22 | Received: by mailredirect.nyi.internal (Postfix, from userid 501) | ||
23 | id A9EF58E9B6; Thu, 17 Aug 2017 12:20:39 -0400 (EDT) | ||
24 | Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) | ||
25 | by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; | ||
26 | Thu, 17 Aug 2017 12:20:39 -0400 | ||
27 | X-Cyrus-Session-Id: sloti36d2t28-3239059-1502986839-5-11465270081887081630 | ||
28 | X-Sieve: CMU Sieve 3.0 | ||
29 | X-Spam-known-sender: yes ("Address thomas.pfeiffer@kde.org in From header is in addressbook"); | ||
30 | in-addressbook | ||
31 | X-Orig-Spam-score: 0.0 | ||
32 | X-Spam-hits: BAYES_00 -1.9, HTML_MESSAGE 0.001, RCVD_IN_DNSWL_MED -2.3, | ||
33 | RCVD_IN_SORBS_SPAM 0.5, RP_MATCHES_RCVD -0.001, SPF_PASS -0.001, | ||
34 | LANGUAGES en, BAYES_USED global, SA_VERSION 3.4.0 | ||
35 | X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='org', | ||
36 | MailFrom='org' | ||
37 | X-Spam-charsets: plain='utf-8', html='utf-8' | ||
38 | X-Resolved-to: chrigi_1@fastmail.fm | ||
39 | X-Delivered-to: chrigi_1@fastmail.fm | ||
40 | X-Mail-from: kde-community-bounces@kde.org | ||
41 | Received: from mx3 ([10.202.2.202]) | ||
42 | by compute1.internal (LMTPProxy); Thu, 17 Aug 2017 12:20:39 -0400 | ||
43 | Authentication-Results: mx3.messagingengine.com; | ||
44 | dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=iaOusBVL; | ||
45 | dmarc=none (p=none;has-list-id=yes) header.from=kde.org; | ||
46 | spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org; | ||
47 | x-google-dkim=pass (2048-bit rsa key) header.d=1e100.net header.i=@1e100.net header.b=J3ZGQfFP | ||
48 | Received-SPF: pass | ||
49 | (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) | ||
50 | receiver=mx3.messagingengine.com; | ||
51 | identity=mailfrom; | ||
52 | envelope-from="kde-community-bounces@kde.org"; | ||
53 | helo=postbox.kde.org; | ||
54 | client-ip=46.4.96.248 | ||
55 | Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) | ||
56 | (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) | ||
57 | (No client certificate requested) | ||
58 | by mx3.messagingengine.com (Postfix) with ESMTPS | ||
59 | for <chrigi_1@fastmail.fm>; Thu, 17 Aug 2017 12:20:38 -0400 (EDT) | ||
60 | DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; | ||
61 | t=1502986836; bh=NN9eLPZMdRJe0stu0TDb+ROhjuNPhd/mDnhblsQ4F04=; | ||
62 | h=From:Subject:Date:References:To:In-Reply-To:Reply-To:List-Id: | ||
63 | List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: | ||
64 | From; | ||
65 | b=iaOusBVLSdEJElb2uoxf5ubKrt5iXH5zKZqAsGo/Ltor16eJ57YIP6QGSNn+L7fCO | ||
66 | QHgR+fL1/OCWmfEs80xz7ycwjVTdHSt8a9nP7EwwLfQFJ3b1bCs8hNFyLpwrlzH87p | ||
67 | 6I1z36M4x53j3Yq7OU5DIWw7TieU2TaHCCClC1Cg= | ||
68 | X-Original-To: kde-community@kde.org | ||
69 | X-Remote-Delivered-To: kde-community@localhost.kde.org | ||
70 | Received-SPF: Pass (sender SPF authorized) identity=mailfrom; | ||
71 | client-ip=209.85.128.181; helo=mail-wr0-f181.google.com; | ||
72 | envelope-from=t.pfeiffer.ux@gmail.com; receiver=kde-community@kde.org | ||
73 | Received: from mail-wr0-f181.google.com (mail-wr0-f181.google.com | ||
74 | [209.85.128.181]) | ||
75 | by postbox.kde.org (Postfix) with ESMTPS id A2098A0194 | ||
76 | for <kde-community@kde.org>; Thu, 17 Aug 2017 16:20:19 +0000 (UTC) | ||
77 | Received: by mail-wr0-f181.google.com with SMTP id f8so3729162wrf.3 | ||
78 | for <kde-community@kde.org>; Thu, 17 Aug 2017 09:20:19 -0700 (PDT) | ||
79 | X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; | ||
80 | d=1e100.net; s=20161025; | ||
81 | h=x-gm-message-state:from:mime-version:subject:date:references:to | ||
82 | :in-reply-to:message-id; | ||
83 | bh=wicjkfxhAhrD+Lja6y+RkFl7BL7WSAOVLHUYZTaQM+E=; | ||
84 | b=J3ZGQfFPOcZSNOlqbFSZ/oBBPQSnoMN2pIBb5YlfFBYeCY2Rt6Xx0X0S/wET6IAcE6 | ||
85 | ZILrUjwPh9q3Bjhx0x+CAGscD/sNJBosuBoVrE1ZFX2d8prqRz9D8fNeeCtuPnRgkDmm | ||
86 | EBW3JP5ifajIMbUnHPevV1W8er5VY1uqWW/z6lZu7iH1zabPs+5wS+X0M1xx71xBxTb1 | ||
87 | Dx4jpLO/SRNSEIKZ0q1l0p6f9/9P9VScWbyDw7NeI1yj0GfRhNSP64dlQU3Z07vqaoKP | ||
88 | vfhpG0gFX/FEr0+MPz2r10v6LP1iACBlhOHwHZxYLTz/mNwvHvsLB6JWFoZ0FuwLRQFN | ||
89 | X47g== | ||
90 | X-Gm-Message-State: AHYfb5hGX37YHJwSkL5Gin7U/eRe+E5RLYqxnYErKBibvkrRhrJDArNX | ||
91 | VyIneA7/u3wUDC0Wvl8= | ||
92 | X-Received: by 10.223.176.5 with SMTP id f5mr3522751wra.194.1502986818721; | ||
93 | Thu, 17 Aug 2017 09:20:18 -0700 (PDT) | ||
94 | Received: from [172.16.5.187] ([109.109.206.114]) | ||
95 | by smtp.gmail.com with ESMTPSA id 5sm4544042wre.5.2017.08.17.09.20.17 | ||
96 | for <kde-community@kde.org> | ||
97 | (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); | ||
98 | Thu, 17 Aug 2017 09:20:17 -0700 (PDT) | ||
99 | From: Thomas Pfeiffer <thomas.pfeiffer@kde.org> | ||
100 | Content-Type: multipart/alternative; | ||
101 | boundary="Apple-Mail=_AF2C4455-1CF7-489B-98CD-6BFD8687BF81" | ||
102 | Mime-Version: 1.0 (Mac OS X Mail 10.3 \(3273\)) | ||
103 | Subject: Re: Telemetry Policy | ||
104 | Date: Thu, 17 Aug 2017 18:20:16 +0200 | ||
105 | References: <2048912.XfIJe3ZSdj@vkpc5> <2990543.KVDkBByYO0@minixfox> | ||
106 | <CACpu024EH1OeDqwL94QK33eq4sCGjKjwedcQDR_PWjprBevzfg@mail.gmail.com> | ||
107 | <5231282.Ch11jfsTMl@lenovo> <B95D7D2A-23A9-4245-AAC0-8A3FAE330090@kde.org> | ||
108 | To: informing about and discussing non-technical community topics | ||
109 | <kde-community@kde.org> | ||
110 | In-Reply-To: <B95D7D2A-23A9-4245-AAC0-8A3FAE330090@kde.org> | ||
111 | Message-Id: <5A696707-744C-4035-A8FA-CA83EE8691D6@kde.org> | ||
112 | X-Mailer: Apple Mail (2.3273) | ||
113 | X-BeenThere: kde-community@kde.org | ||
114 | X-Mailman-Version: 2.1.16 | ||
115 | Precedence: list | ||
116 | Reply-To: informing about and discussing non-technical community topics | ||
117 | <kde-community@kde.org> | ||
118 | List-Id: informing about and discussing non-technical community topics | ||
119 | <kde-community.kde.org> | ||
120 | List-Unsubscribe: <https://mail.kde.org/mailman/options/kde-community>, | ||
121 | <mailto:kde-community-request@kde.org?subject=unsubscribe> | ||
122 | List-Archive: <http://mail.kde.org/pipermail/kde-community/> | ||
123 | List-Post: <mailto:kde-community@kde.org> | ||
124 | List-Help: <mailto:kde-community-request@kde.org?subject=help> | ||
125 | List-Subscribe: <https://mail.kde.org/mailman/listinfo/kde-community>, | ||
126 | <mailto:kde-community-request@kde.org?subject=subscribe> | ||
127 | Errors-To: kde-community-bounces@kde.org | ||
128 | Sender: "kde-community" <kde-community-bounces@kde.org> | ||
129 | |||
130 | |||
131 | --Apple-Mail=_AF2C4455-1CF7-489B-98CD-6BFD8687BF81 | ||
132 | Content-Transfer-Encoding: quoted-printable | ||
133 | Content-Type: text/plain; | ||
134 | charset=utf-8 | ||
135 | |||
136 | |||
137 | > On 17. Aug 2017, at 17:38, Mirko Boehm - KDE <mirko@kde.org> wrote: | ||
138 | >=20 | ||
139 | > Hi,=20 | ||
140 | >=20 | ||
141 | >> On 17. Aug 2017, at 01:46, Thomas Pfeiffer <thomas.pfeiffer@kde.org = | ||
142 | <mailto:thomas.pfeiffer@kde.org>> wrote: | ||
143 | >>=20 | ||
144 | >> Hi Valorie, | ||
145 | >> Even if opt-out for some data is legally and even morally fine, it = | ||
146 | does not=20 | ||
147 | >> align with the values we communicate to our users: | ||
148 | >> Unlike Mozilla's Mission, our Vision mentions privacy explicitly, and = | ||
149 | we're=20 | ||
150 | >> striving to make privacy our USP. | ||
151 | >=20 | ||
152 | > We seem to assume a contradiction between telemetry and privacy. I = | ||
153 | believe this is a knee-jerk reaction. We can implement telemetry in a = | ||
154 | way that privacy is not violated. In fact, I would say that it follows = | ||
155 | from our vision that we should do this. | ||
156 | >=20 | ||
157 | |||
158 | The problem is: I expect users to have the same knee-jerk reaction. I = | ||
159 | don=E2=80=99t see us being able to explain to users that actually their = | ||
160 | privacy is perfectly safe before they freak out. | ||
161 | Privacy-minded Free Software users have freaked out in the past over = | ||
162 | things which objectively speaking were not a huge deal. | ||
163 | It=E2=80=99s emotion more than rational arguments | ||
164 | |||
165 | |||
166 | --Apple-Mail=_AF2C4455-1CF7-489B-98CD-6BFD8687BF81 | ||
167 | Content-Transfer-Encoding: quoted-printable | ||
168 | Content-Type: text/html; | ||
169 | charset=utf-8 | ||
170 | |||
171 | <html><head><meta http-equiv=3D"Content-Type" content=3D"text/html = | ||
172 | charset=3Dutf-8"></head><body style=3D"word-wrap: break-word; = | ||
173 | -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" = | ||
174 | class=3D""><br class=3D""><div><blockquote type=3D"cite" class=3D""><div = | ||
175 | class=3D"">On 17. Aug 2017, at 17:38, Mirko Boehm - KDE <<a = | ||
176 | href=3D"mailto:mirko@kde.org" class=3D"">mirko@kde.org</a>> = | ||
177 | wrote:</div><br class=3D"Apple-interchange-newline"><div class=3D""><meta = | ||
178 | http-equiv=3D"Content-Type" content=3D"text/html charset=3Dus-ascii" = | ||
179 | class=3D""><div style=3D"word-wrap: break-word; -webkit-nbsp-mode: = | ||
180 | space; -webkit-line-break: after-white-space;" class=3D"">Hi, <div = | ||
181 | class=3D""><br class=3D""><div class=3D""><blockquote type=3D"cite" = | ||
182 | class=3D""><div class=3D"">On 17. Aug 2017, at 01:46, Thomas Pfeiffer = | ||
183 | <<a href=3D"mailto:thomas.pfeiffer@kde.org" = | ||
184 | class=3D"">thomas.pfeiffer@kde.org</a>> wrote:</div><br = | ||
185 | class=3D"Apple-interchange-newline"><div class=3D""><span = | ||
186 | style=3D"font-family: Menlo-Regular; font-size: 11px; font-style: = | ||
187 | normal; font-variant-caps: normal; font-weight: normal; letter-spacing: = | ||
188 | normal; text-align: start; text-indent: 0px; text-transform: none; = | ||
189 | white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; = | ||
190 | float: none; display: inline !important;" class=3D"">Hi = | ||
191 | Valorie,</span><br style=3D"font-family: Menlo-Regular; font-size: 11px; = | ||
192 | font-style: normal; font-variant-caps: normal; font-weight: normal; = | ||
193 | letter-spacing: normal; text-align: start; text-indent: 0px; = | ||
194 | text-transform: none; white-space: normal; word-spacing: 0px; = | ||
195 | -webkit-text-stroke-width: 0px;" class=3D""><span style=3D"font-family: = | ||
196 | Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: = | ||
197 | normal; font-weight: normal; letter-spacing: normal; text-align: start; = | ||
198 | text-indent: 0px; text-transform: none; white-space: normal; = | ||
199 | word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: = | ||
200 | inline !important;" class=3D"">Even if opt-out for some data is legally = | ||
201 | and even morally fine, it does not<span = | ||
202 | class=3D"Apple-converted-space"> </span></span><br = | ||
203 | style=3D"font-family: Menlo-Regular; font-size: 11px; font-style: = | ||
204 | normal; font-variant-caps: normal; font-weight: normal; letter-spacing: = | ||
205 | normal; text-align: start; text-indent: 0px; text-transform: none; = | ||
206 | white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" = | ||
207 | class=3D""><span style=3D"font-family: Menlo-Regular; font-size: 11px; = | ||
208 | font-style: normal; font-variant-caps: normal; font-weight: normal; = | ||
209 | letter-spacing: normal; text-align: start; text-indent: 0px; = | ||
210 | text-transform: none; white-space: normal; word-spacing: 0px; = | ||
211 | -webkit-text-stroke-width: 0px; float: none; display: inline = | ||
212 | !important;" class=3D"">align with the values we communicate to our = | ||
213 | users:</span><br style=3D"font-family: Menlo-Regular; font-size: 11px; = | ||
214 | font-style: normal; font-variant-caps: normal; font-weight: normal; = | ||
215 | letter-spacing: normal; text-align: start; text-indent: 0px; = | ||
216 | text-transform: none; white-space: normal; word-spacing: 0px; = | ||
217 | -webkit-text-stroke-width: 0px;" class=3D""><span style=3D"font-family: = | ||
218 | Menlo-Regular; font-size: 11px; font-style: normal; font-variant-caps: = | ||
219 | normal; font-weight: normal; letter-spacing: normal; text-align: start; = | ||
220 | text-indent: 0px; text-transform: none; white-space: normal; = | ||
221 | word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: = | ||
222 | inline !important;" class=3D"">Unlike Mozilla's Mission, our Vision = | ||
223 | mentions privacy explicitly, and we're<span = | ||
224 | class=3D"Apple-converted-space"> </span></span><br = | ||
225 | style=3D"font-family: Menlo-Regular; font-size: 11px; font-style: = | ||
226 | normal; font-variant-caps: normal; font-weight: normal; letter-spacing: = | ||
227 | normal; text-align: start; text-indent: 0px; text-transform: none; = | ||
228 | white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" = | ||
229 | class=3D""><span style=3D"font-family: Menlo-Regular; font-size: 11px; = | ||
230 | font-style: normal; font-variant-caps: normal; font-weight: normal; = | ||
231 | letter-spacing: normal; text-align: start; text-indent: 0px; = | ||
232 | text-transform: none; white-space: normal; word-spacing: 0px; = | ||
233 | -webkit-text-stroke-width: 0px; float: none; display: inline = | ||
234 | !important;" class=3D"">striving to make privacy our USP.</span><br = | ||
235 | style=3D"font-family: Menlo-Regular; font-size: 11px; font-style: = | ||
236 | normal; font-variant-caps: normal; font-weight: normal; letter-spacing: = | ||
237 | normal; text-align: start; text-indent: 0px; text-transform: none; = | ||
238 | white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" = | ||
239 | class=3D""></div></blockquote><br class=3D""></div><div class=3D"">We = | ||
240 | seem to assume a contradiction between telemetry and privacy. I believe = | ||
241 | this is a knee-jerk reaction. We can implement telemetry in a way that = | ||
242 | privacy is not violated. In fact, I would say that it follows from our = | ||
243 | vision that we should do this.</div><div class=3D""><br = | ||
244 | class=3D""></div></div></div></div></blockquote><div><br = | ||
245 | class=3D""></div>The problem is: I expect users to have the same = | ||
246 | knee-jerk reaction. I don=E2=80=99t see us being able to explain to = | ||
247 | users that actually their privacy is perfectly safe before they freak = | ||
248 | out.</div><div>Privacy-minded Free Software users have freaked out in = | ||
249 | the past over things which objectively speaking were not a huge = | ||
250 | deal.</div><div>It=E2=80=99s emotion more than rational = | ||
251 | arguments</div><br class=3D""></body></html>= | ||
252 | |||
253 | --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 @@ | |||
1 | Return-Path: <kde-community-bounces@kde.org> | ||
2 | Received: from imapb010.mykolab.com ([unix socket]) | ||
3 | by imapb010.mykolab.com (Cyrus 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14) with LMTPA; | ||
4 | Thu, 17 Aug 2017 18:30:41 +0200 | ||
5 | X-Sieve: CMU Sieve 2.4 | ||
6 | Received: from int-mx001.mykolab.com (unknown [10.9.13.1]) | ||
7 | by imapb010.mykolab.com (Postfix) with ESMTPS id 92811150C3DE0 | ||
8 | for <christian@mailqueue.ch>; Thu, 17 Aug 2017 18:30:41 +0200 (CEST) | ||
9 | Received: from mx.kolabnow.com (unknown [10.9.4.3]) | ||
10 | by int-mx001.mykolab.com (Postfix) with ESMTPS id 7973B11D | ||
11 | for <christian@mailqueue.ch>; Thu, 17 Aug 2017 18:30:41 +0200 (CEST) | ||
12 | X-Virus-Scanned: amavisd-new at mykolab.com | ||
13 | Authentication-Results: ext-mx-in003.mykolab.com (amavisd-new); | ||
14 | dkim=pass (1024-bit key) header.d=kde.org header.b=q4j4OOKP; | ||
15 | dkim=fail (2048-bit key) reason="fail (message has been altered)" | ||
16 | header.d=gmail.com header.b=DJRXq7Se | ||
17 | X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 | ||
18 | Received: from forward1-smtp.messagingengine.com (forward1-smtp.messagingengine.com [66.111.4.223]) | ||
19 | by ext-mx-in003.mykolab.com (Postfix) with ESMTPS id 3E01E292D | ||
20 | for <christian@mailqueue.ch>; Thu, 17 Aug 2017 18:30:29 +0200 (CEST) | ||
21 | Received: from mailredirect.nyi.internal (imap36.nyi.internal [10.202.2.86]) | ||
22 | by mailforward.nyi.internal (Postfix) with ESMTP id 89BC31A23 | ||
23 | for <christian@mailqueue.ch>; Thu, 17 Aug 2017 12:30:28 -0400 (EDT) | ||
24 | Received: by mailredirect.nyi.internal (Postfix, from userid 501) | ||
25 | id 6EC348E9B6; Thu, 17 Aug 2017 12:30:28 -0400 (EDT) | ||
26 | Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) | ||
27 | by sloti36d2t28 (Cyrus fastmail-fmjessie44745-15358-git-fastmail-15358) with LMTPA; | ||
28 | Thu, 17 Aug 2017 12:30:28 -0400 | ||
29 | X-Cyrus-Session-Id: sloti36d2t28-3239059-1502987428-2-12164706007640762698 | ||
30 | X-Sieve: CMU Sieve 3.0 | ||
31 | X-Spam-known-sender: no | ||
32 | X-Orig-Spam-score: 0.0 | ||
33 | X-Spam-hits: BAYES_00 -1.9, HTML_MESSAGE 0.001, RCVD_IN_DNSWL_MED -2.3, | ||
34 | RP_MATCHES_RCVD -0.001, SPF_PASS -0.001, LANGUAGES en, BAYES_USED global, | ||
35 | SA_VERSION 3.4.0 | ||
36 | X-Spam-source: IP='46.4.96.248', Host='postbox.kde.org', Country='DE', FromHeader='org', | ||
37 | MailFrom='org' | ||
38 | X-Spam-charsets: plain='UTF-8', html='UTF-8' | ||
39 | X-Resolved-to: chrigi_1@fastmail.fm | ||
40 | X-Delivered-to: chrigi_1@fastmail.fm | ||
41 | X-Mail-from: kde-community-bounces@kde.org | ||
42 | Received: from mx1 ([10.202.2.200]) | ||
43 | by compute1.internal (LMTPProxy); Thu, 17 Aug 2017 12:30:28 -0400 | ||
44 | Authentication-Results: mx1.messagingengine.com; | ||
45 | dkim=fail (message has been altered; 2048-bit rsa key sha256) header.d=gmail.com header.i=@gmail.com header.b=DJRXq7Se; | ||
46 | dkim=pass (1024-bit rsa key sha256) header.d=kde.org header.i=@kde.org header.b=q4j4OOKP; | ||
47 | dmarc=none (p=none;has-list-id=yes) header.from=kde.org; | ||
48 | spf=pass smtp.mailfrom=kde-community-bounces@kde.org smtp.helo=postbox.kde.org; | ||
49 | x-google-dkim=fail (message has been altered; 2048-bit rsa key) header.d=1e100.net header.i=@1e100.net header.b=U7Pdj/LB | ||
50 | Received-SPF: pass | ||
51 | (kde.org: 46.4.96.248 is authorized to use 'kde-community-bounces@kde.org' in 'mfrom' identity (mechanism 'mx' matched)) | ||
52 | receiver=mx1.messagingengine.com; | ||
53 | identity=mailfrom; | ||
54 | envelope-from="kde-community-bounces@kde.org"; | ||
55 | helo=postbox.kde.org; | ||
56 | client-ip=46.4.96.248 | ||
57 | Received: from postbox.kde.org (postbox.kde.org [46.4.96.248]) | ||
58 | (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) | ||
59 | (No client certificate requested) | ||
60 | by mx1.messagingengine.com (Postfix) with ESMTPS | ||
61 | for <chrigi_1@fastmail.fm>; Thu, 17 Aug 2017 12:30:27 -0400 (EDT) | ||
62 | DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=kde.org; s=default; | ||
63 | t=1502987424; bh=P5C3gzzCdP/NQgV0POjgD3g9Hpun4leANxLktFzWpbo=; | ||
64 | h=In-Reply-To:References:From:Date:Subject:To:Reply-To:List-Id: | ||
65 | List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: | ||
66 | From; | ||
67 | b=q4j4OOKPbM6MLGfTlM1WlnmVrh2PfQSKPYcLEoHUjBwoiu+oacbJb5cxmPkadvddx | ||
68 | MIYmJyog8F4NCNZCIi5vzNkit8vaUJgHws3pk+0uIFo9SdOBkFBfTXSGsDBWB2AdL5 | ||
69 | wryEwxZKOqEDcECpTNEEmQykU3MYwLBw7sD+KJjY= | ||
70 | X-Original-To: kde-community@kde.org | ||
71 | X-Remote-Delivered-To: kde-community@localhost.kde.org | ||
72 | Received-SPF: Pass (sender SPF authorized) identity=mailfrom; | ||
73 | client-ip=2607:f8b0:4003:c06::232; helo=mail-oi0-x232.google.com; | ||
74 | envelope-from=kexipl@gmail.com; receiver=kde-community@kde.org | ||
75 | Authentication-Results: postbox.kde.org; dkim=pass | ||
76 | reason="2048-bit key; unprotected key" | ||
77 | header.d=gmail.com header.i=@gmail.com header.b=DJRXq7Se; | ||
78 | dkim-adsp=pass; dkim-atps=neutral | ||
79 | Received: from mail-oi0-x232.google.com (mail-oi0-x232.google.com | ||
80 | [IPv6:2607:f8b0:4003:c06::232]) | ||
81 | by postbox.kde.org (Postfix) with ESMTPS id A4F67A014D | ||
82 | for <kde-community@kde.org>; Thu, 17 Aug 2017 16:30:09 +0000 (UTC) | ||
83 | Received: by mail-oi0-x232.google.com with SMTP id f11so71799456oic.0 | ||
84 | for <kde-community@kde.org>; Thu, 17 Aug 2017 09:30:09 -0700 (PDT) | ||
85 | DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; | ||
86 | h=mime-version:sender:in-reply-to:references:from:date:message-id | ||
87 | :subject:to; bh=P5C3gzzCdP/NQgV0POjgD3g9Hpun4leANxLktFzWpbo=; | ||
88 | b=DJRXq7SewhEpbavrA6kFk0TPbF9526gl1WpH2O4R7hpuM5tJVqLoT4b53UfmZyGeDw | ||
89 | pSdW599ZTY3WLsK29IZ5buua1TgJeSLgN+PWKfTJAFW7qAZaJo6pRIpqSgETEEk/BdMc | ||
90 | KtqYdBD/IkwUVx5LAuQikyNn1HrKbti/tbc/YiI23f5TRxfIQZb7DOvOaAi1bZO8jEFq | ||
91 | 5EHEVcrjvIR2S4HHWxen9rZvGIotVN3womdK8b0t+Wx+Kt0qv06px9jNF0mTqLKhCJAz | ||
92 | los9Tpv/7RI0JiQyfPzl7kMQjU3i/pyA1u6b6t69ALfUQcjv25NcwhSaQbWIi9DN8rLg | ||
93 | Lc7g== | ||
94 | X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; | ||
95 | d=1e100.net; s=20161025; | ||
96 | h=x-gm-message-state:mime-version:sender:in-reply-to:references:from | ||
97 | :date:message-id:subject:to; | ||
98 | bh=P5C3gzzCdP/NQgV0POjgD3g9Hpun4leANxLktFzWpbo=; | ||
99 | b=U7Pdj/LBlwGbtXVpnpJudVk938b0fKTIRhK+Lc9IfB9zZhXh3FGwX5kWSUObEOT3hX | ||
100 | BXRk0cWvJYHpuGUnLXx/Wjen3j6283GHvDvPhfagyTZbGJohkRMEkxLwFh4ZsJ87M71t | ||
101 | pqLLayDjqDHj5jVuko5TDPTtRL8mjzPM7r0DQKu1GYkYtiNLE5JlGR9OsqK8ZH78Wkf8 | ||
102 | PWUT2BD+mkOE03gFEYpTA0oQW1iwv+wN5xySzaUOlBVfxUUx69EOLnFuRthkQHXcnlGG | ||
103 | rchW44D/eiSVU7JWK1Tk2IKNK+ERiq2/zftSmKRzpbwfv6D8De0PZOJPyi89kS9t2I2L | ||
104 | ar9g== | ||
105 | X-Gm-Message-State: AHYfb5g28N+JHV5G6R5j0X0hpMFpCnu/TuLNw/idrsMKyvGOUXdbQiIn | ||
106 | whIAqO9js0sL5H92k3yqqJIGhuicWA== | ||
107 | X-Received: by 10.202.108.130 with SMTP id h124mr8149045oic.289.1502987407944; | ||
108 | Thu, 17 Aug 2017 09:30:07 -0700 (PDT) | ||
109 | MIME-Version: 1.0 | ||
110 | Received: by 10.182.45.227 with HTTP; Thu, 17 Aug 2017 09:29:27 -0700 (PDT) | ||
111 | In-Reply-To: <5A696707-744C-4035-A8FA-CA83EE8691D6@kde.org> | ||
112 | References: <2048912.XfIJe3ZSdj@vkpc5> <2990543.KVDkBByYO0@minixfox> | ||
113 | <CACpu024EH1OeDqwL94QK33eq4sCGjKjwedcQDR_PWjprBevzfg@mail.gmail.com> | ||
114 | <5231282.Ch11jfsTMl@lenovo> <B95D7D2A-23A9-4245-AAC0-8A3FAE330090@kde.org> | ||
115 | <5A696707-744C-4035-A8FA-CA83EE8691D6@kde.org> | ||
116 | From: Jaroslaw Staniek <staniek@kde.org> | ||
117 | Date: Thu, 17 Aug 2017 18:29:27 +0200 | ||
118 | X-Google-Sender-Auth: LxL4QEJfN3UTITM2I0VbgyX7420 | ||
119 | Message-ID: <CAOj7QQ0WsTCfu9hoq+DTKMGTW=+KObo7HG2_YU1QZ6eOGwQbAQ@mail.gmail.com> | ||
120 | Subject: Re: Telemetry Policy | ||
121 | To: informing about and discussing non-technical community topics | ||
122 | <kde-community@kde.org> | ||
123 | Content-Type: multipart/alternative; boundary="001a1142e7548d73010556f58604" | ||
124 | X-BeenThere: kde-community@kde.org | ||
125 | X-Mailman-Version: 2.1.16 | ||
126 | Precedence: list | ||
127 | Reply-To: informing about and discussing non-technical community topics | ||
128 | <kde-community@kde.org> | ||
129 | List-Id: informing about and discussing non-technical community topics | ||
130 | <kde-community.kde.org> | ||
131 | List-Unsubscribe: <https://mail.kde.org/mailman/options/kde-community>, | ||
132 | <mailto:kde-community-request@kde.org?subject=unsubscribe> | ||
133 | List-Archive: <http://mail.kde.org/pipermail/kde-community/> | ||
134 | List-Post: <mailto:kde-community@kde.org> | ||
135 | List-Help: <mailto:kde-community-request@kde.org?subject=help> | ||
136 | List-Subscribe: <https://mail.kde.org/mailman/listinfo/kde-community>, | ||
137 | <mailto:kde-community-request@kde.org?subject=subscribe> | ||
138 | Errors-To: kde-community-bounces@kde.org | ||
139 | Sender: "kde-community" <kde-community-bounces@kde.org> | ||
140 | |||
141 | --001a1142e7548d73010556f58604 | ||
142 | Content-Type: text/plain; charset="UTF-8" | ||
143 | Content-Transfer-Encoding: quoted-printable | ||
144 | |||
145 | On 17 August 2017 at 18:20, Thomas Pfeiffer <thomas.pfeiffer@kde.org> wrote= | ||
146 | : | ||
147 | |||
148 | > | ||
149 | > On 17. Aug 2017, at 17:38, Mirko Boehm - KDE <mirko@kde.org> wrote: | ||
150 | > | ||
151 | > Hi, | ||
152 | > | ||
153 | > On 17. Aug 2017, at 01:46, Thomas Pfeiffer <thomas.pfeiffer@kde.org> | ||
154 | > wrote: | ||
155 | > | ||
156 | > Hi Valorie, | ||
157 | > Even if opt-out for some data is legally and even morally fine, it does n= | ||
158 | ot | ||
159 | > | ||
160 | > align with the values we communicate to our users: | ||
161 | > Unlike Mozilla's Mission, our Vision mentions privacy explicitly, and we'= | ||
162 | re | ||
163 | > | ||
164 | > striving to make privacy our USP. | ||
165 | > | ||
166 | > | ||
167 | > We seem to assume a contradiction between telemetry and privacy. I believ= | ||
168 | e | ||
169 | > this is a knee-jerk reaction. We can implement telemetry in a way that | ||
170 | > privacy is not violated. In fact, I would say that it follows from our | ||
171 | > vision that we should do this. | ||
172 | > | ||
173 | > | ||
174 | > The problem is: I expect users to have the same knee-jerk reaction. I | ||
175 | > don=E2=80=99t see us being able to explain to users that actually their p= | ||
176 | rivacy is | ||
177 | > perfectly safe before they freak out. | ||
178 | > Privacy-minded Free Software users have freaked out in the past over | ||
179 | > things which objectively speaking were not a huge deal. | ||
180 | > It=E2=80=99s emotion more than rational arguments | ||
181 | > | ||
182 | > | ||
183 | =E2=80=8BIt's hard to argue here or generalize to all app's communities. Kr= | ||
184 | ita | ||
185 | community for example is different than gcc community in these aspects. | ||
186 | |||
187 | --=20 | ||
188 | regards, Jaroslaw Staniek | ||
189 | |||
190 | KDE: | ||
191 | : A world-wide network of software engineers, artists, writers, translators | ||
192 | : and facilitators committed to Free Software development - http://kde.org | ||
193 | Calligra Suite: | ||
194 | : A graphic art and office suite - http://calligra.org | ||
195 | Kexi: | ||
196 | : A visual database apps builder - http://calligra.org/kexi | ||
197 | Qt Certified Specialist: | ||
198 | : http://www.linkedin.com/in/jstaniek | ||
199 | |||
200 | --001a1142e7548d73010556f58604 | ||
201 | Content-Type: text/html; charset="UTF-8" | ||
202 | Content-Transfer-Encoding: quoted-printable | ||
203 | |||
204 | <div dir=3D"ltr"><div class=3D"gmail_default" style=3D"font-family:monospac= | ||
205 | e,monospace;font-size:small"><br></div><div class=3D"gmail_extra"><br><div = | ||
206 | class=3D"gmail_quote">On 17 August 2017 at 18:20, Thomas Pfeiffer <span dir= | ||
207 | =3D"ltr"><<a href=3D"mailto:thomas.pfeiffer@kde.org" target=3D"_blank">t= | ||
208 | homas.pfeiffer@kde.org</a>></span> wrote:<br><blockquote class=3D"gmail_= | ||
209 | quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1= | ||
210 | ex"><div style=3D"word-wrap:break-word"><br><div><span class=3D""><blockquo= | ||
211 | te type=3D"cite"><div>On 17. Aug 2017, at 17:38, Mirko Boehm - KDE <<a h= | ||
212 | ref=3D"mailto:mirko@kde.org" target=3D"_blank">mirko@kde.org</a>> wrote:= | ||
213 | </div><br class=3D"m_-9083494930210199564Apple-interchange-newline"><div><d= | ||
214 | iv style=3D"word-wrap:break-word">Hi,=C2=A0<div><br><div><blockquote type= | ||
215 | =3D"cite"><div>On 17. Aug 2017, at 01:46, Thomas Pfeiffer <<a href=3D"ma= | ||
216 | ilto:thomas.pfeiffer@kde.org" target=3D"_blank">thomas.pfeiffer@kde.org</a>= | ||
217 | > wrote:</div><br class=3D"m_-9083494930210199564Apple-interchange-newli= | ||
218 | ne"><div><span style=3D"font-family:Menlo-Regular;font-size:11px;font-style= | ||
219 | :normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;t= | ||
220 | ext-align:start;text-indent:0px;text-transform:none;white-space:normal;word= | ||
221 | -spacing:0px;float:none;display:inline!important">Hi Valorie,</span><br sty= | ||
222 | le=3D"font-family:Menlo-Regular;font-size:11px;font-style:normal;font-varia= | ||
223 | nt-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;te= | ||
224 | xt-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><spa= | ||
225 | n style=3D"font-family:Menlo-Regular;font-size:11px;font-style:normal;font-= | ||
226 | variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:sta= | ||
227 | rt;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;= | ||
228 | float:none;display:inline!important">Even if opt-out for some data is legal= | ||
229 | ly and even morally fine, it does not<span class=3D"m_-9083494930210199564A= | ||
230 | pple-converted-space">=C2=A0</span></span><br style=3D"font-family:Menlo-Re= | ||
231 | gular;font-size:11px;font-style:normal;font-variant-caps:normal;font-weight= | ||
232 | :normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transfo= | ||
233 | rm:none;white-space:normal;word-spacing:0px"><span style=3D"font-family:Men= | ||
234 | lo-Regular;font-size:11px;font-style:normal;font-variant-caps:normal;font-w= | ||
235 | eight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-tr= | ||
236 | ansform:none;white-space:normal;word-spacing:0px;float:none;display:inline!= | ||
237 | important">align with the values we communicate to our users:</span><br sty= | ||
238 | le=3D"font-family:Menlo-Regular;font-size:11px;font-style:normal;font-varia= | ||
239 | nt-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;te= | ||
240 | xt-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><spa= | ||
241 | n style=3D"font-family:Menlo-Regular;font-size:11px;font-style:normal;font-= | ||
242 | variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:sta= | ||
243 | rt;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;= | ||
244 | float:none;display:inline!important">Unlike Mozilla's Mission, our Visi= | ||
245 | on mentions privacy explicitly, and we're<span class=3D"m_-908349493021= | ||
246 | 0199564Apple-converted-space">=C2=A0</span></span><br style=3D"font-family:= | ||
247 | Menlo-Regular;font-size:11px;font-style:normal;font-variant-caps:normal;fon= | ||
248 | t-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text= | ||
249 | -transform:none;white-space:normal;word-spacing:0px"><span style=3D"font-fa= | ||
250 | mily:Menlo-Regular;font-size:11px;font-style:normal;font-variant-caps:norma= | ||
251 | l;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px= | ||
252 | ;text-transform:none;white-space:normal;word-spacing:0px;float:none;display= | ||
253 | :inline!important">striving to make privacy our USP.</span><br style=3D"fon= | ||
254 | t-family:Menlo-Regular;font-size:11px;font-style:normal;font-variant-caps:n= | ||
255 | ormal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent= | ||
256 | :0px;text-transform:none;white-space:normal;word-spacing:0px"></div></block= | ||
257 | quote><br></div><div>We seem to assume a contradiction between telemetry an= | ||
258 | d privacy. I believe this is a knee-jerk reaction. We can implement telemet= | ||
259 | ry in a way that privacy is not violated. In fact, I would say that it foll= | ||
260 | ows from our vision that we should do this.</div><div><br></div></div></div= | ||
261 | ></div></blockquote><div><br></div></span>The problem is: I expect users to= | ||
262 | have the same knee-jerk reaction. I don=E2=80=99t see us being able to exp= | ||
263 | lain to users that actually their privacy is perfectly safe before they fre= | ||
264 | ak out.</div><div>Privacy-minded Free Software users have freaked out in th= | ||
265 | e past over things which objectively speaking were not a huge deal.</div><d= | ||
266 | iv>It=E2=80=99s emotion more than rational arguments</div><br></div></block= | ||
267 | quote></div><br><div class=3D"gmail_default" style=3D"font-family:monospace= | ||
268 | ,monospace;font-size:small">=E2=80=8BIt's hard to argue here or general= | ||
269 | ize to all app's communities. Krita community for example is different = | ||
270 | than gcc community in these aspects.</div><div><br></div>-- <br><div class= | ||
271 | =3D"gmail_signature" data-smartmail=3D"gmail_signature">regards, Jaroslaw S= | ||
272 | taniek<br><br>KDE:<br>: A world-wide network of software engineers, artists= | ||
273 | , writers, translators<br>: and facilitators committed to Free Software dev= | ||
274 | elopment - <a href=3D"http://kde.org" target=3D"_blank">http://kde.org</a><= | ||
275 | br>Calligra Suite:<br>: A graphic art and office suite - <a href=3D"http://= | ||
276 | calligra.org" target=3D"_blank">http://calligra.org</a><br>Kexi:<br>: A vis= | ||
277 | ual database apps builder - <a href=3D"http://calligra.org/kexi" target=3D"= | ||
278 | _blank">http://calligra.org/kexi</a><br>Qt Certified Specialist:<br>: <a hr= | ||
279 | ef=3D"http://www.linkedin.com/in/jstaniek" target=3D"_blank">http://www.lin= | ||
280 | kedin.com/in/jstaniek</a></div> | ||
281 | </div></div> | ||
282 | |||
283 | --001a1142e7548d73010556f58604-- | ||