diff --git a/package/lean/qBittorrent/Makefile b/package/lean/qBittorrent/Makefile
index 3bd02e265..7ef3b1d22 100644
--- a/package/lean/qBittorrent/Makefile
+++ b/package/lean/qBittorrent/Makefile
@@ -1,12 +1,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=qbittorrent
-PKG_VERSION:=4.1.9
-PKG_RELEASE=5
+PKG_VERSION:=4.2.0
+PKG_RELEASE=1
PKG_SOURCE:=$(PKG_NAME)-release-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/qbittorrent/qBittorrent/tar.gz/release-$(PKG_VERSION)?
-PKG_HASH:=620127f73f88ed3f2b2e4195cbc641f7c27f967d3b045e45f7916c0995fd61fe
+PKG_HASH:=2f367b89d7049c09e808fc5f7c338ce1820d91bcaecddcad681e9ba18b13206d
PKG_BUILD_DIR:=$(BUILD_DIR)/qBittorrent-release-$(PKG_VERSION)
diff --git a/package/lean/qBittorrent/patches/001-remove-ico-not-for-webui.patch b/package/lean/qBittorrent/patches/001-remove-ico-not-for-webui.patch
deleted file mode 100644
index ee27bbaca..000000000
--- a/package/lean/qBittorrent/patches/001-remove-ico-not-for-webui.patch
+++ /dev/null
@@ -1,126 +0,0 @@
---- a/src/icons/icons.qrc
-+++ b/src/icons/icons.qrc
-@@ -250,38 +250,16 @@
- flags/zm.svg
- flags/zw.svg
- L.gif
-- loading.png
- qbt-theme/application-exit.svg
-- qbt-theme/application-rss+xml.svg
-- qbt-theme/application-x-mswinurl.svg
- qbt-theme/checked.svg
- qbt-theme/configure.svg
-- qbt-theme/dialog-cancel.svg
-- qbt-theme/dialog-information.svg
-- qbt-theme/dialog-warning.svg
- qbt-theme/document-edit-verify.svg
- qbt-theme/document-edit.svg
-- qbt-theme/document-encrypt.svg
-- qbt-theme/document-import.svg
-- qbt-theme/document-new.svg
-- qbt-theme/document-properties.svg
-- qbt-theme/document-save.svg
-- qbt-theme/download.svg
-- qbt-theme/edit-clear-history.svg
- qbt-theme/edit-clear.svg
- qbt-theme/edit-copy.svg
-- qbt-theme/edit-cut.svg
- qbt-theme/edit-delete.svg
-- qbt-theme/edit-find-user.svg
- qbt-theme/edit-find.svg
-- qbt-theme/edit-paste.svg
- qbt-theme/edit-rename.svg
-- qbt-theme/folder-documents.svg
-- qbt-theme/folder-download.svg
-- qbt-theme/folder-new.svg
-- qbt-theme/folder-remote.svg
-- qbt-theme/gear.svg
-- qbt-theme/gear32.svg
- qbt-theme/go-bottom.svg
- qbt-theme/go-down.svg
- qbt-theme/go-top.svg
-@@ -295,43 +273,15 @@
- qbt-theme/kt-set-max-upload-speed.png
- qbt-theme/list-add.svg
- qbt-theme/list-remove.svg
-- qbt-theme/mail-folder-inbox.svg
-- qbt-theme/mail-mark-read.svg
- qbt-theme/media-playback-pause.svg
- qbt-theme/media-playback-start.svg
- qbt-theme/media-seek-forward.svg
-- qbt-theme/network-server.svg
-- qbt-theme/network-wired.svg
-- qbt-theme/object-locked.svg
-- qbt-theme/office-chart-line.svg
-- qbt-theme/preferences-desktop.svg
-- qbt-theme/preferences-other.svg
-- qbt-theme/preferences-system-network.svg
-- qbt-theme/preferences-web-browser-cookies.svg
-- qbt-theme/rss-config.png
- qbt-theme/security-high.svg
- qbt-theme/security-low.svg
-- qbt-theme/services.svg
-- qbt-theme/speedometer.svg
- qbt-theme/system-log-out.svg
-- qbt-theme/tab-close.svg
-- qbt-theme/task-attention.svg
-- qbt-theme/task-complete.png
-- qbt-theme/task-ongoing.png
-- qbt-theme/task-reject.png
-- qbt-theme/text-plain.svg
-- qbt-theme/tools-report-bug.svg
-- qbt-theme/unavailable.svg
-- qbt-theme/user-group-delete.svg
-- qbt-theme/user-group-new.svg
-- qbt-theme/view-calendar-journal.svg
- qbt-theme/view-categories.svg
-- qbt-theme/view-filter.svg
-- qbt-theme/view-preview.svg
-- qbt-theme/view-refresh.svg
- qbt-theme/view-statistics.svg
- qbt-theme/wallet-open.svg
-- qbt-theme/webui.svg
- skin/arrow-right.gif
- skin/bg-dropdown.gif
- skin/bg-handle-horizontal.gif
-@@ -342,7 +292,6 @@
- skin/completed.svg
- skin/connected.svg
- skin/disconnected.svg
-- skin/dock-tabs.gif
- skin/download.svg
- skin/downloading.svg
- skin/error.svg
-@@ -353,14 +302,11 @@
- skin/handle-icon-horizontal.gif
- skin/handle-icon.gif
- skin/knob.gif
-- skin/logo-blank.gif
- skin/logo.gif
- skin/logo2.gif
- skin/mascot.png
- skin/paused.svg
- skin/qbittorrent-tray.svg
-- skin/qbittorrent-tray-dark.svg
-- skin/qbittorrent-tray-light.svg
- skin/qbittorrent32.png
- skin/queued.svg
- skin/ratio.svg
-@@ -370,17 +316,12 @@
- skin/spacer.gif
- skin/spinner-placeholder.gif
- skin/spinner.gif
-- skin/splash.png
- skin/stalledDL.svg
- skin/stalledUP.svg
- skin/tabs.gif
- skin/toolbox-divider.gif
-- skin/toolbox-divider2.gif
- skin/uploading.svg
- slow.png
- slow_off.png
-- sphere.png
-- sphere2.png
-- url.png
-
-
diff --git a/package/lean/qBittorrent/patches/002-add-autoban-function.patch b/package/lean/qBittorrent/patches/002-add-autoban-function.patch
deleted file mode 100644
index 8de0f1e47..000000000
--- a/package/lean/qBittorrent/patches/002-add-autoban-function.patch
+++ /dev/null
@@ -1,807 +0,0 @@
---- a/src/base/bittorrent/peerinfo.cpp
-+++ b/src/base/bittorrent/peerinfo.cpp
-@@ -186,11 +186,26 @@ PeerAddress PeerInfo::address() const
- m_nativeInfo.ip.port());
- }
-
-+int PeerInfo::port() const
-+{
-+ return m_nativeInfo.ip.port();
-+}
-+
- QString PeerInfo::client() const
- {
- return QString::fromStdString(m_nativeInfo.client);
- }
-
-+QString PeerInfo::pid() const
-+{
-+ return QString::fromStdString(m_nativeInfo.pid.to_string());
-+}
-+
-+QString PeerInfo::pidtoclient() const
-+{
-+ return QString::fromStdString(libt::identify_client(m_nativeInfo.pid));
-+}
-+
- qreal PeerInfo::progress() const
- {
- return m_nativeInfo.progress;
---- a/src/base/bittorrent/peerinfo.h
-+++ b/src/base/bittorrent/peerinfo.h
-@@ -34,6 +34,7 @@
- #include
-
- #include
-+#include
-
- namespace BitTorrent
- {
-@@ -85,7 +86,10 @@ namespace BitTorrent
- bool isPlaintextEncrypted() const;
-
- PeerAddress address() const;
-+ int port() const;
- QString client() const;
-+ QString pid() const;
-+ QString pidtoclient() const;
- qreal progress() const;
- int payloadUpSpeed() const;
- int payloadDownSpeed() const;
---- a/src/base/bittorrent/session.cpp
-+++ b/src/base/bittorrent/session.cpp
-@@ -69,6 +69,7 @@
- #endif
-
- #include "base/algorithm.h"
-+#include "base/bittorrent/peerinfo.h"
- #include "base/exceptions.h"
- #include "base/global.h"
- #include "base/logger.h"
-@@ -335,6 +336,8 @@ Session::Session(QObject *parent)
- , m_isAltGlobalSpeedLimitEnabled(BITTORRENT_SESSION_KEY("UseAlternativeGlobalSpeedLimit"), false)
- , m_isBandwidthSchedulerEnabled(BITTORRENT_SESSION_KEY("BandwidthSchedulerEnabled"), false)
- , m_saveResumeDataInterval(BITTORRENT_SESSION_KEY("SaveResumeDataInterval"), 60)
-+ , m_autoBanUnknownPeer(BITTORRENT_SESSION_KEY("AutoBanUnknownPeer"), true)
-+ , m_showTrackerAuthWindow(BITTORRENT_SESSION_KEY("ShowTrackerAuthWindow"), true)
- , m_port(BITTORRENT_SESSION_KEY("Port"), 8999)
- , m_useRandomPort(BITTORRENT_SESSION_KEY("UseRandomPort"), false)
- , m_networkInterface(BITTORRENT_SESSION_KEY("Interface"))
-@@ -502,6 +505,7 @@ Session::Session(QObject *parent)
- libt::ip_filter filter;
- processBannedIPs(filter);
- m_nativeSession->set_ip_filter(filter);
-+ loadOfflineFilter();
- }
-
- m_categories = map_cast(m_storedCategories);
-@@ -518,6 +522,17 @@ Session::Session(QObject *parent)
- connect(m_refreshTimer, &QTimer::timeout, this, &Session::refresh);
- m_refreshTimer->start();
-
-+ // Unban Timer
-+ m_unbanTimer = new QTimer(this);
-+ m_unbanTimer->setInterval(500);
-+ connect(m_unbanTimer, &QTimer::timeout, this, &Session::processUnbanRequest);
-+
-+ // Ban Timer
-+ m_banTimer = new QTimer(this);
-+ m_banTimer->setInterval(500);
-+ connect(m_banTimer, &QTimer::timeout, this, &Session::autoBanBadClient);
-+ m_banTimer->start();
-+
- m_statistics = new Statistics(this);
-
- updateSeedingLimitTimer();
-@@ -1077,6 +1092,7 @@ void Session::configure()
- enableIPFilter();
- else
- disableIPFilter();
-+ loadOfflineFilter();
- m_IPFilteringChanged = false;
- }
-
-@@ -1905,6 +1921,95 @@ void Session::banIP(const QString &ip)
- }
- }
-
-+bool Session::checkAccessFlags(const QString &ip)
-+{
-+ libt::ip_filter filter = m_nativeSession->get_ip_filter();
-+ boost::system::error_code ec;
-+ libt::address addr = libt::address::from_string(ip.toLatin1().constData(), ec);
-+ Q_ASSERT(!ec);
-+ if (ec) return false;
-+ return filter.access(addr);
-+}
-+
-+void Session::tempblockIP(const QString &ip)
-+{
-+ libt::ip_filter filter = m_nativeSession->get_ip_filter();
-+ boost::system::error_code ec;
-+ libt::address addr = libt::address::from_string(ip.toLatin1().constData(), ec);
-+ Q_ASSERT(!ec);
-+ if (ec) return;
-+ filter.add_rule(addr, addr, libt::ip_filter::blocked);
-+ m_nativeSession->set_ip_filter(filter);
-+ insertQueue(ip);
-+}
-+
-+void Session::removeBlockedIP(const QString &ip)
-+{
-+ libt::ip_filter filter = m_nativeSession->get_ip_filter();
-+ boost::system::error_code ec;
-+ libt::address addr = libt::address::from_string(ip.toLatin1().constData(), ec);
-+ Q_ASSERT(!ec);
-+ if (ec) return;
-+ filter.add_rule(addr, addr, 0);
-+ m_nativeSession->set_ip_filter(filter);
-+}
-+
-+void Session::eraseIPFilter()
-+{
-+ q_bannedIPs.clear();
-+ q_unbanTime.clear();
-+ if (isIPFilteringEnabled()) {
-+ enableIPFilter();
-+ } else {
-+ disableIPFilter();
-+ loadOfflineFilter();
-+ }
-+}
-+
-+void Session::autoBanBadClient()
-+{
-+ const BitTorrent::SessionStatus tStatus = BitTorrent::Session::instance()->status();
-+ if (tStatus.peersCount > 0) {
-+ bool m_AutoBan = BitTorrent::Session::instance()->isAutoBanUnknownPeerEnabled();
-+ foreach (BitTorrent::TorrentHandle *const torrent, BitTorrent::Session::instance()->torrents()) {
-+ QList peers = torrent->peers();
-+ foreach (const BitTorrent::PeerInfo &peer, peers) {
-+ BitTorrent::PeerAddress addr = peer.address();
-+ if (addr.ip.isNull()) continue;
-+ QString ip = addr.ip.toString();
-+ int port = peer.port();
-+ QString client = peer.client();
-+ QString ptoc = peer.pidtoclient();
-+ QString pid = peer.pid().left(8);
-+ QString country = peer.country();
-+
-+ QRegExp IDFilter("-(XL|SD|XF|QD|BN|DL)(\\d+)-");
-+ QRegExp UAFilter("\\d+.\\d+.\\d+.\\d+");
-+ if (IDFilter.exactMatch(pid) || UAFilter.exactMatch(client)) {
-+ qDebug("Auto Banning bad Peer %s...", ip.toLocal8Bit().data());
-+ Logger::instance()->addMessage(tr("Auto banning bad Peer '%1'...'%2'...'%3'...'%4'").arg(ip).arg(pid).arg(ptoc).arg(country));
-+ tempblockIP(ip);
-+ continue;
-+ }
-+
-+ if(m_AutoBan) {
-+ if (client.contains("Unknown") && country == "CN") {
-+ qDebug("Auto Banning Unknown Peer %s...", ip.toLocal8Bit().data());
-+ Logger::instance()->addMessage(tr("Auto banning Unknown Peer '%1'...'%2'...'%3'...'%4'").arg(ip).arg(pid).arg(ptoc).arg(country));
-+ tempblockIP(ip);
-+ continue;
-+ }
-+ if (port >= 65000 && country == "CN" && client.contains("Transmission")) {
-+ qDebug("Auto Banning Offline Downloader %s...", ip.toLocal8Bit().data());
-+ Logger::instance()->addMessage(tr("Auto banning Offline Downloader '%1:%2'...'%3'...'%4'...'%5'").arg(ip).arg(port).arg(pid).arg(ptoc).arg(country));
-+ tempblockIP(ip);
-+ }
-+ }
-+ }
-+ }
-+ }
-+}
-+
- // Delete a torrent from the session, given its hash
- // deleteLocalFiles = true means that the torrent will be removed from the hard-drive too
- bool Session::deleteTorrent(const QString &hash, bool deleteLocalFiles)
-@@ -2787,6 +2892,30 @@ void Session::setSaveResumeDataInterval(
- }
- }
-
-+bool Session::isAutoBanUnknownPeerEnabled() const
-+{
-+ return m_autoBanUnknownPeer;
-+}
-+
-+void Session::setAutoBanUnknownPeer(bool value)
-+{
-+ if (value != isAutoBanUnknownPeerEnabled()) {
-+ m_autoBanUnknownPeer = value;
-+ }
-+}
-+
-+bool Session::isShowTrackerAuthWindow() const
-+{
-+ return m_showTrackerAuthWindow;
-+}
-+
-+void Session::setShowTrackerAuthWindow(bool value)
-+{
-+ if (value != isShowTrackerAuthWindow()) {
-+ m_showTrackerAuthWindow = value;
-+ }
-+}
-+
- int Session::port() const
- {
- static int randomPort = Utils::Random::rand(1024, 65535);
-@@ -3877,6 +4006,220 @@ void Session::disableIPFilter()
- m_nativeSession->set_ip_filter(filter);
- }
-
-+// Insert banned IP to Queue
-+void Session::insertQueue(QString ip)
-+{
-+ q_bannedIPs.enqueue(ip);
-+ q_unbanTime.enqueue(QDateTime::currentMSecsSinceEpoch() + 60 * 60 * 1000);
-+
-+ if (!m_unbanTimer->isActive()) {
-+ m_unbanTimer->start();
-+ }
-+}
-+
-+// Process Unban Queue
-+void Session::processUnbanRequest()
-+{
-+ if (q_bannedIPs.isEmpty() && q_unbanTime.isEmpty()) {
-+ m_unbanTimer->stop();
-+ }
-+ else if (m_isActive) {
-+ return;
-+ }
-+ else {
-+ m_isActive = true;
-+ int64_t currentTime = QDateTime::currentMSecsSinceEpoch();
-+ int64_t nextTime = q_unbanTime.dequeue();
-+ int delayTime = int(nextTime - currentTime);
-+ QString nextIP = q_bannedIPs.dequeue();
-+ if (delayTime < 0) {
-+ QTimer::singleShot(0, [=] { BitTorrent::Session::instance()->removeBlockedIP(nextIP); m_isActive = false; });
-+ }
-+ else {
-+ QTimer::singleShot(delayTime, [=] { BitTorrent::Session::instance()->removeBlockedIP(nextIP); m_isActive = false; });
-+ }
-+ }
-+}
-+
-+// Handle ipfilter.dat
-+int trim(char* const data, int start, int end)
-+{
-+ if (start >= end) return start;
-+ int newStart = start;
-+
-+ for (int i = start; i <= end; ++i) {
-+ if (isspace(data[i]) != 0) {
-+ data[i] = '\0';
-+ }
-+ else {
-+ newStart = i;
-+ break;
-+ }
-+ }
-+
-+ for (int i = end; i >= start; --i) {
-+ if (isspace(data[i]) != 0)
-+ data[i] = '\0';
-+ else
-+ break;
-+ }
-+
-+ return newStart;
-+}
-+
-+int findAndNullDelimiter(char *const data, char delimiter, int start, int end)
-+{
-+ for (int i = start; i <= end; ++i) {
-+ if (data[i] == delimiter) {
-+ data[i] = '\0';
-+ return i;
-+ }
-+ }
-+
-+ return -1;
-+}
-+
-+int Session::parseOfflineFilterFile(QString ipDat, libt::ip_filter &filter)
-+{
-+ int ruleCount = 0;
-+ QFile file(ipDat);
-+ if (!file.exists()) return ruleCount;
-+
-+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
-+ LogMsg(tr("I/O Error: Could not open IP filter file in read mode."), Log::CRITICAL);
-+ return ruleCount;
-+ }
-+
-+ std::vector buffer(2 * 1024 * 1024, 0); // seems a bit faster than QVector
-+ qint64 bytesRead = 0;
-+ int offset = 0;
-+ int start = 0;
-+ int endOfLine = -1;
-+ int nbLine = 0;
-+
-+ while (true) {
-+ bytesRead = file.read(buffer.data() + offset, 2 * 1024 * 1024 - offset - 1);
-+ if (bytesRead < 0)
-+ break;
-+ int dataSize = bytesRead + offset;
-+ if (bytesRead == 0 && dataSize == 0)
-+ break;
-+
-+ for (start = 0; start < dataSize; ++start) {
-+ endOfLine = -1;
-+ // The file might have ended without the last line having a newline
-+ if (!(bytesRead == 0 && dataSize > 0)) {
-+ for (int i = start; i < dataSize; ++i) {
-+ if (buffer[i] == '\n') {
-+ endOfLine = i;
-+ // We need to NULL the newline in case the line has only an IP range.
-+ // In that case the parser won't work for the end IP, because it ends
-+ // with the newline and not with a number.
-+ buffer[i] = '\0';
-+ break;
-+ }
-+ }
-+ }
-+ else {
-+ endOfLine = dataSize;
-+ buffer[dataSize] = '\0';
-+ }
-+
-+ if (endOfLine == -1) {
-+ // read the next chunk from file
-+ // but first move(copy) the leftover data to the front of the buffer
-+ offset = dataSize - start;
-+ memmove(buffer.data(), buffer.data() + start, offset);
-+ break;
-+ }
-+ else {
-+ ++nbLine;
-+ }
-+
-+ if ((buffer[start] == '#')
-+ || ((buffer[start] == '/') && ((start + 1 < dataSize) && (buffer[start + 1] == '/')))) {
-+ start = endOfLine;
-+ continue;
-+ }
-+
-+ // Each line should follow this format:
-+ // 001.009.096.105 - 001.009.096.105 , 000 , Some organization
-+ // The 3rd entry is access level and if above 127 the IP range isn't blocked.
-+ int firstComma = findAndNullDelimiter(buffer.data(), ',', start, endOfLine);
-+ if (firstComma != -1)
-+ findAndNullDelimiter(buffer.data(), ',', firstComma + 1, endOfLine);
-+
-+ // Check if there is an access value (apparently not mandatory)
-+ if (firstComma != -1) {
-+ // There is possibly one
-+ const long int nbAccess = strtol(buffer.data() + firstComma + 1, nullptr, 10);
-+ // Ignoring this rule because access value is too high
-+ if (nbAccess > 127L) {
-+ start = endOfLine;
-+ continue;
-+ }
-+ }
-+
-+ // IP Range should be split by a dash
-+ int endOfIPRange = ((firstComma == -1) ? (endOfLine - 1) : (firstComma - 1));
-+ int delimIP = findAndNullDelimiter(buffer.data(), '-', start, endOfIPRange);
-+ if (delimIP == -1) {
-+ start = endOfLine;
-+ continue;
-+ }
-+
-+ boost::system::error_code ec;
-+ int newStart = trim(buffer.data(), start, delimIP - 1);
-+ libt::address startAddr = libt::address::from_string(buffer.data() + newStart, ec);
-+ Q_ASSERT(!ec);
-+ if (ec) {
-+ start = endOfLine;
-+ continue;
-+ }
-+
-+ newStart = trim(buffer.data(), delimIP + 1, endOfIPRange);
-+ libt::address endAddr = libt::address::from_string(buffer.data() + newStart, ec);
-+ Q_ASSERT(!ec);
-+ if (ec) {
-+ start = endOfLine;
-+ continue;
-+ }
-+
-+ if ((startAddr.is_v4() != endAddr.is_v4())
-+ || (startAddr.is_v6() != endAddr.is_v6())) {
-+ start = endOfLine;
-+ continue;
-+ }
-+
-+ start = endOfLine;
-+
-+ filter.add_rule(startAddr, endAddr, libt::ip_filter::blocked);
-+ ++ruleCount;
-+ }
-+
-+ if (start >= dataSize)
-+ offset = 0;
-+ }
-+
-+ return ruleCount;
-+}
-+
-+void Session::loadOfflineFilter() {
-+ int Count = 0;
-+ libt::ip_filter offlineFilter = m_nativeSession->get_ip_filter();
-+
-+#if defined(Q_OS_WIN)
-+ Count = parseOfflineFilterFile("./ipfilter.dat", offlineFilter);
-+#endif
-+
-+#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
-+ Count = parseOfflineFilterFile(QDir::home().absoluteFilePath(".config")+"/qBittorrent/ipfilter.dat", offlineFilter);
-+#endif
-+
-+ m_nativeSession->set_ip_filter(offlineFilter);
-+ Logger::instance()->addMessage(tr("Successfully parsed the offline downloader IP filter: %1 rules were applied.", "%1 is a number").arg(Count));
-+}
-+
- void Session::recursiveTorrentDownload(const InfoHash &hash)
- {
- TorrentHandle *const torrent = m_torrents.value(hash);
-@@ -4063,6 +4406,7 @@ void Session::handleIPFilterParsed(int r
- }
- Logger::instance()->addMessage(tr("Successfully parsed the provided IP filter: %1 rules were applied.", "%1 is a number").arg(ruleCount));
- emit IPFilterParsed(false, ruleCount);
-+ loadOfflineFilter();
- }
-
- void Session::handleIPFilterError()
---- a/src/base/bittorrent/session.h
-+++ b/src/base/bittorrent/session.h
-@@ -40,8 +40,10 @@
- #include
- #include
- #include
-+#include
- #include
- #include
-+#include
- #include
- #include
-
-@@ -341,6 +343,10 @@ namespace BitTorrent
-
- uint saveResumeDataInterval() const;
- void setSaveResumeDataInterval(uint value);
-+ bool isAutoBanUnknownPeerEnabled() const;
-+ void setAutoBanUnknownPeer(bool value);
-+ bool isShowTrackerAuthWindow() const;
-+ void setShowTrackerAuthWindow(bool value);
- int port() const;
- void setPort(int port);
- bool useRandomPort() const;
-@@ -467,6 +473,19 @@ namespace BitTorrent
- void setMaxRatioAction(MaxRatioAction act);
-
- void banIP(const QString &ip);
-+ bool checkAccessFlags(const QString &ip);
-+ void tempblockIP(const QString &ip);
-+ void removeBlockedIP(const QString &ip);
-+ void eraseIPFilter();
-+ void autoBanBadClient();
-+
-+ // Unban Timer
-+ bool m_isActive = false;
-+ QQueue q_bannedIPs;
-+ QQueue q_unbanTime;
-+ QTimer *m_unbanTimer;
-+ QTimer *m_banTimer;
-+ void insertQueue(QString ip);
-
- bool isKnownTorrent(const InfoHash &hash) const;
- bool addTorrent(QString source, const AddTorrentParams ¶ms = AddTorrentParams());
-@@ -546,6 +565,9 @@ namespace BitTorrent
- void tagAdded(const QString &tag);
- void tagRemoved(const QString &tag);
-
-+ public slots:
-+ void processUnbanRequest();
-+
- private slots:
- void configureDeferred();
- void readAlerts();
-@@ -601,6 +623,8 @@ namespace BitTorrent
- void populateAdditionalTrackers();
- void enableIPFilter();
- void disableIPFilter();
-+ int parseOfflineFilterFile(QString ipDat, libtorrent::ip_filter &filter);
-+ void loadOfflineFilter();
-
- bool addTorrent_impl(CreateTorrentParams params, const MagnetUri &magnetUri,
- TorrentInfo torrentInfo = TorrentInfo(),
-@@ -713,6 +737,8 @@ namespace BitTorrent
- CachedSettingValue m_isAltGlobalSpeedLimitEnabled;
- CachedSettingValue m_isBandwidthSchedulerEnabled;
- CachedSettingValue m_saveResumeDataInterval;
-+ CachedSettingValue m_autoBanUnknownPeer;
-+ CachedSettingValue m_showTrackerAuthWindow;
- CachedSettingValue m_port;
- CachedSettingValue m_useRandomPort;
- CachedSettingValue m_networkInterface;
---- a/src/base/bittorrent/torrenthandle.cpp
-+++ b/src/base/bittorrent/torrenthandle.cpp
-@@ -1561,7 +1561,8 @@ void TorrentHandle::handleTrackerErrorAl
- m_trackerInfos[trackerUrl].lastMessage = message;
-
- if (p->status_code == 401)
-- m_session->handleTorrentTrackerAuthenticationRequired(this, trackerUrl);
-+ if (Preferences::instance()->getShowTrackerAuthWindow())
-+ m_session->handleTorrentTrackerAuthenticationRequired(this, trackerUrl);
-
- m_session->handleTorrentTrackerError(this, trackerUrl);
- }
---- a/src/base/preferences.cpp
-+++ b/src/base/preferences.cpp
-@@ -1090,6 +1090,26 @@ void Preferences::setTrayIconStyle(TrayI
- }
- #endif
-
-+bool Preferences::getAutoBanUnknownPeer() const
-+{
-+ return value("Preferences/Advanced/AutoBanUnknownPeer", false).toBool();
-+}
-+
-+void Preferences::setAutoBanUnknownPeer(const bool checked)
-+{
-+ setValue("Preferences/Advanced/AutoBanUnknownPeer", checked);
-+}
-+
-+bool Preferences::getShowTrackerAuthWindow() const
-+{
-+ return value("Preferences/Advanced/ShowTrackerAuthWindow", true).toBool();
-+}
-+
-+void Preferences::setShowTrackerAuthWindow(const bool checked)
-+{
-+ setValue("Preferences/Advanced/ShowTrackerAuthWindow", checked);
-+}
-+
- // Stuff that don't appear in the Options GUI but are saved
- // in the same file.
-
---- a/src/base/preferences.h
-+++ b/src/base/preferences.h
-@@ -300,6 +300,10 @@ public:
- TrayIcon::Style trayIconStyle() const;
- void setTrayIconStyle(TrayIcon::Style style);
- #endif // Q_OS_MAC
-+ bool getAutoBanUnknownPeer() const;
-+ void setAutoBanUnknownPeer(const bool checked);
-+ bool getShowTrackerAuthWindow() const;
-+ void setShowTrackerAuthWindow(const bool checked);
-
- // Stuff that don't appear in the Options GUI but are saved
- // in the same file.
---- a/src/base/settingsstorage.cpp
-+++ b/src/base/settingsstorage.cpp
-@@ -91,6 +91,8 @@ namespace
- {"BitTorrent/Session/InterfaceName", "Preferences/Connection/InterfaceName"},
- {"BitTorrent/Session/InterfaceAddress", "Preferences/Connection/InterfaceAddress"},
- {"BitTorrent/Session/SaveResumeDataInterval", "Preferences/Downloads/SaveResumeDataInterval"},
-+ {"BitTorrent/Session/AutoBanUnknownPeer", "Preferences/Advanced/AutoBanUnknownPeer"},
-+ {"BitTorrent/Session/ShowTrackerAuthWindow", "Preferences/Advanced/ShowTrackerAuthWindow"},
- {"BitTorrent/Session/Encryption", "Preferences/Bittorrent/Encryption"},
- {"BitTorrent/Session/ForceProxy", "Preferences/Connection/ProxyForce"},
- {"BitTorrent/Session/ProxyPeerConnections", "Preferences/Connection/ProxyPeerConnections"},
---- a/src/gui/advancedsettings.cpp
-+++ b/src/gui/advancedsettings.cpp
-@@ -60,6 +60,8 @@ enum AdvSettingsRows
- NETWORK_LISTEN_IPV6,
- // behavior
- SAVE_RESUME_DATA_INTERVAL,
-+ CONFIRM_AUTO_BAN,
-+ SHOW_TRACKER_AUTH_WINDOW,
- CONFIRM_RECHECK_TORRENT,
- RECHECK_COMPLETED,
- #if defined(Q_OS_WIN) || defined(Q_OS_MAC)
-@@ -215,6 +217,10 @@ void AdvancedSettings::saveAdvancedSetti
- // Announce IP
- QHostAddress addr(lineEditAnnounceIP.text().trimmed());
- session->setAnnounceIP(addr.isNull() ? "" : addr.toString());
-+ // Auto ban Unknown Peer
-+ session->setAutoBanUnknownPeer(cb_auto_ban_unknown_peer.isChecked());
-+ // Show Tracker Authenticaion Window
-+ session->setShowTrackerAuthWindow(cb_show_tracker_auth_window.isChecked());
-
- // Program notification
- MainWindow *const mainWindow = static_cast(QCoreApplication::instance())->mainWindow();
-@@ -465,6 +471,12 @@ void AdvancedSettings::loadAdvancedSetti
- // Announce IP
- lineEditAnnounceIP.setText(session->announceIP());
- addRow(ANNOUNCE_IP, tr("IP Address to report to trackers (requires restart)"), &lineEditAnnounceIP);
-+ // Auto Ban Unknown Peer from China
-+ cb_auto_ban_unknown_peer.setChecked(session->isAutoBanUnknownPeerEnabled());
-+ addRow(CONFIRM_AUTO_BAN, tr("Auto Ban Unknown Peer from China"), &cb_auto_ban_unknown_peer);
-+ // Show Tracker Authenticaion Window
-+ cb_show_tracker_auth_window.setChecked(session->isShowTrackerAuthWindow());
-+ addRow(SHOW_TRACKER_AUTH_WINDOW, tr("Show Tracker Authenticaion Window"), &cb_show_tracker_auth_window);
-
- // Program notifications
- const MainWindow *const mainWindow = static_cast(QCoreApplication::instance())->mainWindow();
---- a/src/gui/advancedsettings.h
-+++ b/src/gui/advancedsettings.h
-@@ -65,7 +65,8 @@ private:
- QCheckBox checkBoxOsCache, checkBoxRecheckCompleted, checkBoxResolveCountries, checkBoxResolveHosts, checkBoxSuperSeeding,
- checkBoxProgramNotifications, checkBoxTorrentAddedNotifications, checkBoxTrackerFavicon, checkBoxTrackerStatus,
- checkBoxConfirmTorrentRecheck, checkBoxConfirmRemoveAllTags, checkBoxListenIPv6, checkBoxAnnounceAllTrackers, checkBoxAnnounceAllTiers,
-- checkBoxGuidedReadCache, checkBoxMultiConnectionsPerIp, checkBoxSuggestMode, checkBoxCoalesceRW, checkBoxSpeedWidgetEnabled;
-+ checkBoxGuidedReadCache, checkBoxMultiConnectionsPerIp, checkBoxSuggestMode, checkBoxCoalesceRW, checkBoxSpeedWidgetEnabled,
-+ cb_auto_ban_unknown_peer, cb_show_tracker_auth_window;
- QComboBox comboBoxInterface, comboBoxInterfaceAddress, comboBoxUtpMixedMode, comboBoxChokingAlgorithm, comboBoxSeedChokingAlgorithm;
- QLineEdit lineEditAnnounceIP;
-
---- a/src/gui/mainwindow.cpp
-+++ b/src/gui/mainwindow.cpp
-@@ -73,6 +73,7 @@
- #include "addnewtorrentdialog.h"
- #include "application.h"
- #include "autoexpandabledialog.h"
-+#include "base/bittorrent/peerinfo.h"
- #include "cookiesdialog.h"
- #include "downloadfromurldialog.h"
- #include "executionlogwidget.h"
---- a/src/gui/properties/peerlistdelegate.h
-+++ b/src/gui/properties/peerlistdelegate.h
-@@ -49,6 +49,7 @@ public:
- CONNECTION,
- FLAGS,
- CLIENT,
-+ PEERID,
- PROGRESS,
- DOWN_SPEED,
- UP_SPEED,
---- a/src/gui/properties/peerlistwidget.cpp
-+++ b/src/gui/properties/peerlistwidget.cpp
-@@ -75,6 +75,7 @@ PeerListWidget::PeerListWidget(Propertie
- m_listModel->setHeaderData(PeerListDelegate::FLAGS, Qt::Horizontal, tr("Flags"));
- m_listModel->setHeaderData(PeerListDelegate::CONNECTION, Qt::Horizontal, tr("Connection"));
- m_listModel->setHeaderData(PeerListDelegate::CLIENT, Qt::Horizontal, tr("Client", "i.e.: Client application"));
-+ m_listModel->setHeaderData(PeerListDelegate::PEERID, Qt::Horizontal, tr("Peer ID", "i.e.: Client Peer ID"));
- m_listModel->setHeaderData(PeerListDelegate::PROGRESS, Qt::Horizontal, tr("Progress", "i.e: % downloaded"));
- m_listModel->setHeaderData(PeerListDelegate::DOWN_SPEED, Qt::Horizontal, tr("Down Speed", "i.e: Download speed"));
- m_listModel->setHeaderData(PeerListDelegate::UP_SPEED, Qt::Horizontal, tr("Up Speed", "i.e: Upload speed"));
-@@ -288,8 +289,13 @@ void PeerListWidget::banSelectedPeers()
- for (const QModelIndex &index : selectedIndexes) {
- int row = m_proxyModel->mapToSource(index).row();
- QString ip = m_listModel->data(m_listModel->index(row, PeerListDelegate::IP_HIDDEN)).toString();
-+ QString client = m_listModel->data(m_listModel->index(row, PeerListDelegate::CLIENT)).toString();
-+ QString peerid = m_listModel->data(m_listModel->index(row, PeerListDelegate::PEERID)).toString();
-+ QHostAddress host;
-+ host.setAddress(ip);
-+ const QString countryName = Net::GeoIPManager::CountryName(Net::GeoIPManager::instance()->lookup(host));
- qDebug("Banning peer %s...", ip.toLocal8Bit().data());
-- Logger::instance()->addMessage(tr("Manually banning peer '%1'...").arg(ip));
-+ Logger::instance()->addMessage(tr("Manually banning peer '%1'...'%2'...'%3'...'%4'").arg(ip).arg(peerid).arg(client).arg(countryName));
- BitTorrent::Session::instance()->banIP(ip);
- }
- // Refresh list
-@@ -398,6 +404,7 @@ QStandardItem *PeerListWidget::addPeer(c
- m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flags());
- m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flagsDescription(), Qt::ToolTipRole);
- m_listModel->setData(m_listModel->index(row, PeerListDelegate::CLIENT), peer.client().toHtmlEscaped());
-+ m_listModel->setData(m_listModel->index(row, PeerListDelegate::PEERID), peer.pid().left(8).toHtmlEscaped());
- m_listModel->setData(m_listModel->index(row, PeerListDelegate::PROGRESS), peer.progress());
- m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWN_SPEED), peer.payloadDownSpeed());
- m_listModel->setData(m_listModel->index(row, PeerListDelegate::UP_SPEED), peer.payloadUpSpeed());
-@@ -429,6 +436,7 @@ void PeerListWidget::updatePeer(const QS
- m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flags());
- m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flagsDescription(), Qt::ToolTipRole);
- m_listModel->setData(m_listModel->index(row, PeerListDelegate::CLIENT), peer.client().toHtmlEscaped());
-+ m_listModel->setData(m_listModel->index(row, PeerListDelegate::PEERID), peer.pid().left(8).toHtmlEscaped());
- m_listModel->setData(m_listModel->index(row, PeerListDelegate::PROGRESS), peer.progress());
- m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWN_SPEED), peer.payloadDownSpeed());
- m_listModel->setData(m_listModel->index(row, PeerListDelegate::UP_SPEED), peer.payloadUpSpeed());
---- a/src/webui/api/appcontroller.cpp
-+++ b/src/webui/api/appcontroller.cpp
-@@ -153,6 +153,7 @@ void AppController::preferencesAction()
- data["ip_filter_path"] = Utils::Fs::toNativePath(session->IPFilterFile());
- data["ip_filter_trackers"] = session->isTrackerFilteringEnabled();
- data["banned_IPs"] = session->bannedIPs().join("\n");
-+ data["auto_ban_unknown_peer"] = session->isAutoBanUnknownPeerEnabled();
-
- // Speed
- // Global Rate Limits
-@@ -401,6 +402,8 @@ void AppController::setPreferencesAction
- session->setTrackerFilteringEnabled(m["ip_filter_trackers"].toBool());
- if (m.contains("banned_IPs"))
- session->setBannedIPs(m["banned_IPs"].toString().split('\n'));
-+ if (m.contains("auto_ban_unknown_peer"))
-+ session->setAutoBanUnknownPeer(m["auto_ban_unknown_peer"].toBool());
-
- // Speed
- // Global Rate Limits
---- a/src/webui/api/transfercontroller.cpp
-+++ b/src/webui/api/transfercontroller.cpp
-@@ -30,6 +30,7 @@
-
- #include
-
-+#include "base/logger.h"
- #include "base/bittorrent/session.h"
-
- const char KEY_TRANSFER_DLSPEED[] = "dl_info_speed";
-@@ -111,3 +112,37 @@ void TransferController::speedLimitsMode
- {
- setResult(QString::number(BitTorrent::Session::instance()->isAltGlobalSpeedLimitEnabled()));
- }
-+
-+void TransferController::tempblockPeerAction()
-+{
-+ checkParams({"ip"});
-+ QString ip = params()["ip"];
-+ boost::system::error_code ec;
-+ boost::asio::ip::address addr = boost::asio::ip::address::from_string(ip.toStdString(), ec);
-+ bool isBanned = BitTorrent::Session::instance()->checkAccessFlags(QString::fromStdString(addr.to_string()));
-+
-+ if (ip.isEmpty()) {
-+ setResult(QLatin1String("IP field should not be empty."));
-+ return;
-+ }
-+
-+ if (ec) {
-+ setResult(QLatin1String("The given IP address is not valid."));
-+ return;
-+ }
-+
-+ if (isBanned) {
-+ setResult(QLatin1String("The given IP address already exists."));
-+ return;
-+ }
-+
-+ BitTorrent::Session::instance()->tempblockIP(ip);
-+ Logger::instance()->addMessage(tr("Peer '%1' banned via Web API.").arg(ip));
-+ setResult(QLatin1String("Done."));
-+}
-+
-+void TransferController::resetIPFilterAction()
-+{
-+ BitTorrent::Session::instance()->eraseIPFilter();
-+ setResult(QLatin1String("Erased."));
-+}
---- a/src/webui/api/transfercontroller.h
-+++ b/src/webui/api/transfercontroller.h
-@@ -46,4 +46,6 @@ private slots:
- void downloadLimitAction();
- void setUploadLimitAction();
- void setDownloadLimitAction();
-+ void tempblockPeerAction();
-+ void resetIPFilterAction();
- };
---- a/src/webui/www/private/preferences_content.html
-+++ b/src/webui/www/private/preferences_content.html
-@@ -377,6 +377,8 @@
-
-
-
-+
-+
-
-
-
-@@ -1252,6 +1254,7 @@
- $('ipfilter_text').setProperty('value', pref.ip_filter_path);
- $('ipfilter_trackers_checkbox').setProperty('checked', pref.ip_filter_trackers);
- $('banned_IPs_textarea').setProperty('value', pref.banned_IPs);
-+ $('auto_ban_unknown_peer_checkbox').setProperty('checked', pref.auto_ban_unknown_peer);
- updateFilterSettings();
-
- // Speed tab
-@@ -1502,6 +1505,7 @@
- settings.set('ip_filter_path', $('ipfilter_text').getProperty('value'));
- settings.set('ip_filter_trackers', $('ipfilter_trackers_checkbox').getProperty('checked'));
- settings.set('banned_IPs', $('banned_IPs_textarea').getProperty('value'));
-+ settings.set('auto_ban_unknown_peer', $('auto_ban_unknown_peer_checkbox').getProperty('checked'));
-
- // Speed tab
- // Global Rate Limits