Browse Source

Merge pull request #18528 from glassez/proxy

Allow to use proxy per subsystem
adaptive-webui-19844
Vladimir Golovnev 2 years ago committed by GitHub
parent
commit
f5b5312cf0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 51
      src/app/upgrade.cpp
  2. 2
      src/base/bittorrent/session.h
  3. 85
      src/base/bittorrent/sessionimpl.cpp
  4. 3
      src/base/bittorrent/sessionimpl.h
  5. 8
      src/base/net/dnsupdater.cpp
  6. 37
      src/base/net/downloadhandlerimpl.cpp
  7. 49
      src/base/net/downloadhandlerimpl.h
  8. 218
      src/base/net/downloadmanager.cpp
  9. 24
      src/base/net/downloadmanager.h
  10. 4
      src/base/net/geoipmanager.cpp
  11. 73
      src/base/net/proxyconfigurationmanager.cpp
  12. 16
      src/base/net/proxyconfigurationmanager.h
  13. 31
      src/base/preferences.cpp
  14. 7
      src/base/preferences.h
  15. 5
      src/base/rss/rss_feed.cpp
  16. 62
      src/base/search/searchpluginmanager.cpp
  17. 1
      src/base/search/searchpluginmanager.h
  18. 7
      src/gui/addnewtorrentdialog.cpp
  19. 5
      src/gui/mainwindow.cpp
  20. 134
      src/gui/optionsdialog.cpp
  21. 3
      src/gui/optionsdialog.h
  22. 126
      src/gui/optionsdialog.ui
  23. 5
      src/gui/programupdater.cpp
  24. 4
      src/gui/properties/trackersadditiondialog.cpp
  25. 5
      src/gui/search/pluginselectdialog.cpp
  26. 4
      src/gui/transferlistfilterswidget.cpp
  27. 26
      src/webui/api/appcontroller.cpp
  28. 2
      src/webui/webapplication.h
  29. 122
      src/webui/www/private/views/preferences.html

51
src/app/upgrade.cpp

@ -44,7 +44,7 @@
namespace namespace
{ {
const int MIGRATION_VERSION = 5; const int MIGRATION_VERSION = 6;
const QString MIGRATION_VERSION_KEY = u"Meta/MigrationVersion"_qs; const QString MIGRATION_VERSION_KEY = u"Meta/MigrationVersion"_qs;
void exportWebUIHttpsFiles() void exportWebUIHttpsFiles()
@ -343,7 +343,7 @@ namespace
switch (number) switch (number)
{ {
case 0: case 0:
settingsStorage->storeValue(key, Net::ProxyType::None); settingsStorage->storeValue(key, u"None"_qs);
break; break;
case 1: case 1:
settingsStorage->storeValue(key, Net::ProxyType::HTTP); settingsStorage->storeValue(key, Net::ProxyType::HTTP);
@ -352,10 +352,10 @@ namespace
settingsStorage->storeValue(key, Net::ProxyType::SOCKS5); settingsStorage->storeValue(key, Net::ProxyType::SOCKS5);
break; break;
case 3: case 3:
settingsStorage->storeValue(key, Net::ProxyType::HTTP_PW); settingsStorage->storeValue(key, u"HTTP_PW"_qs);
break; break;
case 4: case 4:
settingsStorage->storeValue(key, Net::ProxyType::SOCKS5_PW); settingsStorage->storeValue(key, u"SOCKS5_PW"_qs);
break; break;
case 5: case 5:
settingsStorage->storeValue(key, Net::ProxyType::SOCKS4); settingsStorage->storeValue(key, Net::ProxyType::SOCKS4);
@ -369,6 +369,46 @@ namespace
} }
} }
void migrateProxySettings()
{
auto *settingsStorage = SettingsStorage::instance();
const auto proxyType = settingsStorage->loadValue<QString>(u"Network/Proxy/Type"_qs, u"None"_qs);
const auto onlyForTorrents = settingsStorage->loadValue<bool>(u"Network/Proxy/OnlyForTorrents"_qs)
|| (proxyType == u"SOCKS4");
if (proxyType == u"None")
{
settingsStorage->storeValue(u"Network/Proxy/Type"_qs, Net::ProxyType::HTTP);
settingsStorage->storeValue(u"Network/Proxy/Profiles/BitTorrent"_qs, false);
settingsStorage->storeValue(u"Network/Proxy/Profiles/RSS"_qs, false);
settingsStorage->storeValue(u"Network/Proxy/Profiles/Misc"_qs, false);
}
else
{
settingsStorage->storeValue(u"Network/Proxy/Profiles/BitTorrent"_qs, true);
settingsStorage->storeValue(u"Network/Proxy/Profiles/RSS"_qs, !onlyForTorrents);
settingsStorage->storeValue(u"Network/Proxy/Profiles/Misc"_qs, !onlyForTorrents);
if (proxyType == u"HTTP_PW"_qs)
{
settingsStorage->storeValue(u"Network/Proxy/Type"_qs, Net::ProxyType::HTTP);
settingsStorage->storeValue(u"Network/Proxy/AuthEnabled"_qs, true);
}
else if (proxyType == u"SOCKS5_PW"_qs)
{
settingsStorage->storeValue(u"Network/Proxy/Type"_qs, Net::ProxyType::SOCKS5);
settingsStorage->storeValue(u"Network/Proxy/AuthEnabled"_qs, true);
}
}
settingsStorage->removeValue(u"Network/Proxy/OnlyForTorrents"_qs);
const auto proxyHostnameLookup = settingsStorage->loadValue<bool>(u"BitTorrent/Session/ProxyHostnameLookup"_qs);
settingsStorage->storeValue(u"Network/Proxy/HostnameLookupEnabled"_qs, proxyHostnameLookup);
settingsStorage->removeValue(u"BitTorrent/Session/ProxyHostnameLookup"_qs);
}
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
void migrateMemoryPrioritySettings() void migrateMemoryPrioritySettings()
{ {
@ -442,6 +482,9 @@ bool upgrade()
migrateChineseLocale(); migrateChineseLocale();
} }
if (version < 6)
migrateProxySettings();
version = MIGRATION_VERSION; version = MIGRATION_VERSION;
} }

2
src/base/bittorrent/session.h

@ -262,8 +262,6 @@ namespace BitTorrent
virtual void setMaxActiveCheckingTorrents(int val) = 0; virtual void setMaxActiveCheckingTorrents(int val) = 0;
virtual bool isProxyPeerConnectionsEnabled() const = 0; virtual bool isProxyPeerConnectionsEnabled() const = 0;
virtual void setProxyPeerConnectionsEnabled(bool enabled) = 0; virtual void setProxyPeerConnectionsEnabled(bool enabled) = 0;
virtual bool isProxyHostnameLookupEnabled() const = 0;
virtual void setProxyHostnameLookupEnabled(bool enabled) = 0;
virtual ChokingAlgorithm chokingAlgorithm() const = 0; virtual ChokingAlgorithm chokingAlgorithm() const = 0;
virtual void setChokingAlgorithm(ChokingAlgorithm mode) = 0; virtual void setChokingAlgorithm(ChokingAlgorithm mode) = 0;
virtual SeedChokingAlgorithm seedChokingAlgorithm() const = 0; virtual SeedChokingAlgorithm seedChokingAlgorithm() const = 0;

85
src/base/bittorrent/sessionimpl.cpp

@ -42,7 +42,10 @@
#include <iphlpapi.h> #include <iphlpapi.h>
#endif #endif
#include <boost/asio/ip/tcp.hpp>
#include <libtorrent/add_torrent_params.hpp> #include <libtorrent/add_torrent_params.hpp>
#include <libtorrent/address.hpp>
#include <libtorrent/alert_types.hpp> #include <libtorrent/alert_types.hpp>
#include <libtorrent/error_code.hpp> #include <libtorrent/error_code.hpp>
#include <libtorrent/extensions/smart_ban.hpp> #include <libtorrent/extensions/smart_ban.hpp>
@ -495,7 +498,6 @@ SessionImpl::SessionImpl(QObject *parent)
, m_encryption(BITTORRENT_SESSION_KEY(u"Encryption"_qs), 0) , m_encryption(BITTORRENT_SESSION_KEY(u"Encryption"_qs), 0)
, m_maxActiveCheckingTorrents(BITTORRENT_SESSION_KEY(u"MaxActiveCheckingTorrents"_qs), 1) , m_maxActiveCheckingTorrents(BITTORRENT_SESSION_KEY(u"MaxActiveCheckingTorrents"_qs), 1)
, m_isProxyPeerConnectionsEnabled(BITTORRENT_SESSION_KEY(u"ProxyPeerConnections"_qs), false) , m_isProxyPeerConnectionsEnabled(BITTORRENT_SESSION_KEY(u"ProxyPeerConnections"_qs), false)
, m_isProxyHostnameLookupEnabled(BITTORRENT_SESSION_KEY(u"ProxyHostnameLookup"_qs), true)
, m_chokingAlgorithm(BITTORRENT_SESSION_KEY(u"ChokingAlgorithm"_qs), ChokingAlgorithm::FixedSlots , m_chokingAlgorithm(BITTORRENT_SESSION_KEY(u"ChokingAlgorithm"_qs), ChokingAlgorithm::FixedSlots
, clampValue(ChokingAlgorithm::FixedSlots, ChokingAlgorithm::RateBased)) , clampValue(ChokingAlgorithm::FixedSlots, ChokingAlgorithm::RateBased))
, m_seedChokingAlgorithm(BITTORRENT_SESSION_KEY(u"SeedChokingAlgorithm"_qs), SeedChokingAlgorithm::FastestUpload , m_seedChokingAlgorithm(BITTORRENT_SESSION_KEY(u"SeedChokingAlgorithm"_qs), SeedChokingAlgorithm::FastestUpload
@ -1629,44 +1631,47 @@ lt::settings_pack SessionImpl::loadLTSettings() const
settingsPack.set_int(lt::settings_pack::active_checking, maxActiveCheckingTorrents()); settingsPack.set_int(lt::settings_pack::active_checking, maxActiveCheckingTorrents());
// proxy // proxy
const auto proxyManager = Net::ProxyConfigurationManager::instance(); settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::none);
const Net::ProxyConfiguration proxyConfig = proxyManager->proxyConfiguration(); if (Preferences::instance()->useProxyForBT())
switch (proxyConfig.type)
{ {
case Net::ProxyType::HTTP: const auto proxyManager = Net::ProxyConfigurationManager::instance();
settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::http); const Net::ProxyConfiguration proxyConfig = proxyManager->proxyConfiguration();
break;
case Net::ProxyType::HTTP_PW: switch (proxyConfig.type)
settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::http_pw); {
break; case Net::ProxyType::SOCKS4:
case Net::ProxyType::SOCKS4: settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::socks4);
settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::socks4); break;
break;
case Net::ProxyType::SOCKS5: case Net::ProxyType::HTTP:
settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::socks5); if (proxyConfig.authEnabled)
break; settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::http_pw);
case Net::ProxyType::SOCKS5_PW: else
settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::socks5_pw); settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::http);
break; break;
case Net::ProxyType::None:
default: case Net::ProxyType::SOCKS5:
settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::none); if (proxyConfig.authEnabled)
} settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::socks5_pw);
else
settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::socks5);
break;
default:
break;
}
if (proxyConfig.type != Net::ProxyType::None)
{
settingsPack.set_str(lt::settings_pack::proxy_hostname, proxyConfig.ip.toStdString()); settingsPack.set_str(lt::settings_pack::proxy_hostname, proxyConfig.ip.toStdString());
settingsPack.set_int(lt::settings_pack::proxy_port, proxyConfig.port); settingsPack.set_int(lt::settings_pack::proxy_port, proxyConfig.port);
if (proxyManager->isAuthenticationRequired()) if (proxyConfig.authEnabled)
{ {
settingsPack.set_str(lt::settings_pack::proxy_username, proxyConfig.username.toStdString()); settingsPack.set_str(lt::settings_pack::proxy_username, proxyConfig.username.toStdString());
settingsPack.set_str(lt::settings_pack::proxy_password, proxyConfig.password.toStdString()); settingsPack.set_str(lt::settings_pack::proxy_password, proxyConfig.password.toStdString());
} }
settingsPack.set_bool(lt::settings_pack::proxy_peer_connections, isProxyPeerConnectionsEnabled()); settingsPack.set_bool(lt::settings_pack::proxy_peer_connections, isProxyPeerConnectionsEnabled());
settingsPack.set_bool(lt::settings_pack::proxy_hostnames, isProxyHostnameLookupEnabled()); settingsPack.set_bool(lt::settings_pack::proxy_hostnames, proxyConfig.hostnameLookupEnabled);
} }
settingsPack.set_bool(lt::settings_pack::announce_to_all_trackers, announceToAllTrackers()); settingsPack.set_bool(lt::settings_pack::announce_to_all_trackers, announceToAllTrackers());
@ -2493,7 +2498,7 @@ bool SessionImpl::addTorrent(const QString &source, const AddTorrentParams &para
LogMsg(tr("Downloading torrent, please wait... Source: \"%1\"").arg(source)); LogMsg(tr("Downloading torrent, please wait... Source: \"%1\"").arg(source));
// Launch downloader // Launch downloader
Net::DownloadManager::instance()->download(Net::DownloadRequest(source).limit(MAX_TORRENT_SIZE) Net::DownloadManager::instance()->download(Net::DownloadRequest(source).limit(MAX_TORRENT_SIZE)
, this, &SessionImpl::handleDownloadFinished); , Preferences::instance()->useProxyForGeneralPurposes(), this, &SessionImpl::handleDownloadFinished);
m_downloadedTorrents[source] = params; m_downloadedTorrents[source] = params;
return true; return true;
} }
@ -3542,20 +3547,6 @@ void SessionImpl::setProxyPeerConnectionsEnabled(const bool enabled)
} }
} }
bool SessionImpl::isProxyHostnameLookupEnabled() const
{
return m_isProxyHostnameLookupEnabled;
}
void SessionImpl::setProxyHostnameLookupEnabled(const bool enabled)
{
if (enabled != isProxyHostnameLookupEnabled())
{
m_isProxyHostnameLookupEnabled = enabled;
configureDeferred();
}
}
ChokingAlgorithm SessionImpl::chokingAlgorithm() const ChokingAlgorithm SessionImpl::chokingAlgorithm() const
{ {
return m_chokingAlgorithm; return m_chokingAlgorithm;
@ -5791,8 +5782,12 @@ void SessionImpl::handleSocks5Alert(const lt::socks5_alert *p) const
{ {
if (p->error) if (p->error)
{ {
LogMsg(tr("SOCKS5 proxy error. Message: \"%1\"").arg(QString::fromStdString(p->message())) const auto addr = p->ip.address();
, Log::WARNING); const QString endpoint = (addr.is_v6() ? u"[%1]:%2"_qs : u"%1:%2"_qs)
.arg(QString::fromStdString(addr.to_string()), QString::number(p->ip.port()));
LogMsg(tr("SOCKS5 proxy error. Address: %1. Message: \"%2\".")
.arg(endpoint, QString::fromLocal8Bit(p->error.message().c_str()))
, Log::WARNING);
} }
} }

3
src/base/bittorrent/sessionimpl.h

@ -239,8 +239,6 @@ namespace BitTorrent
void setMaxActiveCheckingTorrents(int val) override; void setMaxActiveCheckingTorrents(int val) override;
bool isProxyPeerConnectionsEnabled() const override; bool isProxyPeerConnectionsEnabled() const override;
void setProxyPeerConnectionsEnabled(bool enabled) override; void setProxyPeerConnectionsEnabled(bool enabled) override;
bool isProxyHostnameLookupEnabled() const override;
void setProxyHostnameLookupEnabled(bool enabled) override;
ChokingAlgorithm chokingAlgorithm() const override; ChokingAlgorithm chokingAlgorithm() const override;
void setChokingAlgorithm(ChokingAlgorithm mode) override; void setChokingAlgorithm(ChokingAlgorithm mode) override;
SeedChokingAlgorithm seedChokingAlgorithm() const override; SeedChokingAlgorithm seedChokingAlgorithm() const override;
@ -655,7 +653,6 @@ namespace BitTorrent
CachedSettingValue<int> m_encryption; CachedSettingValue<int> m_encryption;
CachedSettingValue<int> m_maxActiveCheckingTorrents; CachedSettingValue<int> m_maxActiveCheckingTorrents;
CachedSettingValue<bool> m_isProxyPeerConnectionsEnabled; CachedSettingValue<bool> m_isProxyPeerConnectionsEnabled;
CachedSettingValue<bool> m_isProxyHostnameLookupEnabled;
CachedSettingValue<ChokingAlgorithm> m_chokingAlgorithm; CachedSettingValue<ChokingAlgorithm> m_chokingAlgorithm;
CachedSettingValue<SeedChokingAlgorithm> m_seedChokingAlgorithm; CachedSettingValue<SeedChokingAlgorithm> m_seedChokingAlgorithm;
CachedSettingValue<QStringList> m_storedTags; CachedSettingValue<QStringList> m_storedTags;

8
src/base/net/dnsupdater.cpp

@ -80,8 +80,8 @@ void DNSUpdater::checkPublicIP()
Q_ASSERT(m_state == OK); Q_ASSERT(m_state == OK);
DownloadManager::instance()->download( DownloadManager::instance()->download(
DownloadRequest(u"http://checkip.dyndns.org"_qs).userAgent(QStringLiteral("qBittorrent/" QBT_VERSION_2)) DownloadRequest(u"http://checkip.dyndns.org"_qs).userAgent(QStringLiteral("qBittorrent/" QBT_VERSION_2))
, this, &DNSUpdater::ipRequestFinished); , Preferences::instance()->useProxyForGeneralPurposes(), this, &DNSUpdater::ipRequestFinished);
m_lastIPCheckTime = QDateTime::currentDateTime(); m_lastIPCheckTime = QDateTime::currentDateTime();
} }
@ -128,8 +128,8 @@ void DNSUpdater::updateDNSService()
m_lastIPCheckTime = QDateTime::currentDateTime(); m_lastIPCheckTime = QDateTime::currentDateTime();
DownloadManager::instance()->download( DownloadManager::instance()->download(
DownloadRequest(getUpdateUrl()).userAgent(QStringLiteral("qBittorrent/" QBT_VERSION_2)) DownloadRequest(getUpdateUrl()).userAgent(QStringLiteral("qBittorrent/" QBT_VERSION_2))
, this, &DNSUpdater::ipUpdateFinished); , Preferences::instance()->useProxyForGeneralPurposes(), this, &DNSUpdater::ipUpdateFinished);
} }
QString DNSUpdater::getUpdateUrl() const QString DNSUpdater::getUpdateUrl() const

37
src/base/net/downloadhandlerimpl.cpp

@ -56,16 +56,18 @@ namespace
} }
} }
DownloadHandlerImpl::DownloadHandlerImpl(Net::DownloadManager *manager, const Net::DownloadRequest &downloadRequest) Net::DownloadHandlerImpl::DownloadHandlerImpl(DownloadManager *manager
, const DownloadRequest &downloadRequest, const bool useProxy)
: DownloadHandler {manager} : DownloadHandler {manager}
, m_manager {manager} , m_manager {manager}
, m_downloadRequest {downloadRequest} , m_downloadRequest {downloadRequest}
, m_useProxy {useProxy}
{ {
m_result.url = url(); m_result.url = url();
m_result.status = Net::DownloadStatus::Success; m_result.status = DownloadStatus::Success;
} }
void DownloadHandlerImpl::cancel() void Net::DownloadHandlerImpl::cancel()
{ {
if (m_reply) if (m_reply)
{ {
@ -78,7 +80,7 @@ void DownloadHandlerImpl::cancel()
} }
} }
void DownloadHandlerImpl::assignNetworkReply(QNetworkReply *reply) void Net::DownloadHandlerImpl::assignNetworkReply(QNetworkReply *reply)
{ {
Q_ASSERT(reply); Q_ASSERT(reply);
Q_ASSERT(!m_reply); Q_ASSERT(!m_reply);
@ -91,17 +93,22 @@ void DownloadHandlerImpl::assignNetworkReply(QNetworkReply *reply)
} }
// Returns original url // Returns original url
QString DownloadHandlerImpl::url() const QString Net::DownloadHandlerImpl::url() const
{ {
return m_downloadRequest.url(); return m_downloadRequest.url();
} }
const Net::DownloadRequest DownloadHandlerImpl::downloadRequest() const Net::DownloadRequest Net::DownloadHandlerImpl::downloadRequest() const
{ {
return m_downloadRequest; return m_downloadRequest;
} }
void DownloadHandlerImpl::processFinishedDownload() bool Net::DownloadHandlerImpl::useProxy() const
{
return m_useProxy;
}
void Net::DownloadHandlerImpl::processFinishedDownload()
{ {
qDebug("Download finished: %s", qUtf8Printable(url())); qDebug("Download finished: %s", qUtf8Printable(url()));
@ -156,7 +163,7 @@ void DownloadHandlerImpl::processFinishedDownload()
finish(); finish();
} }
void DownloadHandlerImpl::checkDownloadSize(const qint64 bytesReceived, const qint64 bytesTotal) void Net::DownloadHandlerImpl::checkDownloadSize(const qint64 bytesReceived, const qint64 bytesTotal)
{ {
if ((bytesTotal > 0) && (bytesTotal <= m_downloadRequest.limit())) if ((bytesTotal > 0) && (bytesTotal <= m_downloadRequest.limit()))
{ {
@ -175,7 +182,7 @@ void DownloadHandlerImpl::checkDownloadSize(const qint64 bytesReceived, const qi
} }
} }
void DownloadHandlerImpl::handleRedirection(const QUrl &newUrl) void Net::DownloadHandlerImpl::handleRedirection(const QUrl &newUrl)
{ {
if (m_redirectionCount >= MAX_REDIRECTIONS) if (m_redirectionCount >= MAX_REDIRECTIONS)
{ {
@ -202,9 +209,9 @@ void DownloadHandlerImpl::handleRedirection(const QUrl &newUrl)
} }
auto redirected = static_cast<DownloadHandlerImpl *>( auto redirected = static_cast<DownloadHandlerImpl *>(
m_manager->download(Net::DownloadRequest(m_downloadRequest).url(newUrlString))); m_manager->download(DownloadRequest(m_downloadRequest).url(newUrlString), useProxy()));
redirected->m_redirectionCount = m_redirectionCount + 1; redirected->m_redirectionCount = m_redirectionCount + 1;
connect(redirected, &DownloadHandlerImpl::finished, this, [this](const Net::DownloadResult &result) connect(redirected, &DownloadHandlerImpl::finished, this, [this](const DownloadResult &result)
{ {
m_result = result; m_result = result;
m_result.url = url(); m_result.url = url();
@ -212,18 +219,18 @@ void DownloadHandlerImpl::handleRedirection(const QUrl &newUrl)
}); });
} }
void DownloadHandlerImpl::setError(const QString &error) void Net::DownloadHandlerImpl::setError(const QString &error)
{ {
m_result.errorString = error; m_result.errorString = error;
m_result.status = Net::DownloadStatus::Failed; m_result.status = DownloadStatus::Failed;
} }
void DownloadHandlerImpl::finish() void Net::DownloadHandlerImpl::finish()
{ {
emit finished(m_result); emit finished(m_result);
} }
QString DownloadHandlerImpl::errorCodeToString(const QNetworkReply::NetworkError status) QString Net::DownloadHandlerImpl::errorCodeToString(const QNetworkReply::NetworkError status)
{ {
switch (status) switch (status)
{ {

49
src/base/net/downloadhandlerimpl.h

@ -36,33 +36,38 @@
class QObject; class QObject;
class QUrl; class QUrl;
class DownloadHandlerImpl final : public Net::DownloadHandler namespace Net
{ {
Q_OBJECT class DownloadHandlerImpl final : public DownloadHandler
Q_DISABLE_COPY_MOVE(DownloadHandlerImpl) {
Q_OBJECT
Q_DISABLE_COPY_MOVE(DownloadHandlerImpl)
public: public:
DownloadHandlerImpl(Net::DownloadManager *manager, const Net::DownloadRequest &downloadRequest); DownloadHandlerImpl(DownloadManager *manager, const DownloadRequest &downloadRequest, bool useProxy);
void cancel() override; void cancel() override;
QString url() const; QString url() const;
const Net::DownloadRequest downloadRequest() const; DownloadRequest downloadRequest() const;
bool useProxy() const;
void assignNetworkReply(QNetworkReply *reply); void assignNetworkReply(QNetworkReply *reply);
private: private:
void processFinishedDownload(); void processFinishedDownload();
void checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal); void checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal);
void handleRedirection(const QUrl &newUrl); void handleRedirection(const QUrl &newUrl);
void setError(const QString &error); void setError(const QString &error);
void finish(); void finish();
static QString errorCodeToString(QNetworkReply::NetworkError status); static QString errorCodeToString(QNetworkReply::NetworkError status);
Net::DownloadManager *m_manager = nullptr; DownloadManager *m_manager = nullptr;
QNetworkReply *m_reply = nullptr; QNetworkReply *m_reply = nullptr;
const Net::DownloadRequest m_downloadRequest; const DownloadRequest m_downloadRequest;
short m_redirectionCount = 0; const bool m_useProxy = false;
Net::DownloadResult m_result; short m_redirectionCount = 0;
}; DownloadResult m_result;
};
}

218
src/base/net/downloadmanager.cpp

@ -33,6 +33,7 @@
#include <QDateTime> #include <QDateTime>
#include <QDebug> #include <QDebug>
#include <QNetworkAccessManager>
#include <QNetworkCookie> #include <QNetworkCookie>
#include <QNetworkCookieJar> #include <QNetworkCookieJar>
#include <QNetworkProxy> #include <QNetworkProxy>
@ -51,101 +52,81 @@ namespace
{ {
// Disguise as Firefox to avoid web server banning // Disguise as Firefox to avoid web server banning
const char DEFAULT_USER_AGENT[] = "Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0"; const char DEFAULT_USER_AGENT[] = "Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0";
}
class NetworkCookieJar final : public QNetworkCookieJar class Net::DownloadManager::NetworkCookieJar final : public QNetworkCookieJar
{
public:
explicit NetworkCookieJar(QObject *parent = nullptr)
: QNetworkCookieJar(parent)
{ {
public: const QDateTime now = QDateTime::currentDateTime();
explicit NetworkCookieJar(QObject *parent = nullptr) QList<QNetworkCookie> cookies = Preferences::instance()->getNetworkCookies();
: QNetworkCookieJar(parent) for (const QNetworkCookie &cookie : asConst(Preferences::instance()->getNetworkCookies()))
{ {
const QDateTime now = QDateTime::currentDateTime(); if (cookie.isSessionCookie() || (cookie.expirationDate() <= now))
QList<QNetworkCookie> cookies = Preferences::instance()->getNetworkCookies(); cookies.removeAll(cookie);
for (const QNetworkCookie &cookie : asConst(Preferences::instance()->getNetworkCookies()))
{
if (cookie.isSessionCookie() || (cookie.expirationDate() <= now))
cookies.removeAll(cookie);
}
setAllCookies(cookies);
} }
~NetworkCookieJar() override setAllCookies(cookies);
}
~NetworkCookieJar() override
{
const QDateTime now = QDateTime::currentDateTime();
QList<QNetworkCookie> cookies = allCookies();
for (const QNetworkCookie &cookie : asConst(allCookies()))
{ {
const QDateTime now = QDateTime::currentDateTime(); if (cookie.isSessionCookie() || (cookie.expirationDate() <= now))
QList<QNetworkCookie> cookies = allCookies(); cookies.removeAll(cookie);
for (const QNetworkCookie &cookie : asConst(allCookies()))
{
if (cookie.isSessionCookie() || (cookie.expirationDate() <= now))
cookies.removeAll(cookie);
}
Preferences::instance()->setNetworkCookies(cookies);
} }
using QNetworkCookieJar::allCookies; Preferences::instance()->setNetworkCookies(cookies);
using QNetworkCookieJar::setAllCookies; }
QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const override using QNetworkCookieJar::allCookies;
{ using QNetworkCookieJar::setAllCookies;
const QDateTime now = QDateTime::currentDateTime();
QList<QNetworkCookie> cookies = QNetworkCookieJar::cookiesForUrl(url);
for (const QNetworkCookie &cookie : asConst(QNetworkCookieJar::cookiesForUrl(url)))
{
if (!cookie.isSessionCookie() && (cookie.expirationDate() <= now))
cookies.removeAll(cookie);
}
return cookies;
}
bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url) override QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const override
{
const QDateTime now = QDateTime::currentDateTime();
QList<QNetworkCookie> cookies = QNetworkCookieJar::cookiesForUrl(url);
for (const QNetworkCookie &cookie : asConst(QNetworkCookieJar::cookiesForUrl(url)))
{ {
const QDateTime now = QDateTime::currentDateTime(); if (!cookie.isSessionCookie() && (cookie.expirationDate() <= now))
QList<QNetworkCookie> cookies = cookieList; cookies.removeAll(cookie);
for (const QNetworkCookie &cookie : cookieList)
{
if (!cookie.isSessionCookie() && (cookie.expirationDate() <= now))
cookies.removeAll(cookie);
}
return QNetworkCookieJar::setCookiesFromUrl(cookies, url);
} }
};
QNetworkRequest createNetworkRequest(const Net::DownloadRequest &downloadRequest)
{
QNetworkRequest request {downloadRequest.url()};
if (downloadRequest.userAgent().isEmpty()) return cookies;
request.setRawHeader("User-Agent", DEFAULT_USER_AGENT); }
else
request.setRawHeader("User-Agent", downloadRequest.userAgent().toUtf8());
// Spoof HTTP Referer to allow adding torrent link from Torcache/KickAssTorrents bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url) override
request.setRawHeader("Referer", request.url().toEncoded().data()); {
#ifdef QT_NO_COMPRESS const QDateTime now = QDateTime::currentDateTime();
// The macro "QT_NO_COMPRESS" defined in QT will disable the zlib related features QList<QNetworkCookie> cookies = cookieList;
// and reply data auto-decompression in QT will also be disabled. But we can support for (const QNetworkCookie &cookie : cookieList)
// gzip encoding and manually decompress the reply data. {
request.setRawHeader("Accept-Encoding", "gzip"); if (!cookie.isSessionCookie() && (cookie.expirationDate() <= now))
#endif cookies.removeAll(cookie);
// Qt doesn't support Magnet protocol so we need to handle redirections manually }
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy);
return request; return QNetworkCookieJar::setCookiesFromUrl(cookies, url);
} }
} };
Net::DownloadManager *Net::DownloadManager::m_instance = nullptr; Net::DownloadManager *Net::DownloadManager::m_instance = nullptr;
Net::DownloadManager::DownloadManager(QObject *parent) Net::DownloadManager::DownloadManager(QObject *parent)
: QObject(parent) : QObject(parent)
, m_networkCookieJar {new NetworkCookieJar(this)}
, m_networkManager {new QNetworkAccessManager(this)}
{ {
connect(&m_networkManager, &QNetworkAccessManager::sslErrors, this, &Net::DownloadManager::ignoreSslErrors); m_networkManager->setCookieJar(m_networkCookieJar);
connect(&m_networkManager, &QNetworkAccessManager::finished, this, &DownloadManager::handleReplyFinished); connect(m_networkManager, &QNetworkAccessManager::sslErrors, this, &Net::DownloadManager::ignoreSslErrors);
connect(ProxyConfigurationManager::instance(), &ProxyConfigurationManager::proxyConfigurationChanged connect(ProxyConfigurationManager::instance(), &ProxyConfigurationManager::proxyConfigurationChanged
, this, &DownloadManager::applyProxySettings); , this, &DownloadManager::applyProxySettings);
m_networkManager.setCookieJar(new NetworkCookieJar(this)); connect(Preferences::instance(), &Preferences::changed, this, &DownloadManager::applyProxySettings);
applyProxySettings(); applyProxySettings();
} }
@ -166,14 +147,18 @@ Net::DownloadManager *Net::DownloadManager::instance()
return m_instance; return m_instance;
} }
Net::DownloadHandler *Net::DownloadManager::download(const DownloadRequest &downloadRequest) Net::DownloadHandler *Net::DownloadManager::download(const DownloadRequest &downloadRequest, const bool useProxy)
{ {
// Process download request // Process download request
const QNetworkRequest request = createNetworkRequest(downloadRequest); const ServiceID id = ServiceID::fromURL(downloadRequest.url());
const ServiceID id = ServiceID::fromURL(request.url());
const bool isSequentialService = m_sequentialServices.contains(id); const bool isSequentialService = m_sequentialServices.contains(id);
auto downloadHandler = new DownloadHandlerImpl {this, downloadRequest}; auto downloadHandler = new DownloadHandlerImpl(this, downloadRequest, useProxy);
connect(downloadHandler, &DownloadHandler::finished, this
, [this, downloadHandler]
{
handleDownloadFinished(downloadHandler);
});
connect(downloadHandler, &DownloadHandler::finished, downloadHandler, &QObject::deleteLater); connect(downloadHandler, &DownloadHandler::finished, downloadHandler, &QObject::deleteLater);
connect(downloadHandler, &QObject::destroyed, this, [this, id, downloadHandler]() connect(downloadHandler, &QObject::destroyed, this, [this, id, downloadHandler]()
{ {
@ -189,7 +174,7 @@ Net::DownloadHandler *Net::DownloadManager::download(const DownloadRequest &down
qDebug("Downloading %s...", qUtf8Printable(downloadRequest.url())); qDebug("Downloading %s...", qUtf8Printable(downloadRequest.url()));
if (isSequentialService) if (isSequentialService)
m_busyServices.insert(id); m_busyServices.insert(id);
downloadHandler->assignNetworkReply(m_networkManager.get(request)); processRequest(downloadHandler);
} }
return downloadHandler; return downloadHandler;
@ -202,32 +187,32 @@ void Net::DownloadManager::registerSequentialService(const Net::ServiceID &servi
QList<QNetworkCookie> Net::DownloadManager::cookiesForUrl(const QUrl &url) const QList<QNetworkCookie> Net::DownloadManager::cookiesForUrl(const QUrl &url) const
{ {
return m_networkManager.cookieJar()->cookiesForUrl(url); return m_networkCookieJar->cookiesForUrl(url);
} }
bool Net::DownloadManager::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url) bool Net::DownloadManager::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url)
{ {
return m_networkManager.cookieJar()->setCookiesFromUrl(cookieList, url); return m_networkCookieJar->setCookiesFromUrl(cookieList, url);
} }
QList<QNetworkCookie> Net::DownloadManager::allCookies() const QList<QNetworkCookie> Net::DownloadManager::allCookies() const
{ {
return static_cast<NetworkCookieJar *>(m_networkManager.cookieJar())->allCookies(); return m_networkCookieJar->allCookies();
} }
void Net::DownloadManager::setAllCookies(const QList<QNetworkCookie> &cookieList) void Net::DownloadManager::setAllCookies(const QList<QNetworkCookie> &cookieList)
{ {
static_cast<NetworkCookieJar *>(m_networkManager.cookieJar())->setAllCookies(cookieList); m_networkCookieJar->setAllCookies(cookieList);
} }
bool Net::DownloadManager::deleteCookie(const QNetworkCookie &cookie) bool Net::DownloadManager::deleteCookie(const QNetworkCookie &cookie)
{ {
return static_cast<NetworkCookieJar *>(m_networkManager.cookieJar())->deleteCookie(cookie); return m_networkCookieJar->deleteCookie(cookie);
} }
bool Net::DownloadManager::hasSupportedScheme(const QString &url) bool Net::DownloadManager::hasSupportedScheme(const QString &url)
{ {
const QStringList schemes = instance()->m_networkManager.supportedSchemes(); const QStringList schemes = QNetworkAccessManager().supportedSchemes();
return std::any_of(schemes.cbegin(), schemes.cend(), [&url](const QString &scheme) return std::any_of(schemes.cbegin(), schemes.cend(), [&url](const QString &scheme)
{ {
return url.startsWith((scheme + u':'), Qt::CaseInsensitive); return url.startsWith((scheme + u':'), Qt::CaseInsensitive);
@ -238,46 +223,47 @@ void Net::DownloadManager::applyProxySettings()
{ {
const auto *proxyManager = ProxyConfigurationManager::instance(); const auto *proxyManager = ProxyConfigurationManager::instance();
const ProxyConfiguration proxyConfig = proxyManager->proxyConfiguration(); const ProxyConfiguration proxyConfig = proxyManager->proxyConfiguration();
QNetworkProxy proxy;
if (!proxyManager->isProxyOnlyForTorrents() && (proxyConfig.type != ProxyType::None)) m_proxy = QNetworkProxy(QNetworkProxy::NoProxy);
if (proxyConfig.type != ProxyType::SOCKS4)
{ {
// Proxy enabled // Proxy enabled
proxy.setHostName(proxyConfig.ip); if (proxyConfig.type == ProxyType::SOCKS5)
proxy.setPort(proxyConfig.port);
// Default proxy type is HTTP, we must change if it is SOCKS5
if ((proxyConfig.type == ProxyType::SOCKS5) || (proxyConfig.type == ProxyType::SOCKS5_PW))
{ {
qDebug() << Q_FUNC_INFO << "using SOCKS proxy"; qDebug() << Q_FUNC_INFO << "using SOCKS proxy";
proxy.setType(QNetworkProxy::Socks5Proxy); m_proxy.setType(QNetworkProxy::Socks5Proxy);
} }
else else
{ {
qDebug() << Q_FUNC_INFO << "using HTTP proxy"; qDebug() << Q_FUNC_INFO << "using HTTP proxy";
proxy.setType(QNetworkProxy::HttpProxy); m_proxy.setType(QNetworkProxy::HttpProxy);
} }
m_proxy.setHostName(proxyConfig.ip);
m_proxy.setPort(proxyConfig.port);
// Authentication? // Authentication?
if (proxyManager->isAuthenticationRequired()) if (proxyConfig.authEnabled)
{ {
qDebug("Proxy requires authentication, authenticating..."); qDebug("Proxy requires authentication, authenticating...");
proxy.setUser(proxyConfig.username); m_proxy.setUser(proxyConfig.username);
proxy.setPassword(proxyConfig.password); m_proxy.setPassword(proxyConfig.password);
} }
}
else
{
proxy.setType(QNetworkProxy::NoProxy);
}
m_networkManager.setProxy(proxy); if (proxyConfig.hostnameLookupEnabled)
m_proxy.setCapabilities(m_proxy.capabilities() | QNetworkProxy::HostNameLookupCapability);
else
m_proxy.setCapabilities(m_proxy.capabilities() & ~QNetworkProxy::HostNameLookupCapability);
}
} }
void Net::DownloadManager::handleReplyFinished(const QNetworkReply *reply) void Net::DownloadManager::handleDownloadFinished(DownloadHandlerImpl *finishedHandler)
{ {
// QNetworkReply::url() may be different from that of the original request // QNetworkReply::url() may be different from that of the original request
// so we need QNetworkRequest::url() to properly process Sequential Services // so we need QNetworkRequest::url() to properly process Sequential Services
// in the case when the redirection occurred. // in the case when the redirection occurred.
const ServiceID id = ServiceID::fromURL(reply->request().url()); const ServiceID id = ServiceID::fromURL(finishedHandler->url());
const auto waitingJobsIter = m_waitingJobs.find(id); const auto waitingJobsIter = m_waitingJobs.find(id);
if ((waitingJobsIter == m_waitingJobs.end()) || waitingJobsIter.value().isEmpty()) if ((waitingJobsIter == m_waitingJobs.end()) || waitingJobsIter.value().isEmpty())
{ {
@ -286,12 +272,38 @@ void Net::DownloadManager::handleReplyFinished(const QNetworkReply *reply)
return; return;
} }
auto handler = static_cast<DownloadHandlerImpl *>(waitingJobsIter.value().dequeue()); auto handler = waitingJobsIter.value().dequeue();
qDebug("Downloading %s...", qUtf8Printable(handler->url())); qDebug("Downloading %s...", qUtf8Printable(handler->url()));
handler->assignNetworkReply(m_networkManager.get(createNetworkRequest(handler->downloadRequest()))); processRequest(handler);
handler->disconnect(this); handler->disconnect(this);
} }
void Net::DownloadManager::processRequest(DownloadHandlerImpl *downloadHandler)
{
m_networkManager->setProxy((downloadHandler->useProxy() == true) ? m_proxy : QNetworkProxy(QNetworkProxy::NoProxy));
const DownloadRequest downloadRequest = downloadHandler->downloadRequest();
QNetworkRequest request {downloadRequest.url()};
if (downloadRequest.userAgent().isEmpty())
request.setRawHeader("User-Agent", DEFAULT_USER_AGENT);
else
request.setRawHeader("User-Agent", downloadRequest.userAgent().toUtf8());
// Spoof HTTP Referer to allow adding torrent link from Torcache/KickAssTorrents
request.setRawHeader("Referer", request.url().toEncoded().data());
#ifdef QT_NO_COMPRESS
// The macro "QT_NO_COMPRESS" defined in QT will disable the zlib related features
// and reply data auto-decompression in QT will also be disabled. But we can support
// gzip encoding and manually decompress the reply data.
request.setRawHeader("Accept-Encoding", "gzip");
#endif
// Qt doesn't support Magnet protocol so we need to handle redirections manually
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy);
downloadHandler->assignNetworkReply(m_networkManager->get(request));
}
void Net::DownloadManager::ignoreSslErrors(QNetworkReply *reply, const QList<QSslError> &errors) void Net::DownloadManager::ignoreSslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
{ {
QStringList errorList; QStringList errorList;

24
src/base/net/downloadmanager.h

@ -31,13 +31,14 @@
#include <QtGlobal> #include <QtGlobal>
#include <QHash> #include <QHash>
#include <QNetworkAccessManager> #include <QNetworkProxy>
#include <QObject> #include <QObject>
#include <QQueue> #include <QQueue>
#include <QSet> #include <QSet>
#include "base/path.h" #include "base/path.h"
class QNetworkAccessManager;
class QNetworkCookie; class QNetworkCookie;
class QNetworkReply; class QNetworkReply;
class QSslError; class QSslError;
@ -123,6 +124,8 @@ namespace Net
void finished(const DownloadResult &result); void finished(const DownloadResult &result);
}; };
class DownloadHandlerImpl;
class DownloadManager : public QObject class DownloadManager : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -133,10 +136,10 @@ namespace Net
static void freeInstance(); static void freeInstance();
static DownloadManager *instance(); static DownloadManager *instance();
DownloadHandler *download(const DownloadRequest &downloadRequest); DownloadHandler *download(const DownloadRequest &downloadRequest, bool useProxy);
template <typename Context, typename Func> template <typename Context, typename Func>
void download(const DownloadRequest &downloadRequest, Context context, Func &&slot); void download(const DownloadRequest &downloadRequest, bool useProxy, Context context, Func &&slot);
void registerSequentialService(const ServiceID &serviceID); void registerSequentialService(const ServiceID &serviceID);
@ -152,23 +155,28 @@ namespace Net
void ignoreSslErrors(QNetworkReply *, const QList<QSslError> &); void ignoreSslErrors(QNetworkReply *, const QList<QSslError> &);
private: private:
class NetworkCookieJar;
explicit DownloadManager(QObject *parent = nullptr); explicit DownloadManager(QObject *parent = nullptr);
void applyProxySettings(); void applyProxySettings();
void handleReplyFinished(const QNetworkReply *reply); void handleDownloadFinished(DownloadHandlerImpl *finishedHandler);
void processRequest(DownloadHandlerImpl *downloadHandler);
static DownloadManager *m_instance; static DownloadManager *m_instance;
QNetworkAccessManager m_networkManager; NetworkCookieJar *m_networkCookieJar = nullptr;
QNetworkAccessManager *m_networkManager = nullptr;
QNetworkProxy m_proxy;
QSet<ServiceID> m_sequentialServices; QSet<ServiceID> m_sequentialServices;
QSet<ServiceID> m_busyServices; QSet<ServiceID> m_busyServices;
QHash<ServiceID, QQueue<DownloadHandler *>> m_waitingJobs; QHash<ServiceID, QQueue<DownloadHandlerImpl *>> m_waitingJobs;
}; };
template <typename Context, typename Func> template <typename Context, typename Func>
void DownloadManager::download(const DownloadRequest &downloadRequest, Context context, Func &&slot) void DownloadManager::download(const DownloadRequest &downloadRequest, bool useProxy, Context context, Func &&slot)
{ {
const DownloadHandler *handler = download(downloadRequest); const DownloadHandler *handler = download(downloadRequest, useProxy);
connect(handler, &DownloadHandler::finished, context, slot); connect(handler, &DownloadHandler::finished, context, slot);
} }
} }

4
src/base/net/geoipmanager.cpp

@ -129,7 +129,9 @@ void GeoIPManager::downloadDatabaseFile()
{ {
const QDateTime curDatetime = QDateTime::currentDateTimeUtc(); const QDateTime curDatetime = QDateTime::currentDateTimeUtc();
const QString curUrl = DATABASE_URL.arg(QLocale::c().toString(curDatetime, u"yyyy-MM")); const QString curUrl = DATABASE_URL.arg(QLocale::c().toString(curDatetime, u"yyyy-MM"));
DownloadManager::instance()->download({curUrl}, this, &GeoIPManager::downloadFinished); DownloadManager::instance()->download(
{curUrl}, Preferences::instance()->useProxyForGeneralPurposes()
, this, &GeoIPManager::downloadFinished);
} }
QString GeoIPManager::lookup(const QHostAddress &hostAddr) const QString GeoIPManager::lookup(const QHostAddress &hostAddr) const

73
src/base/net/proxyconfigurationmanager.cpp

@ -35,8 +35,10 @@ bool Net::operator==(const ProxyConfiguration &left, const ProxyConfiguration &r
return (left.type == right.type) return (left.type == right.type)
&& (left.ip == right.ip) && (left.ip == right.ip)
&& (left.port == right.port) && (left.port == right.port)
&& (left.authEnabled == right.authEnabled)
&& (left.username == right.username) && (left.username == right.username)
&& (left.password == right.password); && (left.password == right.password)
&& (left.hostnameLookupEnabled == right.hostnameLookupEnabled);
} }
bool Net::operator!=(const ProxyConfiguration &left, const ProxyConfiguration &right) bool Net::operator!=(const ProxyConfiguration &left, const ProxyConfiguration &right)
@ -49,22 +51,24 @@ using namespace Net;
ProxyConfigurationManager *ProxyConfigurationManager::m_instance = nullptr; ProxyConfigurationManager *ProxyConfigurationManager::m_instance = nullptr;
ProxyConfigurationManager::ProxyConfigurationManager(QObject *parent) ProxyConfigurationManager::ProxyConfigurationManager(QObject *parent)
: QObject {parent} : QObject(parent)
, m_storeProxyOnlyForTorrents {SETTINGS_KEY(u"OnlyForTorrents"_qs)}
, m_storeProxyType {SETTINGS_KEY(u"Type"_qs)} , m_storeProxyType {SETTINGS_KEY(u"Type"_qs)}
, m_storeProxyIP {SETTINGS_KEY(u"IP"_qs)} , m_storeProxyIP {SETTINGS_KEY(u"IP"_qs)}
, m_storeProxyPort {SETTINGS_KEY(u"Port"_qs)} , m_storeProxyPort {SETTINGS_KEY(u"Port"_qs)}
, m_storeProxyAuthEnabled {SETTINGS_KEY(u"AuthEnabled"_qs)}
, m_storeProxyUsername {SETTINGS_KEY(u"Username"_qs)} , m_storeProxyUsername {SETTINGS_KEY(u"Username"_qs)}
, m_storeProxyPassword {SETTINGS_KEY(u"Password"_qs)} , m_storeProxyPassword {SETTINGS_KEY(u"Password"_qs)}
, m_storeProxyHostnameLookupEnabled {SETTINGS_KEY(u"HostnameLookupEnabled"_qs)}
{ {
m_config.type = m_storeProxyType.get(ProxyType::None); m_config.type = m_storeProxyType.get(ProxyType::HTTP);
if ((m_config.type < ProxyType::None) || (m_config.type > ProxyType::SOCKS4)) if ((m_config.type < ProxyType::HTTP) || (m_config.type > ProxyType::SOCKS4))
m_config.type = ProxyType::None; m_config.type = ProxyType::HTTP;
m_config.ip = m_storeProxyIP.get(u"0.0.0.0"_qs); m_config.ip = m_storeProxyIP.get(u"0.0.0.0"_qs);
m_config.port = m_storeProxyPort.get(8080); m_config.port = m_storeProxyPort.get(8080);
m_config.authEnabled = m_storeProxyAuthEnabled;
m_config.username = m_storeProxyUsername; m_config.username = m_storeProxyUsername;
m_config.password = m_storeProxyPassword; m_config.password = m_storeProxyPassword;
configureProxy(); m_config.hostnameLookupEnabled = m_storeProxyHostnameLookupEnabled.get(true);
} }
void ProxyConfigurationManager::initInstance() void ProxyConfigurationManager::initInstance()
@ -97,62 +101,11 @@ void ProxyConfigurationManager::setProxyConfiguration(const ProxyConfiguration &
m_storeProxyType = config.type; m_storeProxyType = config.type;
m_storeProxyIP = config.ip; m_storeProxyIP = config.ip;
m_storeProxyPort = config.port; m_storeProxyPort = config.port;
m_storeProxyAuthEnabled = config.authEnabled;
m_storeProxyUsername = config.username; m_storeProxyUsername = config.username;
m_storeProxyPassword = config.password; m_storeProxyPassword = config.password;
configureProxy(); m_storeProxyHostnameLookupEnabled = config.hostnameLookupEnabled;
emit proxyConfigurationChanged(); emit proxyConfigurationChanged();
} }
} }
bool ProxyConfigurationManager::isProxyOnlyForTorrents() const
{
return m_storeProxyOnlyForTorrents || (m_config.type == ProxyType::SOCKS4);
}
void ProxyConfigurationManager::setProxyOnlyForTorrents(const bool onlyForTorrents)
{
m_storeProxyOnlyForTorrents = onlyForTorrents;
}
bool ProxyConfigurationManager::isAuthenticationRequired() const
{
return m_config.type == ProxyType::SOCKS5_PW
|| m_config.type == ProxyType::HTTP_PW;
}
void ProxyConfigurationManager::configureProxy()
{
// Define environment variables for urllib in search engine plugins
QString proxyStrHTTP, proxyStrSOCK;
if (!isProxyOnlyForTorrents())
{
switch (m_config.type)
{
case ProxyType::HTTP_PW:
proxyStrHTTP = u"http://%1:%2@%3:%4"_qs.arg(m_config.username
, m_config.password, m_config.ip, QString::number(m_config.port));
break;
case ProxyType::HTTP:
proxyStrHTTP = u"http://%1:%2"_qs.arg(m_config.ip, QString::number(m_config.port));
break;
case ProxyType::SOCKS5:
proxyStrSOCK = u"%1:%2"_qs.arg(m_config.ip, QString::number(m_config.port));
break;
case ProxyType::SOCKS5_PW:
proxyStrSOCK = u"%1:%2@%3:%4"_qs.arg(m_config.username
, m_config.password, m_config.ip, QString::number(m_config.port));
break;
default:
qDebug("Disabling HTTP communications proxy");
}
qDebug("HTTP communications proxy string: %s"
, qUtf8Printable((m_config.type == ProxyType::SOCKS5) || (m_config.type == ProxyType::SOCKS5_PW)
? proxyStrSOCK : proxyStrHTTP));
}
qputenv("http_proxy", proxyStrHTTP.toLocal8Bit());
qputenv("https_proxy", proxyStrHTTP.toLocal8Bit());
qputenv("sock_proxy", proxyStrSOCK.toLocal8Bit());
}

16
src/base/net/proxyconfigurationmanager.h

@ -39,22 +39,21 @@ namespace Net
enum class ProxyType enum class ProxyType
{ {
None = 0,
HTTP = 1, HTTP = 1,
SOCKS5 = 2, SOCKS5 = 2,
HTTP_PW = 3,
SOCKS5_PW = 4,
SOCKS4 = 5 SOCKS4 = 5
}; };
Q_ENUM_NS(ProxyType) Q_ENUM_NS(ProxyType)
struct ProxyConfiguration struct ProxyConfiguration
{ {
ProxyType type = ProxyType::None; ProxyType type = ProxyType::HTTP;
QString ip = u"0.0.0.0"_qs; QString ip = u"0.0.0.0"_qs;
ushort port = 8080; ushort port = 8080;
bool authEnabled = false;
QString username; QString username;
QString password; QString password;
bool hostnameLookupEnabled = true;
}; };
bool operator==(const ProxyConfiguration &left, const ProxyConfiguration &right); bool operator==(const ProxyConfiguration &left, const ProxyConfiguration &right);
bool operator!=(const ProxyConfiguration &left, const ProxyConfiguration &right); bool operator!=(const ProxyConfiguration &left, const ProxyConfiguration &right);
@ -74,24 +73,19 @@ namespace Net
ProxyConfiguration proxyConfiguration() const; ProxyConfiguration proxyConfiguration() const;
void setProxyConfiguration(const ProxyConfiguration &config); void setProxyConfiguration(const ProxyConfiguration &config);
bool isProxyOnlyForTorrents() const;
void setProxyOnlyForTorrents(bool onlyForTorrents);
bool isAuthenticationRequired() const;
signals: signals:
void proxyConfigurationChanged(); void proxyConfigurationChanged();
private: private:
void configureProxy();
static ProxyConfigurationManager *m_instance; static ProxyConfigurationManager *m_instance;
ProxyConfiguration m_config; ProxyConfiguration m_config;
SettingValue<bool> m_storeProxyOnlyForTorrents;
SettingValue<ProxyType> m_storeProxyType; SettingValue<ProxyType> m_storeProxyType;
SettingValue<QString> m_storeProxyIP; SettingValue<QString> m_storeProxyIP;
SettingValue<ushort> m_storeProxyPort; SettingValue<ushort> m_storeProxyPort;
SettingValue<bool> m_storeProxyAuthEnabled;
SettingValue<QString> m_storeProxyUsername; SettingValue<QString> m_storeProxyUsername;
SettingValue<QString> m_storeProxyPassword; SettingValue<QString> m_storeProxyPassword;
SettingValue<bool> m_storeProxyHostnameLookupEnabled;
}; };
} }

31
src/base/preferences.cpp

@ -1619,6 +1619,37 @@ void Preferences::setNetworkCookies(const QList<QNetworkCookie> &cookies)
setValue(u"Network/Cookies"_qs, rawCookies); setValue(u"Network/Cookies"_qs, rawCookies);
} }
bool Preferences::useProxyForBT() const
{
return value<bool>(u"Network/Proxy/Profiles/BitTorrent"_qs);
}
void Preferences::setUseProxyForBT(const bool value)
{
setValue(u"Network/Proxy/Profiles/BitTorrent"_qs, value);
}
bool Preferences::useProxyForRSS() const
{
return value<bool>(u"Network/Proxy/Profiles/RSS"_qs);
}
void Preferences::setUseProxyForRSS(const bool value)
{
setValue(u"Network/Proxy/Profiles/RSS"_qs, value);
}
bool Preferences::useProxyForGeneralPurposes() const
{
return value<bool>(u"Network/Proxy/Profiles/Misc"_qs);
}
void Preferences::setUseProxyForGeneralPurposes(const bool value)
{
setValue(u"Network/Proxy/Profiles/Misc"_qs, value);
}
bool Preferences::isSpeedWidgetEnabled() const bool Preferences::isSpeedWidgetEnabled() const
{ {
return value(u"SpeedWidget/Enabled"_qs, true); return value(u"SpeedWidget/Enabled"_qs, true);

7
src/base/preferences.h

@ -397,6 +397,13 @@ public:
QList<QNetworkCookie> getNetworkCookies() const; QList<QNetworkCookie> getNetworkCookies() const;
void setNetworkCookies(const QList<QNetworkCookie> &cookies); void setNetworkCookies(const QList<QNetworkCookie> &cookies);
bool useProxyForBT() const;
void setUseProxyForBT(bool value);
bool useProxyForRSS() const;
void setUseProxyForRSS(bool value);
bool useProxyForGeneralPurposes() const;
void setUseProxyForGeneralPurposes(bool value);
// SpeedWidget // SpeedWidget
bool isSpeedWidgetEnabled() const; bool isSpeedWidgetEnabled() const;
void setSpeedWidgetEnabled(bool enabled); void setSpeedWidgetEnabled(bool enabled);

5
src/base/rss/rss_feed.cpp

@ -45,6 +45,7 @@
#include "base/global.h" #include "base/global.h"
#include "base/logger.h" #include "base/logger.h"
#include "base/net/downloadmanager.h" #include "base/net/downloadmanager.h"
#include "base/preferences.h"
#include "base/profile.h" #include "base/profile.h"
#include "base/utils/fs.h" #include "base/utils/fs.h"
#include "feed_serializer.h" #include "feed_serializer.h"
@ -148,7 +149,7 @@ void Feed::refresh()
// NOTE: Should we allow manually refreshing for disabled session? // NOTE: Should we allow manually refreshing for disabled session?
m_downloadHandler = Net::DownloadManager::instance()->download(m_url); m_downloadHandler = Net::DownloadManager::instance()->download(m_url, Preferences::instance()->useProxyForRSS());
connect(m_downloadHandler, &Net::DownloadHandler::finished, this, &Feed::handleDownloadFinished); connect(m_downloadHandler, &Net::DownloadHandler::finished, this, &Feed::handleDownloadFinished);
if (!m_iconPath.exists()) if (!m_iconPath.exists())
@ -378,7 +379,7 @@ void Feed::downloadIcon()
const auto iconUrl = u"%1://%2/favicon.ico"_qs.arg(url.scheme(), url.host()); const auto iconUrl = u"%1://%2/favicon.ico"_qs.arg(url.scheme(), url.host());
Net::DownloadManager::instance()->download( Net::DownloadManager::instance()->download(
Net::DownloadRequest(iconUrl).saveToFile(true).destFileName(m_iconPath) Net::DownloadRequest(iconUrl).saveToFile(true).destFileName(m_iconPath)
, this, &Feed::handleIconDownloadFinished); , Preferences::instance()->useProxyForRSS(), this, &Feed::handleIconDownloadFinished);
} }
int Feed::updateArticles(const QList<QVariantHash> &loadedArticles) int Feed::updateArticles(const QList<QVariantHash> &loadedArticles)

62
src/base/search/searchpluginmanager.cpp

@ -38,10 +38,12 @@
#include <QDomNode> #include <QDomNode>
#include <QPointer> #include <QPointer>
#include <QProcess> #include <QProcess>
#include <QUrl>
#include "base/global.h" #include "base/global.h"
#include "base/logger.h" #include "base/logger.h"
#include "base/net/downloadmanager.h" #include "base/net/downloadmanager.h"
#include "base/net/proxyconfigurationmanager.h"
#include "base/preferences.h" #include "base/preferences.h"
#include "base/profile.h" #include "base/profile.h"
#include "base/utils/bytearray.h" #include "base/utils/bytearray.h"
@ -90,6 +92,12 @@ SearchPluginManager::SearchPluginManager()
Q_ASSERT(!m_instance); // only one instance is allowed Q_ASSERT(!m_instance); // only one instance is allowed
m_instance = this; m_instance = this;
connect(Net::ProxyConfigurationManager::instance(), &Net::ProxyConfigurationManager::proxyConfigurationChanged
, this, &SearchPluginManager::applyProxySettings);
connect(Preferences::instance(), &Preferences::changed
, this, &SearchPluginManager::applyProxySettings);
applyProxySettings();
updateNova(); updateNova();
update(); update();
} }
@ -207,7 +215,8 @@ void SearchPluginManager::installPlugin(const QString &source)
{ {
using namespace Net; using namespace Net;
DownloadManager::instance()->download(DownloadRequest(source).saveToFile(true) DownloadManager::instance()->download(DownloadRequest(source).saveToFile(true)
, this, &SearchPluginManager::pluginDownloadFinished); , Preferences::instance()->useProxyForGeneralPurposes()
, this, &SearchPluginManager::pluginDownloadFinished);
} }
else else
{ {
@ -323,7 +332,8 @@ void SearchPluginManager::checkForUpdates()
// Download version file from update server // Download version file from update server
using namespace Net; using namespace Net;
DownloadManager::instance()->download({m_updateUrl + u"versions.txt"} DownloadManager::instance()->download({m_updateUrl + u"versions.txt"}
, this, &SearchPluginManager::versionInfoDownloadFinished); , Preferences::instance()->useProxyForGeneralPurposes()
, this, &SearchPluginManager::versionInfoDownloadFinished);
} }
SearchDownloadHandler *SearchPluginManager::downloadTorrent(const QString &siteUrl, const QString &url) SearchDownloadHandler *SearchPluginManager::downloadTorrent(const QString &siteUrl, const QString &url)
@ -378,6 +388,54 @@ Path SearchPluginManager::engineLocation()
return location; return location;
} }
void SearchPluginManager::applyProxySettings()
{
const auto *proxyManager = Net::ProxyConfigurationManager::instance();
const Net::ProxyConfiguration proxyConfig = proxyManager->proxyConfiguration();
// Define environment variables for urllib in search engine plugins
QString proxyStrHTTP, proxyStrSOCK;
if (Preferences::instance()->useProxyForGeneralPurposes())
{
switch (proxyConfig.type)
{
case Net::ProxyType::HTTP:
if (proxyConfig.authEnabled)
{
proxyStrHTTP = u"http://%1:%2@%3:%4"_qs.arg(proxyConfig.username
, proxyConfig.password, proxyConfig.ip, QString::number(proxyConfig.port));
}
else
{
proxyStrHTTP = u"http://%1:%2"_qs.arg(proxyConfig.ip, QString::number(proxyConfig.port));
}
break;
case Net::ProxyType::SOCKS5:
if (proxyConfig.authEnabled)
{
proxyStrSOCK = u"%1:%2@%3:%4"_qs.arg(proxyConfig.username
, proxyConfig.password, proxyConfig.ip, QString::number(proxyConfig.port));
}
else
{
proxyStrSOCK = u"%1:%2"_qs.arg(proxyConfig.ip, QString::number(proxyConfig.port));
}
break;
default:
qDebug("Disabling HTTP communications proxy");
}
qDebug("HTTP communications proxy string: %s"
, qUtf8Printable((proxyConfig.type == Net::ProxyType::SOCKS5) ? proxyStrSOCK : proxyStrHTTP));
}
qputenv("http_proxy", proxyStrHTTP.toLocal8Bit());
qputenv("https_proxy", proxyStrHTTP.toLocal8Bit());
qputenv("sock_proxy", proxyStrSOCK.toLocal8Bit());
}
void SearchPluginManager::versionInfoDownloadFinished(const Net::DownloadResult &result) void SearchPluginManager::versionInfoDownloadFinished(const Net::DownloadResult &result)
{ {
if (result.status == Net::DownloadStatus::Success) if (result.status == Net::DownloadStatus::Success)

1
src/base/search/searchpluginmanager.h

@ -104,6 +104,7 @@ signals:
void checkForUpdatesFailed(const QString &reason); void checkForUpdatesFailed(const QString &reason);
private: private:
void applyProxySettings();
void update(); void update();
void updateNova(); void updateNova();
void parseVersionInfo(const QByteArray &info); void parseVersionInfo(const QByteArray &info);

7
src/gui/addnewtorrentdialog.cpp

@ -32,6 +32,7 @@
#include <algorithm> #include <algorithm>
#include <QAction> #include <QAction>
#include <QDateTime>
#include <QDebug> #include <QDebug>
#include <QDir> #include <QDir>
#include <QFileDialog> #include <QFileDialog>
@ -51,6 +52,7 @@
#include "base/bittorrent/torrentcontentlayout.h" #include "base/bittorrent/torrentcontentlayout.h"
#include "base/global.h" #include "base/global.h"
#include "base/net/downloadmanager.h" #include "base/net/downloadmanager.h"
#include "base/preferences.h"
#include "base/settingsstorage.h" #include "base/settingsstorage.h"
#include "base/torrentfileguard.h" #include "base/torrentfileguard.h"
#include "base/utils/compare.h" #include "base/utils/compare.h"
@ -474,8 +476,9 @@ void AddNewTorrentDialog::show(const QString &source, const BitTorrent::AddTorre
{ {
// Launch downloader // Launch downloader
Net::DownloadManager::instance()->download( Net::DownloadManager::instance()->download(
Net::DownloadRequest(source).limit(MAX_TORRENT_SIZE) Net::DownloadRequest(source).limit(MAX_TORRENT_SIZE)
, dlg, &AddNewTorrentDialog::handleDownloadFinished); , Preferences::instance()->useProxyForGeneralPurposes()
, dlg, &AddNewTorrentDialog::handleDownloadFinished);
return; return;
} }

5
src/gui/mainwindow.cpp

@ -1948,8 +1948,9 @@ void MainWindow::installPython()
const auto installerURL = u"https://www.python.org/ftp/python/3.8.10/python-3.8.10.exe"_qs; const auto installerURL = u"https://www.python.org/ftp/python/3.8.10/python-3.8.10.exe"_qs;
#endif #endif
Net::DownloadManager::instance()->download( Net::DownloadManager::instance()->download(
Net::DownloadRequest(installerURL).saveToFile(true) Net::DownloadRequest(installerURL).saveToFile(true)
, this, &MainWindow::pythonDownloadFinished); , Preferences::instance()->useProxyForGeneralPurposes()
, this, &MainWindow::pythonDownloadFinished);
} }
void MainWindow::pythonDownloadFinished(const Net::DownloadResult &result) void MainWindow::pythonDownloadFinished(const Net::DownloadResult &result)

134
src/gui/optionsdialog.cpp

@ -52,7 +52,6 @@
#include "base/rss/rss_session.h" #include "base/rss/rss_session.h"
#include "base/torrentfileguard.h" #include "base/torrentfileguard.h"
#include "base/torrentfileswatcher.h" #include "base/torrentfileswatcher.h"
#include "base/utils/fs.h"
#include "base/utils/misc.h" #include "base/utils/misc.h"
#include "base/utils/net.h" #include "base/utils/net.h"
#include "base/utils/password.h" #include "base/utils/password.h"
@ -770,42 +769,25 @@ void OptionsDialog::loadConnectionTabOptions()
} }
const auto *proxyConfigManager = Net::ProxyConfigurationManager::instance(); const auto *proxyConfigManager = Net::ProxyConfigurationManager::instance();
Net::ProxyConfiguration proxyConf = proxyConfigManager->proxyConfiguration(); const Net::ProxyConfiguration proxyConf = proxyConfigManager->proxyConfiguration();
using Net::ProxyType;
bool useProxyAuth = false; m_ui->comboProxyType->addItem(tr("SOCKS4"), QVariant::fromValue(Net::ProxyType::SOCKS4));
switch (proxyConf.type) m_ui->comboProxyType->addItem(tr("SOCKS5"), QVariant::fromValue(Net::ProxyType::SOCKS5));
{ m_ui->comboProxyType->addItem(tr("HTTP"), QVariant::fromValue(Net::ProxyType::HTTP));
case ProxyType::SOCKS4: m_ui->comboProxyType->setCurrentIndex(m_ui->comboProxyType->findData(QVariant::fromValue(proxyConf.type)));
m_ui->comboProxyType->setCurrentIndex(1); adjustProxyOptions();
break;
case ProxyType::SOCKS5_PW:
useProxyAuth = true;
// fallthrough
case ProxyType::SOCKS5:
m_ui->comboProxyType->setCurrentIndex(2);
break;
case ProxyType::HTTP_PW:
useProxyAuth = true;
// fallthrough
case ProxyType::HTTP:
m_ui->comboProxyType->setCurrentIndex(3);
break;
default:
m_ui->comboProxyType->setCurrentIndex(0);
}
m_ui->textProxyIP->setText(proxyConf.ip); m_ui->textProxyIP->setText(proxyConf.ip);
m_ui->spinProxyPort->setValue(proxyConf.port); m_ui->spinProxyPort->setValue(proxyConf.port);
m_ui->checkProxyAuth->setChecked(useProxyAuth); m_ui->checkProxyAuth->setChecked(proxyConf.authEnabled);
m_ui->textProxyUsername->setText(proxyConf.username); m_ui->textProxyUsername->setText(proxyConf.username);
m_ui->textProxyPassword->setText(proxyConf.password); m_ui->textProxyPassword->setText(proxyConf.password);
m_ui->checkProxyHostnameLookup->setChecked(proxyConf.hostnameLookupEnabled);
m_ui->checkProxyBitTorrent->setChecked(Preferences::instance()->useProxyForBT());
m_ui->checkProxyPeerConnections->setChecked(session->isProxyPeerConnectionsEnabled()); m_ui->checkProxyPeerConnections->setChecked(session->isProxyPeerConnectionsEnabled());
m_ui->isProxyOnlyForTorrents->setChecked(proxyConfigManager->isProxyOnlyForTorrents()); m_ui->checkProxyRSS->setChecked(Preferences::instance()->useProxyForRSS());
m_ui->checkProxyHostnameLookup->setChecked(session->isProxyHostnameLookupEnabled()); m_ui->checkProxyMisc->setChecked(Preferences::instance()->useProxyForGeneralPurposes());
enableProxy(m_ui->comboProxyType->currentIndex());
m_ui->checkIPFilter->setChecked(session->isIPFilteringEnabled()); m_ui->checkIPFilter->setChecked(session->isIPFilteringEnabled());
m_ui->textFilterPath->setDialogCaption(tr("Choose an IP filter file")); m_ui->textFilterPath->setDialogCaption(tr("Choose an IP filter file"));
@ -830,14 +812,17 @@ void OptionsDialog::loadConnectionTabOptions()
connect(m_ui->spinMaxUploads, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); connect(m_ui->spinMaxUploads, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
connect(m_ui->spinMaxUploadsPerTorrent, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); connect(m_ui->spinMaxUploadsPerTorrent, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
connect(m_ui->comboProxyType, qComboBoxCurrentIndexChanged, this, &ThisType::enableProxy); connect(m_ui->comboProxyType, qComboBoxCurrentIndexChanged, this, &ThisType::adjustProxyOptions);
connect(m_ui->comboProxyType, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); connect(m_ui->comboProxyType, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
connect(m_ui->textProxyIP, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); connect(m_ui->textProxyIP, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
connect(m_ui->spinProxyPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton); connect(m_ui->spinProxyPort, qSpinBoxValueChanged, this, &ThisType::enableApplyButton);
connect(m_ui->checkProxyBitTorrent, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkProxyBitTorrent, &QGroupBox::toggled, this, &ThisType::adjustProxyOptions);
connect(m_ui->checkProxyPeerConnections, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkProxyPeerConnections, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->isProxyOnlyForTorrents, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkProxyHostnameLookup, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkProxyHostnameLookup, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkProxyRSS, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkProxyMisc, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkProxyAuth, &QGroupBox::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkProxyAuth, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->textProxyUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); connect(m_ui->textProxyUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
@ -868,13 +853,17 @@ void OptionsDialog::saveConnectionTabOptions() const
proxyConf.type = getProxyType(); proxyConf.type = getProxyType();
proxyConf.ip = getProxyIp(); proxyConf.ip = getProxyIp();
proxyConf.port = getProxyPort(); proxyConf.port = getProxyPort();
proxyConf.authEnabled = m_ui->checkProxyAuth->isChecked();
proxyConf.username = getProxyUsername(); proxyConf.username = getProxyUsername();
proxyConf.password = getProxyPassword(); proxyConf.password = getProxyPassword();
proxyConfigManager->setProxyOnlyForTorrents(m_ui->isProxyOnlyForTorrents->isChecked()); proxyConf.hostnameLookupEnabled = m_ui->checkProxyHostnameLookup->isChecked();
proxyConfigManager->setProxyConfiguration(proxyConf); proxyConfigManager->setProxyConfiguration(proxyConf);
Preferences::instance()->setUseProxyForBT(m_ui->checkProxyBitTorrent->isChecked());
Preferences::instance()->setUseProxyForRSS(m_ui->checkProxyRSS->isChecked());
Preferences::instance()->setUseProxyForGeneralPurposes(m_ui->checkProxyMisc->isChecked());
session->setProxyPeerConnectionsEnabled(m_ui->checkProxyPeerConnections->isChecked()); session->setProxyPeerConnectionsEnabled(m_ui->checkProxyPeerConnections->isChecked());
session->setProxyHostnameLookupEnabled(m_ui->checkProxyHostnameLookup->isChecked());
// IPFilter // IPFilter
session->setIPFilteringEnabled(isIPFilteringEnabled()); session->setIPFilteringEnabled(isIPFilteringEnabled());
@ -1321,21 +1310,7 @@ bool OptionsDialog::isIPFilteringEnabled() const
Net::ProxyType OptionsDialog::getProxyType() const Net::ProxyType OptionsDialog::getProxyType() const
{ {
switch (m_ui->comboProxyType->currentIndex()) return m_ui->comboProxyType->currentData().value<Net::ProxyType>();
{
case 1:
return Net::ProxyType::SOCKS4;
case 2:
if (isProxyAuthEnabled())
return Net::ProxyType::SOCKS5_PW;
return Net::ProxyType::SOCKS5;
case 3:
if (isProxyAuthEnabled())
return Net::ProxyType::HTTP_PW;
return Net::ProxyType::HTTP;
default:
return Net::ProxyType::None;
}
} }
int OptionsDialog::getPort() const int OptionsDialog::getPort() const
@ -1512,41 +1487,29 @@ void OptionsDialog::toggleComboRatioLimitAct()
m_ui->comboRatioLimitAct->setEnabled(m_ui->checkMaxRatio->isChecked() || m_ui->checkMaxSeedingMinutes->isChecked()); m_ui->comboRatioLimitAct->setEnabled(m_ui->checkMaxRatio->isChecked() || m_ui->checkMaxSeedingMinutes->isChecked());
} }
void OptionsDialog::enableProxy(const int index) void OptionsDialog::adjustProxyOptions()
{ {
if (index >= 1) const auto currentProxyType = m_ui->comboProxyType->currentData().value<Net::ProxyType>();
{ // Any proxy type is used const bool isAuthSupported = (currentProxyType != Net::ProxyType::SOCKS4);
//enable
m_ui->lblProxyIP->setEnabled(true); m_ui->checkProxyAuth->setEnabled(isAuthSupported);
m_ui->textProxyIP->setEnabled(true);
m_ui->lblProxyPort->setEnabled(true); if (currentProxyType == Net::ProxyType::SOCKS4)
m_ui->spinProxyPort->setEnabled(true); {
m_ui->checkProxyPeerConnections->setEnabled(true); m_ui->labelProxyTypeIncompatible->setVisible(true);
if (index >= 2)
{ // SOCKS5 or HTTP m_ui->checkProxyHostnameLookup->setEnabled(false);
m_ui->checkProxyAuth->setEnabled(true); m_ui->checkProxyRSS->setEnabled(false);
m_ui->isProxyOnlyForTorrents->setEnabled(true); m_ui->checkProxyMisc->setEnabled(false);
m_ui->checkProxyHostnameLookup->setEnabled(true);
}
else
{
m_ui->checkProxyAuth->setEnabled(false);
m_ui->isProxyOnlyForTorrents->setEnabled(false);
m_ui->isProxyOnlyForTorrents->setChecked(true);
m_ui->checkProxyHostnameLookup->setEnabled(false);
}
} }
else else
{ // No proxy {
// disable // SOCKS5 or HTTP
m_ui->lblProxyIP->setEnabled(false); m_ui->labelProxyTypeIncompatible->setVisible(false);
m_ui->textProxyIP->setEnabled(false);
m_ui->lblProxyPort->setEnabled(false); m_ui->checkProxyHostnameLookup->setEnabled(true);
m_ui->spinProxyPort->setEnabled(false); m_ui->checkProxyRSS->setEnabled(true);
m_ui->checkProxyPeerConnections->setEnabled(false); m_ui->checkProxyMisc->setEnabled(true);
m_ui->isProxyOnlyForTorrents->setEnabled(false);
m_ui->checkProxyHostnameLookup->setEnabled(false);
m_ui->checkProxyAuth->setEnabled(false);
} }
} }
@ -1578,11 +1541,6 @@ bool OptionsDialog::isProxyEnabled() const
return m_ui->comboProxyType->currentIndex(); return m_ui->comboProxyType->currentIndex();
} }
bool OptionsDialog::isProxyAuthEnabled() const
{
return m_ui->checkProxyAuth->isChecked();
}
QString OptionsDialog::getProxyIp() const QString OptionsDialog::getProxyIp() const
{ {
return m_ui->textProxyIP->text().trimmed(); return m_ui->textProxyIP->text().trimmed();

3
src/gui/optionsdialog.h

@ -85,7 +85,7 @@ public slots:
void showConnectionTab(); void showConnectionTab();
private slots: private slots:
void enableProxy(int index); void adjustProxyOptions();
void on_buttonBox_accepted(); void on_buttonBox_accepted();
void on_buttonBox_rejected(); void on_buttonBox_rejected();
void applySettings(); void applySettings();
@ -168,7 +168,6 @@ private:
int getMaxSeedingMinutes() const; int getMaxSeedingMinutes() const;
// Proxy options // Proxy options
bool isProxyEnabled() const; bool isProxyEnabled() const;
bool isProxyAuthEnabled() const;
QString getProxyIp() const; QString getProxyIp() const;
unsigned short getProxyPort() const; unsigned short getProxyPort() const;
QString getProxyUsername() const; QString getProxyUsername() const;

126
src/gui/optionsdialog.ui

@ -1800,51 +1800,20 @@ readme[0-9].txt: filter 'readme1.txt', 'readme2.txt' but not 'readme10.txt'.</st
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QComboBox" name="comboProxyType"> <widget class="QComboBox" name="comboProxyType" />
<item>
<property name="text">
<string>(None)</string>
</property>
</item>
<item>
<property name="text">
<string>SOCKS4</string>
</property>
</item>
<item>
<property name="text">
<string>SOCKS5</string>
</property>
</item>
<item>
<property name="text">
<string>HTTP</string>
</property>
</item>
</widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="lblProxyIP"> <widget class="QLabel" name="lblProxyIP">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text"> <property name="text">
<string>Host:</string> <string>Host:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLineEdit" name="textProxyIP"> <widget class="QLineEdit" name="textProxyIP" />
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="lblProxyPort"> <widget class="QLabel" name="lblProxyPort">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text"> <property name="text">
<string>Port:</string> <string>Port:</string>
</property> </property>
@ -1852,9 +1821,6 @@ readme[0-9].txt: filter 'readme1.txt', 'readme2.txt' but not 'readme10.txt'.</st
</item> </item>
<item> <item>
<widget class="QSpinBox" name="spinProxyPort"> <widget class="QSpinBox" name="spinProxyPort">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum"> <property name="minimum">
<number>1</number> <number>1</number>
</property> </property>
@ -1869,38 +1835,21 @@ readme[0-9].txt: filter 'readme1.txt', 'readme2.txt' but not 'readme10.txt'.</st
</layout> </layout>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="checkProxyPeerConnections"> <widget class="QLabel" name="labelProxyTypeIncompatible">
<property name="enabled"> <property name="font">
<bool>false</bool> <font>
</property> <italic>true</italic>
<property name="toolTip"> </font>
<string>Otherwise, the proxy server is only used for tracker connections</string>
</property>
<property name="text">
<string>Use proxy for peer connections</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="isProxyOnlyForTorrents">
<property name="toolTip">
<string>RSS feeds, search engine, software updates or anything else other than torrent transfers and related operations (such as peer exchanges) will use a direct connection</string>
</property> </property>
<property name="text"> <property name="text">
<string>Use proxy only for torrents</string> <string>Some options are incompatible with the chosen proxy type!</string>
</property>
<property name="checked">
<bool>false</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="checkProxyHostnameLookup"> <widget class="QCheckBox" name="checkProxyHostnameLookup">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip"> <property name="toolTip">
<string>If checked, hostname lookups are done via the proxy.</string> <string>If checked, hostname lookups are done via the proxy</string>
</property> </property>
<property name="text"> <property name="text">
<string>Use proxy for hostname lookups</string> <string>Use proxy for hostname lookups</string>
@ -1960,6 +1909,57 @@ readme[0-9].txt: filter 'readme1.txt', 'readme2.txt' but not 'readme10.txt'.</st
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QGroupBox" name="checkProxyBitTorrent">
<property name="title">
<string>Use proxy for BitTorrent purposes</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayoutProxyBitTorrent">
<item>
<widget class="QCheckBox" name="checkProxyPeerConnections">
<property name="toolTip">
<string>Otherwise, the proxy server is only used for tracker connections</string>
</property>
<property name="text">
<string>Use proxy for peer connections</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkProxyRSS">
<property name="toolTip">
<string>RSS feeds will use proxy</string>
</property>
<property name="text">
<string>Use proxy for RSS purposes</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkProxyMisc">
<property name="toolTip">
<string>Search engine, software updates or anything else will use proxy</string>
</property>
<property name="text">
<string>Use proxy for general purposes</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -3716,12 +3716,14 @@ Use ';' to split multiple entries. Can use wildcard '*'.</string>
<tabstop>comboProxyType</tabstop> <tabstop>comboProxyType</tabstop>
<tabstop>textProxyIP</tabstop> <tabstop>textProxyIP</tabstop>
<tabstop>spinProxyPort</tabstop> <tabstop>spinProxyPort</tabstop>
<tabstop>checkProxyPeerConnections</tabstop>
<tabstop>isProxyOnlyForTorrents</tabstop>
<tabstop>checkProxyHostnameLookup</tabstop> <tabstop>checkProxyHostnameLookup</tabstop>
<tabstop>checkProxyAuth</tabstop> <tabstop>checkProxyAuth</tabstop>
<tabstop>textProxyUsername</tabstop> <tabstop>textProxyUsername</tabstop>
<tabstop>textProxyPassword</tabstop> <tabstop>textProxyPassword</tabstop>
<tabstop>checkProxyBitTorrent</tabstop>
<tabstop>checkProxyPeerConnections</tabstop>
<tabstop>checkProxyRSS</tabstop>
<tabstop>checkProxyMisc</tabstop>
<tabstop>checkIPFilter</tabstop> <tabstop>checkIPFilter</tabstop>
<tabstop>textFilterPath</tabstop> <tabstop>textFilterPath</tabstop>
<tabstop>IpFilterRefreshBtn</tabstop> <tabstop>IpFilterRefreshBtn</tabstop>

5
src/gui/programupdater.cpp

@ -45,6 +45,7 @@
#include "base/global.h" #include "base/global.h"
#include "base/net/downloadmanager.h" #include "base/net/downloadmanager.h"
#include "base/preferences.h"
#include "base/utils/version.h" #include "base/utils/version.h"
#include "base/version.h" #include "base/version.h"
@ -76,8 +77,8 @@ void ProgramUpdater::checkForUpdates() const
// Don't change this User-Agent. In case our updater goes haywire, // Don't change this User-Agent. In case our updater goes haywire,
// the filehost can identify it and contact us. // the filehost can identify it and contact us.
Net::DownloadManager::instance()->download( Net::DownloadManager::instance()->download(
Net::DownloadRequest(RSS_URL).userAgent(QStringLiteral("qBittorrent/" QBT_VERSION_2 " ProgramUpdater (www.qbittorrent.org)")) Net::DownloadRequest(RSS_URL).userAgent(QStringLiteral("qBittorrent/" QBT_VERSION_2 " ProgramUpdater (www.qbittorrent.org)"))
, this, &ProgramUpdater::rssDownloadFinished); , Preferences::instance()->useProxyForGeneralPurposes(), this, &ProgramUpdater::rssDownloadFinished);
} }
QString ProgramUpdater::getNewVersion() const QString ProgramUpdater::getNewVersion() const

4
src/gui/properties/trackersadditiondialog.cpp

@ -38,6 +38,7 @@
#include "base/bittorrent/trackerentry.h" #include "base/bittorrent/trackerentry.h"
#include "base/global.h" #include "base/global.h"
#include "base/net/downloadmanager.h" #include "base/net/downloadmanager.h"
#include "base/preferences.h"
#include "gui/uithememanager.h" #include "gui/uithememanager.h"
#include "ui_trackersadditiondialog.h" #include "ui_trackersadditiondialog.h"
@ -87,7 +88,8 @@ void TrackersAdditionDialog::onDownloadButtonClicked()
m_ui->downloadButton->setEnabled(false); m_ui->downloadButton->setEnabled(false);
setCursor(Qt::WaitCursor); setCursor(Qt::WaitCursor);
Net::DownloadManager::instance()->download(url, this, &TrackersAdditionDialog::onTorrentListDownloadFinished); Net::DownloadManager::instance()->download(url, Preferences::instance()->useProxyForGeneralPurposes()
, this, &TrackersAdditionDialog::onTorrentListDownloadFinished);
} }
void TrackersAdditionDialog::onTorrentListDownloadFinished(const Net::DownloadResult &result) void TrackersAdditionDialog::onTorrentListDownloadFinished(const Net::DownloadResult &result)

5
src/gui/search/pluginselectdialog.cpp

@ -40,6 +40,7 @@
#include "base/global.h" #include "base/global.h"
#include "base/net/downloadmanager.h" #include "base/net/downloadmanager.h"
#include "base/preferences.h"
#include "base/utils/fs.h" #include "base/utils/fs.h"
#include "gui/autoexpandabledialog.h" #include "gui/autoexpandabledialog.h"
#include "gui/uithememanager.h" #include "gui/uithememanager.h"
@ -311,8 +312,8 @@ void PluginSelectDialog::addNewPlugin(const QString &pluginName)
// Icon is missing, we must download it // Icon is missing, we must download it
using namespace Net; using namespace Net;
DownloadManager::instance()->download( DownloadManager::instance()->download(
DownloadRequest(plugin->url + u"/favicon.ico").saveToFile(true) DownloadRequest(plugin->url + u"/favicon.ico").saveToFile(true)
, this, &PluginSelectDialog::iconDownloadFinished); , Preferences::instance()->useProxyForGeneralPurposes(), this, &PluginSelectDialog::iconDownloadFinished);
} }
item->setText(PLUGIN_VERSION, plugin->version.toString()); item->setText(PLUGIN_VERSION, plugin->version.toString());
} }

4
src/gui/transferlistfilterswidget.cpp

@ -658,8 +658,8 @@ void TrackerFiltersList::downloadFavicon(const QString &url)
{ {
if (!m_downloadTrackerFavicon) return; if (!m_downloadTrackerFavicon) return;
Net::DownloadManager::instance()->download( Net::DownloadManager::instance()->download(
Net::DownloadRequest(url).saveToFile(true) Net::DownloadRequest(url).saveToFile(true), Preferences::instance()->useProxyForGeneralPurposes()
, this, &TrackerFiltersList::handleFavicoDownloadFinished); , this, &TrackerFiltersList::handleFavicoDownloadFinished);
} }
void TrackerFiltersList::handleFavicoDownloadFinished(const Net::DownloadResult &result) void TrackerFiltersList::handleFavicoDownloadFinished(const Net::DownloadResult &result)

26
src/webui/api/appcontroller.cpp

@ -194,16 +194,18 @@ void AppController::preferencesAction()
// Proxy Server // Proxy Server
const auto *proxyManager = Net::ProxyConfigurationManager::instance(); const auto *proxyManager = Net::ProxyConfigurationManager::instance();
Net::ProxyConfiguration proxyConf = proxyManager->proxyConfiguration(); Net::ProxyConfiguration proxyConf = proxyManager->proxyConfiguration();
data[u"proxy_type"_qs] = static_cast<int>(proxyConf.type); data[u"proxy_type"_qs] = Utils::String::fromEnum(proxyConf.type);
data[u"proxy_ip"_qs] = proxyConf.ip; data[u"proxy_ip"_qs] = proxyConf.ip;
data[u"proxy_port"_qs] = proxyConf.port; data[u"proxy_port"_qs] = proxyConf.port;
data[u"proxy_auth_enabled"_qs] = proxyManager->isAuthenticationRequired(); // deprecated data[u"proxy_auth_enabled"_qs] = proxyConf.authEnabled;
data[u"proxy_username"_qs] = proxyConf.username; data[u"proxy_username"_qs] = proxyConf.username;
data[u"proxy_password"_qs] = proxyConf.password; data[u"proxy_password"_qs] = proxyConf.password;
data[u"proxy_hostname_lookup"_qs] = proxyConf.hostnameLookupEnabled;
data[u"proxy_bittorrent"_qs] = pref->useProxyForBT();
data[u"proxy_peer_connections"_qs] = session->isProxyPeerConnectionsEnabled(); data[u"proxy_peer_connections"_qs] = session->isProxyPeerConnectionsEnabled();
data[u"proxy_torrents_only"_qs] = proxyManager->isProxyOnlyForTorrents(); data[u"proxy_rss"_qs] = pref->useProxyForRSS();
data[u"proxy_hostname_lookup"_qs] = session->isProxyHostnameLookupEnabled(); data[u"proxy_misc"_qs] = pref->useProxyForGeneralPurposes();
// IP Filtering // IP Filtering
data[u"ip_filter_enabled"_qs] = session->isIPFilteringEnabled(); data[u"ip_filter_enabled"_qs] = session->isIPFilteringEnabled();
@ -610,23 +612,29 @@ void AppController::setPreferencesAction()
auto proxyManager = Net::ProxyConfigurationManager::instance(); auto proxyManager = Net::ProxyConfigurationManager::instance();
Net::ProxyConfiguration proxyConf = proxyManager->proxyConfiguration(); Net::ProxyConfiguration proxyConf = proxyManager->proxyConfiguration();
if (hasKey(u"proxy_type"_qs)) if (hasKey(u"proxy_type"_qs))
proxyConf.type = static_cast<Net::ProxyType>(it.value().toInt()); proxyConf.type = Utils::String::toEnum(it.value().toString(), Net::ProxyType::HTTP);
if (hasKey(u"proxy_ip"_qs)) if (hasKey(u"proxy_ip"_qs))
proxyConf.ip = it.value().toString(); proxyConf.ip = it.value().toString();
if (hasKey(u"proxy_port"_qs)) if (hasKey(u"proxy_port"_qs))
proxyConf.port = it.value().toUInt(); proxyConf.port = it.value().toUInt();
if (hasKey(u"proxy_auth_enabled"_qs))
proxyConf.authEnabled = it.value().toBool();
if (hasKey(u"proxy_username"_qs)) if (hasKey(u"proxy_username"_qs))
proxyConf.username = it.value().toString(); proxyConf.username = it.value().toString();
if (hasKey(u"proxy_password"_qs)) if (hasKey(u"proxy_password"_qs))
proxyConf.password = it.value().toString(); proxyConf.password = it.value().toString();
if (hasKey(u"proxy_hostname_lookup"_qs))
proxyConf.hostnameLookupEnabled = it.value().toBool();
proxyManager->setProxyConfiguration(proxyConf); proxyManager->setProxyConfiguration(proxyConf);
if (hasKey(u"proxy_bittorrent"_qs))
pref->setUseProxyForBT(it.value().toBool());
if (hasKey(u"proxy_peer_connections"_qs)) if (hasKey(u"proxy_peer_connections"_qs))
session->setProxyPeerConnectionsEnabled(it.value().toBool()); session->setProxyPeerConnectionsEnabled(it.value().toBool());
if (hasKey(u"proxy_torrents_only"_qs)) if (hasKey(u"proxy_rss"_qs))
proxyManager->setProxyOnlyForTorrents(it.value().toBool()); pref->setUseProxyForRSS(it.value().toBool());
if (hasKey(u"proxy_hostname_lookup"_qs)) if (hasKey(u"proxy_misc"_qs))
session->setProxyHostnameLookupEnabled(it.value().toBool()); pref->setUseProxyForGeneralPurposes(it.value().toBool());
// IP Filtering // IP Filtering
if (hasKey(u"ip_filter_enabled"_qs)) if (hasKey(u"ip_filter_enabled"_qs))

2
src/webui/webapplication.h

@ -52,7 +52,7 @@
#include "base/utils/version.h" #include "base/utils/version.h"
#include "api/isessionmanager.h" #include "api/isessionmanager.h"
inline const Utils::Version<3, 2> API_VERSION {2, 8, 20}; inline const Utils::Version<3, 2> API_VERSION {2, 9, 0};
class APIController; class APIController;
class AuthController; class AuthController;

122
src/webui/www/private/views/preferences.html

@ -350,10 +350,9 @@
</td> </td>
<td> <td>
<select id="peer_proxy_type_select" onchange="qBittorrent.Preferences.updatePeerProxySettings();"> <select id="peer_proxy_type_select" onchange="qBittorrent.Preferences.updatePeerProxySettings();">
<option value="none">QBT_TR((None))QBT_TR[CONTEXT=OptionsDialog]</option> <option value="SOCKS4">QBT_TR(SOCKS4)QBT_TR[CONTEXT=OptionsDialog]</option>
<option value="socks4">QBT_TR(SOCKS4)QBT_TR[CONTEXT=OptionsDialog]</option> <option value="SOCKS5">QBT_TR(SOCKS5)QBT_TR[CONTEXT=OptionsDialog]</option>
<option value="socks5">QBT_TR(SOCKS5)QBT_TR[CONTEXT=OptionsDialog]</option> <option value="HTTP">QBT_TR(HTTP)QBT_TR[CONTEXT=OptionsDialog]</option>
<option value="http">QBT_TR(HTTP)QBT_TR[CONTEXT=OptionsDialog]</option>
</select> </select>
</td> </td>
<td> <td>
@ -370,18 +369,12 @@
</td> </td>
</tr> </tr>
</table> </table>
<div class="formRow">
<input type="checkbox" id="use_peer_proxy_checkbox" />
<label for="use_peer_proxy_checkbox">QBT_TR(Use proxy for peer connections)QBT_TR[CONTEXT=OptionsDialog]</label>
</div>
<div class="formRow">
<input type="checkbox" id="proxy_only_for_torrents_checkbox" />
<label for="proxy_only_for_torrents_checkbox">QBT_TR(Use proxy only for torrents)QBT_TR[CONTEXT=OptionsDialog]</label>
</div>
<div class="formRow"> <div class="formRow">
<input type="checkbox" id="proxyHostnameLookupCheckbox" title="QBT_TR(If checked, hostname lookups are done via the proxy.)QBT_TR[CONTEXT=OptionsDialog]" /> <input type="checkbox" id="proxyHostnameLookupCheckbox" title="QBT_TR(If checked, hostname lookups are done via the proxy.)QBT_TR[CONTEXT=OptionsDialog]" />
<label for="proxyHostnameLookupCheckbox">QBT_TR(Use proxy for hostname lookup)QBT_TR[CONTEXT=OptionsDialog]</label> <label for="proxyHostnameLookupCheckbox">QBT_TR(Use proxy for hostname lookup)QBT_TR[CONTEXT=OptionsDialog]</label>
</div> </div>
<fieldset class="settings"> <fieldset class="settings">
<legend> <legend>
<input type="checkbox" id="peer_proxy_auth_checkbox" onclick="qBittorrent.Preferences.updatePeerProxyAuthSettings();" /> <input type="checkbox" id="peer_proxy_auth_checkbox" onclick="qBittorrent.Preferences.updatePeerProxyAuthSettings();" />
@ -409,6 +402,25 @@
<span>QBT_TR(Info: The password is saved unencrypted)QBT_TR[CONTEXT=OptionsDialog]</span> <span>QBT_TR(Info: The password is saved unencrypted)QBT_TR[CONTEXT=OptionsDialog]</span>
</div> </div>
</fieldset> </fieldset>
<fieldset class="settings">
<legend>
<input type="checkbox" id="proxy_bittorrent_checkbox" onclick="qBittorrent.Preferences.updatePeerProxySettings();" />
<label for="proxy_bittorrent_checkbox">QBT_TR(Use proxy for BitTorrent purposes)QBT_TR[CONTEXT=OptionsDialog]</label>
</legend>
<div class="formRow">
<input type="checkbox" id="use_peer_proxy_checkbox" />
<label for="use_peer_proxy_checkbox">QBT_TR(Use proxy for peer connections)QBT_TR[CONTEXT=OptionsDialog]</label>
</div>
</fieldset>
<div class="formRow">
<input type="checkbox" id="proxy_rss_checkbox" />
<label for="proxy_rss_checkbox">QBT_TR(Use proxy for RSS purposes)QBT_TR[CONTEXT=OptionsDialog]</label>
</div>
<div class="formRow">
<input type="checkbox" id="proxy_misc_checkbox" />
<label for="proxy_misc_checkbox">QBT_TR(Use proxy for general purposes)QBT_TR[CONTEXT=OptionsDialog]</label>
</div>
</fieldset> </fieldset>
<fieldset class="settings"> <fieldset class="settings">
@ -1575,21 +1587,14 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
}; };
const updatePeerProxySettings = function() { const updatePeerProxySettings = function() {
const isPeerProxyTypeSelected = $('peer_proxy_type_select').getProperty('value') != "none";
$('peer_proxy_host_text').setProperty('disabled', !isPeerProxyTypeSelected);
$('peer_proxy_port_value').setProperty('disabled', !isPeerProxyTypeSelected);
$('use_peer_proxy_checkbox').setProperty('disabled', !isPeerProxyTypeSelected);
const proxyType = $('peer_proxy_type_select').getProperty('value'); const proxyType = $('peer_proxy_type_select').getProperty('value');
const isPeerProxyAuthenticatable = (proxyType === "socks5") || (proxyType === "http"); const isProxySocks4 = (proxyType === "SOCKS4");
$('proxy_only_for_torrents_checkbox').setProperty('disabled', !isPeerProxyAuthenticatable);
if ($('peer_proxy_type_select').getProperty('value') === "socks4") $('peer_proxy_auth_checkbox').setProperty('disabled', isProxySocks4);
$('proxy_only_for_torrents_checkbox').setProperty('checked', true); $('use_peer_proxy_checkbox').setProperty('disabled', !$('proxy_bittorrent_checkbox').getProperty('checked'));
$('proxyHostnameLookupCheckbox').setProperty('disabled', isProxySocks4);
const canPeerProxyResolveHostnames = (proxyType === "socks5") || (proxyType === "http"); $('proxy_rss_checkbox').setProperty('disabled', isProxySocks4);
$('proxyHostnameLookupCheckbox').setProperty('disabled', !canPeerProxyResolveHostnames); $('proxy_misc_checkbox').setProperty('disabled', isProxySocks4);
$('peer_proxy_auth_checkbox').setProperty('disabled', !isPeerProxyAuthenticatable);
updatePeerProxyAuthSettings(); updatePeerProxyAuthSettings();
}; };
@ -1945,31 +1950,18 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
updateMaxUploadsPerTorrentEnabled(); updateMaxUploadsPerTorrentEnabled();
// Proxy Server // Proxy Server
switch (pref.proxy_type.toInt()) { $('peer_proxy_type_select').setProperty('value', pref.proxy_type);
case 5: //SOCKS4
$('peer_proxy_type_select').setProperty('value', 'socks4');
break;
case 2: // SOCKS5
case 4: // SOCKS5_PW
$('peer_proxy_type_select').setProperty('value', 'socks5');
break;
case 1: // HTTP
case 3: // HTTP_PW
$('peer_proxy_type_select').setProperty('value', 'http');
break;
default: // NONE
$('peer_proxy_type_select').setProperty('value', 'none');
}
updatePeerProxySettings();
$('peer_proxy_host_text').setProperty('value', pref.proxy_ip); $('peer_proxy_host_text').setProperty('value', pref.proxy_ip);
$('peer_proxy_port_value').setProperty('value', pref.proxy_port); $('peer_proxy_port_value').setProperty('value', pref.proxy_port);
$('use_peer_proxy_checkbox').setProperty('checked', pref.proxy_peer_connections);
$('proxy_only_for_torrents_checkbox').setProperty('checked', pref.proxy_torrents_only);
$('proxyHostnameLookupCheckbox').setProperty('checked', pref.proxy_hostname_lookup);
$('peer_proxy_auth_checkbox').setProperty('checked', pref.proxy_auth_enabled); $('peer_proxy_auth_checkbox').setProperty('checked', pref.proxy_auth_enabled);
updatePeerProxyAuthSettings();
$('peer_proxy_username_text').setProperty('value', pref.proxy_username); $('peer_proxy_username_text').setProperty('value', pref.proxy_username);
$('peer_proxy_password_text').setProperty('value', pref.proxy_password); $('peer_proxy_password_text').setProperty('value', pref.proxy_password);
$('proxyHostnameLookupCheckbox').setProperty('checked', pref.proxy_hostname_lookup);
$('proxy_bittorrent_checkbox').setProperty('checked', pref.proxy_bittorrent);
$('use_peer_proxy_checkbox').setProperty('checked', pref.proxy_peer_connections);
$('proxy_rss_checkbox').setProperty('checked', pref.proxy_rss);
$('proxy_misc_checkbox').setProperty('checked', pref.proxy_misc);
updatePeerProxySettings();
// IP Filtering // IP Filtering
$('ipfilter_text_checkbox').setProperty('checked', pref.ip_filter_enabled); $('ipfilter_text_checkbox').setProperty('checked', pref.ip_filter_enabled);
@ -2286,43 +2278,17 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
settings.set('max_uploads_per_torrent', max_uploads_per_torrent); settings.set('max_uploads_per_torrent', max_uploads_per_torrent);
// Proxy Server // Proxy Server
const proxy_type_str = $('peer_proxy_type_select').getProperty('value'); settings.set('proxy_type', $('peer_proxy_type_select').getProperty('value'));
let proxy_type = 0;
let proxy_auth_enabled = false;
if (proxy_type_str == "socks5") {
if ($('peer_proxy_auth_checkbox').getProperty('checked')) {
proxy_type = 4;
proxy_auth_enabled = true;
}
else {
proxy_type = 2;
}
}
else {
if (proxy_type_str == "socks4") {
proxy_type = 5;
}
else {
if (proxy_type_str == "http") {
if ($('peer_proxy_auth_checkbox').getProperty('checked')) {
proxy_type = 3;
proxy_auth_enabled = true;
}
else {
proxy_type = 1;
}
}
}
}
settings.set('proxy_type', proxy_type);
settings.set('proxy_auth_enabled', proxy_auth_enabled);
settings.set('proxy_ip', $('peer_proxy_host_text').getProperty('value')); settings.set('proxy_ip', $('peer_proxy_host_text').getProperty('value'));
settings.set('proxy_port', $('peer_proxy_port_value').getProperty('value').toInt()); settings.set('proxy_port', $('peer_proxy_port_value').getProperty('value').toInt());
settings.set('proxy_peer_connections', $('use_peer_proxy_checkbox').getProperty('checked')); settings.set('proxy_auth_enabled', $('peer_proxy_auth_checkbox').getProperty('checked'));
settings.set('proxy_torrents_only', $('proxy_only_for_torrents_checkbox').getProperty('checked'));
settings.set('proxy_hostname_lookup', $('proxyHostnameLookupCheckbox').getProperty('checked'));
settings.set('proxy_username', $('peer_proxy_username_text').getProperty('value')); settings.set('proxy_username', $('peer_proxy_username_text').getProperty('value'));
settings.set('proxy_password', $('peer_proxy_password_text').getProperty('value')); settings.set('proxy_password', $('peer_proxy_password_text').getProperty('value'));
settings.set('proxy_hostname_lookup', $('proxyHostnameLookupCheckbox').getProperty('checked'));
settings.set('proxy_bittorrent', $('proxy_bittorrent_checkbox').getProperty('checked'));
settings.set('proxy_peer_connections', $('use_peer_proxy_checkbox').getProperty('checked'));
settings.set('proxy_rss', $('proxy_rss_checkbox').getProperty('checked'));
settings.set('proxy_misc', $('proxy_misc_checkbox').getProperty('checked'));
// IP Filtering // IP Filtering
settings.set('ip_filter_enabled', $('ipfilter_text_checkbox').getProperty('checked')); settings.set('ip_filter_enabled', $('ipfilter_text_checkbox').getProperty('checked'));

Loading…
Cancel
Save