Merge pull request #4413 from glassez/dlmgr

Improve Download Manager. Closes #4305
This commit is contained in:
sledgehammer999 2016-01-05 10:10:08 -06:00
commit 52d08f7112
13 changed files with 319 additions and 248 deletions

View file

@ -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);

View file

@ -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();

View file

@ -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;

View file

@ -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
};
};
}

View file

@ -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;

View file

@ -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();

View file

@ -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);
}

View file

@ -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;

View file

@ -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()

View file

@ -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;
};

View file

@ -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;
}

View file

@ -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();

View file

@ -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);
}
}