diff --git a/src/app/upgrade.cpp b/src/app/upgrade.cpp index 01d3ddef8..2cdb52260 100644 --- a/src/app/upgrade.cpp +++ b/src/app/upgrade.cpp @@ -44,7 +44,7 @@ namespace { - const int MIGRATION_VERSION = 5; + const int MIGRATION_VERSION = 6; const QString MIGRATION_VERSION_KEY = u"Meta/MigrationVersion"_qs; void exportWebUIHttpsFiles() @@ -343,7 +343,7 @@ namespace switch (number) { case 0: - settingsStorage->storeValue(key, Net::ProxyType::None); + settingsStorage->storeValue(key, u"None"_qs); break; case 1: settingsStorage->storeValue(key, Net::ProxyType::HTTP); @@ -352,10 +352,10 @@ namespace settingsStorage->storeValue(key, Net::ProxyType::SOCKS5); break; case 3: - settingsStorage->storeValue(key, Net::ProxyType::HTTP_PW); + settingsStorage->storeValue(key, u"HTTP_PW"_qs); break; case 4: - settingsStorage->storeValue(key, Net::ProxyType::SOCKS5_PW); + settingsStorage->storeValue(key, u"SOCKS5_PW"_qs); break; case 5: settingsStorage->storeValue(key, Net::ProxyType::SOCKS4); @@ -369,6 +369,46 @@ namespace } } + void migrateProxySettings() + { + auto *settingsStorage = SettingsStorage::instance(); + const auto proxyType = settingsStorage->loadValue(u"Network/Proxy/Type"_qs, u"None"_qs); + const auto onlyForTorrents = settingsStorage->loadValue(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(u"BitTorrent/Session/ProxyHostnameLookup"_qs); + settingsStorage->storeValue(u"Network/Proxy/HostnameLookupEnabled"_qs, proxyHostnameLookup); + settingsStorage->removeValue(u"BitTorrent/Session/ProxyHostnameLookup"_qs); + } + #ifdef Q_OS_WIN void migrateMemoryPrioritySettings() { @@ -442,6 +482,9 @@ bool upgrade() migrateChineseLocale(); } + if (version < 6) + migrateProxySettings(); + version = MIGRATION_VERSION; } diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 777eaae15..e4c9bdb8a 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -262,8 +262,6 @@ namespace BitTorrent virtual void setMaxActiveCheckingTorrents(int val) = 0; virtual bool isProxyPeerConnectionsEnabled() const = 0; virtual void setProxyPeerConnectionsEnabled(bool enabled) = 0; - virtual bool isProxyHostnameLookupEnabled() const = 0; - virtual void setProxyHostnameLookupEnabled(bool enabled) = 0; virtual ChokingAlgorithm chokingAlgorithm() const = 0; virtual void setChokingAlgorithm(ChokingAlgorithm mode) = 0; virtual SeedChokingAlgorithm seedChokingAlgorithm() const = 0; diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index 45dea93ad..a7f950453 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -42,7 +42,10 @@ #include #endif +#include + #include +#include #include #include #include @@ -495,7 +498,6 @@ SessionImpl::SessionImpl(QObject *parent) , m_encryption(BITTORRENT_SESSION_KEY(u"Encryption"_qs), 0) , m_maxActiveCheckingTorrents(BITTORRENT_SESSION_KEY(u"MaxActiveCheckingTorrents"_qs), 1) , 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 , clampValue(ChokingAlgorithm::FixedSlots, ChokingAlgorithm::RateBased)) , 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()); // proxy - const auto proxyManager = Net::ProxyConfigurationManager::instance(); - const Net::ProxyConfiguration proxyConfig = proxyManager->proxyConfiguration(); - - switch (proxyConfig.type) + settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::none); + if (Preferences::instance()->useProxyForBT()) { - case Net::ProxyType::HTTP: - settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::http); - break; - case Net::ProxyType::HTTP_PW: - settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::http_pw); - break; - case Net::ProxyType::SOCKS4: - settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::socks4); - break; - case Net::ProxyType::SOCKS5: - settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::socks5); - break; - case Net::ProxyType::SOCKS5_PW: - settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::socks5_pw); - break; - case Net::ProxyType::None: - default: - settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::none); - } + const auto proxyManager = Net::ProxyConfigurationManager::instance(); + const Net::ProxyConfiguration proxyConfig = proxyManager->proxyConfiguration(); + + switch (proxyConfig.type) + { + case Net::ProxyType::SOCKS4: + settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::socks4); + break; + + case Net::ProxyType::HTTP: + if (proxyConfig.authEnabled) + settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::http_pw); + else + settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::http); + break; + + case Net::ProxyType::SOCKS5: + 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_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_password, proxyConfig.password.toStdString()); } 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()); @@ -2493,7 +2498,7 @@ bool SessionImpl::addTorrent(const QString &source, const AddTorrentParams ¶ LogMsg(tr("Downloading torrent, please wait... Source: \"%1\"").arg(source)); // Launch downloader Net::DownloadManager::instance()->download(Net::DownloadRequest(source).limit(MAX_TORRENT_SIZE) - , this, &SessionImpl::handleDownloadFinished); + , Preferences::instance()->useProxyForGeneralPurposes(), this, &SessionImpl::handleDownloadFinished); m_downloadedTorrents[source] = params; 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 { return m_chokingAlgorithm; @@ -5791,8 +5782,12 @@ void SessionImpl::handleSocks5Alert(const lt::socks5_alert *p) const { if (p->error) { - LogMsg(tr("SOCKS5 proxy error. Message: \"%1\"").arg(QString::fromStdString(p->message())) - , Log::WARNING); + const auto addr = p->ip.address(); + 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); } } diff --git a/src/base/bittorrent/sessionimpl.h b/src/base/bittorrent/sessionimpl.h index a7d378a3e..2b7e2ca7d 100644 --- a/src/base/bittorrent/sessionimpl.h +++ b/src/base/bittorrent/sessionimpl.h @@ -239,8 +239,6 @@ namespace BitTorrent void setMaxActiveCheckingTorrents(int val) override; bool isProxyPeerConnectionsEnabled() const override; void setProxyPeerConnectionsEnabled(bool enabled) override; - bool isProxyHostnameLookupEnabled() const override; - void setProxyHostnameLookupEnabled(bool enabled) override; ChokingAlgorithm chokingAlgorithm() const override; void setChokingAlgorithm(ChokingAlgorithm mode) override; SeedChokingAlgorithm seedChokingAlgorithm() const override; @@ -655,7 +653,6 @@ namespace BitTorrent CachedSettingValue m_encryption; CachedSettingValue m_maxActiveCheckingTorrents; CachedSettingValue m_isProxyPeerConnectionsEnabled; - CachedSettingValue m_isProxyHostnameLookupEnabled; CachedSettingValue m_chokingAlgorithm; CachedSettingValue m_seedChokingAlgorithm; CachedSettingValue m_storedTags; diff --git a/src/base/net/dnsupdater.cpp b/src/base/net/dnsupdater.cpp index 864dcdb42..fb1a588e9 100644 --- a/src/base/net/dnsupdater.cpp +++ b/src/base/net/dnsupdater.cpp @@ -80,8 +80,8 @@ void DNSUpdater::checkPublicIP() Q_ASSERT(m_state == OK); DownloadManager::instance()->download( - DownloadRequest(u"http://checkip.dyndns.org"_qs).userAgent(QStringLiteral("qBittorrent/" QBT_VERSION_2)) - , this, &DNSUpdater::ipRequestFinished); + DownloadRequest(u"http://checkip.dyndns.org"_qs).userAgent(QStringLiteral("qBittorrent/" QBT_VERSION_2)) + , Preferences::instance()->useProxyForGeneralPurposes(), this, &DNSUpdater::ipRequestFinished); m_lastIPCheckTime = QDateTime::currentDateTime(); } @@ -128,8 +128,8 @@ void DNSUpdater::updateDNSService() m_lastIPCheckTime = QDateTime::currentDateTime(); DownloadManager::instance()->download( - DownloadRequest(getUpdateUrl()).userAgent(QStringLiteral("qBittorrent/" QBT_VERSION_2)) - , this, &DNSUpdater::ipUpdateFinished); + DownloadRequest(getUpdateUrl()).userAgent(QStringLiteral("qBittorrent/" QBT_VERSION_2)) + , Preferences::instance()->useProxyForGeneralPurposes(), this, &DNSUpdater::ipUpdateFinished); } QString DNSUpdater::getUpdateUrl() const diff --git a/src/base/net/downloadhandlerimpl.cpp b/src/base/net/downloadhandlerimpl.cpp index deac598c9..e08a394a1 100644 --- a/src/base/net/downloadhandlerimpl.cpp +++ b/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} , m_manager {manager} , m_downloadRequest {downloadRequest} + , m_useProxy {useProxy} { 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) { @@ -78,7 +80,7 @@ void DownloadHandlerImpl::cancel() } } -void DownloadHandlerImpl::assignNetworkReply(QNetworkReply *reply) +void Net::DownloadHandlerImpl::assignNetworkReply(QNetworkReply *reply) { Q_ASSERT(reply); Q_ASSERT(!m_reply); @@ -91,17 +93,22 @@ void DownloadHandlerImpl::assignNetworkReply(QNetworkReply *reply) } // Returns original url -QString DownloadHandlerImpl::url() const +QString Net::DownloadHandlerImpl::url() const { return m_downloadRequest.url(); } -const Net::DownloadRequest DownloadHandlerImpl::downloadRequest() const +Net::DownloadRequest Net::DownloadHandlerImpl::downloadRequest() const { return m_downloadRequest; } -void DownloadHandlerImpl::processFinishedDownload() +bool Net::DownloadHandlerImpl::useProxy() const +{ + return m_useProxy; +} + +void Net::DownloadHandlerImpl::processFinishedDownload() { qDebug("Download finished: %s", qUtf8Printable(url())); @@ -156,7 +163,7 @@ void DownloadHandlerImpl::processFinishedDownload() 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())) { @@ -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) { @@ -202,9 +209,9 @@ void DownloadHandlerImpl::handleRedirection(const QUrl &newUrl) } auto redirected = static_cast( - m_manager->download(Net::DownloadRequest(m_downloadRequest).url(newUrlString))); + m_manager->download(DownloadRequest(m_downloadRequest).url(newUrlString), useProxy())); 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.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.status = Net::DownloadStatus::Failed; + m_result.status = DownloadStatus::Failed; } -void DownloadHandlerImpl::finish() +void Net::DownloadHandlerImpl::finish() { emit finished(m_result); } -QString DownloadHandlerImpl::errorCodeToString(const QNetworkReply::NetworkError status) +QString Net::DownloadHandlerImpl::errorCodeToString(const QNetworkReply::NetworkError status) { switch (status) { diff --git a/src/base/net/downloadhandlerimpl.h b/src/base/net/downloadhandlerimpl.h index 875849e01..8903daf9b 100644 --- a/src/base/net/downloadhandlerimpl.h +++ b/src/base/net/downloadhandlerimpl.h @@ -36,33 +36,38 @@ class QObject; class QUrl; -class DownloadHandlerImpl final : public Net::DownloadHandler +namespace Net { - Q_OBJECT - Q_DISABLE_COPY_MOVE(DownloadHandlerImpl) + class DownloadHandlerImpl final : public DownloadHandler + { + Q_OBJECT + Q_DISABLE_COPY_MOVE(DownloadHandlerImpl) -public: - DownloadHandlerImpl(Net::DownloadManager *manager, const Net::DownloadRequest &downloadRequest); + public: + DownloadHandlerImpl(DownloadManager *manager, const DownloadRequest &downloadRequest, bool useProxy); - void cancel() override; + void cancel() override; - QString url() const; - const Net::DownloadRequest downloadRequest() const; + QString url() const; + DownloadRequest downloadRequest() const; + bool useProxy() const; - void assignNetworkReply(QNetworkReply *reply); + void assignNetworkReply(QNetworkReply *reply); -private: - void processFinishedDownload(); - void checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal); - void handleRedirection(const QUrl &newUrl); - void setError(const QString &error); - void finish(); + private: + void processFinishedDownload(); + void checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal); + void handleRedirection(const QUrl &newUrl); + void setError(const QString &error); + void finish(); - static QString errorCodeToString(QNetworkReply::NetworkError status); + static QString errorCodeToString(QNetworkReply::NetworkError status); - Net::DownloadManager *m_manager = nullptr; - QNetworkReply *m_reply = nullptr; - const Net::DownloadRequest m_downloadRequest; - short m_redirectionCount = 0; - Net::DownloadResult m_result; -}; + DownloadManager *m_manager = nullptr; + QNetworkReply *m_reply = nullptr; + const DownloadRequest m_downloadRequest; + const bool m_useProxy = false; + short m_redirectionCount = 0; + DownloadResult m_result; + }; +} diff --git a/src/base/net/downloadmanager.cpp b/src/base/net/downloadmanager.cpp index da5c80c43..ffadffedc 100644 --- a/src/base/net/downloadmanager.cpp +++ b/src/base/net/downloadmanager.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -51,101 +52,81 @@ namespace { // 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"; - - class NetworkCookieJar final : public QNetworkCookieJar - { - public: - explicit NetworkCookieJar(QObject *parent = nullptr) - : QNetworkCookieJar(parent) - { - const QDateTime now = QDateTime::currentDateTime(); - QList cookies = Preferences::instance()->getNetworkCookies(); - for (const QNetworkCookie &cookie : asConst(Preferences::instance()->getNetworkCookies())) - { - if (cookie.isSessionCookie() || (cookie.expirationDate() <= now)) - cookies.removeAll(cookie); - } - - setAllCookies(cookies); - } - - ~NetworkCookieJar() override - { - const QDateTime now = QDateTime::currentDateTime(); - QList cookies = allCookies(); - for (const QNetworkCookie &cookie : asConst(allCookies())) - { - if (cookie.isSessionCookie() || (cookie.expirationDate() <= now)) - cookies.removeAll(cookie); - } - - Preferences::instance()->setNetworkCookies(cookies); - } - - using QNetworkCookieJar::allCookies; - using QNetworkCookieJar::setAllCookies; - - QList cookiesForUrl(const QUrl &url) const override - { - const QDateTime now = QDateTime::currentDateTime(); - QList 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 &cookieList, const QUrl &url) override - { - const QDateTime now = QDateTime::currentDateTime(); - QList cookies = cookieList; - 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()) - 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); - - return request; - } } +class Net::DownloadManager::NetworkCookieJar final : public QNetworkCookieJar +{ +public: + explicit NetworkCookieJar(QObject *parent = nullptr) + : QNetworkCookieJar(parent) + { + const QDateTime now = QDateTime::currentDateTime(); + QList cookies = Preferences::instance()->getNetworkCookies(); + for (const QNetworkCookie &cookie : asConst(Preferences::instance()->getNetworkCookies())) + { + if (cookie.isSessionCookie() || (cookie.expirationDate() <= now)) + cookies.removeAll(cookie); + } + + setAllCookies(cookies); + } + + ~NetworkCookieJar() override + { + const QDateTime now = QDateTime::currentDateTime(); + QList cookies = allCookies(); + for (const QNetworkCookie &cookie : asConst(allCookies())) + { + if (cookie.isSessionCookie() || (cookie.expirationDate() <= now)) + cookies.removeAll(cookie); + } + + Preferences::instance()->setNetworkCookies(cookies); + } + + using QNetworkCookieJar::allCookies; + using QNetworkCookieJar::setAllCookies; + + QList cookiesForUrl(const QUrl &url) const override + { + const QDateTime now = QDateTime::currentDateTime(); + QList 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 &cookieList, const QUrl &url) override + { + const QDateTime now = QDateTime::currentDateTime(); + QList cookies = cookieList; + for (const QNetworkCookie &cookie : cookieList) + { + if (!cookie.isSessionCookie() && (cookie.expirationDate() <= now)) + cookies.removeAll(cookie); + } + + return QNetworkCookieJar::setCookiesFromUrl(cookies, url); + } +}; + Net::DownloadManager *Net::DownloadManager::m_instance = nullptr; Net::DownloadManager::DownloadManager(QObject *parent) : QObject(parent) + , m_networkCookieJar {new NetworkCookieJar(this)} + , m_networkManager {new QNetworkAccessManager(this)} { - connect(&m_networkManager, &QNetworkAccessManager::sslErrors, this, &Net::DownloadManager::ignoreSslErrors); - connect(&m_networkManager, &QNetworkAccessManager::finished, this, &DownloadManager::handleReplyFinished); + m_networkManager->setCookieJar(m_networkCookieJar); + connect(m_networkManager, &QNetworkAccessManager::sslErrors, this, &Net::DownloadManager::ignoreSslErrors); + connect(ProxyConfigurationManager::instance(), &ProxyConfigurationManager::proxyConfigurationChanged , this, &DownloadManager::applyProxySettings); - m_networkManager.setCookieJar(new NetworkCookieJar(this)); + connect(Preferences::instance(), &Preferences::changed, this, &DownloadManager::applyProxySettings); applyProxySettings(); } @@ -166,14 +147,18 @@ Net::DownloadManager *Net::DownloadManager::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 - const QNetworkRequest request = createNetworkRequest(downloadRequest); - const ServiceID id = ServiceID::fromURL(request.url()); + const ServiceID id = ServiceID::fromURL(downloadRequest.url()); 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, &QObject::destroyed, this, [this, id, downloadHandler]() { @@ -189,7 +174,7 @@ Net::DownloadHandler *Net::DownloadManager::download(const DownloadRequest &down qDebug("Downloading %s...", qUtf8Printable(downloadRequest.url())); if (isSequentialService) m_busyServices.insert(id); - downloadHandler->assignNetworkReply(m_networkManager.get(request)); + processRequest(downloadHandler); } return downloadHandler; @@ -202,32 +187,32 @@ void Net::DownloadManager::registerSequentialService(const Net::ServiceID &servi QList Net::DownloadManager::cookiesForUrl(const QUrl &url) const { - return m_networkManager.cookieJar()->cookiesForUrl(url); + return m_networkCookieJar->cookiesForUrl(url); } bool Net::DownloadManager::setCookiesFromUrl(const QList &cookieList, const QUrl &url) { - return m_networkManager.cookieJar()->setCookiesFromUrl(cookieList, url); + return m_networkCookieJar->setCookiesFromUrl(cookieList, url); } QList Net::DownloadManager::allCookies() const { - return static_cast(m_networkManager.cookieJar())->allCookies(); + return m_networkCookieJar->allCookies(); } void Net::DownloadManager::setAllCookies(const QList &cookieList) { - static_cast(m_networkManager.cookieJar())->setAllCookies(cookieList); + m_networkCookieJar->setAllCookies(cookieList); } bool Net::DownloadManager::deleteCookie(const QNetworkCookie &cookie) { - return static_cast(m_networkManager.cookieJar())->deleteCookie(cookie); + return m_networkCookieJar->deleteCookie(cookie); } 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 url.startsWith((scheme + u':'), Qt::CaseInsensitive); @@ -238,46 +223,47 @@ void Net::DownloadManager::applyProxySettings() { const auto *proxyManager = ProxyConfigurationManager::instance(); 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.setHostName(proxyConfig.ip); - 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)) + if (proxyConfig.type == ProxyType::SOCKS5) { qDebug() << Q_FUNC_INFO << "using SOCKS proxy"; - proxy.setType(QNetworkProxy::Socks5Proxy); + m_proxy.setType(QNetworkProxy::Socks5Proxy); } else { 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? - if (proxyManager->isAuthenticationRequired()) + if (proxyConfig.authEnabled) { qDebug("Proxy requires authentication, authenticating..."); - proxy.setUser(proxyConfig.username); - proxy.setPassword(proxyConfig.password); + m_proxy.setUser(proxyConfig.username); + 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 // so we need QNetworkRequest::url() to properly process Sequential Services // 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); if ((waitingJobsIter == m_waitingJobs.end()) || waitingJobsIter.value().isEmpty()) { @@ -286,12 +272,38 @@ void Net::DownloadManager::handleReplyFinished(const QNetworkReply *reply) return; } - auto handler = static_cast(waitingJobsIter.value().dequeue()); + auto handler = waitingJobsIter.value().dequeue(); qDebug("Downloading %s...", qUtf8Printable(handler->url())); - handler->assignNetworkReply(m_networkManager.get(createNetworkRequest(handler->downloadRequest()))); + processRequest(handler); 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 &errors) { QStringList errorList; diff --git a/src/base/net/downloadmanager.h b/src/base/net/downloadmanager.h index 32fcab175..c56755794 100644 --- a/src/base/net/downloadmanager.h +++ b/src/base/net/downloadmanager.h @@ -31,13 +31,14 @@ #include #include -#include +#include #include #include #include #include "base/path.h" +class QNetworkAccessManager; class QNetworkCookie; class QNetworkReply; class QSslError; @@ -123,6 +124,8 @@ namespace Net void finished(const DownloadResult &result); }; + class DownloadHandlerImpl; + class DownloadManager : public QObject { Q_OBJECT @@ -133,10 +136,10 @@ namespace Net static void freeInstance(); static DownloadManager *instance(); - DownloadHandler *download(const DownloadRequest &downloadRequest); + DownloadHandler *download(const DownloadRequest &downloadRequest, bool useProxy); template - 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); @@ -152,23 +155,28 @@ namespace Net void ignoreSslErrors(QNetworkReply *, const QList &); private: + class NetworkCookieJar; + explicit DownloadManager(QObject *parent = nullptr); void applyProxySettings(); - void handleReplyFinished(const QNetworkReply *reply); + void handleDownloadFinished(DownloadHandlerImpl *finishedHandler); + void processRequest(DownloadHandlerImpl *downloadHandler); static DownloadManager *m_instance; - QNetworkAccessManager m_networkManager; + NetworkCookieJar *m_networkCookieJar = nullptr; + QNetworkAccessManager *m_networkManager = nullptr; + QNetworkProxy m_proxy; QSet m_sequentialServices; QSet m_busyServices; - QHash> m_waitingJobs; + QHash> m_waitingJobs; }; template - 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); } } diff --git a/src/base/net/geoipmanager.cpp b/src/base/net/geoipmanager.cpp index 5bd235d0c..c4a32b9ce 100644 --- a/src/base/net/geoipmanager.cpp +++ b/src/base/net/geoipmanager.cpp @@ -129,7 +129,9 @@ void GeoIPManager::downloadDatabaseFile() { const QDateTime curDatetime = QDateTime::currentDateTimeUtc(); 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 diff --git a/src/base/net/proxyconfigurationmanager.cpp b/src/base/net/proxyconfigurationmanager.cpp index 915b3b554..46d4cc006 100644 --- a/src/base/net/proxyconfigurationmanager.cpp +++ b/src/base/net/proxyconfigurationmanager.cpp @@ -35,8 +35,10 @@ bool Net::operator==(const ProxyConfiguration &left, const ProxyConfiguration &r return (left.type == right.type) && (left.ip == right.ip) && (left.port == right.port) + && (left.authEnabled == right.authEnabled) && (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) @@ -49,22 +51,24 @@ using namespace Net; ProxyConfigurationManager *ProxyConfigurationManager::m_instance = nullptr; ProxyConfigurationManager::ProxyConfigurationManager(QObject *parent) - : QObject {parent} - , m_storeProxyOnlyForTorrents {SETTINGS_KEY(u"OnlyForTorrents"_qs)} + : QObject(parent) , m_storeProxyType {SETTINGS_KEY(u"Type"_qs)} , m_storeProxyIP {SETTINGS_KEY(u"IP"_qs)} , m_storeProxyPort {SETTINGS_KEY(u"Port"_qs)} + , m_storeProxyAuthEnabled {SETTINGS_KEY(u"AuthEnabled"_qs)} , m_storeProxyUsername {SETTINGS_KEY(u"Username"_qs)} , m_storeProxyPassword {SETTINGS_KEY(u"Password"_qs)} + , m_storeProxyHostnameLookupEnabled {SETTINGS_KEY(u"HostnameLookupEnabled"_qs)} { - m_config.type = m_storeProxyType.get(ProxyType::None); - if ((m_config.type < ProxyType::None) || (m_config.type > ProxyType::SOCKS4)) - m_config.type = ProxyType::None; + m_config.type = m_storeProxyType.get(ProxyType::HTTP); + if ((m_config.type < ProxyType::HTTP) || (m_config.type > ProxyType::SOCKS4)) + m_config.type = ProxyType::HTTP; m_config.ip = m_storeProxyIP.get(u"0.0.0.0"_qs); m_config.port = m_storeProxyPort.get(8080); + m_config.authEnabled = m_storeProxyAuthEnabled; m_config.username = m_storeProxyUsername; m_config.password = m_storeProxyPassword; - configureProxy(); + m_config.hostnameLookupEnabled = m_storeProxyHostnameLookupEnabled.get(true); } void ProxyConfigurationManager::initInstance() @@ -97,62 +101,11 @@ void ProxyConfigurationManager::setProxyConfiguration(const ProxyConfiguration & m_storeProxyType = config.type; m_storeProxyIP = config.ip; m_storeProxyPort = config.port; + m_storeProxyAuthEnabled = config.authEnabled; m_storeProxyUsername = config.username; m_storeProxyPassword = config.password; - configureProxy(); + m_storeProxyHostnameLookupEnabled = config.hostnameLookupEnabled; 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()); -} diff --git a/src/base/net/proxyconfigurationmanager.h b/src/base/net/proxyconfigurationmanager.h index f154d020c..830d1ba5b 100644 --- a/src/base/net/proxyconfigurationmanager.h +++ b/src/base/net/proxyconfigurationmanager.h @@ -39,22 +39,21 @@ namespace Net enum class ProxyType { - None = 0, HTTP = 1, SOCKS5 = 2, - HTTP_PW = 3, - SOCKS5_PW = 4, SOCKS4 = 5 }; Q_ENUM_NS(ProxyType) struct ProxyConfiguration { - ProxyType type = ProxyType::None; + ProxyType type = ProxyType::HTTP; QString ip = u"0.0.0.0"_qs; ushort port = 8080; + bool authEnabled = false; QString username; QString password; + bool hostnameLookupEnabled = true; }; 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; void setProxyConfiguration(const ProxyConfiguration &config); - bool isProxyOnlyForTorrents() const; - void setProxyOnlyForTorrents(bool onlyForTorrents); - - bool isAuthenticationRequired() const; signals: void proxyConfigurationChanged(); private: - void configureProxy(); - static ProxyConfigurationManager *m_instance; ProxyConfiguration m_config; - SettingValue m_storeProxyOnlyForTorrents; SettingValue m_storeProxyType; SettingValue m_storeProxyIP; SettingValue m_storeProxyPort; + SettingValue m_storeProxyAuthEnabled; SettingValue m_storeProxyUsername; SettingValue m_storeProxyPassword; + SettingValue m_storeProxyHostnameLookupEnabled; }; } diff --git a/src/base/preferences.cpp b/src/base/preferences.cpp index e2aade35d..9e2636997 100644 --- a/src/base/preferences.cpp +++ b/src/base/preferences.cpp @@ -1619,6 +1619,37 @@ void Preferences::setNetworkCookies(const QList &cookies) setValue(u"Network/Cookies"_qs, rawCookies); } +bool Preferences::useProxyForBT() const +{ + return value(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(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(u"Network/Proxy/Profiles/Misc"_qs); +} + + +void Preferences::setUseProxyForGeneralPurposes(const bool value) +{ + setValue(u"Network/Proxy/Profiles/Misc"_qs, value); +} + bool Preferences::isSpeedWidgetEnabled() const { return value(u"SpeedWidget/Enabled"_qs, true); diff --git a/src/base/preferences.h b/src/base/preferences.h index 86e81cae7..2cc338133 100644 --- a/src/base/preferences.h +++ b/src/base/preferences.h @@ -397,6 +397,13 @@ public: QList getNetworkCookies() const; void setNetworkCookies(const QList &cookies); + bool useProxyForBT() const; + void setUseProxyForBT(bool value); + bool useProxyForRSS() const; + void setUseProxyForRSS(bool value); + bool useProxyForGeneralPurposes() const; + void setUseProxyForGeneralPurposes(bool value); + // SpeedWidget bool isSpeedWidgetEnabled() const; void setSpeedWidgetEnabled(bool enabled); diff --git a/src/base/rss/rss_feed.cpp b/src/base/rss/rss_feed.cpp index c25f678cb..1502db0ad 100644 --- a/src/base/rss/rss_feed.cpp +++ b/src/base/rss/rss_feed.cpp @@ -45,6 +45,7 @@ #include "base/global.h" #include "base/logger.h" #include "base/net/downloadmanager.h" +#include "base/preferences.h" #include "base/profile.h" #include "base/utils/fs.h" #include "feed_serializer.h" @@ -148,7 +149,7 @@ void Feed::refresh() // 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); 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()); Net::DownloadManager::instance()->download( Net::DownloadRequest(iconUrl).saveToFile(true).destFileName(m_iconPath) - , this, &Feed::handleIconDownloadFinished); + , Preferences::instance()->useProxyForRSS(), this, &Feed::handleIconDownloadFinished); } int Feed::updateArticles(const QList &loadedArticles) diff --git a/src/base/search/searchpluginmanager.cpp b/src/base/search/searchpluginmanager.cpp index 2d7cae0a0..e5881bd2c 100644 --- a/src/base/search/searchpluginmanager.cpp +++ b/src/base/search/searchpluginmanager.cpp @@ -38,10 +38,12 @@ #include #include #include +#include #include "base/global.h" #include "base/logger.h" #include "base/net/downloadmanager.h" +#include "base/net/proxyconfigurationmanager.h" #include "base/preferences.h" #include "base/profile.h" #include "base/utils/bytearray.h" @@ -90,6 +92,12 @@ SearchPluginManager::SearchPluginManager() Q_ASSERT(!m_instance); // only one instance is allowed m_instance = this; + connect(Net::ProxyConfigurationManager::instance(), &Net::ProxyConfigurationManager::proxyConfigurationChanged + , this, &SearchPluginManager::applyProxySettings); + connect(Preferences::instance(), &Preferences::changed + , this, &SearchPluginManager::applyProxySettings); + applyProxySettings(); + updateNova(); update(); } @@ -207,7 +215,8 @@ void SearchPluginManager::installPlugin(const QString &source) { using namespace Net; DownloadManager::instance()->download(DownloadRequest(source).saveToFile(true) - , this, &SearchPluginManager::pluginDownloadFinished); + , Preferences::instance()->useProxyForGeneralPurposes() + , this, &SearchPluginManager::pluginDownloadFinished); } else { @@ -323,7 +332,8 @@ void SearchPluginManager::checkForUpdates() // Download version file from update server using namespace Net; 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) @@ -378,6 +388,54 @@ Path SearchPluginManager::engineLocation() 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) { if (result.status == Net::DownloadStatus::Success) diff --git a/src/base/search/searchpluginmanager.h b/src/base/search/searchpluginmanager.h index 0f3aa64dd..e87e9d8a4 100644 --- a/src/base/search/searchpluginmanager.h +++ b/src/base/search/searchpluginmanager.h @@ -104,6 +104,7 @@ signals: void checkForUpdatesFailed(const QString &reason); private: + void applyProxySettings(); void update(); void updateNova(); void parseVersionInfo(const QByteArray &info); diff --git a/src/gui/addnewtorrentdialog.cpp b/src/gui/addnewtorrentdialog.cpp index 342fec91e..faa492989 100644 --- a/src/gui/addnewtorrentdialog.cpp +++ b/src/gui/addnewtorrentdialog.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -51,6 +52,7 @@ #include "base/bittorrent/torrentcontentlayout.h" #include "base/global.h" #include "base/net/downloadmanager.h" +#include "base/preferences.h" #include "base/settingsstorage.h" #include "base/torrentfileguard.h" #include "base/utils/compare.h" @@ -474,8 +476,9 @@ void AddNewTorrentDialog::show(const QString &source, const BitTorrent::AddTorre { // Launch downloader Net::DownloadManager::instance()->download( - Net::DownloadRequest(source).limit(MAX_TORRENT_SIZE) - , dlg, &AddNewTorrentDialog::handleDownloadFinished); + Net::DownloadRequest(source).limit(MAX_TORRENT_SIZE) + , Preferences::instance()->useProxyForGeneralPurposes() + , dlg, &AddNewTorrentDialog::handleDownloadFinished); return; } diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index f68802d4e..1efebd8b3 100644 --- a/src/gui/mainwindow.cpp +++ b/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; #endif Net::DownloadManager::instance()->download( - Net::DownloadRequest(installerURL).saveToFile(true) - , this, &MainWindow::pythonDownloadFinished); + Net::DownloadRequest(installerURL).saveToFile(true) + , Preferences::instance()->useProxyForGeneralPurposes() + , this, &MainWindow::pythonDownloadFinished); } void MainWindow::pythonDownloadFinished(const Net::DownloadResult &result) diff --git a/src/gui/optionsdialog.cpp b/src/gui/optionsdialog.cpp index afa03b70a..96b0817d8 100644 --- a/src/gui/optionsdialog.cpp +++ b/src/gui/optionsdialog.cpp @@ -52,7 +52,6 @@ #include "base/rss/rss_session.h" #include "base/torrentfileguard.h" #include "base/torrentfileswatcher.h" -#include "base/utils/fs.h" #include "base/utils/misc.h" #include "base/utils/net.h" #include "base/utils/password.h" @@ -770,42 +769,25 @@ void OptionsDialog::loadConnectionTabOptions() } const auto *proxyConfigManager = Net::ProxyConfigurationManager::instance(); - Net::ProxyConfiguration proxyConf = proxyConfigManager->proxyConfiguration(); - using Net::ProxyType; - bool useProxyAuth = false; - switch (proxyConf.type) - { - case ProxyType::SOCKS4: - m_ui->comboProxyType->setCurrentIndex(1); - break; + const Net::ProxyConfiguration proxyConf = proxyConfigManager->proxyConfiguration(); - case ProxyType::SOCKS5_PW: - useProxyAuth = true; - // fallthrough - case ProxyType::SOCKS5: - m_ui->comboProxyType->setCurrentIndex(2); - break; + m_ui->comboProxyType->addItem(tr("SOCKS4"), QVariant::fromValue(Net::ProxyType::SOCKS4)); + m_ui->comboProxyType->addItem(tr("SOCKS5"), QVariant::fromValue(Net::ProxyType::SOCKS5)); + m_ui->comboProxyType->addItem(tr("HTTP"), QVariant::fromValue(Net::ProxyType::HTTP)); + m_ui->comboProxyType->setCurrentIndex(m_ui->comboProxyType->findData(QVariant::fromValue(proxyConf.type))); + adjustProxyOptions(); - 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->spinProxyPort->setValue(proxyConf.port); - m_ui->checkProxyAuth->setChecked(useProxyAuth); + m_ui->checkProxyAuth->setChecked(proxyConf.authEnabled); m_ui->textProxyUsername->setText(proxyConf.username); 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->isProxyOnlyForTorrents->setChecked(proxyConfigManager->isProxyOnlyForTorrents()); - m_ui->checkProxyHostnameLookup->setChecked(session->isProxyHostnameLookupEnabled()); - enableProxy(m_ui->comboProxyType->currentIndex()); + m_ui->checkProxyRSS->setChecked(Preferences::instance()->useProxyForRSS()); + m_ui->checkProxyMisc->setChecked(Preferences::instance()->useProxyForGeneralPurposes()); m_ui->checkIPFilter->setChecked(session->isIPFilteringEnabled()); 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->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->textProxyIP, &QLineEdit::textChanged, 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->isProxyOnlyForTorrents, &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->textProxyUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); @@ -868,13 +853,17 @@ void OptionsDialog::saveConnectionTabOptions() const proxyConf.type = getProxyType(); proxyConf.ip = getProxyIp(); proxyConf.port = getProxyPort(); + proxyConf.authEnabled = m_ui->checkProxyAuth->isChecked(); proxyConf.username = getProxyUsername(); proxyConf.password = getProxyPassword(); - proxyConfigManager->setProxyOnlyForTorrents(m_ui->isProxyOnlyForTorrents->isChecked()); + proxyConf.hostnameLookupEnabled = m_ui->checkProxyHostnameLookup->isChecked(); 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->setProxyHostnameLookupEnabled(m_ui->checkProxyHostnameLookup->isChecked()); // IPFilter session->setIPFilteringEnabled(isIPFilteringEnabled()); @@ -1321,21 +1310,7 @@ bool OptionsDialog::isIPFilteringEnabled() const Net::ProxyType OptionsDialog::getProxyType() const { - switch (m_ui->comboProxyType->currentIndex()) - { - 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; - } + return m_ui->comboProxyType->currentData().value(); } int OptionsDialog::getPort() const @@ -1512,41 +1487,29 @@ void OptionsDialog::toggleComboRatioLimitAct() m_ui->comboRatioLimitAct->setEnabled(m_ui->checkMaxRatio->isChecked() || m_ui->checkMaxSeedingMinutes->isChecked()); } -void OptionsDialog::enableProxy(const int index) +void OptionsDialog::adjustProxyOptions() { - if (index >= 1) - { // Any proxy type is used - //enable - m_ui->lblProxyIP->setEnabled(true); - m_ui->textProxyIP->setEnabled(true); - m_ui->lblProxyPort->setEnabled(true); - m_ui->spinProxyPort->setEnabled(true); - m_ui->checkProxyPeerConnections->setEnabled(true); - if (index >= 2) - { // SOCKS5 or HTTP - m_ui->checkProxyAuth->setEnabled(true); - m_ui->isProxyOnlyForTorrents->setEnabled(true); - 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); - } + const auto currentProxyType = m_ui->comboProxyType->currentData().value(); + const bool isAuthSupported = (currentProxyType != Net::ProxyType::SOCKS4); + + m_ui->checkProxyAuth->setEnabled(isAuthSupported); + + if (currentProxyType == Net::ProxyType::SOCKS4) + { + m_ui->labelProxyTypeIncompatible->setVisible(true); + + m_ui->checkProxyHostnameLookup->setEnabled(false); + m_ui->checkProxyRSS->setEnabled(false); + m_ui->checkProxyMisc->setEnabled(false); } else - { // No proxy - // disable - m_ui->lblProxyIP->setEnabled(false); - m_ui->textProxyIP->setEnabled(false); - m_ui->lblProxyPort->setEnabled(false); - m_ui->spinProxyPort->setEnabled(false); - m_ui->checkProxyPeerConnections->setEnabled(false); - m_ui->isProxyOnlyForTorrents->setEnabled(false); - m_ui->checkProxyHostnameLookup->setEnabled(false); - m_ui->checkProxyAuth->setEnabled(false); + { + // SOCKS5 or HTTP + m_ui->labelProxyTypeIncompatible->setVisible(false); + + m_ui->checkProxyHostnameLookup->setEnabled(true); + m_ui->checkProxyRSS->setEnabled(true); + m_ui->checkProxyMisc->setEnabled(true); } } @@ -1578,11 +1541,6 @@ bool OptionsDialog::isProxyEnabled() const return m_ui->comboProxyType->currentIndex(); } -bool OptionsDialog::isProxyAuthEnabled() const -{ - return m_ui->checkProxyAuth->isChecked(); -} - QString OptionsDialog::getProxyIp() const { return m_ui->textProxyIP->text().trimmed(); diff --git a/src/gui/optionsdialog.h b/src/gui/optionsdialog.h index 819f0a694..5f56e7545 100644 --- a/src/gui/optionsdialog.h +++ b/src/gui/optionsdialog.h @@ -85,7 +85,7 @@ public slots: void showConnectionTab(); private slots: - void enableProxy(int index); + void adjustProxyOptions(); void on_buttonBox_accepted(); void on_buttonBox_rejected(); void applySettings(); @@ -168,7 +168,6 @@ private: int getMaxSeedingMinutes() const; // Proxy options bool isProxyEnabled() const; - bool isProxyAuthEnabled() const; QString getProxyIp() const; unsigned short getProxyPort() const; QString getProxyUsername() const; diff --git a/src/gui/optionsdialog.ui b/src/gui/optionsdialog.ui index 2693cef96..9260af724 100644 --- a/src/gui/optionsdialog.ui +++ b/src/gui/optionsdialog.ui @@ -1800,51 +1800,20 @@ readme[0-9].txt: filter 'readme1.txt', 'readme2.txt' but not 'readme10.txt'. - - - - (None) - - - - - SOCKS4 - - - - - SOCKS5 - - - - - HTTP - - - + - - false - Host: - - - false - - + - - false - Port: @@ -1852,9 +1821,6 @@ readme[0-9].txt: filter 'readme1.txt', 'readme2.txt' but not 'readme10.txt'. - - false - 1 @@ -1869,38 +1835,21 @@ readme[0-9].txt: filter 'readme1.txt', 'readme2.txt' but not 'readme10.txt'. - - - false - - - Otherwise, the proxy server is only used for tracker connections + + + + true + - Use proxy for peer connections - - - - - - - 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 - - - Use proxy only for torrents - - - false + Some options are incompatible with the chosen proxy type! - - true - - If checked, hostname lookups are done via the proxy. + If checked, hostname lookups are done via the proxy Use proxy for hostname lookups @@ -1960,6 +1909,57 @@ readme[0-9].txt: filter 'readme1.txt', 'readme2.txt' but not 'readme10.txt'. + + + + Use proxy for BitTorrent purposes + + + true + + + false + + + + + + Otherwise, the proxy server is only used for tracker connections + + + Use proxy for peer connections + + + + + + + + + + RSS feeds will use proxy + + + Use proxy for RSS purposes + + + false + + + + + + + Search engine, software updates or anything else will use proxy + + + Use proxy for general purposes + + + false + + + @@ -3716,12 +3716,14 @@ Use ';' to split multiple entries. Can use wildcard '*'. comboProxyType textProxyIP spinProxyPort - checkProxyPeerConnections - isProxyOnlyForTorrents checkProxyHostnameLookup checkProxyAuth textProxyUsername textProxyPassword + checkProxyBitTorrent + checkProxyPeerConnections + checkProxyRSS + checkProxyMisc checkIPFilter textFilterPath IpFilterRefreshBtn diff --git a/src/gui/programupdater.cpp b/src/gui/programupdater.cpp index 1c745a1cc..7d6de7807 100644 --- a/src/gui/programupdater.cpp +++ b/src/gui/programupdater.cpp @@ -45,6 +45,7 @@ #include "base/global.h" #include "base/net/downloadmanager.h" +#include "base/preferences.h" #include "base/utils/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, // the filehost can identify it and contact us. Net::DownloadManager::instance()->download( - Net::DownloadRequest(RSS_URL).userAgent(QStringLiteral("qBittorrent/" QBT_VERSION_2 " ProgramUpdater (www.qbittorrent.org)")) - , this, &ProgramUpdater::rssDownloadFinished); + Net::DownloadRequest(RSS_URL).userAgent(QStringLiteral("qBittorrent/" QBT_VERSION_2 " ProgramUpdater (www.qbittorrent.org)")) + , Preferences::instance()->useProxyForGeneralPurposes(), this, &ProgramUpdater::rssDownloadFinished); } QString ProgramUpdater::getNewVersion() const diff --git a/src/gui/properties/trackersadditiondialog.cpp b/src/gui/properties/trackersadditiondialog.cpp index 5b154c994..ed5f5df92 100644 --- a/src/gui/properties/trackersadditiondialog.cpp +++ b/src/gui/properties/trackersadditiondialog.cpp @@ -38,6 +38,7 @@ #include "base/bittorrent/trackerentry.h" #include "base/global.h" #include "base/net/downloadmanager.h" +#include "base/preferences.h" #include "gui/uithememanager.h" #include "ui_trackersadditiondialog.h" @@ -87,7 +88,8 @@ void TrackersAdditionDialog::onDownloadButtonClicked() m_ui->downloadButton->setEnabled(false); 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) diff --git a/src/gui/search/pluginselectdialog.cpp b/src/gui/search/pluginselectdialog.cpp index 33fb63703..e97e627c7 100644 --- a/src/gui/search/pluginselectdialog.cpp +++ b/src/gui/search/pluginselectdialog.cpp @@ -40,6 +40,7 @@ #include "base/global.h" #include "base/net/downloadmanager.h" +#include "base/preferences.h" #include "base/utils/fs.h" #include "gui/autoexpandabledialog.h" #include "gui/uithememanager.h" @@ -311,8 +312,8 @@ void PluginSelectDialog::addNewPlugin(const QString &pluginName) // Icon is missing, we must download it using namespace Net; DownloadManager::instance()->download( - DownloadRequest(plugin->url + u"/favicon.ico").saveToFile(true) - , this, &PluginSelectDialog::iconDownloadFinished); + DownloadRequest(plugin->url + u"/favicon.ico").saveToFile(true) + , Preferences::instance()->useProxyForGeneralPurposes(), this, &PluginSelectDialog::iconDownloadFinished); } item->setText(PLUGIN_VERSION, plugin->version.toString()); } diff --git a/src/gui/transferlistfilterswidget.cpp b/src/gui/transferlistfilterswidget.cpp index 394596d78..e2eee9e0b 100644 --- a/src/gui/transferlistfilterswidget.cpp +++ b/src/gui/transferlistfilterswidget.cpp @@ -658,8 +658,8 @@ void TrackerFiltersList::downloadFavicon(const QString &url) { if (!m_downloadTrackerFavicon) return; Net::DownloadManager::instance()->download( - Net::DownloadRequest(url).saveToFile(true) - , this, &TrackerFiltersList::handleFavicoDownloadFinished); + Net::DownloadRequest(url).saveToFile(true), Preferences::instance()->useProxyForGeneralPurposes() + , this, &TrackerFiltersList::handleFavicoDownloadFinished); } void TrackerFiltersList::handleFavicoDownloadFinished(const Net::DownloadResult &result) diff --git a/src/webui/api/appcontroller.cpp b/src/webui/api/appcontroller.cpp index 39a432ee4..889689876 100644 --- a/src/webui/api/appcontroller.cpp +++ b/src/webui/api/appcontroller.cpp @@ -194,16 +194,18 @@ void AppController::preferencesAction() // Proxy Server const auto *proxyManager = Net::ProxyConfigurationManager::instance(); Net::ProxyConfiguration proxyConf = proxyManager->proxyConfiguration(); - data[u"proxy_type"_qs] = static_cast(proxyConf.type); + data[u"proxy_type"_qs] = Utils::String::fromEnum(proxyConf.type); data[u"proxy_ip"_qs] = proxyConf.ip; 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_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_torrents_only"_qs] = proxyManager->isProxyOnlyForTorrents(); - data[u"proxy_hostname_lookup"_qs] = session->isProxyHostnameLookupEnabled(); + data[u"proxy_rss"_qs] = pref->useProxyForRSS(); + data[u"proxy_misc"_qs] = pref->useProxyForGeneralPurposes(); // IP Filtering data[u"ip_filter_enabled"_qs] = session->isIPFilteringEnabled(); @@ -610,23 +612,29 @@ void AppController::setPreferencesAction() auto proxyManager = Net::ProxyConfigurationManager::instance(); Net::ProxyConfiguration proxyConf = proxyManager->proxyConfiguration(); if (hasKey(u"proxy_type"_qs)) - proxyConf.type = static_cast(it.value().toInt()); + proxyConf.type = Utils::String::toEnum(it.value().toString(), Net::ProxyType::HTTP); if (hasKey(u"proxy_ip"_qs)) proxyConf.ip = it.value().toString(); if (hasKey(u"proxy_port"_qs)) proxyConf.port = it.value().toUInt(); + if (hasKey(u"proxy_auth_enabled"_qs)) + proxyConf.authEnabled = it.value().toBool(); if (hasKey(u"proxy_username"_qs)) proxyConf.username = it.value().toString(); if (hasKey(u"proxy_password"_qs)) proxyConf.password = it.value().toString(); + if (hasKey(u"proxy_hostname_lookup"_qs)) + proxyConf.hostnameLookupEnabled = it.value().toBool(); proxyManager->setProxyConfiguration(proxyConf); + if (hasKey(u"proxy_bittorrent"_qs)) + pref->setUseProxyForBT(it.value().toBool()); if (hasKey(u"proxy_peer_connections"_qs)) session->setProxyPeerConnectionsEnabled(it.value().toBool()); - if (hasKey(u"proxy_torrents_only"_qs)) - proxyManager->setProxyOnlyForTorrents(it.value().toBool()); - if (hasKey(u"proxy_hostname_lookup"_qs)) - session->setProxyHostnameLookupEnabled(it.value().toBool()); + if (hasKey(u"proxy_rss"_qs)) + pref->setUseProxyForRSS(it.value().toBool()); + if (hasKey(u"proxy_misc"_qs)) + pref->setUseProxyForGeneralPurposes(it.value().toBool()); // IP Filtering if (hasKey(u"ip_filter_enabled"_qs)) diff --git a/src/webui/webapplication.h b/src/webui/webapplication.h index b4351002e..79e0740f9 100644 --- a/src/webui/webapplication.h +++ b/src/webui/webapplication.h @@ -52,7 +52,7 @@ #include "base/utils/version.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 AuthController; diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index fca47c2b9..cc9648e63 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -350,10 +350,9 @@ @@ -370,18 +369,12 @@ -
- - -
-
- - -
+
+
@@ -409,6 +402,25 @@ QBT_TR(Info: The password is saved unencrypted)QBT_TR[CONTEXT=OptionsDialog]
+ +
+ + + + +
+ + +
+
+
+ + +
+
+ + +
@@ -1575,21 +1587,14 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD }; 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 isPeerProxyAuthenticatable = (proxyType === "socks5") || (proxyType === "http"); - $('proxy_only_for_torrents_checkbox').setProperty('disabled', !isPeerProxyAuthenticatable); + const isProxySocks4 = (proxyType === "SOCKS4"); - if ($('peer_proxy_type_select').getProperty('value') === "socks4") - $('proxy_only_for_torrents_checkbox').setProperty('checked', true); - - const canPeerProxyResolveHostnames = (proxyType === "socks5") || (proxyType === "http"); - $('proxyHostnameLookupCheckbox').setProperty('disabled', !canPeerProxyResolveHostnames); - - $('peer_proxy_auth_checkbox').setProperty('disabled', !isPeerProxyAuthenticatable); + $('peer_proxy_auth_checkbox').setProperty('disabled', isProxySocks4); + $('use_peer_proxy_checkbox').setProperty('disabled', !$('proxy_bittorrent_checkbox').getProperty('checked')); + $('proxyHostnameLookupCheckbox').setProperty('disabled', isProxySocks4); + $('proxy_rss_checkbox').setProperty('disabled', isProxySocks4); + $('proxy_misc_checkbox').setProperty('disabled', isProxySocks4); updatePeerProxyAuthSettings(); }; @@ -1945,31 +1950,18 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD updateMaxUploadsPerTorrentEnabled(); // Proxy Server - switch (pref.proxy_type.toInt()) { - 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_type_select').setProperty('value', pref.proxy_type); $('peer_proxy_host_text').setProperty('value', pref.proxy_ip); $('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); - updatePeerProxyAuthSettings(); $('peer_proxy_username_text').setProperty('value', pref.proxy_username); $('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 $('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); // Proxy Server - const proxy_type_str = $('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_type', $('peer_proxy_type_select').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_peer_connections', $('use_peer_proxy_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_auth_enabled', $('peer_proxy_auth_checkbox').getProperty('checked')); settings.set('proxy_username', $('peer_proxy_username_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 settings.set('ip_filter_enabled', $('ipfilter_text_checkbox').getProperty('checked'));