mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-11-27 03:39:39 +03:00
Merge pull request #4413 from glassez/dlmgr
Improve Download Manager. Closes #4305
This commit is contained in:
commit
52d08f7112
13 changed files with 319 additions and 248 deletions
|
@ -462,10 +462,10 @@ void Application::cleanup()
|
|||
#ifndef DISABLE_COUNTRIES_RESOLUTION
|
||||
Net::GeoIPManager::freeInstance();
|
||||
#endif
|
||||
Net::DownloadManager::freeInstance();
|
||||
Preferences::freeInstance();
|
||||
Logger::freeInstance();
|
||||
IconProvider::freeInstance();
|
||||
Net::DownloadManager::freeInstance();
|
||||
#ifndef DISABLE_GUI
|
||||
#ifdef Q_OS_WIN
|
||||
typedef BOOL (WINAPI *PSHUTDOWNBRDESTROY)(HWND);
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "base/utils/misc.h"
|
||||
#include "base/utils/string.h"
|
||||
#include "base/qinisettings.h"
|
||||
#include "base/preferences.h"
|
||||
|
||||
bool userAcceptsUpgrade()
|
||||
{
|
||||
|
@ -114,6 +115,9 @@ bool upgradeResumeFile(const QString &filepath, const QVariantHash &oldTorrent,
|
|||
|
||||
bool upgrade(bool ask = true)
|
||||
{
|
||||
// Move RSS cookies to common storage
|
||||
Preferences::instance()->moveRSSCookies();
|
||||
|
||||
QIniSettings *oldResumeSettings = new QIniSettings("qBittorrent", "qBittorrent-resume");
|
||||
QString oldResumeFilename = oldResumeSettings->fileName();
|
||||
QVariantHash oldResumeData = oldResumeSettings->value("torrents").toHash();
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QDebug>
|
||||
#include <QRegExp>
|
||||
#include <QStringList>
|
||||
|
@ -37,6 +36,8 @@
|
|||
#endif
|
||||
|
||||
#include "base/logger.h"
|
||||
#include "base/net/downloadmanager.h"
|
||||
#include "base/net/downloadhandler.h"
|
||||
#include "dnsupdater.h"
|
||||
|
||||
using namespace Net;
|
||||
|
@ -76,65 +77,62 @@ DNSUpdater::~DNSUpdater()
|
|||
void DNSUpdater::checkPublicIP()
|
||||
{
|
||||
Q_ASSERT(m_state == OK);
|
||||
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
|
||||
connect(manager, SIGNAL(finished(QNetworkReply *)), SLOT(ipRequestFinished(QNetworkReply *)));
|
||||
|
||||
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(
|
||||
"http://checkip.dyndns.org", false, 0, false,
|
||||
QString("qBittorrent/%1").arg(VERSION));
|
||||
connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), SLOT(ipRequestFinished(QString, QByteArray)));
|
||||
connect(handler, SIGNAL(downloadFailed(QString, QString)), SLOT(ipRequestFailed(QString, QString)));
|
||||
|
||||
m_lastIPCheckTime = QDateTime::currentDateTime();
|
||||
QNetworkRequest request;
|
||||
request.setUrl(QUrl("http://checkip.dyndns.org"));
|
||||
request.setRawHeader("User-Agent", "qBittorrent/" VERSION);
|
||||
manager->get(request);
|
||||
}
|
||||
|
||||
void DNSUpdater::ipRequestFinished(QNetworkReply *reply)
|
||||
void DNSUpdater::ipRequestFinished(const QString &url, const QByteArray &data)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
if (reply->error()) {
|
||||
// Error
|
||||
qWarning() << Q_FUNC_INFO << "Error:" << reply->errorString();
|
||||
}
|
||||
else {
|
||||
// Parse response
|
||||
QRegExp ipregex("Current IP Address:\\s+([^<]+)</body>");
|
||||
QString ret = reply->readAll();
|
||||
if (ipregex.indexIn(ret) >= 0) {
|
||||
QString ip_str = ipregex.cap(1);
|
||||
qDebug() << Q_FUNC_INFO << "Regular expression captured the following IP:" << ip_str;
|
||||
QHostAddress new_ip(ip_str);
|
||||
if (!new_ip.isNull()) {
|
||||
if (m_lastIP != new_ip) {
|
||||
qDebug() << Q_FUNC_INFO << "The IP address changed, report the change to DynDNS...";
|
||||
qDebug() << m_lastIP.toString() << "->" << new_ip.toString();
|
||||
m_lastIP = new_ip;
|
||||
updateDNSService();
|
||||
}
|
||||
}
|
||||
else {
|
||||
qWarning() << Q_FUNC_INFO << "Failed to construct a QHostAddress from the IP string";
|
||||
Q_UNUSED(url);
|
||||
|
||||
// Parse response
|
||||
QRegExp ipregex("Current IP Address:\\s+([^<]+)</body>");
|
||||
if (ipregex.indexIn(data) >= 0) {
|
||||
QString ipStr = ipregex.cap(1);
|
||||
qDebug() << Q_FUNC_INFO << "Regular expression captured the following IP:" << ipStr;
|
||||
QHostAddress newIp(ipStr);
|
||||
if (!newIp.isNull()) {
|
||||
if (m_lastIP != newIp) {
|
||||
qDebug() << Q_FUNC_INFO << "The IP address changed, report the change to DynDNS...";
|
||||
qDebug() << m_lastIP.toString() << "->" << newIp.toString();
|
||||
m_lastIP = newIp;
|
||||
updateDNSService();
|
||||
}
|
||||
}
|
||||
else {
|
||||
qWarning() << Q_FUNC_INFO << "Regular expression failed to capture the IP address";
|
||||
qWarning() << Q_FUNC_INFO << "Failed to construct a QHostAddress from the IP string";
|
||||
}
|
||||
}
|
||||
// Clean up
|
||||
reply->deleteLater();
|
||||
sender()->deleteLater();
|
||||
else {
|
||||
qWarning() << Q_FUNC_INFO << "Regular expression failed to capture the IP address";
|
||||
}
|
||||
}
|
||||
|
||||
void DNSUpdater::ipRequestFailed(const QString &url, const QString &error)
|
||||
{
|
||||
Q_UNUSED(url);
|
||||
qWarning() << "IP request failed:" << error;
|
||||
}
|
||||
|
||||
void DNSUpdater::updateDNSService()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
// Prepare request
|
||||
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
|
||||
connect(manager, SIGNAL(finished(QNetworkReply *)), SLOT(ipUpdateFinished(QNetworkReply *)));
|
||||
|
||||
m_lastIPCheckTime = QDateTime::currentDateTime();
|
||||
QNetworkRequest request;
|
||||
request.setUrl(getUpdateUrl());
|
||||
request.setRawHeader("User-Agent", "qBittorrent/" VERSION);
|
||||
manager->get(request);
|
||||
DownloadHandler *handler = DownloadManager::instance()->downloadUrl(
|
||||
getUpdateUrl(), false, 0, false,
|
||||
QString("qBittorrent/%1").arg(VERSION));
|
||||
connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), SLOT(ipUpdateFinished(QString, QByteArray)));
|
||||
connect(handler, SIGNAL(downloadFailed(QString, QString)), SLOT(ipUpdateFailed(QString, QString)));
|
||||
}
|
||||
|
||||
QUrl DNSUpdater::getUpdateUrl() const
|
||||
QString DNSUpdater::getUpdateUrl() const
|
||||
{
|
||||
QUrl url;
|
||||
#ifdef QT_NO_OPENSSL
|
||||
|
@ -172,22 +170,20 @@ QUrl DNSUpdater::getUpdateUrl() const
|
|||
Q_ASSERT(url.isValid());
|
||||
|
||||
qDebug() << Q_FUNC_INFO << url.toString();
|
||||
return url;
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
void DNSUpdater::ipUpdateFinished(QNetworkReply *reply)
|
||||
void DNSUpdater::ipUpdateFinished(const QString &url, const QByteArray &data)
|
||||
{
|
||||
if (reply->error()) {
|
||||
// Error
|
||||
qWarning() << Q_FUNC_INFO << "Error:" << reply->errorString();
|
||||
}
|
||||
else {
|
||||
// Parse reply
|
||||
processIPUpdateReply(reply->readAll());
|
||||
}
|
||||
// Clean up
|
||||
reply->deleteLater();
|
||||
sender()->deleteLater();
|
||||
Q_UNUSED(url);
|
||||
// Parse reply
|
||||
processIPUpdateReply(data);
|
||||
}
|
||||
|
||||
void DNSUpdater::ipUpdateFailed(const QString &url, const QString &error)
|
||||
{
|
||||
Q_UNUSED(url);
|
||||
qWarning() << "IP update failed:" << error;
|
||||
}
|
||||
|
||||
void DNSUpdater::processIPUpdateReply(const QString &reply)
|
||||
|
@ -196,16 +192,19 @@ void DNSUpdater::processIPUpdateReply(const QString &reply)
|
|||
qDebug() << Q_FUNC_INFO << reply;
|
||||
QString code = reply.split(" ").first();
|
||||
qDebug() << Q_FUNC_INFO << "Code:" << code;
|
||||
if (code == "good" || code == "nochg") {
|
||||
|
||||
if ((code == "good") || (code == "nochg")) {
|
||||
logger->addMessage(tr("Your dynamic DNS was successfully updated."), Log::INFO);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((code == "911") || (code == "dnserr")) {
|
||||
logger->addMessage(tr("Dynamic DNS error: The service is temporarily unavailable, it will be retried in 30 minutes."), Log::CRITICAL);
|
||||
m_lastIP.clear();
|
||||
// It will retry in 30 minutes because the timer was not stopped
|
||||
return;
|
||||
}
|
||||
|
||||
// Everything bellow is an error, stop updating until the user updates something
|
||||
m_ipCheckTimer.stop();
|
||||
m_lastIP.clear();
|
||||
|
@ -214,23 +213,27 @@ void DNSUpdater::processIPUpdateReply(const QString &reply)
|
|||
m_state = INVALID_CREDS;
|
||||
return;
|
||||
}
|
||||
|
||||
if (code == "badauth") {
|
||||
logger->addMessage(tr("Dynamic DNS error: Invalid username/password."), Log::CRITICAL);
|
||||
m_state = INVALID_CREDS;
|
||||
return;
|
||||
}
|
||||
|
||||
if (code == "badagent") {
|
||||
logger->addMessage(tr("Dynamic DNS error: qBittorrent was blacklisted by the service, please report a bug at http://bugs.qbittorrent.org."),
|
||||
Log::CRITICAL);
|
||||
m_state = FATAL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (code == "!donator") {
|
||||
logger->addMessage(tr("Dynamic DNS error: %1 was returned by the service, please report a bug at http://bugs.qbittorrent.org.").arg("!donator"),
|
||||
Log::CRITICAL);
|
||||
m_state = FATAL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (code == "abuse") {
|
||||
logger->addMessage(tr("Dynamic DNS error: Your username was blocked due to abuse."), Log::CRITICAL);
|
||||
m_state = FATAL;
|
||||
|
|
|
@ -33,15 +33,15 @@
|
|||
|
||||
#include <QObject>
|
||||
#include <QHostAddress>
|
||||
#include <QNetworkReply>
|
||||
#include <QDateTime>
|
||||
#include <QTimer>
|
||||
|
||||
#include "base/preferences.h"
|
||||
|
||||
namespace Net
|
||||
{
|
||||
{
|
||||
// Based on http://www.dyndns.com/developers/specs/
|
||||
class DNSUpdater : public QObject
|
||||
class DNSUpdater: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -56,15 +56,25 @@ namespace Net
|
|||
|
||||
private slots:
|
||||
void checkPublicIP();
|
||||
void ipRequestFinished(QNetworkReply *reply);
|
||||
void ipRequestFinished(const QString &url, const QByteArray &data);
|
||||
void ipRequestFailed(const QString &url, const QString &error);
|
||||
void updateDNSService();
|
||||
void ipUpdateFinished(QNetworkReply *reply);
|
||||
void ipUpdateFinished(const QString &url, const QByteArray &data);
|
||||
void ipUpdateFailed(const QString &url, const QString &error);
|
||||
|
||||
private:
|
||||
QUrl getUpdateUrl() const;
|
||||
enum State
|
||||
{
|
||||
OK,
|
||||
INVALID_CREDS,
|
||||
FATAL
|
||||
};
|
||||
|
||||
static const int IP_CHECK_INTERVAL_MS = 1800000; // 30 min
|
||||
|
||||
QString getUpdateUrl() const;
|
||||
void processIPUpdateReply(const QString &reply);
|
||||
|
||||
private:
|
||||
QHostAddress m_lastIP;
|
||||
QDateTime m_lastIPCheckTime;
|
||||
QTimer m_ipCheckTimer;
|
||||
|
@ -74,16 +84,6 @@ namespace Net
|
|||
QString m_domain;
|
||||
QString m_username;
|
||||
QString m_password;
|
||||
|
||||
private:
|
||||
static const int IP_CHECK_INTERVAL_MS = 1800000; // 30 min
|
||||
|
||||
enum State
|
||||
{
|
||||
OK,
|
||||
INVALID_CREDS,
|
||||
FATAL
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -27,11 +27,13 @@
|
|||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkProxy>
|
||||
#include <QNetworkCookieJar>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkCookie>
|
||||
#include <QNetworkCookieJar>
|
||||
#include <QSslError>
|
||||
#include <QUrl>
|
||||
#include <QDebug>
|
||||
|
@ -40,6 +42,74 @@
|
|||
#include "downloadhandler.h"
|
||||
#include "downloadmanager.h"
|
||||
|
||||
// Spoof Firefox 38 user agent to avoid web server banning
|
||||
const char DEFAULT_USER_AGENT[] = "Mozilla/5.0 (X11; Linux i686; rv:38.0) Gecko/20100101 Firefox/38.0";
|
||||
|
||||
namespace
|
||||
{
|
||||
class NetworkCookieJar: public QNetworkCookieJar
|
||||
{
|
||||
public:
|
||||
explicit NetworkCookieJar(QObject *parent = 0)
|
||||
: QNetworkCookieJar(parent)
|
||||
{
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
QList<QNetworkCookie> cookies = Preferences::instance()->getNetworkCookies();
|
||||
foreach (const QNetworkCookie &cookie, Preferences::instance()->getNetworkCookies()) {
|
||||
if (cookie.isSessionCookie() || (cookie.expirationDate() <= now))
|
||||
cookies.removeAll(cookie);
|
||||
}
|
||||
|
||||
setAllCookies(cookies);
|
||||
}
|
||||
|
||||
~NetworkCookieJar()
|
||||
{
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
QList<QNetworkCookie> cookies = allCookies();
|
||||
foreach (const QNetworkCookie &cookie, allCookies()) {
|
||||
if (cookie.isSessionCookie() || (cookie.expirationDate() <= now))
|
||||
cookies.removeAll(cookie);
|
||||
}
|
||||
|
||||
Preferences::instance()->setNetworkCookies(cookies);
|
||||
}
|
||||
|
||||
#ifndef QBT_USES_QT5
|
||||
virtual bool deleteCookie(const QNetworkCookie &cookie)
|
||||
{
|
||||
auto myCookies = allCookies();
|
||||
myCookies.removeAll(cookie);
|
||||
setAllCookies(myCookies);
|
||||
}
|
||||
#endif
|
||||
|
||||
QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const override
|
||||
{
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
QList<QNetworkCookie> cookies = QNetworkCookieJar::cookiesForUrl(url);
|
||||
foreach (const QNetworkCookie &cookie, QNetworkCookieJar::cookiesForUrl(url)) {
|
||||
if (!cookie.isSessionCookie() && (cookie.expirationDate() <= now))
|
||||
cookies.removeAll(cookie);
|
||||
}
|
||||
|
||||
return cookies;
|
||||
}
|
||||
|
||||
bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url) override
|
||||
{
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
QList<QNetworkCookie> cookies = cookieList;
|
||||
foreach (const QNetworkCookie &cookie, cookieList) {
|
||||
if (!cookie.isSessionCookie() && (cookie.expirationDate() <= now))
|
||||
cookies.removeAll(cookie);
|
||||
}
|
||||
|
||||
return QNetworkCookieJar::setCookiesFromUrl(cookies, url);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
using namespace Net;
|
||||
|
||||
DownloadManager *DownloadManager::m_instance = 0;
|
||||
|
@ -50,10 +120,7 @@ DownloadManager::DownloadManager(QObject *parent)
|
|||
#ifndef QT_NO_OPENSSL
|
||||
connect(&m_networkManager, SIGNAL(sslErrors(QNetworkReply *, QList<QSslError>)), this, SLOT(ignoreSslErrors(QNetworkReply *, QList<QSslError>)));
|
||||
#endif
|
||||
}
|
||||
|
||||
DownloadManager::~DownloadManager()
|
||||
{
|
||||
m_networkManager.setCookieJar(new NetworkCookieJar(this));
|
||||
}
|
||||
|
||||
void DownloadManager::initInstance()
|
||||
|
@ -75,7 +142,7 @@ DownloadManager *DownloadManager::instance()
|
|||
return m_instance;
|
||||
}
|
||||
|
||||
DownloadHandler *DownloadManager::downloadUrl(const QString &url, bool saveToFile, qint64 limit, bool handleRedirectToMagnet)
|
||||
DownloadHandler *DownloadManager::downloadUrl(const QString &url, bool saveToFile, qint64 limit, bool handleRedirectToMagnet, const QString &userAgent)
|
||||
{
|
||||
// Update proxy settings
|
||||
applyProxySettings();
|
||||
|
@ -85,29 +152,36 @@ DownloadHandler *DownloadManager::downloadUrl(const QString &url, bool saveToFil
|
|||
const QUrl qurl = QUrl::fromEncoded(url.toUtf8());
|
||||
QNetworkRequest request(qurl);
|
||||
|
||||
// Spoof Firefox 38 user agent to avoid web server banning
|
||||
request.setRawHeader("User-Agent", "Mozilla/5.0 (X11; Linux i686; rv:38.0) Gecko/20100101 Firefox/38.0");
|
||||
if (userAgent.isEmpty())
|
||||
request.setRawHeader("User-Agent", DEFAULT_USER_AGENT);
|
||||
else
|
||||
request.setRawHeader("User-Agent", userAgent.toUtf8());
|
||||
|
||||
// Spoof HTTP Referer to allow adding torrent link from Torcache/KickAssTorrents
|
||||
request.setRawHeader("Referer", request.url().toEncoded().data());
|
||||
|
||||
qDebug("Downloading %s...", request.url().toEncoded().data());
|
||||
qDebug() << "Cookies:" << m_networkManager.cookieJar()->cookiesForUrl(request.url());
|
||||
// accept gzip
|
||||
request.setRawHeader("Accept-Encoding", "gzip");
|
||||
return new DownloadHandler(m_networkManager.get(request), this, saveToFile, limit, handleRedirectToMagnet);
|
||||
}
|
||||
|
||||
QList<QNetworkCookie> DownloadManager::cookiesForUrl(const QString &url) const
|
||||
QList<QNetworkCookie> DownloadManager::cookiesForUrl(const QUrl &url) const
|
||||
{
|
||||
return m_networkManager.cookieJar()->cookiesForUrl(url);
|
||||
}
|
||||
|
||||
bool DownloadManager::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url)
|
||||
{
|
||||
qDebug("Setting %d cookies for url: %s", cookieList.size(), qPrintable(url.toString()));
|
||||
return m_networkManager.cookieJar()->setCookiesFromUrl(cookieList, url);
|
||||
}
|
||||
|
||||
bool DownloadManager::deleteCookie(const QNetworkCookie &cookie)
|
||||
{
|
||||
return static_cast<NetworkCookieJar *>(m_networkManager.cookieJar())->deleteCookie(cookie);
|
||||
}
|
||||
|
||||
void DownloadManager::applyProxySettings()
|
||||
{
|
||||
QNetworkProxy proxy;
|
||||
|
|
|
@ -33,12 +33,10 @@
|
|||
#include <QObject>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QNetworkReply;
|
||||
class QNetworkCookie;
|
||||
class QSslError;
|
||||
class QUrl;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Net
|
||||
{
|
||||
|
@ -53,9 +51,10 @@ namespace Net
|
|||
static void freeInstance();
|
||||
static DownloadManager *instance();
|
||||
|
||||
DownloadHandler *downloadUrl(const QString &url, bool saveToFile = false, qint64 limit = 0, bool handleRedirectToMagnet = false);
|
||||
QList<QNetworkCookie> cookiesForUrl(const QString &url) const;
|
||||
DownloadHandler *downloadUrl(const QString &url, bool saveToFile = false, qint64 limit = 0, bool handleRedirectToMagnet = false, const QString &userAgent = "");
|
||||
QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const;
|
||||
bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url);
|
||||
bool deleteCookie(const QNetworkCookie &cookie);
|
||||
|
||||
private slots:
|
||||
#ifndef QT_NO_OPENSSL
|
||||
|
@ -63,8 +62,7 @@ namespace Net
|
|||
#endif
|
||||
|
||||
private:
|
||||
DownloadManager(QObject *parent = 0);
|
||||
~DownloadManager();
|
||||
explicit DownloadManager(QObject *parent = 0);
|
||||
|
||||
void applyProxySettings();
|
||||
|
||||
|
|
|
@ -996,12 +996,12 @@ void Preferences::setFilteringEnabled(bool enabled)
|
|||
|
||||
bool Preferences::isFilteringTrackerEnabled() const
|
||||
{
|
||||
return value("Preferences/IPFilter/FilterTracker", false).toBool();
|
||||
return value("Preferences/IPFilter/FilterTracker", false).toBool();
|
||||
}
|
||||
|
||||
void Preferences::setFilteringTrackerEnabled(bool enabled)
|
||||
{
|
||||
setValue("Preferences/IPFilter/FilterTracker", enabled);
|
||||
setValue("Preferences/IPFilter/FilterTracker", enabled);
|
||||
}
|
||||
|
||||
QString Preferences::getFilter() const
|
||||
|
@ -2494,45 +2494,57 @@ void Preferences::setToolbarTextPosition(const int position)
|
|||
setValue("Toolbar/textPosition", position);
|
||||
}
|
||||
|
||||
QList<QByteArray> Preferences::getHostNameCookies(const QString &host_name) const
|
||||
void Preferences::moveRSSCookies()
|
||||
{
|
||||
QMap<QString, QVariant> hosts_table = value("Rss/hosts_cookies").toMap();
|
||||
if (!hosts_table.contains(host_name)) return QList<QByteArray>();
|
||||
QByteArray raw_cookies = hosts_table.value(host_name).toByteArray();
|
||||
return raw_cookies.split(':');
|
||||
}
|
||||
|
||||
QList<QNetworkCookie> Preferences::getHostNameQNetworkCookies(const QString& host_name) const
|
||||
{
|
||||
QList<QNetworkCookie> cookies;
|
||||
const QList<QByteArray> raw_cookies = getHostNameCookies(host_name);
|
||||
foreach (const QByteArray& raw_cookie, raw_cookies) {
|
||||
QList<QByteArray> cookie_parts = raw_cookie.split('=');
|
||||
if (cookie_parts.size() == 2) {
|
||||
qDebug("Loading cookie: %s = %s", cookie_parts.first().constData(), cookie_parts.last().constData());
|
||||
cookies << QNetworkCookie(cookie_parts.first(), cookie_parts.last());
|
||||
QList<QNetworkCookie> cookies = getNetworkCookies();
|
||||
QVariantMap hostsTable = value("Rss/hosts_cookies").toMap();
|
||||
foreach (const QString &key, hostsTable.keys()) {
|
||||
QVariant value = hostsTable[key];
|
||||
QList<QByteArray> rawCookies = value.toByteArray().split(':');
|
||||
foreach (const QByteArray &rawCookie, rawCookies) {
|
||||
foreach (QNetworkCookie cookie, QNetworkCookie::parseCookies(rawCookie)) {
|
||||
cookie.setDomain(key);
|
||||
cookie.setPath("/");
|
||||
cookie.setExpirationDate(QDateTime::currentDateTime().addYears(10));
|
||||
cookies << cookie;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setNetworkCookies(cookies);
|
||||
|
||||
QWriteLocker locker(&lock);
|
||||
dirty = true;
|
||||
timer.start();
|
||||
m_data.remove("Rss/hosts_cookies");
|
||||
}
|
||||
|
||||
QList<QNetworkCookie> Preferences::getNetworkCookies() const
|
||||
{
|
||||
QList<QNetworkCookie> cookies;
|
||||
QStringList rawCookies = value("Network/Cookies").toStringList();
|
||||
foreach (const QString &rawCookie, rawCookies)
|
||||
cookies << QNetworkCookie::parseCookies(rawCookie.toUtf8());
|
||||
|
||||
return cookies;
|
||||
}
|
||||
|
||||
void Preferences::setHostNameCookies(const QString &host_name, const QList<QByteArray> &cookies)
|
||||
void Preferences::setNetworkCookies(const QList<QNetworkCookie> &cookies)
|
||||
{
|
||||
QMap<QString, QVariant> hosts_table = value("Rss/hosts_cookies").toMap();
|
||||
QByteArray raw_cookies = "";
|
||||
foreach (const QByteArray& cookie, cookies)
|
||||
raw_cookies += cookie + ":";
|
||||
if (raw_cookies.endsWith(":"))
|
||||
raw_cookies.chop(1);
|
||||
hosts_table.insert(host_name, raw_cookies);
|
||||
setValue("Rss/hosts_cookies", hosts_table);
|
||||
QStringList rawCookies;
|
||||
foreach (const QNetworkCookie &cookie, cookies)
|
||||
rawCookies << cookie.toRawForm();
|
||||
|
||||
setValue("Network/Cookies", rawCookies);
|
||||
}
|
||||
|
||||
int Preferences::getSpeedWidgetPeriod() const {
|
||||
int Preferences::getSpeedWidgetPeriod() const
|
||||
{
|
||||
return value("SpeedWidget/period", 1).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setSpeedWidgetPeriod(const int period) {
|
||||
void Preferences::setSpeedWidgetPeriod(const int period)
|
||||
{
|
||||
setValue("SpeedWidget/period", period);
|
||||
}
|
||||
|
||||
|
|
|
@ -534,9 +534,12 @@ public:
|
|||
void setRssFeedsUrls(const QStringList &rssFeeds);
|
||||
QStringList getRssFeedsAliases() const;
|
||||
void setRssFeedsAliases(const QStringList &rssAliases);
|
||||
QList<QByteArray> getHostNameCookies(const QString &host_name) const;
|
||||
QList<QNetworkCookie> getHostNameQNetworkCookies(const QString& host_name) const;
|
||||
void setHostNameCookies(const QString &host_name, const QList<QByteArray> &cookies);
|
||||
|
||||
// Network
|
||||
QList<QNetworkCookie> getNetworkCookies() const;
|
||||
void setNetworkCookies(const QList<QNetworkCookie> &cookies);
|
||||
// Temporary method for upgrade purposes
|
||||
void moveRSSCookies();
|
||||
|
||||
// SpeedWidget
|
||||
int getSpeedWidgetPeriod() const;
|
||||
|
|
|
@ -28,23 +28,20 @@
|
|||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QXmlStreamReader>
|
||||
#include <QNetworkProxy>
|
||||
#include <QDesktopServices>
|
||||
#include <QDebug>
|
||||
#include <QRegExp>
|
||||
#include <QStringList>
|
||||
|
||||
#include "programupdater.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "base/preferences.h"
|
||||
#include "base/net/downloadmanager.h"
|
||||
#include "base/net/downloadhandler.h"
|
||||
#include "programupdater.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
const QUrl RSS_URL("http://www.fosshub.com/software/feedqBittorent");
|
||||
const QString RSS_URL("http://www.fosshub.com/software/feedqBittorent");
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
const QString OS_TYPE("Mac OS X");
|
||||
|
@ -59,99 +56,73 @@ ProgramUpdater::ProgramUpdater(QObject *parent, bool invokedByUser)
|
|||
: QObject(parent)
|
||||
, m_invokedByUser(invokedByUser)
|
||||
{
|
||||
m_networkManager = new QNetworkAccessManager(this);
|
||||
Preferences* const pref = Preferences::instance();
|
||||
// Proxy support
|
||||
if (pref->isProxyEnabled()) {
|
||||
QNetworkProxy proxy;
|
||||
switch(pref->getProxyType()) {
|
||||
case Proxy::SOCKS4:
|
||||
case Proxy::SOCKS5:
|
||||
case Proxy::SOCKS5_PW:
|
||||
proxy.setType(QNetworkProxy::Socks5Proxy);
|
||||
default:
|
||||
proxy.setType(QNetworkProxy::HttpProxy);
|
||||
break;
|
||||
}
|
||||
proxy.setHostName(pref->getProxyIp());
|
||||
proxy.setPort(pref->getProxyPort());
|
||||
// Proxy authentication
|
||||
if (pref->isProxyAuthEnabled()) {
|
||||
proxy.setUser(pref->getProxyUsername());
|
||||
proxy.setPassword(pref->getProxyPassword());
|
||||
}
|
||||
m_networkManager->setProxy(proxy);
|
||||
}
|
||||
}
|
||||
|
||||
ProgramUpdater::~ProgramUpdater()
|
||||
{
|
||||
delete m_networkManager;
|
||||
}
|
||||
|
||||
void ProgramUpdater::checkForUpdates()
|
||||
{
|
||||
// SIGNAL/SLOT
|
||||
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)),
|
||||
this, SLOT(rssDownloadFinished(QNetworkReply*)));
|
||||
// Send the request
|
||||
QNetworkRequest request(RSS_URL);
|
||||
// Don't change this User-Agent. In case our updater goes haywire, the filehost can indetify it and contact us.
|
||||
request.setRawHeader("User-Agent", QString("qBittorrent/%1 ProgramUpdater (www.qbittorrent.org)").arg(VERSION).toLocal8Bit());
|
||||
m_networkManager->get(request);
|
||||
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(
|
||||
RSS_URL, false, 0, false,
|
||||
// Don't change this User-Agent. In case our updater goes haywire,
|
||||
// the filehost can identify it and contact us.
|
||||
QString("qBittorrent/%1 ProgramUpdater (www.qbittorrent.org)").arg(VERSION));
|
||||
connect(handler, SIGNAL(downloadFinished(QString,QByteArray)), SLOT(rssDownloadFinished(QString,QByteArray)));
|
||||
connect(handler, SIGNAL(downloadFailed(QString,QString)), SLOT(rssDownloadFailed(QString,QString)));
|
||||
}
|
||||
|
||||
void ProgramUpdater::rssDownloadFinished(QNetworkReply *reply)
|
||||
void ProgramUpdater::rssDownloadFinished(const QString &url, const QByteArray &data)
|
||||
{
|
||||
// Disconnect SIGNAL/SLOT
|
||||
disconnect(m_networkManager, 0, this, 0);
|
||||
Q_UNUSED(url);
|
||||
|
||||
qDebug("Finished downloading the new qBittorrent updates RSS");
|
||||
QString version;
|
||||
|
||||
if (!reply->error()) {
|
||||
qDebug("No download error, good.");
|
||||
QXmlStreamReader xml(reply);
|
||||
bool inItem = false;
|
||||
QString updateLink;
|
||||
QString type;
|
||||
QXmlStreamReader xml(data);
|
||||
bool inItem = false;
|
||||
QString updateLink;
|
||||
QString type;
|
||||
|
||||
while (!xml.atEnd()) {
|
||||
xml.readNext();
|
||||
while (!xml.atEnd()) {
|
||||
xml.readNext();
|
||||
|
||||
if (xml.isStartElement()) {
|
||||
if (xml.name() == "item")
|
||||
inItem = true;
|
||||
else if (inItem && xml.name() == "link")
|
||||
updateLink = getStringValue(xml);
|
||||
else if (inItem && xml.name() == "type")
|
||||
type = getStringValue(xml);
|
||||
else if (inItem && xml.name() == "version")
|
||||
version = getStringValue(xml);
|
||||
}
|
||||
else if (xml.isEndElement()) {
|
||||
if (inItem && xml.name() == "item") {
|
||||
if (type.compare(OS_TYPE, Qt::CaseInsensitive) == 0) {
|
||||
qDebug("The last update available is %s", qPrintable(version));
|
||||
if (!version.isEmpty()) {
|
||||
qDebug("Detected version is %s", qPrintable(version));
|
||||
if (isVersionMoreRecent(version))
|
||||
m_updateUrl = updateLink;
|
||||
}
|
||||
break;
|
||||
if (xml.isStartElement()) {
|
||||
if (xml.name() == "item")
|
||||
inItem = true;
|
||||
else if (inItem && xml.name() == "link")
|
||||
updateLink = getStringValue(xml);
|
||||
else if (inItem && xml.name() == "type")
|
||||
type = getStringValue(xml);
|
||||
else if (inItem && xml.name() == "version")
|
||||
version = getStringValue(xml);
|
||||
}
|
||||
else if (xml.isEndElement()) {
|
||||
if (inItem && xml.name() == "item") {
|
||||
if (type.compare(OS_TYPE, Qt::CaseInsensitive) == 0) {
|
||||
qDebug("The last update available is %s", qPrintable(version));
|
||||
if (!version.isEmpty()) {
|
||||
qDebug("Detected version is %s", qPrintable(version));
|
||||
if (isVersionMoreRecent(version))
|
||||
m_updateUrl = updateLink;
|
||||
}
|
||||
|
||||
inItem = false;
|
||||
updateLink.clear();
|
||||
type.clear();
|
||||
version.clear();
|
||||
break;
|
||||
}
|
||||
|
||||
inItem = false;
|
||||
updateLink.clear();
|
||||
type.clear();
|
||||
version.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emit updateCheckFinished(!m_updateUrl.isEmpty(), version, m_invokedByUser);
|
||||
// Clean up
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void ProgramUpdater::rssDownloadFailed(const QString &url, const QString &error)
|
||||
{
|
||||
Q_UNUSED(url);
|
||||
|
||||
qDebug() << "Downloading the new qBittorrent updates RSS failed:" << error;
|
||||
emit updateCheckFinished(false, QString(), m_invokedByUser);
|
||||
}
|
||||
|
||||
void ProgramUpdater::updateProgram()
|
||||
|
|
|
@ -34,30 +34,27 @@
|
|||
#include <QObject>
|
||||
#include <QUrl>
|
||||
|
||||
class QNetworkReply;
|
||||
class QNetworkAccessManager;
|
||||
|
||||
class ProgramUpdater: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ProgramUpdater(QObject *parent = 0, bool invokedByUser = false);
|
||||
~ProgramUpdater();
|
||||
|
||||
void checkForUpdates();
|
||||
void updateProgram();
|
||||
|
||||
protected:
|
||||
bool isVersionMoreRecent(const QString &remoteVersion) const;
|
||||
|
||||
protected slots:
|
||||
void rssDownloadFinished(QNetworkReply* reply);
|
||||
|
||||
signals:
|
||||
void updateCheckFinished(bool updateAvailable, QString version, bool invokedByUser);
|
||||
|
||||
private slots:
|
||||
void rssDownloadFinished(const QString &url, const QByteArray &data);
|
||||
void rssDownloadFailed(const QString &url, const QString &error);
|
||||
|
||||
private:
|
||||
bool isVersionMoreRecent(const QString &remoteVersion) const;
|
||||
|
||||
QString m_updateUrl;
|
||||
QNetworkAccessManager *m_networkManager;
|
||||
bool m_invokedByUser;
|
||||
};
|
||||
|
||||
|
|
|
@ -31,12 +31,14 @@
|
|||
#include "cookiesdlg.h"
|
||||
#include "ui_cookiesdlg.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "base/net/downloadmanager.h"
|
||||
|
||||
#include <QNetworkCookie>
|
||||
#include <QDateTime>
|
||||
|
||||
enum CookiesCols { COOKIE_KEY, COOKIE_VALUE};
|
||||
|
||||
CookiesDlg::CookiesDlg(QWidget *parent, const QList<QByteArray> &raw_cookies) :
|
||||
CookiesDlg::CookiesDlg(const QUrl &url, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::CookiesDlg)
|
||||
{
|
||||
|
@ -46,13 +48,13 @@ CookiesDlg::CookiesDlg(QWidget *parent, const QList<QByteArray> &raw_cookies) :
|
|||
ui->del_btn->setIcon(GuiIconProvider::instance()->getIcon("list-remove"));
|
||||
|
||||
ui->infos_lbl->setText(tr("Common keys for cookies are: '%1', '%2'.\nYou should get this information from your Web browser preferences.").arg("uid").arg("pass"));
|
||||
foreach (const QByteArray &raw_cookie, raw_cookies) {
|
||||
QList<QByteArray> cookie_parts = raw_cookie.split('=');
|
||||
if (cookie_parts.size() != 2) continue;
|
||||
|
||||
QList<QNetworkCookie> cookies = Net::DownloadManager::instance()->cookiesForUrl(url);
|
||||
foreach (const QNetworkCookie &cookie, cookies) {
|
||||
const int i = ui->cookiesTable->rowCount();
|
||||
ui->cookiesTable->setRowCount(i+1);
|
||||
ui->cookiesTable->setItem(i, COOKIE_KEY, new QTableWidgetItem(cookie_parts.first().data()));
|
||||
ui->cookiesTable->setItem(i, COOKIE_VALUE, new QTableWidgetItem(cookie_parts.last().data()));
|
||||
ui->cookiesTable->setItem(i, COOKIE_KEY, new QTableWidgetItem(QString(cookie.name())));
|
||||
ui->cookiesTable->setItem(i, COOKIE_VALUE, new QTableWidgetItem(QString(cookie.value())));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,8 +77,9 @@ void CookiesDlg::on_del_btn_clicked() {
|
|||
}
|
||||
}
|
||||
|
||||
QList<QByteArray> CookiesDlg::getCookies() const {
|
||||
QList<QByteArray> ret;
|
||||
QList<QNetworkCookie> CookiesDlg::getCookies() const {
|
||||
QList<QNetworkCookie> ret;
|
||||
auto now = QDateTime::currentDateTime();
|
||||
for (int i=0; i<ui->cookiesTable->rowCount(); ++i) {
|
||||
QString key;
|
||||
if (ui->cookiesTable->item(i, COOKIE_KEY))
|
||||
|
@ -85,20 +88,23 @@ QList<QByteArray> CookiesDlg::getCookies() const {
|
|||
if (ui->cookiesTable->item(i, COOKIE_VALUE))
|
||||
value = ui->cookiesTable->item(i, COOKIE_VALUE)->text().trimmed();
|
||||
if (!key.isEmpty() && !value.isEmpty()) {
|
||||
const QString raw_cookie = key+"="+value;
|
||||
qDebug("Cookie: %s", qPrintable(raw_cookie));
|
||||
ret << raw_cookie.toLocal8Bit();
|
||||
QNetworkCookie cookie(key.toUtf8(), value.toUtf8());
|
||||
// TODO: Delete this hack when advanced Cookie dialog will be implemented.
|
||||
cookie.setExpirationDate(now.addYears(10));
|
||||
qDebug("Cookie: %s", cookie.toRawForm().data());
|
||||
ret << cookie;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QList<QByteArray> CookiesDlg::askForCookies(QWidget *parent, const QList<QByteArray> &raw_cookies, bool *ok) {
|
||||
CookiesDlg dlg(parent, raw_cookies);
|
||||
bool CookiesDlg::askForCookies(QWidget *parent, const QUrl &url, QList<QNetworkCookie> &out)
|
||||
{
|
||||
CookiesDlg dlg(url, parent);
|
||||
if (dlg.exec()) {
|
||||
*ok = true;
|
||||
return dlg.getCookies();
|
||||
out = dlg.getCookies();
|
||||
return true;
|
||||
}
|
||||
*ok = false;
|
||||
return QList<QByteArray>();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -32,22 +32,24 @@
|
|||
#define COOKIESDLG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QList>
|
||||
|
||||
class QNetworkCookie;
|
||||
class QUrl;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
class CookiesDlg;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class CookiesDlg : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CookiesDlg(QWidget *parent = 0, const QList<QByteArray> &raw_cookies = QList<QByteArray>());
|
||||
explicit CookiesDlg(const QUrl &url, QWidget *parent = 0);
|
||||
~CookiesDlg();
|
||||
QList<QByteArray> getCookies() const;
|
||||
static QList<QByteArray> askForCookies(QWidget *parent, const QList<QByteArray> &raw_cookies, bool *ok);
|
||||
QList<QNetworkCookie> getCookies() const;
|
||||
static bool askForCookies(QWidget *parent, const QUrl &url, QList<QNetworkCookie> &out);
|
||||
|
||||
protected slots:
|
||||
void on_add_btn_clicked();
|
||||
|
|
|
@ -142,18 +142,19 @@ void RSSImp::displayItemsListMenu(const QPoint&)
|
|||
void RSSImp::on_actionManage_cookies_triggered()
|
||||
{
|
||||
Q_ASSERT(!m_feedList->selectedItems().empty());
|
||||
// Get feed hostname
|
||||
QString feed_url = m_feedList->getItemID(m_feedList->selectedItems().first());
|
||||
QString feed_hostname = QUrl::fromEncoded(feed_url.toUtf8()).host();
|
||||
qDebug("RSS Feed hostname is: %s", qPrintable(feed_hostname));
|
||||
Q_ASSERT(!feed_hostname.isEmpty());
|
||||
bool ok = false;
|
||||
Preferences* const pref = Preferences::instance();
|
||||
QList<QByteArray> raw_cookies = CookiesDlg::askForCookies(this, pref->getHostNameCookies(feed_hostname), &ok);
|
||||
if (ok) {
|
||||
qDebug() << "Settings cookies for host name: " << feed_hostname;
|
||||
pref->setHostNameCookies(feed_hostname, raw_cookies);
|
||||
Net::DownloadManager::instance()->setCookiesFromUrl(pref->getHostNameQNetworkCookies(feed_hostname), feed_hostname);
|
||||
|
||||
// TODO: Create advanced application wide Cookie dialog and use it everywhere.
|
||||
QUrl feedUrl = QUrl::fromEncoded(m_feedList->getItemID(m_feedList->selectedItems().first()).toUtf8());
|
||||
QList<QNetworkCookie> cookies;
|
||||
if (CookiesDlg::askForCookies(this, feedUrl, cookies)) {
|
||||
auto downloadManager = Net::DownloadManager::instance();
|
||||
QList<QNetworkCookie> oldCookies = downloadManager->cookiesForUrl(feedUrl);
|
||||
foreach (const QNetworkCookie &oldCookie, oldCookies) {
|
||||
if (!cookies.contains(oldCookie))
|
||||
downloadManager->deleteCookie(oldCookie);
|
||||
}
|
||||
|
||||
downloadManager->setCookiesFromUrl(cookies, feedUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue