summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--user/trojita/APKBUILD33
-rw-r--r--user/trojita/attachments.patch68
-rw-r--r--user/trojita/deprecated1.patch369
-rw-r--r--user/trojita/deprecated2.patch28
-rw-r--r--user/trojita/deprecated3.patch37
-rw-r--r--user/trojita/fetch-task.patch204
-rw-r--r--user/trojita/plaintext-upgrade-attack.patch221
-rw-r--r--user/trojita/pwstorage.patch52
-rw-r--r--user/trojita/segfault-sorting-mailboxes.patch72
-rw-r--r--user/trojita/signedness.patch71
-rw-r--r--user/trojita/statusbar-fix.patch167
-rw-r--r--user/trojita/testfix.patch85
12 files changed, 1404 insertions, 3 deletions
diff --git a/user/trojita/APKBUILD b/user/trojita/APKBUILD
index a78279253..265b1850a 100644
--- a/user/trojita/APKBUILD
+++ b/user/trojita/APKBUILD
@@ -2,7 +2,7 @@
# Maintainer: Sheila Aman <sheila@vulpine.house>
pkgname=trojita
pkgver=0.7
-pkgrel=1
+pkgrel=2
pkgdesc="Qt-based IMAP email client"
url="http://trojita.flaska.net/"
arch="all"
@@ -18,6 +18,17 @@ source="https://sourceforge.net/projects/trojita/files/src/trojita-$pkgver.tar.x
fix-gpg.patch
CVE-2019-10734.patch
CVE-2020-15047.patch
+ attachments.patch
+ fetch-task.patch
+ testfix.patch
+ plaintext-upgrade-attack.patch
+ pwstorage.patch
+ segfault-sorting-mailboxes.patch
+ signedness.patch
+ statusbar-fix.patch
+ deprecated1.patch
+ deprecated2.patch
+ deprecated3.patch
"
# secfixes:
@@ -25,6 +36,11 @@ source="https://sourceforge.net/projects/trojita/files/src/trojita-$pkgver.tar.x
# - CVE-2019-10734
# - CVE-2020-15047
+prepare() {
+ default_prepare
+ sed -e "s/--dirty//" -i "$builddir"/cmake/TrojitaVersion.cmake
+}
+
build() {
if [ "$CBUILD" != "$CHOST" ]; then
CMAKE_CROSSOPTS="-DCMAKE_SYSTEM_NAME=Linux -DCMAKE_HOST_SYSTEM_NAME=Linux"
@@ -34,7 +50,7 @@ build() {
-DCMAKE_INSTALL_LIBDIR=lib \
-DBUILD_SHARED_LIBS=True \
-DCMAKE_BUILD_TYPE=RelWithDebugInfo \
- -DCMAKE_CXX_FLAGS="$CXXFLAGS" \
+ -DCMAKE_CXX_FLAGS="$CXXFLAGS -Wno-deprecated" \
-DCMAKE_C_FLAGS="$CFLAGS" \
-DWITH_GPGMEPP=ON \
${CMAKE_CROSSOPTS} .
@@ -54,4 +70,15 @@ sha512sums="fe4d9316f97d913619f27d24a5023c3d8dd4a6b9fb058651be12c67188f394aa8cbb
740c2410d7236d722482f05dd1d2c681e35543620823cb7c1396710081f9de4f6ae530c5b5442ecf5d08a8e552f0697f3a35bf51e07a3b4336dec7021b665706 use-qgpgme.patch
9d0fbf7c0b0f6975990a7705f9d43043e5807401cee179d7a07f9514856332d6bb1aa8448e84d0083003c34a3bb181080b973e8c1f77d1b5a8930d07d57702da fix-gpg.patch
db96a566924b5d7b80787ab624af3726d5dd3459653192436a377d6482ab73801a7dcca1df1b1d937cf0d0798b827e04f8ef2c1124f91dc9da3e8036ef61e28a CVE-2019-10734.patch
-2477612aca1e558fa3ba2b434a701cc255c573ac7e2001e7b5921c9b991f7c95720f53b70b49824e36bafb53ab53477950cb8d436e637fda4d59c7ec5883ce5f CVE-2020-15047.patch"
+2477612aca1e558fa3ba2b434a701cc255c573ac7e2001e7b5921c9b991f7c95720f53b70b49824e36bafb53ab53477950cb8d436e637fda4d59c7ec5883ce5f CVE-2020-15047.patch
+714b6d3b8a791783039f51d98b5d14b2b01ec3228993500623c980c09d04c38e6f26d236efa7fc722d68cd72692b646e5c4b2ca13d3d9b342e2072afb466ded0 attachments.patch
+af6d1951fe89a1347b0793175e2348c9cf883792bd576cead9cd70b83546d3dd29a59390c167e76d67413f822368d16892f11dac08da2ce0d9ed53e51b2c0d52 fetch-task.patch
+762c10e004e51d229f5a88410b049716abe3bd25f7ff904b031c1d6ed4a637449e47e2219c5ac85db36517d7599f48cd8a15a0cc2d87ba9e5cba79d483bf8d84 testfix.patch
+1ed2feb300304c58902e034767747610641c998b7a33fede01ff850b298074a04b0aa23332f8b37ecd9d798c35126d0d8f2e7560699c672a2195f110891cbe1a plaintext-upgrade-attack.patch
+86f5dce6bbc7926105bb2950aa15ca469a65cb29d1197d660a3de8ebbe19bb54a945803c542540c168f0b9dc3bfbde58e160bb4f47e0c418fcbb81744f3f60a2 pwstorage.patch
+93b8e795ef3f4423f1a1cce4ca87d146252af33259be2ed597af822a5c8b4abca2292055799c5b5ab70983b8dbba667e516dfe28e6c26705266f3f05b275ad4b segfault-sorting-mailboxes.patch
+83fd69307bb6c34c72a566e06674cc63f330d967d50812067c66633d9cfeb450410257042d489d4be591af383725e5d5f465421675065140fab6c6a40ab55484 signedness.patch
+b17f19a7c9a02fbf711b6e960bf9679caf591c35b59ec636293d341286135aaef7e6d137076502a2087375d30bf75cd5c8d67bcf726f75b0ab76aae0d8f24927 statusbar-fix.patch
+7a7d71e415c2b3e11c962eedf5fe3b5b22579fc86855a904a8d4c1ee2bf300d0872e0a9081644c33b197b2ad5eda9b0209fe7bccfcce466efd9924ea52282fe5 deprecated1.patch
+2f1c1de165f8fede77cbb0fe9a5cc1139def4d903692adefcc25a14fcec0c50f1070d458ddaa17bdb2c999f54c3dbf6e6403ccd5c897f4c861a1df7d121e978a deprecated2.patch
+bce7713fb5bef29b2b189d281dee57ddfc57f1c0601f424aba2185668215878b9bfd3bb80f0d2f8b73219e782db5e64973e79190fe62afa8ba98327535139146 deprecated3.patch"
diff --git a/user/trojita/attachments.patch b/user/trojita/attachments.patch
new file mode 100644
index 000000000..38d11316e
--- /dev/null
+++ b/user/trojita/attachments.patch
@@ -0,0 +1,68 @@
+From cf2364b80fa8ae844df8350cd5833d47cce235f2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jkt@kde.org>
+Date: Mon, 9 Mar 2020 08:24:48 -0700
+Subject: [PATCH] Fix possible crash when downloading attachments
+
+Turns out we've been happily deleting network replies from the
+QNetworkReply::finished(). That was never a good thing to do, but it did
+not use to crash with older Qt. Now it does.
+
+After changing to deleteLater(), there's a window for
+already-deregistered replies to generate events, therefore the assert
+has to go, too, otherwise Bad Things happen:
+
+ (gdb) bt
+ #0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
+ #1 0x00007ffff16bdcd2 in __GI_abort () at abort.c:89
+ #2 0x00007ffff2400bcb in qt_message_fatal (context=..., message=<synthetic pointer>...) at /var/tmp/portage/dev-qt/qtcore-5.13.9999/work/qtcore-5.13.9999/src/corelib/global/qlogging.cpp:1904
+ #3 QMessageLogger::fatal (this=this@entry=0x7fffffffc990, msg=msg@entry=0x7ffff2690b10 "ASSERT: \"%s\" in file %s, line %d") at /var/tmp/portage/dev-qt/qtcore-5.13.9999/work/qtcore-5.13.9999/src/corelib/global/qlogging.cpp:888
+ #4 0x00007ffff23fff7c in qt_assert (assertion=assertion@entry=0x5555558451d7 "reply", file=file@entry=0x555555841a38 "/home/jkt/work/prog/trojita/src/Imap/Network/FileDownloadManager.cpp", line=line@entry=142)
+ at /var/tmp/portage/dev-qt/qtcore-5.13.9999/work/qtcore-5.13.9999/src/corelib/global/qglobal.cpp:3247
+ #5 0x00005555555da840 in Imap::Network::FileDownloadManager::onPartDataTransfered (this=0x555556a20990)
+ #6 0x00007ffff25f1bdf in QtPrivate::QSlotObjectBase::call (a=0x7fffffffcaa0, r=0x555556a20990, this=0x5555569f99c0) at ../../include/QtCore/../../../qtcore-5.13.9999/src/corelib/kernel/qobjectdefs_impl.h:394
+ #7 QMetaObject::activate(QObject*, int, int, void**) () at /var/tmp/portage/dev-qt/qtcore-5.13.9999/work/qtcore-5.13.9999/src/corelib/kernel/qobject.cpp:3787
+ #8 0x00007ffff25f20b7 in QMetaObject::activate (sender=sender@entry=0x555556a21370, m=m@entry=0x7ffff3f96b00 <QNetworkReply::staticMetaObject>, local_signal_index=local_signal_index@entry=1, argv=argv@entry=0x0)
+ at /var/tmp/portage/dev-qt/qtcore-5.13.9999/work/qtcore-5.13.9999/src/corelib/kernel/qobject.cpp:3658
+ #9 0x00007ffff3d3cbf3 in QNetworkReply::finished (this=this@entry=0x555556a21370) at .moc/moc_qnetworkreply.cpp:385
+ #10 0x0000555555709485 in Imap::Network::MsgPartNetworkReply::slotMyDataChanged() () at /home/jkt/work/prog/trojita/src/Imap/Network/MsgPartNetworkReply.cpp:112
+
+BUG: 417697
+Reported-by: Stefan de Konink <stefan@konink.de>
+Change-Id: I79f340c5a471430a14474472513d0a055c7238d6
+---
+ src/Imap/Network/FileDownloadManager.cpp | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/src/Imap/Network/FileDownloadManager.cpp b/src/Imap/Network/FileDownloadManager.cpp
+index 16b6c8df..c3f72176 100644
+--- a/src/Imap/Network/FileDownloadManager.cpp
++++ b/src/Imap/Network/FileDownloadManager.cpp
+@@ -139,7 +139,9 @@ void FileDownloadManager::downloadMessage()
+
+ void FileDownloadManager::onPartDataTransfered()
+ {
+- Q_ASSERT(reply);
++ if (!reply) {
++ return;
++ }
+ if (reply->error() == QNetworkReply::NoError) {
+ if (!saving.open(QIODevice::WriteOnly)) {
+ emit transferError(saving.errorString());
+@@ -192,11 +194,11 @@ void FileDownloadManager::onCombinerTransferError(const QString &message)
+
+ void FileDownloadManager::deleteReply(QNetworkReply *reply)
+ {
+- if (reply == this->reply) {
++ if (reply && reply == this->reply) {
+ if (!saved)
+ onPartDataTransfered();
+- delete reply;
+- this->reply = 0;
++ reply->deleteLater();
++ this->reply = nullptr;
+ }
+ }
+
+--
+GitLab
+
diff --git a/user/trojita/deprecated1.patch b/user/trojita/deprecated1.patch
new file mode 100644
index 000000000..e09c0c573
--- /dev/null
+++ b/user/trojita/deprecated1.patch
@@ -0,0 +1,369 @@
+From 297f0d5a1df9c1b9ca5e9287bb2e603985c232cf Mon Sep 17 00:00:00 2001
+From: Heiko Becker <heirecka@exherbo.org>
+Date: Tue, 1 Feb 2022 17:06:49 +0100
+Subject: [PATCH 1/6] Port away from deprecated qSort to std::sort
+
+---
+ src/Imap/Model/MailboxTree.cpp | 2 +-
+ src/Imap/Model/Model.cpp | 7 +++----
+ src/Imap/Model/ThreadingMsgListModel.cpp | 2 +-
+ src/Imap/Parser/Sequence.cpp | 3 ++-
+ src/Imap/Tasks/ObtainSynchronizedMailboxTask.cpp | 2 +-
+ src/Imap/Tasks/SortTask.cpp | 2 +-
+ 6 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/src/Imap/Model/MailboxTree.cpp b/src/Imap/Model/MailboxTree.cpp
+index e61f59c5..d9a03fc3 100644
+--- a/src/Imap/Model/MailboxTree.cpp
++++ b/src/Imap/Model/MailboxTree.cpp
+@@ -590,7 +590,7 @@ void TreeItemMailbox::handleVanished(Model *const model, const Responses::Vanish
+ QModelIndex listIndex = list->toIndex(model);
+
+ auto uids = resp.uids;
+- qSort(uids);
++ std::sort(uids.begin(), uids.end());
+ // Remove duplicates -- even that garbage can be present in a perfectly valid VANISHED :(
+ uids.erase(std::unique(uids.begin(), uids.end()), uids.end());
+
+diff --git a/src/Imap/Model/Model.cpp b/src/Imap/Model/Model.cpp
+index 1d539e22..aff8ea43 100644
+--- a/src/Imap/Model/Model.cpp
++++ b/src/Imap/Model/Model.cpp
+@@ -25,7 +25,6 @@
+ #include <QAuthenticator>
+ #include <QCoreApplication>
+ #include <QDebug>
+-#include <QtAlgorithms>
+ #include "Model.h"
+ #include "Common/FindWithUnknown.h"
+ #include "Common/InvokeMethod.h"
+@@ -350,7 +349,7 @@ void Model::finalizeList(Parser *parser, TreeItemMailbox *mailboxPtr)
+ ++it;
+ }
+ }
+- qSort(mailboxes.begin(), mailboxes.end(), MailboxNameComparator);
++ std::sort(mailboxes.begin(), mailboxes.end(), MailboxNameComparator);
+
+ // Remove duplicates; would be great if this could be done in a STLish way,
+ // but unfortunately std::unique won't help here (the "duped" part of the
+@@ -406,7 +405,7 @@ void Model::finalizeIncrementalList(Parser *parser, const QString &parentMailbox
+ ++it;
+ }
+ }
+- qSort(mailboxes.begin(), mailboxes.end(), MailboxNameComparator);
++ std::sort(mailboxes.begin(), mailboxes.end(), MailboxNameComparator);
+
+ if (mailboxes.size() == 0) {
+ qDebug() << "Weird, no matching LIST response for our prompt after CREATE";
+@@ -1259,7 +1258,7 @@ void Model::copyMoveMessages(TreeItemMailbox *sourceMbox, const QString &destMai
+
+ Q_ASSERT(sourceMbox);
+
+- qSort(uids);
++ std::sort(uids.begin(), uids.end());
+
+ QModelIndexList messages;
+ Sequence seq;
+diff --git a/src/Imap/Model/ThreadingMsgListModel.cpp b/src/Imap/Model/ThreadingMsgListModel.cpp
+index 29786022..76ef94c2 100644
+--- a/src/Imap/Model/ThreadingMsgListModel.cpp
++++ b/src/Imap/Model/ThreadingMsgListModel.cpp
+@@ -718,7 +718,7 @@ void ThreadingMsgListModel::slotIncrementalThreadingAvailable(const Responses::E
+ for (Responses::ESearch::IncrementalThreadingData_t::const_iterator it = data.constBegin(); it != data.constEnd(); ++it) {
+ gatherAllUidsFromThreadNode(affectedUids, it->thread);
+ }
+- qSort(affectedUids);
++ std::sort(affectedUids.begin(), affectedUids.end());
+ QList<TreeItemMessage*> affectedMessages = const_cast<Model*>(realModel)->
+ findMessagesByUids(static_cast<TreeItemMailbox*>(mailboxIndex.internalPointer()), affectedUids);
+ QHash<uint,void *> uidToPtrCache;
+diff --git a/src/Imap/Parser/Sequence.cpp b/src/Imap/Parser/Sequence.cpp
+index 31b257bb..0e2cd314 100644
+--- a/src/Imap/Parser/Sequence.cpp
++++ b/src/Imap/Parser/Sequence.cpp
+@@ -23,6 +23,7 @@
+ #include "Sequence.h"
+ #include <QStringList>
+ #include <QTextStream>
++#include <algorithm>
+
+ namespace Imap
+ {
+@@ -114,7 +115,7 @@ Sequence &Sequence::add(uint num)
+ Sequence Sequence::fromVector(Imap::Uids numbers)
+ {
+ Q_ASSERT(!numbers.isEmpty());
+- qSort(numbers);
++ std::sort(numbers.begin(), numbers.end());
+ Sequence seq(numbers.first());
+ for (int i = 1; i < numbers.size(); ++i) {
+ seq.add(numbers[i]);
+diff --git a/src/Imap/Tasks/ObtainSynchronizedMailboxTask.cpp b/src/Imap/Tasks/ObtainSynchronizedMailboxTask.cpp
+index 9d6f8279..89fdf4ef 100644
+--- a/src/Imap/Tasks/ObtainSynchronizedMailboxTask.cpp
++++ b/src/Imap/Tasks/ObtainSynchronizedMailboxTask.cpp
+@@ -974,7 +974,7 @@ void ObtainSynchronizedMailboxTask::finalizeSearch()
+ }
+ }
+
+- qSort(uidMap);
++ std::sort(uidMap.begin(), uidMap.end());
+ if (!uidMap.isEmpty() && uidMap.front() == 0) {
+ throw MailboxException("UID (E)SEARCH response contains invalid UID zero");
+ }
+diff --git a/src/Imap/Tasks/SortTask.cpp b/src/Imap/Tasks/SortTask.cpp
+index 347ec85e..8c2b4d69 100644
+--- a/src/Imap/Tasks/SortTask.cpp
++++ b/src/Imap/Tasks/SortTask.cpp
+@@ -179,7 +179,7 @@ bool SortTask::handleSearch(const Imap::Responses::Search *const resp)
+ // That just doesn't look like worth it.
+
+ sortResult += resp->items;
+- qSort(sortResult);
++ std::sort(sortResult.begin(), sortResult.end());
+ sortResult.erase(std::unique(sortResult.begin(), sortResult.end()), sortResult.end());
+ return true;
+ }
+--
+GitLab
+
+
+From 268637f7b63059a065dffcb87c13166ebb0d3d3f Mon Sep 17 00:00:00 2001
+From: Heiko Becker <heirecka@exherbo.org>
+Date: Tue, 1 Feb 2022 17:31:43 +0100
+Subject: [PATCH 2/6] Port away from deprecated qFind to std::find
+
+---
+ src/Imap/Model/ThreadingMsgListModel.cpp | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/Imap/Model/ThreadingMsgListModel.cpp b/src/Imap/Model/ThreadingMsgListModel.cpp
+index 76ef94c2..58b606a5 100644
+--- a/src/Imap/Model/ThreadingMsgListModel.cpp
++++ b/src/Imap/Model/ThreadingMsgListModel.cpp
+@@ -1130,7 +1130,7 @@ void ThreadingMsgListModel::pruneTree()
+ Q_ASSERT(parent != threading.end());
+
+ // and the node itself has to be found in its parent's children
+- QList<uint>::iterator childIt = qFind(parent->children.begin(), parent->children.end(), it->internalId);
++ QList<uint>::iterator childIt = std::find(parent->children.begin(), parent->children.end(), it->internalId);
+ Q_ASSERT(childIt != parent->children.end());
+ // The offset of this child might no longer be correct, though -- we're postponing the actual deletion until later
+
+@@ -1175,7 +1175,7 @@ void ThreadingMsgListModel::pruneTree()
+
+ if (parent->internalId == 0) {
+ // Update the list of all thread roots
+- QList<uint>::iterator rootIt = qFind(threadedRootIds.begin(), threadedRootIds.end(), it->internalId);
++ QList<uint>::iterator rootIt = std::find(threadedRootIds.begin(), threadedRootIds.end(), it->internalId);
+ if (rootIt != threadedRootIds.end())
+ *rootIt = replaceWith->internalId;
+ }
+--
+GitLab
+
+
+From f06067dfa9bbb28cc385e526e9a7b261fe8448bc Mon Sep 17 00:00:00 2001
+From: Heiko Becker <heirecka@exherbo.org>
+Date: Tue, 1 Feb 2022 17:33:32 +0100
+Subject: [PATCH 3/6] Port away from deprecated qLowerBound to std::lower_bound
+
+---
+ src/Imap/Parser/Sequence.cpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/Imap/Parser/Sequence.cpp b/src/Imap/Parser/Sequence.cpp
+index 0e2cd314..55adb6aa 100644
+--- a/src/Imap/Parser/Sequence.cpp
++++ b/src/Imap/Parser/Sequence.cpp
+@@ -106,7 +106,7 @@ Imap::Uids Sequence::toVector() const
+ Sequence &Sequence::add(uint num)
+ {
+ Q_ASSERT(kind == DISTINCT);
+- auto it = qLowerBound(numbers.begin(), numbers.end(), num);
++ auto it = std::lower_bound(numbers.begin(), numbers.end(), num);
+ if (it == numbers.end() || *it != num)
+ numbers.insert(it, num);
+ return *this;
+--
+GitLab
+
+
+From b7e9532a3209d64c15937e29b359be40fbd2fff7 Mon Sep 17 00:00:00 2001
+From: Heiko Becker <heirecka@exherbo.org>
+Date: Tue, 1 Feb 2022 17:34:15 +0100
+Subject: [PATCH 4/6] Port away from deprecated qLess to std::less
+
+---
+ tests/Misc/test_algorithms.cpp | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/tests/Misc/test_algorithms.cpp b/tests/Misc/test_algorithms.cpp
+index a9a53745..86ce9e16 100644
+--- a/tests/Misc/test_algorithms.cpp
++++ b/tests/Misc/test_algorithms.cpp
+@@ -21,6 +21,7 @@
+ */
+
+ #include <QTest>
++#include <functional>
+ #include "test_algorithms.h"
+
+ #include "Common/FindWithUnknown.h"
+@@ -38,9 +39,9 @@ void TestCommonAlgorithms::testLowerBoundWithUnknown()
+ QFETCH(int, needle);
+ QFETCH(int, offset);
+
+- QList<int>::const_iterator it = Common::linearLowerBoundWithUnknownElements(list.constBegin(), list.constEnd(), needle, isZero, qLess<int>());
++ QList<int>::const_iterator it = Common::linearLowerBoundWithUnknownElements(list.constBegin(), list.constEnd(), needle, isZero, std::less<int>());
+ QCOMPARE(it - list.constBegin(), offset);
+- it = Common::lowerBoundWithUnknownElements(list.constBegin(), list.constEnd(), needle, isZero, qLess<int>());
++ it = Common::lowerBoundWithUnknownElements(list.constBegin(), list.constEnd(), needle, isZero, std::less<int>());
+ QCOMPARE(it - list.constBegin(), offset);
+ }
+
+--
+GitLab
+
+
+From 42ea2f0ec8de8fc2ea3e607d0b694dbd30e3ffaf Mon Sep 17 00:00:00 2001
+From: Heiko Becker <heirecka@exherbo.org>
+Date: Sat, 29 Jan 2022 23:54:40 +0100
+Subject: [PATCH 5/6] Port from the deprecated QProcess::error() to
+ errorOccurred
+
+Raises the Qt requirement to 5.6.
+---
+ CMakeLists.txt | 3 ++-
+ src/MSA/Sendmail.cpp | 2 +-
+ src/Streams/IODeviceSocket.cpp | 2 +-
+ 3 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index a3d54166..54512029 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -69,7 +69,7 @@ else()
+ set(QTKEYCHAIN_DEPENDS "")
+ endif()
+
+-find_package(Qt5Core 5.2 REQUIRED)
++find_package(Qt5Core 5.6 REQUIRED)
+ find_package(Qt5Gui REQUIRED)
+ find_package(Qt5Network REQUIRED)
+ find_package(Qt5Sql REQUIRED)
+@@ -183,6 +183,7 @@ add_definitions(-DQT_STRICT_ITERATORS)
+ add_definitions(-DQT_USE_QSTRINGBUILDER)
+ add_definitions(-DQT_USE_FAST_OPERATOR_PLUS)
+ add_definitions(-DQT_USE_FAST_CONCATENATION)
++add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050600)
+
+ if(NOT MSVC)
+ # We're using C++11's threading features (std::async in particular), and that requires "some threading". With GCC and
+diff --git a/src/MSA/Sendmail.cpp b/src/MSA/Sendmail.cpp
+index f72f4927..d88d16c4 100644
+--- a/src/MSA/Sendmail.cpp
++++ b/src/MSA/Sendmail.cpp
+@@ -30,7 +30,7 @@ Sendmail::Sendmail(QObject *parent, const QString &command, const QStringList &a
+ proc = new QProcess(this);
+ connect(proc, &QProcess::started, this, &Sendmail::handleStarted);
+ connect(proc, static_cast<void (QProcess::*)(int)>(&QProcess::finished), this, &Sendmail::handleFinished);
+- connect(proc, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error), this, &Sendmail::handleError);
++ connect(proc, &QProcess::errorOccurred, this, &Sendmail::handleError);
+ connect(proc, &QIODevice::bytesWritten, this, &Sendmail::handleBytesWritten);
+ }
+
+diff --git a/src/Streams/IODeviceSocket.cpp b/src/Streams/IODeviceSocket.cpp
+index 7998028d..90f8470e 100644
+--- a/src/Streams/IODeviceSocket.cpp
++++ b/src/Streams/IODeviceSocket.cpp
+@@ -141,7 +141,7 @@ ProcessSocket::ProcessSocket(QProcess *proc, const QString &executable, const QS
+ IODeviceSocket(proc), executable(executable), args(args)
+ {
+ connect(proc, &QProcess::stateChanged, this, &ProcessSocket::handleStateChanged);
+- connect(proc, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error), this, &ProcessSocket::handleProcessError);
++ connect(proc, &QProcess::errorOccurred, this, &ProcessSocket::handleProcessError);
+ }
+
+ ProcessSocket::~ProcessSocket()
+--
+GitLab
+
+
+From aee63baa14f3fc318d4aac67b2c740067ffc7929 Mon Sep 17 00:00:00 2001
+From: Heiko Becker <heirecka@exherbo.org>
+Date: Tue, 1 Feb 2022 17:52:12 +0100
+Subject: [PATCH 6/6] Port from deprecated {from,to}Time_t to
+ {from,to}SecsSinceEpock
+
+Raises the Qt requirement to 5.8.
+
+Not raising QT_DISABLE_DEPRECATED_BEFORE=0x050800 yet, because
+QModelIndex.child() was deprecated with 5.8 and it's quite frequenty
+used.
+---
+ CMakeLists.txt | 4 ++--
+ src/Cryptography/GpgMe++.cpp | 4 ++--
+ src/Imap/Model/Utils.cpp | 2 +-
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 54512029..e2cd9108 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -69,7 +69,7 @@ else()
+ set(QTKEYCHAIN_DEPENDS "")
+ endif()
+
+-find_package(Qt5Core 5.6 REQUIRED)
++find_package(Qt5Core 5.8 REQUIRED)
+ find_package(Qt5Gui REQUIRED)
+ find_package(Qt5Network REQUIRED)
+ find_package(Qt5Sql REQUIRED)
+@@ -183,7 +183,7 @@ add_definitions(-DQT_STRICT_ITERATORS)
+ add_definitions(-DQT_USE_QSTRINGBUILDER)
+ add_definitions(-DQT_USE_FAST_OPERATOR_PLUS)
+ add_definitions(-DQT_USE_FAST_CONCATENATION)
+-add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050600)
++add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050700)
+
+ if(NOT MSVC)
+ # We're using C++11's threading features (std::async in particular), and that requires "some threading". With GCC and
+diff --git a/src/Cryptography/GpgMe++.cpp b/src/Cryptography/GpgMe++.cpp
+index 716b8aff..78f8caf5 100644
+--- a/src/Cryptography/GpgMe++.cpp
++++ b/src/Cryptography/GpgMe++.cpp
+@@ -366,7 +366,7 @@ void GpgMePart::extractSignatureStatus(std::shared_ptr<GpgME::Context> ctx, cons
+ } else {
+ signer = QString::fromUtf8(sig.fingerprint());
+ }
+- signDate = QDateTime::fromTime_t(sig.creationTime());
++ signDate = QDateTime::fromSecsSinceEpoch(sig.creationTime());
+
+ if (sig.summary() & GpgME::Signature::Green) {
+ // FIXME: change the above to GpgME::Signature::Valid and react to expired keys/signatures by checking the timestamp
+@@ -462,7 +462,7 @@ void GpgMePart::extractSignatureStatus(std::shared_ptr<GpgME::Context> ctx, cons
+ if (sig.summary() & GpgME::Signature::SigExpired) {
+ ENSURE_LINE_LF(longStatus);
+ longStatus += tr("Signature expired on %1.")
+- .arg(QDateTime::fromTime_t(sig.expirationTime()).toString(Qt::DefaultLocaleShortDate));
++ .arg(QDateTime::fromSecsSinceEpoch(sig.expirationTime()).toString(Qt::DefaultLocaleShortDate));
+ }
+ if (sig.summary() & GpgME::Signature::KeyMissing) {
+ ENSURE_LINE_LF(longStatus);
+diff --git a/src/Imap/Model/Utils.cpp b/src/Imap/Model/Utils.cpp
+index 00b3d4b3..b09341a6 100644
+--- a/src/Imap/Model/Utils.cpp
++++ b/src/Imap/Model/Utils.cpp
+@@ -343,7 +343,7 @@ QString formatDateTimeWithTimeZoneAtEnd(const QDateTime &now, const QString &for
+
+ // Got to cast to a signed type to prevent unsigned underflow here. Also go to 64bits because otherwise there'd
+ // a problem when the value is out-of-range for an int32.
+- int minutesDifference = (static_cast<qint64>(now.toTime_t()) - static_cast<qint64>(nowUtc.toTime_t())) / 60;
++ int minutesDifference = (now.toSecsSinceEpoch() - nowUtc.toSecsSinceEpoch()) / 60;
+ int tzOffsetHours = qAbs(minutesDifference) / 60;
+ int tzOffsetMinutes = qAbs(minutesDifference) % 60;
+ // The rest is just a piece of cake now
+--
+GitLab
+
diff --git a/user/trojita/deprecated2.patch b/user/trojita/deprecated2.patch
new file mode 100644
index 000000000..968f06ec4
--- /dev/null
+++ b/user/trojita/deprecated2.patch
@@ -0,0 +1,28 @@
+From 2869c385e72932cbed7398742b8a4d5e3feda765 Mon Sep 17 00:00:00 2001
+From: Heiko Becker <heirecka@exherbo.org>
+Date: Tue, 24 Mar 2020 13:14:43 +0100
+Subject: [PATCH] Fix build with Qt 5.15.0
+
+QPainterPath is no longer included via qtransform.h (since
+5.15.0-beta2, 50d2acdc93b4de2ba56eb67787e2bdcb21dd4bea in qtbase.git).
+
+Change-Id: Ibb59e769bba8514d86aa886afee26a2395d458ef
+---
+ src/Gui/Window.cpp | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/Gui/Window.cpp b/src/Gui/Window.cpp
+index 65ba2463..8d74874f 100644
+--- a/src/Gui/Window.cpp
++++ b/src/Gui/Window.cpp
+@@ -32,6 +32,7 @@
+ #include <QKeyEvent>
+ #include <QMenuBar>
+ #include <QMessageBox>
++#include <QPainterPath>
+ #include <QProgressBar>
+ #include <QRegularExpression>
+ #include <QScopedPointer>
+--
+GitLab
+
diff --git a/user/trojita/deprecated3.patch b/user/trojita/deprecated3.patch
new file mode 100644
index 000000000..9f1ab3e7e
--- /dev/null
+++ b/user/trojita/deprecated3.patch
@@ -0,0 +1,37 @@
+From 39772585033c1c0aff96f297e93de7be53f9b114 Mon Sep 17 00:00:00 2001
+From: Heiko Becker <heirecka@exherbo.org>
+Date: Sat, 23 Mar 2019 01:17:11 +0100
+Subject: [PATCH] tests: Fix build with Qt 5.13
+
+QTest::toString(QModelIndex) was added in
+7ef0b575b38d267bd3dc14ff46935d556562ff00 and thus causes a build
+error with Qt 5.13 because it's redefined here.
+
+Change-Id: I015800e49cf8d0e87f3541642406396f150d0eeb
+---
+ tests/Imap/test_Imap_BodyParts.cpp | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/tests/Imap/test_Imap_BodyParts.cpp b/tests/Imap/test_Imap_BodyParts.cpp
+index f1c577fa..b6e0421d 100644
+--- a/tests/Imap/test_Imap_BodyParts.cpp
++++ b/tests/Imap/test_Imap_BodyParts.cpp
+@@ -51,6 +51,7 @@ struct Data {
+
+ Q_DECLARE_METATYPE(QList<Data>)
+
++#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
+ namespace QTest {
+ template <>
+ char *toString(const QModelIndex &index)
+@@ -60,6 +61,7 @@ char *toString(const QModelIndex &index)
+ return qstrdup(buf.toUtf8().constData());
+ }
+ }
++#endif
+
+ using namespace Imap::Mailbox;
+
+--
+GitLab
+
diff --git a/user/trojita/fetch-task.patch b/user/trojita/fetch-task.patch
new file mode 100644
index 000000000..378db6477
--- /dev/null
+++ b/user/trojita/fetch-task.patch
@@ -0,0 +1,204 @@
+From b12f18885861b125ed139f83fa27491d4b3f9f4e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jkt@kde.org>
+Date: Mon, 2 Jan 2017 19:01:16 +0100
+Subject: [PATCH] Refactoring: move FETCH finalization to a corresponding Task
+
+The tasks were always meant to be able to directly perform these
+operations. There's no point in stashing all functionality in the Model
+class -- that one is way too big already.
+
+Change-Id: I9adfefbdf2d7ecd3d060e764ace5535be10dd0d3
+---
+ src/Imap/Model/MailboxTree.cpp | 16 +++++++++++----
+ src/Imap/Model/MailboxTree.h | 2 ++
+ src/Imap/Model/Model.cpp | 28 -------------------------
+ src/Imap/Model/Model.h | 1 -
+ src/Imap/Tasks/FetchMsgPartTask.cpp | 32 ++++++++++++++++++++++++++++-
+ src/Imap/Tasks/FetchMsgPartTask.h | 10 +++++----
+ 6 files changed, 51 insertions(+), 38 deletions(-)
+
+diff --git a/src/Imap/Model/MailboxTree.cpp b/src/Imap/Model/MailboxTree.cpp
+index 8c28775f..47ea675c 100644
+--- a/src/Imap/Model/MailboxTree.cpp
++++ b/src/Imap/Model/MailboxTree.cpp
+@@ -1556,8 +1556,12 @@ bool TreeItemMessage::hasNestedAttachments(Model *const model, TreeItemPart *par
+ }
+
+
+-TreeItemPart::TreeItemPart(TreeItem *parent, const QByteArray &mimeType):
+- TreeItem(parent), m_mimeType(mimeType.toLower()), m_octets(0), m_partMime(0), m_partRaw(0)
++TreeItemPart::TreeItemPart(TreeItem *parent, const QByteArray &mimeType)
++ : TreeItem(parent)
++ , m_mimeType(mimeType.toLower())
++ , m_octets(0)
++ , m_partMime(nullptr)
++ , m_partRaw(nullptr)
+ {
+ if (isTopLevelMultiPart()) {
+ // Note that top-level multipart messages are special, their immediate contents
+@@ -1566,8 +1570,12 @@ TreeItemPart::TreeItemPart(TreeItem *parent, const QByteArray &mimeType):
+ }
+ }
+
+-TreeItemPart::TreeItemPart(TreeItem *parent):
+- TreeItem(parent), m_mimeType("text/plain"), m_octets(0), m_partMime(0), m_partRaw(0)
++TreeItemPart::TreeItemPart(TreeItem *parent)
++ : TreeItem(parent)
++ , m_mimeType("text/plain")
++ , m_octets(0)
++ , m_partMime(nullptr)
++ , m_partRaw(nullptr)
+ {
+ }
+
+diff --git a/src/Imap/Model/MailboxTree.h b/src/Imap/Model/MailboxTree.h
+index 5cfd843a..137d4a5f 100644
+--- a/src/Imap/Model/MailboxTree.h
++++ b/src/Imap/Model/MailboxTree.h
+@@ -55,6 +55,7 @@ class TreeItem
+ friend class MsgListModel; // for direct access to m_children
+ friend class ThreadingMsgListModel; // for direct access to m_children
+ friend class UpdateFlagsOfAllMessagesTask; // for direct access to m_children
++ friend class FetchMsgPartTask; // for direct access to m_children
+
+ protected:
+ /** @short Availability of an item */
+@@ -140,6 +141,7 @@ class TreeItemMailbox: public TreeItem
+ friend class DeleteMailboxTask; // for direct access to maintainingTask
+ friend class KeepMailboxOpenTask; // needs access to maintainingTask
+ friend class SubscribeUnsubscribeTask; // needs access to m_metadata.flags
++ friend class FetchMsgPartTask; // needs access to partIdToPtr()
+ static QLatin1String flagNoInferiors;
+ static QLatin1String flagHasNoChildren;
+ static QLatin1String flagHasChildren;
+diff --git a/src/Imap/Model/Model.cpp b/src/Imap/Model/Model.cpp
+index e62ef3dd..dc985d44 100644
+--- a/src/Imap/Model/Model.cpp
++++ b/src/Imap/Model/Model.cpp
+@@ -500,34 +500,6 @@ void Model::emitMessageCountChanged(TreeItemMailbox *const mailbox)
+ emit messageCountPossiblyChanged(mailboxIndex);
+ }
+
+-/** @short Retrieval of a message part has completed */
+-bool Model::finalizeFetchPart(TreeItemMailbox *const mailbox, const uint sequenceNo, const QByteArray &partId)
+-{
+- // At first, verify that the message itself is marked as loaded.
+- // If it isn't, it's probably because of Model::releaseMessageData().
+- TreeItem *item = mailbox->m_children[0]; // TreeItemMsgList
+- item = item->child(sequenceNo - 1, this); // TreeItemMessage
+- Q_ASSERT(item); // FIXME: or rather throw an exception?
+- if (item->accessFetchStatus() == TreeItem::NONE) {
+- // ...and it indeed got released, so let's just return and don't try to check anything
+- return false;
+- }
+-
+- TreeItemPart *part = mailbox->partIdToPtr(this, static_cast<TreeItemMessage *>(item), partId);
+- if (! part) {
+- qDebug() << "Can't verify part fetching status: part is not here!";
+- return false;
+- }
+- if (part->loading()) {
+- part->setFetchStatus(TreeItem::UNAVAILABLE);
+- QModelIndex idx = part->toIndex(this);
+- emit dataChanged(idx, idx);
+- return false;
+- } else {
+- return true;
+- }
+-}
+-
+ void Model::handleCapability(Imap::Parser *ptr, const Imap::Responses::Capability *const resp)
+ {
+ updateCapabilities(ptr, resp->capabilities);
+diff --git a/src/Imap/Model/Model.h b/src/Imap/Model/Model.h
+index 46dce087..114e29ac 100644
+--- a/src/Imap/Model/Model.h
++++ b/src/Imap/Model/Model.h
+@@ -492,7 +492,6 @@ private:
+
+ void finalizeList(Parser *parser, TreeItemMailbox *const mailboxPtr);
+ void finalizeIncrementalList(Parser *parser, const QString &parentMailboxName);
+- bool finalizeFetchPart(TreeItemMailbox *const mailbox, const uint sequenceNo, const QByteArray &partId);
+ void genericHandleFetch(TreeItemMailbox *mailbox, const Imap::Responses::Fetch *const resp);
+
+ void replaceChildMailboxes(TreeItemMailbox *mailboxPtr, const TreeItemChildrenList &mailboxes);
+diff --git a/src/Imap/Tasks/FetchMsgPartTask.cpp b/src/Imap/Tasks/FetchMsgPartTask.cpp
+index c7a49437..40e7ec81 100644
+--- a/src/Imap/Tasks/FetchMsgPartTask.cpp
++++ b/src/Imap/Tasks/FetchMsgPartTask.cpp
+@@ -121,7 +121,7 @@ void FetchMsgPartTask::markPendingItemsUnavailable()
+ QList<TreeItemMessage *> messages = model->findMessagesByUids(mailbox, uids);
+ Q_FOREACH(TreeItemMessage *message, messages) {
+ Q_FOREACH(const QByteArray &partId, parts) {
+- if (model->finalizeFetchPart(mailbox, message->row() + 1, partId)) {
++ if (finalizeFetchPart(mailbox, message->row() + 1, partId)) {
+ log(QLatin1String("Fetched part ") + QString::fromUtf8(partId), Common::LOG_MESSAGES);
+ } else {
+ log(QLatin1String("Received no data for part ") + QString::fromUtf8(partId), Common::LOG_MESSAGES);
+@@ -130,5 +130,35 @@ void FetchMsgPartTask::markPendingItemsUnavailable()
+ }
+ }
+
++/** @short Retrieval of a message part has completed */
++bool FetchMsgPartTask::finalizeFetchPart(TreeItemMailbox *const mailbox, const uint sequenceNo, const QByteArray &partId)
++{
++ Q_ASSERT(model);
++ // At first, verify that the message itself is marked as loaded.
++ // If it isn't, it's probably because of Model::releaseMessageData().
++ TreeItem *item = mailbox->m_children[0]; // TreeItemMsgList
++ item = item->child(sequenceNo - 1, model); // TreeItemMessage
++ Q_ASSERT(item); // FIXME: or rather throw an exception?
++ if (item->accessFetchStatus() == TreeItem::NONE) {
++ // ...and it indeed got released, so let's just return and don't try to check anything
++ return false;
++ }
++
++ TreeItemPart *part = mailbox->partIdToPtr(model, static_cast<TreeItemMessage *>(item), partId);
++ if (!part) {
++ log(QStringLiteral("Can't verify part fetching status: part is not here!"), Common::LOG_MESSAGES);
++ return false;
++ }
++ if (part->loading()) {
++ part->setFetchStatus(TreeItem::UNAVAILABLE);
++ QModelIndex idx = part->toIndex(model);
++ emit model->dataChanged(idx, idx);
++ return false;
++ } else {
++ return true;
++ }
++}
++
++
+ }
+ }
+diff --git a/src/Imap/Tasks/FetchMsgPartTask.h b/src/Imap/Tasks/FetchMsgPartTask.h
+index 4d5b591f..a7e4b2c1 100644
+--- a/src/Imap/Tasks/FetchMsgPartTask.h
++++ b/src/Imap/Tasks/FetchMsgPartTask.h
+@@ -26,10 +26,10 @@
+ #include <QPersistentModelIndex>
+ #include "ImapTask.h"
+
+-namespace Imap
+-{
+-namespace Mailbox
+-{
++namespace Imap {
++namespace Mailbox {
++
++class TreeItemMailbox;
+
+ /** @short Fetch a message part */
+ class FetchMsgPartTask : public ImapTask
+@@ -48,6 +48,8 @@ public:
+ protected slots:
+ void markPendingItemsUnavailable();
+ private:
++ bool finalizeFetchPart(TreeItemMailbox *const mailbox, const uint sequenceNo, const QByteArray &partId);
++
+ CommandHandle tag;
+ ImapTask *conn;
+ Imap::Uids uids;
+--
+GitLab
+
diff --git a/user/trojita/plaintext-upgrade-attack.patch b/user/trojita/plaintext-upgrade-attack.patch
new file mode 100644
index 000000000..f3c30b9aa
--- /dev/null
+++ b/user/trojita/plaintext-upgrade-attack.patch
@@ -0,0 +1,221 @@
+From 27573cf04802fc2fdeb7f7beace4612b22ea1942 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jkt@kde.org>
+Date: Sun, 30 Jan 2022 23:56:31 +0100
+Subject: [PATCH] IMAP: ignore unsolicited LIST and STATUS before we're
+ authenticated
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+These responses were combined with legit responses which arrive from the
+real server later on, after having authenticated, and as a result, a
+malicious active attacker on a network was able to inject extra fake
+mailboxes to the GUI even when upgrading connection from plaintext to a
+secure one via STARTTLS.
+
+These two responses are the only ones which are handled by our pre-task
+code directly in Model.cpp, which means that the state machine has to be
+checked and messages which are received prior to authentication must be
+rejected. Since this is really a pretty serious violation of the IMAP
+state machine, let's not ignore them silently, and simply treat them as
+any other unexpected response.
+
+BUG: 432353
+Change-Id: I9292fcb20215ebe4dbc7a103fc9403dfa97b258b
+Reported-by: Damian Poddebniak
+Co-authored-by: Espen Sandøy Hustad <espen@ehustad.com>
+Reviewed-by: Caspar Schutijser <caspar@schutijser.com>
+---
+ src/Imap/Model/Model.cpp | 7 +-
+ tests/Imap/test_Imap_Tasks_OpenConnection.cpp | 122 +++++++++++++++++-
+ tests/Imap/test_Imap_Tasks_OpenConnection.h | 9 ++
+ 3 files changed, 136 insertions(+), 2 deletions(-)
+
+diff --git a/src/Imap/Model/Model.cpp b/src/Imap/Model/Model.cpp
+index 7a393c7a..79e34658 100644
+--- a/src/Imap/Model/Model.cpp
++++ b/src/Imap/Model/Model.cpp
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 2006 - 2014 Jan Kundrát <jkt@flaska.net>
++/* Copyright (C) 2006 - 2021 Jan Kundrát <jkt@flaska.net>
+
+ This file is part of the Trojita Qt IMAP e-mail client,
+ http://trojita.flaska.net/
+@@ -519,6 +519,8 @@ void Model::handleList(Imap::Parser *ptr, const Imap::Responses::List *const res
+ {
+ if (accessParser(ptr).connState == CONN_STATE_LOGOUT)
+ return;
++ if (accessParser(ptr).connState < CONN_STATE_AUTHENTICATED)
++ throw UnexpectedResponseReceived("Unexpected LIST response before authentication succeeded", *resp);
+ accessParser(ptr).listResponses << *resp;
+ }
+
+@@ -547,6 +549,9 @@ void Model::handleStatus(Imap::Parser *ptr, const Imap::Responses::Status *const
+ {
+ if (accessParser(ptr).connState == CONN_STATE_LOGOUT)
+ return;
++ if (accessParser(ptr).connState < CONN_STATE_AUTHENTICATED)
++ throw UnexpectedResponseReceived("Unexpected STATUS response before authentication succeeded", *resp);
++
+ Q_UNUSED(ptr);
+ TreeItemMailbox *mailbox = findMailboxByName(resp->mailbox);
+ if (! mailbox) {
+diff --git a/tests/Imap/test_Imap_Tasks_OpenConnection.cpp b/tests/Imap/test_Imap_Tasks_OpenConnection.cpp
+index b72898c4..953fe6f9 100644
+--- a/tests/Imap/test_Imap_Tasks_OpenConnection.cpp
++++ b/tests/Imap/test_Imap_Tasks_OpenConnection.cpp
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 2006 - 2014 Jan Kundrát <jkt@flaska.net>
++/* Copyright (C) 2006 - 2021 Jan Kundrát <jkt@flaska.net>
+
+ This file is part of the Trojita Qt IMAP e-mail client,
+ http://trojita.flaska.net/
+@@ -611,5 +611,125 @@ void ImapModelOpenConnectionTest::provideAuthDetails()
+ }
+ }
+
++void ImapModelOpenConnectionTest::dataBug432353()
++{
++ QTest::addColumn<QByteArray>("garbage");
++ QTest::newRow("LIST") << QByteArray("* LIST (\\HasNoChildren) \".\" x\r\n");
++ QTest::newRow("STATUS") << QByteArray("* STATUS INBOX (MESSAGES 123)\r\n");
++}
++
++void ImapModelOpenConnectionTest::testNoListStatusUponConnect_data()
++{
++ dataBug432353();
++}
++
++void ImapModelOpenConnectionTest::testNoListStatusUponConnect()
++{
++ QFETCH(QByteArray, garbage);
++ reinit(TlsRequired::Yes);
++ cEmpty();
++ QCOMPARE(model->rowCount(QModelIndex()), 1);
++ ExpectSingleErrorHere x(this);
++ cServer("* OK foo\r\n" + garbage);
++}
++
++void ImapModelOpenConnectionTest::testNoListStatusStartTls_data()
++{
++ dataBug432353();
++}
++
++void ImapModelOpenConnectionTest::testNoListStatusStartTls()
++{
++ QFETCH(QByteArray, garbage);
++ reinit(TlsRequired::Yes);
++ cEmpty();
++ cServer("* OK [Capability imap4rev1 starttls] foo\r\n");
++ QVERIFY(completedSpy->isEmpty());
++ QVERIFY(authSpy->isEmpty());
++ cClient(t.mk("STARTTLS\r\n"));
++ cServer(t.last("OK will establish secure layer immediately\r\n"));
++ QVERIFY(authSpy->isEmpty());
++ cClient("[*** STARTTLS ***]" + t.mk("CAPABILITY\r\n"));
++ QVERIFY(completedSpy->isEmpty());
++ QVERIFY(authSpy->isEmpty());
++ cServer("* CAPABILITY IMAP4rev1\r\n" + t.last("OK capability completed\r\n"));
++ cClient(t.mk("LOGIN luzr sikrit\r\n"));
++ QCOMPARE(authSpy->size(), 1);
++ ExpectSingleErrorHere x(this);
++ cServer(garbage + t.last("OK [CAPABILITY IMAP4rev1] logged in\r\n"));
++}
++
++void ImapModelOpenConnectionTest::testNoListStatusBeforeAuthenticated_data()
++{
++ dataBug432353();
++}
++
++void ImapModelOpenConnectionTest::testNoListStatusBeforeAuthenticated()
++{
++ QFETCH(QByteArray, garbage);
++ reinit(TlsRequired::Yes);
++ cEmpty();
++ cServer("* OK [Capability imap4rev1 starttls] foo\r\n");
++ QVERIFY(completedSpy->isEmpty());
++ QVERIFY(authSpy->isEmpty());
++ cClient(t.mk("STARTTLS\r\n"));
++ cServer(t.last("OK will establish secure layer immediately\r\n"));
++ QVERIFY(authSpy->isEmpty());
++ cClient("[*** STARTTLS ***]" + t.mk("CAPABILITY\r\n"));
++ QVERIFY(completedSpy->isEmpty());
++ QVERIFY(authSpy->isEmpty());
++ cServer("* CAPABILITY IMAP4rev1\r\n" + t.last("OK capability completed\r\n"));
++ cClient(t.mk("LOGIN luzr sikrit\r\n"));
++ QCOMPARE(authSpy->size(), 1);
++ ExpectSingleErrorHere x(this);
++ cServer(garbage + t.last("OK [CAPABILITY IMAP4rev1] logged in\r\n"));
++}
++
++void ImapModelOpenConnectionTest::testListStatusUnsolicited()
++{
++ model->cache()->setChildMailboxes(QString(),
++ QList<Imap::Mailbox::MailboxMetadata>()
++ << Imap::Mailbox::MailboxMetadata(QLatin1String("INBOX"), QString(), QStringList())
++ );
++
++ reinit(TlsRequired::Yes);
++ cEmpty();
++ cServer("* OK [Capability imap4rev1 starttls] foo\r\n");
++ QVERIFY(completedSpy->isEmpty());
++ QVERIFY(authSpy->isEmpty());
++ cClient(t.mk("STARTTLS\r\n"));
++ cServer(t.last("OK will establish secure layer immediately\r\n"));
++ QVERIFY(authSpy->isEmpty());
++ cClient("[*** STARTTLS ***]" + t.mk("CAPABILITY\r\n"));
++ QVERIFY(completedSpy->isEmpty());
++ QVERIFY(authSpy->isEmpty());
++ cServer("* CAPABILITY IMAP4rev1\r\n" + t.last("OK capability completed\r\n"));
++ cClient(t.mk("LOGIN luzr sikrit\r\n"));
++ QCOMPARE(authSpy->size(), 1);
++ cServer(t.last("OK [CAPABILITY IMAP4rev1] logged in\r\n") +
++ "* LIST (\\HasNoChildren) \".\" abc\r\n"
++ "* LIST (\\HasNoChildren) \".\" def\r\n"
++ "* STATUS INBOX (MESSAGES 123)\r\n"
++ );
++ QCOMPARE(model->rowCount(QModelIndex()), 1);
++ cClient(t.mk("LIST \"\" \"%\"\r\n"));
++ cEmpty();
++ QCOMPARE(completedSpy->size(), 1);
++ QVERIFY(failedSpy->isEmpty());
++ cServer("* LIST (\\Noselect \\HasChildren) \".\" \"xyz\"\r\n"
++ "* LIST (\\HasNoChildren) \".\" \"INBOX\"\r\n"
++ + t.last("OK list done\r\n")
++ + "* STATUS INBOX (MESSAGES 789)\r\n");
++ cEmpty();
++
++ // Mailboxes "abc" and "def" were reported by the server as an async replay after having authenticated,
++ // so there's no reason not to trust them. However, they were received before a LIST was issues,
++ // so they should be probably ignored -- but that is tricky to do properly with command pipelining, etc.
++ QCOMPARE(model->rowCount( QModelIndex() ), 5 /* empty root, INBOX, abc, def, xyz */);
++ QCOMPARE(model->index(1, 0, QModelIndex()).data().toString(), QLatin1String("INBOX"));
++ QCOMPARE(model->index(2, 0, QModelIndex()).data().toString(), QLatin1String("abc"));
++ QCOMPARE(model->index(3, 0, QModelIndex()).data().toString(), QLatin1String("def"));
++ QCOMPARE(model->index(4, 0, QModelIndex()).data().toString(), QLatin1String("xyz"));
++}
+
+ QTEST_GUILESS_MAIN( ImapModelOpenConnectionTest )
+diff --git a/tests/Imap/test_Imap_Tasks_OpenConnection.h b/tests/Imap/test_Imap_Tasks_OpenConnection.h
+index 4df65c05..6a0e2704 100644
+--- a/tests/Imap/test_Imap_Tasks_OpenConnection.h
++++ b/tests/Imap/test_Imap_Tasks_OpenConnection.h
+@@ -70,6 +70,15 @@ private slots:
+
+ void testExcessivePasswordPrompts();
+
++ void dataBug432353();
++ void testNoListStatusUponConnect();
++ void testNoListStatusUponConnect_data();
++ void testNoListStatusStartTls();
++ void testNoListStatusStartTls_data();
++ void testNoListStatusBeforeAuthenticated();
++ void testNoListStatusBeforeAuthenticated_data();
++ void testListStatusUnsolicited();
++
+ void provideAuthDetails();
+ void acceptSsl(const QList<QSslCertificate> &certificateChain, const QList<QSslError> &sslErrors);
+
+--
+GitLab
+
diff --git a/user/trojita/pwstorage.patch b/user/trojita/pwstorage.patch
new file mode 100644
index 000000000..e0cec35ba
--- /dev/null
+++ b/user/trojita/pwstorage.patch
@@ -0,0 +1,52 @@
+From 7481e43116995d744d485655b1de6494d771227e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jkt@kde.org>
+Date: Thu, 16 May 2019 19:28:14 +0200
+Subject: [PATCH] SMTP: Store correct password into the password manager
+
+The configuration ties the SMTP account with the IMAP account (in terms
+of per-profile access), so it was wrong to use the default account name.
+This fixes a rare configuration where the user is:
+
+- using a non-default profile,
+- requires SMTP auth,
+- *and* uses a different set of credentials for SMTP access compared to IMAP.
+
+Change-Id: Id6d341d14bf795943d8f3b7b42fac587a062141d
+---
+ src/Gui/ComposeWidget.cpp | 4 ----
+ src/Gui/SettingsDialog.cpp | 4 +++-
+ 2 files changed, 3 insertions(+), 5 deletions(-)
+
+diff --git a/src/Gui/ComposeWidget.cpp b/src/Gui/ComposeWidget.cpp
+index 104d2790..9fb3192a 100644
+--- a/src/Gui/ComposeWidget.cpp
++++ b/src/Gui/ComposeWidget.cpp
+@@ -660,10 +660,6 @@ void ComposeWidget::passwordRequested(const QString &user, const QString &host)
+ return;
+ }
+
+- // FIXME: use another account-id at some point in future
+- // we are now using the profile to avoid overwriting passwords of
+- // other profiles in secure storage
+- // 'account-0' is the hardcoded value when not using a profile
+ Plugins::PasswordJob *job = password->requestPassword(m_submission->accountId(), QStringLiteral("smtp"));
+ if (!job) {
+ askPassword(user, host);
+diff --git a/src/Gui/SettingsDialog.cpp b/src/Gui/SettingsDialog.cpp
+index a6e9b6b6..2eeb8b12 100644
+--- a/src/Gui/SettingsDialog.cpp
++++ b/src/Gui/SettingsDialog.cpp
+@@ -1078,7 +1078,9 @@ OutgoingPage::OutgoingPage(SettingsDialog *parent, QSettings &s): QScrollArea(pa
+ connect(smtpBurl, &QAbstractButton::toggled, m_smtpAccountSettings, &MSA::Account::setUseBurl);
+ connect(sendmail, &LineEdit::textEditingFinished, m_smtpAccountSettings, &MSA::Account::setPathToSendmail);
+
+- m_pwWatcher = new UiUtils::PasswordWatcher(this, m_parent->pluginManager(), QStringLiteral("account-0"), QStringLiteral("smtp"));
++ m_pwWatcher = new UiUtils::PasswordWatcher(this, m_parent->pluginManager(),
++ profileName.isEmpty() ? QStringLiteral("account-0") : profileName,
++ QStringLiteral("smtp"));
+ connect(m_pwWatcher, &UiUtils::PasswordWatcher::stateChanged, this, &OutgoingPage::updateWidgets);
+ connect(m_pwWatcher, &UiUtils::PasswordWatcher::savingFailed, this, &OutgoingPage::saved);
+ connect(m_pwWatcher, &UiUtils::PasswordWatcher::savingDone, this, &OutgoingPage::saved);
+--
+GitLab
+
diff --git a/user/trojita/segfault-sorting-mailboxes.patch b/user/trojita/segfault-sorting-mailboxes.patch
new file mode 100644
index 000000000..833110983
--- /dev/null
+++ b/user/trojita/segfault-sorting-mailboxes.patch
@@ -0,0 +1,72 @@
+From d4e01b6b2cf476f4892b24bdeaae67f5b9ed2ee2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jkt@kde.org>
+Date: Tue, 1 Feb 2022 21:04:14 +0100
+Subject: [PATCH] MailboxNameComparator: implement "less than", not "less or
+ equal"
+
+This comparator is used for "natural order" sorting of mailboxes. The
+usual way of sorting is via a functor which satisfies the Compare [1]
+C++ named requirement, which is effectively a "less than" operation.
+This code implemented a less-than-or-equal, which means that it was not
+usable for `std::sort` which would segfault:
+
+ 0x00007ffff354a35d in __dynamic_cast () from /nix/store/b0p7nvkwxr65q016zsqicrd4bcg5bv1s-gcc-10.3.0-lib/lib/libstdc++.so.6
+ (gdb) bt
+ #0 0x00007ffff354a35d in __dynamic_cast () from /nix/store/b0p7nvkwxr65q016zsqicrd4bcg5bv1s-gcc-10.3.0-lib/lib/libstdc++.so.6
+ #1 0x00000000005d316c in (anonymous namespace)::MailboxNameComparator (a=0x520041004d005c, b=0x12ac740) at /home/jkt/work/prog/trojita/src/Imap/Model/Model.cpp:74
+ #2 0x00000000005e1d46 in __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(Imap::Mailbox::TreeItem const*, Imap::Mailbox::TreeItem const*)>::operator()<QTypedArrayData<Imap::Mailbox::TreeItem*>::iterator, QTypedArrayData<Imap::Mailbox::TreeItem*>::iterator> (__it2=..., __it1=..., this=<synthetic pointer>) at /nix/store/v819nrv8d33ns36gm4v9vqydq1v95axi-gcc-10.3.0/include/c++/10.3.0/bits/stl_algo.h:1909
+ #3 std::__unguarded_partition<QTypedArrayData<Imap::Mailbox::TreeItem*>::iterator, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(Imap::Mailbox::TreeItem const*, Imap::Mailbox::TreeItem const*)> > (__comp=..., __pivot=..., __last=..., __first=...)
+ at /nix/store/v819nrv8d33ns36gm4v9vqydq1v95axi-gcc-10.3.0/include/c++/10.3.0/bits/stl_algo.h:1909
+ #4 std::__unguarded_partition_pivot<QTypedArrayData<Imap::Mailbox::TreeItem*>::iterator, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(Imap::Mailbox::TreeItem const*, Imap::Mailbox::TreeItem const*)> > (__comp=..., __last=..., __first=...)
+ at /nix/store/v819nrv8d33ns36gm4v9vqydq1v95axi-gcc-10.3.0/include/c++/10.3.0/bits/stl_algo.h:1931
+ #5 std::__introsort_loop<QTypedArrayData<Imap::Mailbox::TreeItem*>::iterator, int, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(Imap::Mailbox::TreeItem const*, Imap::Mailbox::TreeItem const*)> > (__first=..., __last=...,
+ __depth_limit=<optimized out>, __depth_limit@entry=9, __comp=__comp@entry=...) at /nix/store/v819nrv8d33ns36gm4v9vqydq1v95axi-gcc-10.3.0/include/c++/10.3.0/bits/stl_algo.h:1962
+ #6 0x00000000005e1db8 in std::__introsort_loop<QTypedArrayData<Imap::Mailbox::TreeItem*>::iterator, int, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(Imap::Mailbox::TreeItem const*, Imap::Mailbox::TreeItem const*)> > (__first=..., __last=...,
+ __depth_limit=<optimized out>, __depth_limit@entry=10, __comp=__comp@entry=...) at /nix/store/v819nrv8d33ns36gm4v9vqydq1v95axi-gcc-10.3.0/include/c++/10.3.0/bits/stl_algo.h:1964
+ #7 0x00000000005dd6fd in std::__sort<QTypedArrayData<Imap::Mailbox::TreeItem*>::iterator, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(Imap::Mailbox::TreeItem const*, Imap::Mailbox::TreeItem const*)> > (__comp=..., __last=..., __first=...)
+ at /nix/store/v819nrv8d33ns36gm4v9vqydq1v95axi-gcc-10.3.0/include/c++/10.3.0/bits/stl_algo.h:1979
+ #8 std::sort<QTypedArrayData<Imap::Mailbox::TreeItem*>::iterator, bool (*)(Imap::Mailbox::TreeItem const*, Imap::Mailbox::TreeItem const*)> (__first=..., __last=..., __first=..., __last=...,
+ __comp=0x5d3130 <(anonymous namespace)::MailboxNameComparator(Imap::Mailbox::TreeItem const*, Imap::Mailbox::TreeItem const*)>) at /nix/store/v819nrv8d33ns36gm4v9vqydq1v95axi-gcc-10.3.0/include/c++/10.3.0/bits/stl_algo.h:4899
+ #9 Imap::Mailbox::Model::finalizeList (this=0xbfbdb0, parser=<optimized out>, mailboxPtr=0x7ffffffe4438) at /home/jkt/work/prog/trojita/src/Imap/Model/Model.cpp:352
+ #10 0x000000000061d512 in Imap::Mailbox::ListChildMailboxesTask::handleStateHelper (this=0x124d790, resp=0x124e840) at /home/jkt/work/prog/trojita/src/Imap/Tasks/ListChildMailboxesTask.cpp:96
+ #11 0x00000000005deadc in Imap::Mailbox::Model::responseReceived (this=0xbfbdb0, it=...) at /home/jkt/work/prog/trojita/src/Imap/Model/Model.cpp:220
+ #12 0x00007ffff396918c in QObject::event(QEvent*) () from /nix/store/fwc2c76yqyyj0pj6abvsyzlgd2r1rvr0-qtbase-5.15.3/lib/libQt5Core.so.5
+ #13 0x00007ffff441776f in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from /nix/store/fwc2c76yqyyj0pj6abvsyzlgd2r1rvr0-qtbase-5.15.3/lib/libQt5Widgets.so.5
+ #14 0x00007ffff393c40a in QCoreApplication::notifyInternal2(QObject*, QEvent*) () from /nix/store/fwc2c76yqyyj0pj6abvsyzlgd2r1rvr0-qtbase-5.15.3/lib/libQt5Core.so.5
+ #15 0x00007ffff393f451 in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) () from /nix/store/fwc2c76yqyyj0pj6abvsyzlgd2r1rvr0-qtbase-5.15.3/lib/libQt5Core.so.5
+ #16 0x00007ffff3994d93 in ?? () from /nix/store/fwc2c76yqyyj0pj6abvsyzlgd2r1rvr0-qtbase-5.15.3/lib/libQt5Core.so.5
+ #17 0x00007ffff1883aab in g_main_context_dispatch () from /nix/store/1qiv23m1q9fk18rwkzrk29ciz87030lp-glib-2.70.1/lib/libglib-2.0.so.0
+ #18 0x00007ffff1883d58 in g_main_context_iterate.constprop () from /nix/store/1qiv23m1q9fk18rwkzrk29ciz87030lp-glib-2.70.1/lib/libglib-2.0.so.0
+ #19 0x00007ffff1883e0f in g_main_context_iteration () from /nix/store/1qiv23m1q9fk18rwkzrk29ciz87030lp-glib-2.70.1/lib/libglib-2.0.so.0
+ #20 0x00007ffff39943f0 in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /nix/store/fwc2c76yqyyj0pj6abvsyzlgd2r1rvr0-qtbase-5.15.3/lib/libQt5Core.so.5
+ #21 0x00007ffff393adab in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () from /nix/store/fwc2c76yqyyj0pj6abvsyzlgd2r1rvr0-qtbase-5.15.3/lib/libQt5Core.so.5
+ #22 0x00007ffff39433a0 in QCoreApplication::exec() () from /nix/store/fwc2c76yqyyj0pj6abvsyzlgd2r1rvr0-qtbase-5.15.3/lib/libQt5Core.so.5
+ #23 0x000000000047fafb in main (argc=<optimized out>, argv=0x7ffffffe4b80) at /home/jkt/work/prog/trojita/src/Gui/main.cpp:205
+
+[1] https://en.cppreference.com/w/cpp/named_req/Compare
+
+Change-Id: Ib88e377fafc94de7160c63832c8115756d360732
+---
+ src/Imap/Model/Model.cpp | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/Imap/Model/Model.cpp b/src/Imap/Model/Model.cpp
+index 79e34658..1d539e22 100644
+--- a/src/Imap/Model/Model.cpp
++++ b/src/Imap/Model/Model.cpp
+@@ -76,10 +76,10 @@ bool MailboxNameComparator(const TreeItem *const a, const TreeItem *const b)
+ const TreeItemMailbox *const mailboxB = dynamic_cast<const TreeItemMailbox *const>(b);
+
+ if (mailboxA->mailbox() == QLatin1String("INBOX"))
+- return true;
++ return mailboxB->mailbox() != QLatin1String("INBOX");
+ if (mailboxB->mailbox() == QLatin1String("INBOX"))
+ return false;
+- return mailboxA->mailbox().compare(mailboxB->mailbox(), Qt::CaseInsensitive) < 1;
++ return mailboxA->mailbox().compare(mailboxB->mailbox(), Qt::CaseInsensitive) < 0;
+ }
+
+ bool uidComparator(const TreeItem *const item, const uint uid)
+--
+GitLab
+
diff --git a/user/trojita/signedness.patch b/user/trojita/signedness.patch
new file mode 100644
index 000000000..693baf67a
--- /dev/null
+++ b/user/trojita/signedness.patch
@@ -0,0 +1,71 @@
+From e4478df9389894b6498ffe252310cdecd1e58904 Mon Sep 17 00:00:00 2001
+From: Vicente Bergas <vicencb@gmail.com>
+Date: Sat, 3 Feb 2018 19:02:38 +0100
+Subject: [PATCH] Fix signed vs. unsigned math on ARM
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+On ARM systems, `char` is not signed, but unsigned, and therefore code
+like qMin(-11, ...) doesn't really do a correct thing.
+
+Change-Id: I1e03570c8a809cd6d8c699b3bc138a6bd05ce53c
+Signed-off-by: Jan Kundrát <jkt@kde.org>
+---
+ src/Gui/Spinner.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/Gui/Spinner.h b/src/Gui/Spinner.h
+index b8b06b85..2f60ce45 100644
+--- a/src/Gui/Spinner.h
++++ b/src/Gui/Spinner.h
+@@ -82,8 +82,8 @@ private slots:
+ void updateAncestors();
+ void updateGeometry();
+ private:
+- uchar m_step;
+- char m_fadeStep;
++ int m_step;
++ int m_fadeStep;
+ int m_timer;
+ QTimer *m_startTimer;
+ QList<QWidget*> m_ancestors;
+--
+GitLab
+
+From 2202821fad977923d2f69c044ad09b3dc46c804a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jkt@kde.org>
+Date: Fri, 24 Aug 2018 13:44:34 +0200
+Subject: [PATCH] Fix comparison of integer expressions of different signedness
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+ src/Imap/Model/ModelTest/modeltest.cpp: In member function ‘void ModelTest::data()’:
+ src/Imap/Model/ModelTest/modeltest.cpp:422:27: error: comparison of integer expressions of different signedness: ‘int’ and ‘QFlags<Qt::AlignmentFlag>::Int’ {aka ‘unsigned int’} [-Werror=sign-compare]
+ Q_ASSERT(alignment == (alignment & (Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask)));
+ ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Change-Id: I7007e1c0cba20b31d76f6426548ad4fb43480017
+---
+ src/Imap/Model/ModelTest/modeltest.cpp | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/Imap/Model/ModelTest/modeltest.cpp b/src/Imap/Model/ModelTest/modeltest.cpp
+index 24046a24..d2c8fcac 100644
+--- a/src/Imap/Model/ModelTest/modeltest.cpp
++++ b/src/Imap/Model/ModelTest/modeltest.cpp
+@@ -418,8 +418,8 @@ void ModelTest::data()
+ // Check that the alignment is one we know about
+ QVariant textAlignmentVariant = model->data(model->index(0, 0), Qt::TextAlignmentRole);
+ if (textAlignmentVariant.isValid()) {
+- int alignment = textAlignmentVariant.toInt();
+- Q_ASSERT(alignment == (alignment & (Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask)));
++ unsigned int alignment = textAlignmentVariant.toUInt();
++ Q_ASSERT(alignment == (alignment & (Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask)));
+ }
+
+ // General Purpose roles that should return a QColor
+--
+GitLab
+
diff --git a/user/trojita/statusbar-fix.patch b/user/trojita/statusbar-fix.patch
new file mode 100644
index 000000000..4eb556465
--- /dev/null
+++ b/user/trojita/statusbar-fix.patch
@@ -0,0 +1,167 @@
+From 654188c2806c376a4c2b9cdf44e48172c2255a18 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jkt@kde.org>
+Date: Mon, 3 Oct 2016 22:09:17 +0200
+Subject: [PATCH] GUI: Prevent excessive newlines in the PartStatusWidget
+ crypto messages
+
+Previously, there were extra newlines in certain scenarios. The long
+text should never begin with a stray newline.
+
+This might make it easier to see the linked bug.
+
+Change-Id: I72188b08f1562b6cdd30849f9958fdcc9f0504b7
+CCBUG: 369832
+---
+ src/Cryptography/GpgMe++.cpp | 65 ++++++++++++++++++++++++------------
+ 1 file changed, 44 insertions(+), 21 deletions(-)
+
+diff --git a/src/Cryptography/GpgMe++.cpp b/src/Cryptography/GpgMe++.cpp
+index 54275f73..e2fcdfe7 100644
+--- a/src/Cryptography/GpgMe++.cpp
++++ b/src/Cryptography/GpgMe++.cpp
+@@ -290,6 +290,8 @@ QVariant GpgMePart::data(int role) const
+ }
+ }
+
++#define ENSURE_LINE_LF(X) do { if (!X.isEmpty()) { X += LF; } } while (0)
++
+ void GpgMePart::extractSignatureStatus(std::shared_ptr<GpgME::Context> ctx, const GpgME::Signature &sig,
+ const std::vector<std::string> messageUids, const bool wasSigned, const bool wasEncrypted,
+ bool &sigOkDisregardingTrust, bool &sigValidVerified,
+@@ -447,30 +449,38 @@ void GpgMePart::extractSignatureStatus(std::shared_ptr<GpgME::Context> ctx, cons
+
+ // extract the individual error bits
+ if (sig.summary() & GpgME::Signature::KeyRevoked) {
+- longStatus += LF + tr("The key or at least one certificate has been revoked.");
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("The key or at least one certificate has been revoked.");
+ }
+ if (sig.summary() & GpgME::Signature::KeyExpired) {
+ // FIXME: how to get the expiration date?
+- longStatus += LF + tr("The key or one of the certificates has expired.");
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("The key or one of the certificates has expired.");
+ }
+ if (sig.summary() & GpgME::Signature::SigExpired) {
+- longStatus += LF + tr("Signature expired on %1.")
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("Signature expired on %1.")
+ .arg(QDateTime::fromTime_t(sig.expirationTime()).toString(Qt::DefaultLocaleShortDate));
+ }
+ if (sig.summary() & GpgME::Signature::KeyMissing) {
+- longStatus += LF + tr("Can't verify due to a missing key or certificate.");
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("Can't verify due to a missing key or certificate.");
+ }
+ if (sig.summary() & GpgME::Signature::CrlMissing) {
+- longStatus += LF + tr("The CRL (or an equivalent mechanism) is not available.");
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("The CRL (or an equivalent mechanism) is not available.");
+ }
+ if (sig.summary() & GpgME::Signature::CrlTooOld) {
+- longStatus += LF + tr("Available CRL is too old.");
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("Available CRL is too old.");
+ }
+ if (sig.summary() & GpgME::Signature::BadPolicy) {
+- longStatus += LF + tr("A policy requirement was not met.");
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("A policy requirement was not met.");
+ }
+ if (sig.summary() & GpgME::Signature::SysError) {
+- longStatus += LF + tr("A system error occurred. %1")
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("A system error occurred. %1")
+ .arg(QString::fromUtf8(sig.status().asString()));
+ }
+
+@@ -478,22 +488,28 @@ void GpgMePart::extractSignatureStatus(std::shared_ptr<GpgME::Context> ctx, cons
+ // Extract signature validity
+ switch (sig.validity()) {
+ case GpgME::Signature::Undefined:
+- longStatus += LF + tr("Signature validity is undefined.");
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("Signature validity is undefined.");
+ break;
+ case GpgME::Signature::Never:
+- longStatus += LF + tr("Signature validity is never to be trusted.");
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("Signature validity is never to be trusted.");
+ break;
+ case GpgME::Signature::Marginal:
+- longStatus += LF + tr("Signature validity is marginal.");
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("Signature validity is marginal.");
+ break;
+ case GpgME::Signature::Full:
+- longStatus += LF + tr("Signature validity is full.");
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("Signature validity is full.");
+ break;
+ case GpgME::Signature::Ultimate:
+- longStatus += LF + tr("Signature validity is ultimate.");
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("Signature validity is ultimate.");
+ break;
+ case GpgME::Signature::Unknown:
+- longStatus += LF + tr("Signature validity is unknown.");
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("Signature validity is unknown.");
+ break;
+ }
+ }
+@@ -844,7 +860,8 @@ void GpgMeEncrypted::handleDataChanged(const QModelIndex &topLeft, const QModelI
+ if (tldr.isEmpty()) {
+ tldr = tr("Broken encrypted message");
+ }
+- longStatus += LF + tr("Decryption error: %1").arg(QString::fromUtf8(combinedResult.first.error().asString()));
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("Decryption error: %1").arg(QString::fromUtf8(combinedResult.first.error().asString()));
+ icon = QStringLiteral("emblem-error");
+ } else if (tldr.isEmpty()) {
+ tldr = tr("Encrypted message");
+@@ -852,29 +869,35 @@ void GpgMeEncrypted::handleDataChanged(const QModelIndex &topLeft, const QModelI
+ }
+
+ if (combinedResult.first.isWrongKeyUsage()) {
+- longStatus += LF + tr("Wrong key usage, not for encryption");
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("Wrong key usage, not for encryption");
+ }
+ if (auto msg = combinedResult.first.unsupportedAlgorithm()) {
+- longStatus += LF + tr("Unsupported algorithm: %1").arg(QString::fromUtf8(msg));
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("Unsupported algorithm: %1").arg(QString::fromUtf8(msg));
+ }
+
+ for (const auto &recipient: combinedResult.first.recipients()) {
+ GpgME::Error keyError;
+ auto key = ctx->key(recipient.keyID(), keyError, false);
+ if (keyError) {
+- longStatus += LF + tr("Cannot extract recipient %1: %2")
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("Cannot extract recipient %1: %2")
+ .arg(QString::fromUtf8(recipient.keyID()), QString::fromUtf8(keyError.asString()));
+ } else {
+ if (key.numUserIDs()) {
+- longStatus += LF + tr("Encrypted to %1 (%2)")
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("Encrypted to %1 (%2)")
+ .arg(QString::fromUtf8(key.userID(0).id()), QString::fromUtf8(recipient.keyID()));
+ } else {
+- longStatus += LF + tr("Encrypted to %1").arg(QString::fromUtf8(recipient.keyID()));
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("Encrypted to %1").arg(QString::fromUtf8(recipient.keyID()));
+ }
+ }
+ }
+ if (auto fname = combinedResult.first.fileName()) {
+- longStatus += LF + tr("Original filename: %1").arg(QString::fromUtf8(fname));
++ ENSURE_LINE_LF(longStatus);
++ longStatus += tr("Original filename: %1").arg(QString::fromUtf8(fname));
+ }
+
+ if (p) {
+--
+GitLab
+
diff --git a/user/trojita/testfix.patch b/user/trojita/testfix.patch
new file mode 100644
index 000000000..efe36d053
--- /dev/null
+++ b/user/trojita/testfix.patch
@@ -0,0 +1,85 @@
+Required for plaintext-upgrade-attack.patch to run successfully.
+
+From 91d19cb8530cb8df6ec0ee0580abcd98f1957395 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jkt@kde.org>
+Date: Mon, 5 Sep 2016 12:47:28 +0200
+Subject: [PATCH] tests: fix more memleaks
+
+There's some progress, but still plenty of stuff to do:
+
+-SUMMARY: AddressSanitizer: 77490 byte(s) leaked in 1010 allocation(s).
++SUMMARY: AddressSanitizer: 7720 byte(s) leaked in 95 allocation(s).
+
+Change-Id: I133fda902a9bd3f9fe697d7ffe8c57a159c887d8
+---
+ tests/Imap/test_Imap_Tasks_OpenConnection.cpp | 16 ++++++++--------
+ tests/Imap/test_Imap_Tasks_OpenConnection.h | 14 +++++++-------
+ 2 files changed, 15 insertions(+), 15 deletions(-)
+
+diff --git a/tests/Imap/test_Imap_Tasks_OpenConnection.cpp b/tests/Imap/test_Imap_Tasks_OpenConnection.cpp
+index b3a95636..c40297ab 100644
+--- a/tests/Imap/test_Imap_Tasks_OpenConnection.cpp
++++ b/tests/Imap/test_Imap_Tasks_OpenConnection.cpp
+@@ -35,12 +35,11 @@ void ImapModelOpenConnectionTest::initTestCase()
+ {
+ LibMailboxSync::initTestCase();
+ qRegisterMetaType<Imap::Mailbox::ImapTask*>();
+- completedSpy = 0;
+- m_enableAutoLogin = true;
+ }
+
+ void ImapModelOpenConnectionTest::init()
+ {
++ m_enableAutoLogin = true;
+ reinit(TlsRequired::No);
+ }
+
+@@ -56,13 +55,14 @@ void ImapModelOpenConnectionTest::reinit(const TlsRequired tlsRequired)
+ connect(model, &Imap::Mailbox::Model::needsSslDecision, this, &ImapModelOpenConnectionTest::acceptSsl, Qt::QueuedConnection);
+ LibMailboxSync::setModelNetworkPolicy(model, Imap::Mailbox::NETWORK_ONLINE);
+ QCoreApplication::processEvents();
++ delete task;
+ task = new Imap::Mailbox::OpenConnectionTask(model);
+- completedSpy = new QSignalSpy(task, SIGNAL(completed(Imap::Mailbox::ImapTask*)));
+- failedSpy = new QSignalSpy(task, SIGNAL(failed(QString)));
+- authSpy = new QSignalSpy(model, SIGNAL(authRequested()));
+- connErrorSpy = new QSignalSpy(model, SIGNAL(imapError(QString)));
+- startTlsUpgradeSpy = new QSignalSpy(model, SIGNAL(requireStartTlsInFuture()));
+- authErrorSpy = new QSignalSpy(model, SIGNAL(imapAuthErrorChanged(const QString&)));
++ completedSpy.reset(new QSignalSpy(task, SIGNAL(completed(Imap::Mailbox::ImapTask*))));
++ failedSpy.reset(new QSignalSpy(task, SIGNAL(failed(QString))));
++ authSpy.reset(new QSignalSpy(model, SIGNAL(authRequested())));
++ connErrorSpy.reset(new QSignalSpy(model, SIGNAL(imapError(QString))));
++ startTlsUpgradeSpy.reset(new QSignalSpy(model, SIGNAL(requireStartTlsInFuture())));
++ authErrorSpy.reset(new QSignalSpy(model, SIGNAL(imapAuthErrorChanged(const QString&))));
+ t.reset();
+ }
+
+diff --git a/tests/Imap/test_Imap_Tasks_OpenConnection.h b/tests/Imap/test_Imap_Tasks_OpenConnection.h
+index 30f531a2..4df65c05 100644
+--- a/tests/Imap/test_Imap_Tasks_OpenConnection.h
++++ b/tests/Imap/test_Imap_Tasks_OpenConnection.h
+@@ -78,13 +78,13 @@ protected:
+ void reinit(const TlsRequired tlsRequired = TlsRequired::No);
+
+ private:
+- Imap::Mailbox::OpenConnectionTask* task;
+- QSignalSpy* completedSpy;
+- QSignalSpy* failedSpy;
+- QSignalSpy* authSpy;
+- QSignalSpy *connErrorSpy;
+- QSignalSpy *startTlsUpgradeSpy;
+- QSignalSpy *authErrorSpy;
++ QPointer<Imap::Mailbox::OpenConnectionTask> task;
++ std::unique_ptr<QSignalSpy> completedSpy;
++ std::unique_ptr<QSignalSpy> failedSpy;
++ std::unique_ptr<QSignalSpy> authSpy;
++ std::unique_ptr<QSignalSpy> connErrorSpy;
++ std::unique_ptr<QSignalSpy> startTlsUpgradeSpy;
++ std::unique_ptr<QSignalSpy> authErrorSpy;
+
+ bool m_enableAutoLogin;
+ };
+--
+GitLab
+