mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2025-12-17 14:08:03 -06:00
Redesign main core classes.
This commit is contained in:
@@ -32,8 +32,10 @@
|
||||
#include <QLocale>
|
||||
#include <QLibraryInfo>
|
||||
#include <QSysInfo>
|
||||
#include <QProcess>
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
#include "gui/guiiconprovider.h"
|
||||
#ifdef Q_OS_WIN
|
||||
#include <Windows.h>
|
||||
#include <QSharedMemory>
|
||||
@@ -46,26 +48,38 @@
|
||||
#endif // Q_OS_MAC
|
||||
#include "mainwindow.h"
|
||||
#include "addnewtorrentdialog.h"
|
||||
#include "shutdownconfirm.h"
|
||||
#else // DISABLE_GUI
|
||||
#include <iostream>
|
||||
#endif // DISABLE_GUI
|
||||
|
||||
#ifndef DISABLE_WEBUI
|
||||
#include "../webui/webui.h"
|
||||
#include "webui/webui.h"
|
||||
#endif
|
||||
|
||||
#include "application.h"
|
||||
#include "core/logger.h"
|
||||
#include "core/preferences.h"
|
||||
#include "qbtsession.h"
|
||||
#include "core/torrentpersistentdata.h"
|
||||
#include "core/misc.h"
|
||||
#include "core/iconprovider.h"
|
||||
#include "core/scanfoldersmodel.h"
|
||||
#include "core/net/smtp.h"
|
||||
#include "core/net/downloadmanager.h"
|
||||
#include "core/bittorrent/session.h"
|
||||
#include "core/bittorrent/torrenthandle.h"
|
||||
|
||||
static const char PARAMS_SEPARATOR[] = "|";
|
||||
|
||||
Application::Application(const QString &id, int &argc, char **argv)
|
||||
: BaseApplication(id, argc, argv)
|
||||
, m_running(false)
|
||||
#ifndef DISABLE_GUI
|
||||
, m_shutdownAct(NO_SHUTDOWN)
|
||||
#endif
|
||||
{
|
||||
Logger::initInstance();
|
||||
Preferences::initInstance();
|
||||
|
||||
#if defined(Q_OS_MACX) && !defined(DISABLE_GUI)
|
||||
if (QSysInfo::MacintoshVersion > QSysInfo::MV_10_8) {
|
||||
// fix Mac OS X 10.9 (mavericks) font issue
|
||||
@@ -85,6 +99,8 @@ Application::Application(const QString &id, int &argc, char **argv)
|
||||
|
||||
connect(this, SIGNAL(messageReceived(const QString &)), SLOT(processMessage(const QString &)));
|
||||
connect(this, SIGNAL(aboutToQuit()), SLOT(cleanup()));
|
||||
|
||||
Logger::instance()->addMessage(tr("qBittorrent %1 started", "qBittorrent v3.2.0alpha started").arg(VERSION));
|
||||
}
|
||||
|
||||
void Application::processMessage(const QString &message)
|
||||
@@ -98,6 +114,87 @@ void Application::processMessage(const QString &message)
|
||||
m_paramsQueue.append(params);
|
||||
}
|
||||
|
||||
void Application::sendNotificationEmail(BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
// Prepare mail content
|
||||
QString content = QObject::tr("Torrent name: %1").arg(torrent->name()) + "\n";
|
||||
content += QObject::tr("Torrent size: %1").arg(misc::friendlyUnit(torrent->wantedSize())) + "\n";
|
||||
content += QObject::tr("Save path: %1").arg(torrent->savePath()) + "\n\n";
|
||||
content += QObject::tr("The torrent was downloaded in %1.",
|
||||
"The torrent was downloaded in 1 hour and 20 seconds")
|
||||
.arg(misc::userFriendlyDuration(torrent->activeTime())) + "\n\n\n";
|
||||
content += QObject::tr("Thank you for using qBittorrent.") + "\n";
|
||||
|
||||
// Send the notification email
|
||||
Net::Smtp *sender = new Net::Smtp;
|
||||
sender->sendMail("notification@qbittorrent.org",
|
||||
Preferences::instance()->getMailNotificationEmail(),
|
||||
QObject::tr("[qBittorrent] %1 has finished downloading").arg(torrent->name()),
|
||||
content);
|
||||
}
|
||||
|
||||
void Application::torrentFinished(BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
Preferences *const pref = Preferences::instance();
|
||||
|
||||
// AutoRun program
|
||||
if (pref->isAutoRunEnabled()) {
|
||||
QString program = pref->getAutoRunProgram().trimmed();
|
||||
// Replace %f by torrent path
|
||||
program.replace("%f", torrent->savePathParsed());
|
||||
// Replace %n by torrent name
|
||||
program.replace("%n", torrent->name());
|
||||
QProcess::startDetached(program);
|
||||
}
|
||||
|
||||
// Mail notification
|
||||
if (pref->isMailNotificationEnabled())
|
||||
sendNotificationEmail(torrent);
|
||||
}
|
||||
|
||||
void Application::allTorrentsFinished()
|
||||
{
|
||||
Preferences *const pref = Preferences::instance();
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
bool will_shutdown = (pref->shutdownWhenDownloadsComplete()
|
||||
|| pref->shutdownqBTWhenDownloadsComplete()
|
||||
|| pref->suspendWhenDownloadsComplete()
|
||||
|| pref->hibernateWhenDownloadsComplete());
|
||||
|
||||
// Auto-Shutdown
|
||||
if (will_shutdown) {
|
||||
bool suspend = pref->suspendWhenDownloadsComplete();
|
||||
bool hibernate = pref->hibernateWhenDownloadsComplete();
|
||||
bool shutdown = pref->shutdownWhenDownloadsComplete();
|
||||
|
||||
// Confirm shutdown
|
||||
ShutDownAction action = NO_SHUTDOWN;
|
||||
if (suspend)
|
||||
action = SUSPEND_COMPUTER;
|
||||
else if (hibernate)
|
||||
action = HIBERNATE_COMPUTER;
|
||||
else if (shutdown)
|
||||
action = SHUTDOWN_COMPUTER;
|
||||
|
||||
if (!ShutdownConfirmDlg::askForConfirmation(action)) return;
|
||||
|
||||
// Actually shut down
|
||||
if (suspend || hibernate || shutdown) {
|
||||
qDebug("Preparing for auto-shutdown because all downloads are complete!");
|
||||
// Disabling it for next time
|
||||
pref->setShutdownWhenDownloadsComplete(false);
|
||||
pref->setSuspendWhenDownloadsComplete(false);
|
||||
pref->setHibernateWhenDownloadsComplete(false);
|
||||
// Make sure preferences are synced before exiting
|
||||
m_shutdownAct = action;
|
||||
}
|
||||
qDebug("Exiting the application");
|
||||
exit();
|
||||
}
|
||||
#endif // DISABLE_GUI
|
||||
}
|
||||
|
||||
bool Application::sendParams(const QStringList ¶ms)
|
||||
{
|
||||
return sendMessage(params.join(QLatin1String(PARAMS_SEPARATOR)));
|
||||
@@ -114,45 +211,32 @@ void Application::processParams(const QStringList ¶ms)
|
||||
m_window->activate(); // show UI
|
||||
return;
|
||||
}
|
||||
|
||||
const bool useTorrentAdditionDialog = Preferences::instance()->useAdditionDialog();
|
||||
#endif
|
||||
|
||||
foreach (QString param, params) {
|
||||
param = param.trimmed();
|
||||
if (misc::isUrl(param)) {
|
||||
QBtSession::instance()->downloadFromUrl(param);
|
||||
}
|
||||
else {
|
||||
if (param.startsWith("bc://bt/", Qt::CaseInsensitive)) {
|
||||
qDebug("Converting bc link to magnet link");
|
||||
param = misc::bcLinkToMagnet(param);
|
||||
}
|
||||
|
||||
if (param.startsWith("magnet:", Qt::CaseInsensitive)) {
|
||||
#ifndef DISABLE_GUI
|
||||
if (useTorrentAdditionDialog)
|
||||
AddNewTorrentDialog::showMagnet(param, m_window);
|
||||
else
|
||||
if (Preferences::instance()->useAdditionDialog())
|
||||
AddNewTorrentDialog::show(param, m_window);
|
||||
else
|
||||
#endif
|
||||
QBtSession::instance()->addMagnetUri(param);
|
||||
}
|
||||
else {
|
||||
#ifndef DISABLE_GUI
|
||||
if (useTorrentAdditionDialog)
|
||||
AddNewTorrentDialog::showTorrent(param, QString(), m_window);
|
||||
else
|
||||
#endif
|
||||
QBtSession::instance()->addTorrent(param);
|
||||
}
|
||||
}
|
||||
BitTorrent::Session::instance()->addTorrent(param);
|
||||
}
|
||||
}
|
||||
|
||||
int Application::exec(const QStringList ¶ms)
|
||||
{
|
||||
// Resume unfinished torrents
|
||||
QBtSession::instance()->startUpTorrents();
|
||||
Net::DownloadManager::initInstance();
|
||||
#ifdef DISABLE_GUI
|
||||
IconProvider::initInstance();
|
||||
#else
|
||||
GuiIconProvider::initInstance();
|
||||
#endif
|
||||
BitTorrent::Session::initInstance();
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(torrentFinished(BitTorrent::TorrentHandle *const)), SLOT(torrentFinished(BitTorrent::TorrentHandle *const)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(allTorrentsFinished()), SLOT(allTorrentsFinished()));
|
||||
|
||||
ScanFoldersModel::initInstance(this);
|
||||
|
||||
#ifndef DISABLE_WEBUI
|
||||
m_webui = new WebUI;
|
||||
@@ -293,6 +377,8 @@ void Application::initializeTranslation()
|
||||
#if (!defined(DISABLE_GUI) && defined(Q_OS_WIN))
|
||||
void Application::shutdownCleanup(QSessionManager &manager)
|
||||
{
|
||||
Q_UNUSED(manager);
|
||||
|
||||
// This is only needed for a special case on Windows XP.
|
||||
// (but is called for every Windows version)
|
||||
// If a process takes too much time to exit during OS
|
||||
@@ -356,10 +442,13 @@ void Application::cleanup()
|
||||
#ifndef DISABLE_WEBUI
|
||||
delete m_webui;
|
||||
#endif
|
||||
QBtSession::drop();
|
||||
TorrentPersistentData::drop();
|
||||
Preferences::drop();
|
||||
Logger::drop();
|
||||
|
||||
ScanFoldersModel::freeInstance();
|
||||
BitTorrent::Session::freeInstance();
|
||||
Preferences::freeInstance();
|
||||
Logger::freeInstance();
|
||||
IconProvider::freeInstance();
|
||||
Net::DownloadManager::freeInstance();
|
||||
#ifndef DISABLE_GUI
|
||||
#ifdef Q_OS_WIN
|
||||
typedef BOOL (WINAPI *PSHUTDOWNBRDESTROY)(HWND);
|
||||
@@ -369,6 +458,9 @@ void Application::cleanup()
|
||||
shutdownBRDestroy((HWND)m_window->effectiveWinId());
|
||||
#endif // Q_OS_WIN
|
||||
delete m_window;
|
||||
if (m_shutdownAct != NO_SHUTDOWN) {
|
||||
qDebug() << "Sending computer shutdown/suspend/hibernate signal...";
|
||||
misc::shutdownComputer(m_shutdownAct);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -50,10 +50,17 @@ QT_END_NAMESPACE
|
||||
typedef QtSingleCoreApplication BaseApplication;
|
||||
#endif
|
||||
|
||||
#include "core/misc.h"
|
||||
|
||||
#ifndef DISABLE_WEBUI
|
||||
class WebUI;
|
||||
#endif
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class TorrentHandle;
|
||||
}
|
||||
|
||||
class Application : public BaseApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -77,6 +84,8 @@ protected:
|
||||
|
||||
private slots:
|
||||
void processMessage(const QString &message);
|
||||
void torrentFinished(BitTorrent::TorrentHandle *const torrent);
|
||||
void allTorrentsFinished();
|
||||
void cleanup();
|
||||
#if (!defined(DISABLE_GUI) && defined(Q_OS_WIN))
|
||||
void shutdownCleanup(QSessionManager &manager);
|
||||
@@ -87,6 +96,7 @@ private:
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
QPointer<MainWindow> m_window;
|
||||
ShutDownAction m_shutdownAct;
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_WEBUI
|
||||
@@ -99,6 +109,7 @@ private:
|
||||
|
||||
void initializeTranslation();
|
||||
void processParams(const QStringList ¶ms);
|
||||
void sendNotificationEmail(BitTorrent::TorrentHandle *const torrent);
|
||||
};
|
||||
|
||||
#endif // APPLICATION_H
|
||||
|
||||
@@ -68,7 +68,6 @@ Q_IMPORT_PLUGIN(qico)
|
||||
#include "application.h"
|
||||
#include "core/misc.h"
|
||||
#include "core/preferences.h"
|
||||
#include "core/logger.h"
|
||||
|
||||
// Signal handlers
|
||||
#if defined(Q_OS_UNIX) || defined(STACKTRACE_WIN)
|
||||
@@ -120,8 +119,6 @@ QBtCommandLineParameters parseCommandLine();
|
||||
// Main
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
//Initialize logger singleton here to avoid threading issues
|
||||
Logger::instance()->addMessage(QObject::tr("qBittorrent %1 started", "qBittorrent v3.2.0alpha started").arg(VERSION));
|
||||
// We must save it here because QApplication constructor may change it
|
||||
bool isOneArg = (argc == 2);
|
||||
|
||||
|
||||
64
src/core/bittorrent/cachestatus.cpp
Normal file
64
src/core/bittorrent/cachestatus.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include "cachestatus.h"
|
||||
|
||||
using namespace BitTorrent;
|
||||
|
||||
CacheStatus::CacheStatus(const libtorrent::cache_status &nativeStatus)
|
||||
: m_nativeStatus(nativeStatus)
|
||||
{
|
||||
}
|
||||
|
||||
int CacheStatus::totalUsedBuffers() const
|
||||
{
|
||||
return m_nativeStatus.total_used_buffers;
|
||||
}
|
||||
|
||||
qreal CacheStatus::readRatio() const
|
||||
{
|
||||
if (m_nativeStatus.blocks_read > 0)
|
||||
return (static_cast<qreal>(m_nativeStatus.blocks_read_hit) / m_nativeStatus.blocks_read);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int CacheStatus::jobQueueLength() const
|
||||
{
|
||||
return m_nativeStatus.job_queue_length;
|
||||
}
|
||||
|
||||
int CacheStatus::averageJobTime() const
|
||||
{
|
||||
return m_nativeStatus.average_job_time;
|
||||
}
|
||||
|
||||
qlonglong CacheStatus::queuedBytes() const
|
||||
{
|
||||
return m_nativeStatus.queued_bytes;
|
||||
}
|
||||
53
src/core/bittorrent/cachestatus.h
Normal file
53
src/core/bittorrent/cachestatus.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef BITTORRENT_CACHESTATUS_H
|
||||
#define BITTORRENT_CACHESTATUS_H
|
||||
|
||||
#include <libtorrent/disk_io_thread.hpp>
|
||||
#include <QtGlobal>
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class CacheStatus
|
||||
{
|
||||
public:
|
||||
CacheStatus(const libtorrent::cache_status &nativeStatus);
|
||||
|
||||
int totalUsedBuffers() const;
|
||||
qreal readRatio() const;
|
||||
int jobQueueLength() const;
|
||||
int averageJobTime() const;
|
||||
qlonglong queuedBytes() const;
|
||||
|
||||
private:
|
||||
libtorrent::cache_status m_nativeStatus;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // BITTORRENT_CACHESTATUS_H
|
||||
98
src/core/bittorrent/infohash.cpp
Normal file
98
src/core/bittorrent/infohash.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include <QHash>
|
||||
#include "infohash.h"
|
||||
|
||||
using namespace BitTorrent;
|
||||
|
||||
InfoHash::InfoHash()
|
||||
: m_valid(false)
|
||||
{
|
||||
}
|
||||
|
||||
InfoHash::InfoHash(const libtorrent::sha1_hash &nativeHash)
|
||||
: m_valid(true)
|
||||
, m_nativeHash(nativeHash)
|
||||
{
|
||||
char out[(libtorrent::sha1_hash::size * 2) + 1];
|
||||
libtorrent::to_hex((char const*)&m_nativeHash[0], libtorrent::sha1_hash::size, out);
|
||||
m_hashString = QString(out);
|
||||
}
|
||||
|
||||
InfoHash::InfoHash(const QString &hashString)
|
||||
: m_valid(false)
|
||||
, m_hashString(hashString)
|
||||
{
|
||||
QByteArray raw = m_hashString.toLatin1();
|
||||
if (raw.size() == 40)
|
||||
m_valid = libtorrent::from_hex(raw.constData(), 40, (char*)&m_nativeHash[0]);
|
||||
}
|
||||
|
||||
|
||||
InfoHash::InfoHash(const InfoHash &other)
|
||||
: m_valid(other.m_valid)
|
||||
, m_nativeHash(other.m_nativeHash)
|
||||
, m_hashString(other.m_hashString)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool InfoHash::isValid() const
|
||||
{
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
|
||||
InfoHash::operator libtorrent::sha1_hash() const
|
||||
{
|
||||
return m_nativeHash;
|
||||
}
|
||||
|
||||
|
||||
InfoHash::operator QString() const
|
||||
{
|
||||
return m_hashString;
|
||||
}
|
||||
|
||||
|
||||
bool InfoHash::operator==(const InfoHash &other) const
|
||||
{
|
||||
return (m_nativeHash == other.m_nativeHash);
|
||||
}
|
||||
|
||||
|
||||
bool InfoHash::operator!=(const InfoHash &other) const
|
||||
{
|
||||
return (m_nativeHash != other.m_nativeHash);
|
||||
}
|
||||
|
||||
uint qHash(const InfoHash &key, uint seed)
|
||||
{
|
||||
return qHash(static_cast<QString>(key), seed);
|
||||
}
|
||||
67
src/core/bittorrent/infohash.h
Normal file
67
src/core/bittorrent/infohash.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef BITTORRENT_INFOHASH_H
|
||||
#define BITTORRENT_INFOHASH_H
|
||||
|
||||
#include <libtorrent/version.hpp>
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
#include <libtorrent/peer_id.hpp>
|
||||
#else
|
||||
#include <libtorrent/sha1_hash.hpp>
|
||||
#endif
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class InfoHash
|
||||
{
|
||||
public:
|
||||
InfoHash();
|
||||
InfoHash(const libtorrent::sha1_hash &nativeHash);
|
||||
InfoHash(const QString &hashString);
|
||||
InfoHash(const InfoHash &other);
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
operator libtorrent::sha1_hash() const;
|
||||
operator QString() const;
|
||||
bool operator==(const InfoHash &other) const;
|
||||
bool operator!=(const InfoHash &other) const;
|
||||
|
||||
private:
|
||||
bool m_valid;
|
||||
libtorrent::sha1_hash m_nativeHash;
|
||||
QString m_hashString;
|
||||
};
|
||||
}
|
||||
|
||||
uint qHash(const BitTorrent::InfoHash &key, uint seed);
|
||||
|
||||
#endif // BITTORRENT_INFOHASH_H
|
||||
95
src/core/bittorrent/magneturi.cpp
Normal file
95
src/core/bittorrent/magneturi.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include <libtorrent/bencode.hpp>
|
||||
#include <libtorrent/error_code.hpp>
|
||||
#include <libtorrent/magnet_uri.hpp>
|
||||
|
||||
#include "core/utils/string.h"
|
||||
#include "magneturi.h"
|
||||
|
||||
namespace libt = libtorrent;
|
||||
using namespace BitTorrent;
|
||||
|
||||
MagnetUri::MagnetUri(const QString &url)
|
||||
: m_valid(false)
|
||||
, m_url(url)
|
||||
{
|
||||
if (url.isEmpty()) return;
|
||||
|
||||
libt::error_code ec;
|
||||
libt::parse_magnet_uri(url.toUtf8().constData(), m_addTorrentParams, ec);
|
||||
if (ec) return;
|
||||
|
||||
m_valid = true;
|
||||
m_hash = m_addTorrentParams.info_hash;
|
||||
m_name = String::fromStdString(m_addTorrentParams.name);
|
||||
|
||||
foreach (const std::string &tracker, m_addTorrentParams.trackers)
|
||||
m_trackers.append(String::fromStdString(tracker));
|
||||
|
||||
#if LIBTORRENT_VERSION_NUM >= 10000
|
||||
foreach (const std::string &urlSeed, m_addTorrentParams.url_seeds)
|
||||
m_urlSeeds.append(QUrl(urlSeed.c_str()));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MagnetUri::isValid() const
|
||||
{
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
InfoHash MagnetUri::hash() const
|
||||
{
|
||||
return m_hash;
|
||||
}
|
||||
|
||||
QString MagnetUri::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
QList<TrackerEntry> MagnetUri::trackers() const
|
||||
{
|
||||
return m_trackers;
|
||||
}
|
||||
|
||||
QList<QUrl> MagnetUri::urlSeeds() const
|
||||
{
|
||||
return m_urlSeeds;
|
||||
}
|
||||
|
||||
QString MagnetUri::url() const
|
||||
{
|
||||
return m_url;
|
||||
}
|
||||
|
||||
libtorrent::add_torrent_params MagnetUri::addTorrentParams() const
|
||||
{
|
||||
return m_addTorrentParams;
|
||||
}
|
||||
68
src/core/bittorrent/magneturi.h
Normal file
68
src/core/bittorrent/magneturi.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef BITTORRENT_MAGNETURI_H
|
||||
#define BITTORRENT_MAGNETURI_H
|
||||
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QUrl>
|
||||
|
||||
#include <libtorrent/add_torrent_params.hpp>
|
||||
|
||||
#include "infohash.h"
|
||||
#include "trackerentry.h"
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class MagnetUri
|
||||
{
|
||||
public:
|
||||
explicit MagnetUri(const QString &url = QString());
|
||||
|
||||
bool isValid() const;
|
||||
InfoHash hash() const;
|
||||
QString name() const;
|
||||
QList<TrackerEntry> trackers() const;
|
||||
QList<QUrl> urlSeeds() const;
|
||||
QString url() const;
|
||||
|
||||
libtorrent::add_torrent_params addTorrentParams() const;
|
||||
|
||||
private:
|
||||
bool m_valid;
|
||||
QString m_url;
|
||||
InfoHash m_hash;
|
||||
QString m_name;
|
||||
QList<TrackerEntry> m_trackers;
|
||||
QList<QUrl> m_urlSeeds;
|
||||
libtorrent::add_torrent_params m_addTorrentParams;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // BITTORRENT_MAGNETURI_H
|
||||
271
src/core/bittorrent/peerinfo.cpp
Normal file
271
src/core/bittorrent/peerinfo.cpp
Normal file
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include <libtorrent/version.hpp>
|
||||
|
||||
#include "core/utils/string.h"
|
||||
#include "peerinfo.h"
|
||||
|
||||
namespace libt = libtorrent;
|
||||
using namespace BitTorrent;
|
||||
|
||||
// PeerAddress
|
||||
|
||||
PeerAddress::PeerAddress()
|
||||
: port(0)
|
||||
{
|
||||
}
|
||||
|
||||
PeerAddress::PeerAddress(QHostAddress ip, ushort port)
|
||||
: ip(ip)
|
||||
, port(port)
|
||||
{
|
||||
}
|
||||
|
||||
// PeerInfo
|
||||
|
||||
PeerInfo::PeerInfo(const libt::peer_info &nativeInfo)
|
||||
: m_nativeInfo(nativeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
bool PeerInfo::fromDHT() const
|
||||
{
|
||||
return (m_nativeInfo.source & libt::peer_info::dht);
|
||||
}
|
||||
|
||||
bool PeerInfo::fromPeX() const
|
||||
{
|
||||
return (m_nativeInfo.source & libt::peer_info::pex);
|
||||
}
|
||||
|
||||
bool PeerInfo::fromLSD() const
|
||||
{
|
||||
return (m_nativeInfo.source & libt::peer_info::lsd);
|
||||
}
|
||||
|
||||
QString PeerInfo::country() const
|
||||
{
|
||||
return QString(QByteArray(m_nativeInfo.country, 2));
|
||||
}
|
||||
|
||||
|
||||
bool PeerInfo::isInteresting() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::interesting);
|
||||
}
|
||||
|
||||
bool PeerInfo::isChocked() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::choked);
|
||||
}
|
||||
|
||||
bool PeerInfo::isRemoteInterested() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::remote_interested);
|
||||
}
|
||||
|
||||
bool PeerInfo::isRemoteChocked() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::remote_choked);
|
||||
}
|
||||
|
||||
|
||||
bool PeerInfo::isSupportsExtensions() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::supports_extensions);
|
||||
}
|
||||
|
||||
bool PeerInfo::isLocalConnection() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::local_connection);
|
||||
}
|
||||
|
||||
bool PeerInfo::isHandshake() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::handshake);
|
||||
}
|
||||
|
||||
|
||||
bool PeerInfo::isConnecting() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::connecting);
|
||||
}
|
||||
|
||||
bool PeerInfo::isQueued() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::queued);
|
||||
}
|
||||
|
||||
|
||||
bool PeerInfo::isOnParole() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::on_parole);
|
||||
}
|
||||
|
||||
bool PeerInfo::isSeed() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::seed);
|
||||
}
|
||||
|
||||
bool PeerInfo::optimisticUnchoke() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::optimistic_unchoke);
|
||||
}
|
||||
|
||||
|
||||
bool PeerInfo::isSnubbed() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::snubbed);
|
||||
}
|
||||
|
||||
bool PeerInfo::isUploadOnly() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::upload_only);
|
||||
}
|
||||
|
||||
bool PeerInfo::isEndgameMode() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::endgame_mode);
|
||||
}
|
||||
|
||||
|
||||
bool PeerInfo::isHolepunched() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::holepunched);
|
||||
}
|
||||
|
||||
bool PeerInfo::useI2PSocket() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::i2p_socket);
|
||||
}
|
||||
|
||||
bool PeerInfo::useUTPSocket() const
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
return (m_nativeInfo.connection_type & libt::peer_info::bittorrent_utp);
|
||||
#else
|
||||
return (m_nativeInfo.flags & libt::peer_info::utp_socket);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PeerInfo::useSSLSocket() const
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
return false;
|
||||
#else
|
||||
return (m_nativeInfo.flags & libt::peer_info::ssl_socket);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PeerInfo::isRC4Encrypted() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::rc4_encrypted);
|
||||
}
|
||||
|
||||
bool PeerInfo::isPlaintextEncrypted() const
|
||||
{
|
||||
return (m_nativeInfo.flags & libt::peer_info::plaintext_encrypted);
|
||||
}
|
||||
|
||||
|
||||
PeerAddress PeerInfo::address() const
|
||||
{
|
||||
return PeerAddress(QHostAddress(QString::fromStdString(m_nativeInfo.ip.address().to_string())),
|
||||
m_nativeInfo.ip.port());
|
||||
}
|
||||
|
||||
QString PeerInfo::client() const
|
||||
{
|
||||
return String::fromStdString(m_nativeInfo.client);
|
||||
}
|
||||
|
||||
|
||||
qreal PeerInfo::progress() const
|
||||
{
|
||||
return m_nativeInfo.progress;
|
||||
}
|
||||
|
||||
int PeerInfo::payloadUpSpeed() const
|
||||
{
|
||||
return m_nativeInfo.payload_up_speed;
|
||||
}
|
||||
|
||||
|
||||
int PeerInfo::payloadDownSpeed() const
|
||||
{
|
||||
return m_nativeInfo.payload_down_speed;
|
||||
}
|
||||
|
||||
qlonglong PeerInfo::totalUpload() const
|
||||
{
|
||||
return m_nativeInfo.total_upload;
|
||||
}
|
||||
|
||||
|
||||
qlonglong PeerInfo::totalDownload() const
|
||||
{
|
||||
return m_nativeInfo.total_download;
|
||||
}
|
||||
|
||||
QBitArray PeerInfo::pieces() const
|
||||
{
|
||||
QBitArray result(m_nativeInfo.pieces.size());
|
||||
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
typedef size_t pieces_size_t;
|
||||
#else
|
||||
typedef int pieces_size_t;
|
||||
#endif
|
||||
for (pieces_size_t i = 0; i < m_nativeInfo.pieces.size(); ++i)
|
||||
result.setBit(i, m_nativeInfo.pieces.get_bit(i));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString PeerInfo::connectionType() const
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
if (m_nativeInfo.connection_type & libt::peer_info::bittorrent_utp)
|
||||
#else
|
||||
if (m_nativeInfo.flags & libt::peer_info::utp_socket)
|
||||
#endif
|
||||
return QString::fromUtf8("μTP");
|
||||
|
||||
QString connection;
|
||||
switch(m_nativeInfo.connection_type) {
|
||||
case libt::peer_info::http_seed:
|
||||
case libt::peer_info::web_seed:
|
||||
connection = "Web";
|
||||
break;
|
||||
default:
|
||||
connection = "BT";
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
99
src/core/bittorrent/peerinfo.h
Normal file
99
src/core/bittorrent/peerinfo.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef BITTORRENT_PEERINFO_H
|
||||
#define BITTORRENT_PEERINFO_H
|
||||
|
||||
#include <libtorrent/peer_info.hpp>
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QBitArray>
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
struct PeerAddress
|
||||
{
|
||||
QHostAddress ip;
|
||||
ushort port;
|
||||
|
||||
PeerAddress();
|
||||
PeerAddress(QHostAddress ip, ushort port);
|
||||
};
|
||||
|
||||
class PeerInfo
|
||||
{
|
||||
public:
|
||||
PeerInfo(const libtorrent::peer_info &nativeInfo);
|
||||
|
||||
bool fromDHT() const;
|
||||
bool fromPeX() const;
|
||||
bool fromLSD() const;
|
||||
|
||||
bool isInteresting() const;
|
||||
bool isChocked() const;
|
||||
bool isRemoteInterested() const;
|
||||
bool isRemoteChocked() const;
|
||||
bool isSupportsExtensions() const;
|
||||
bool isLocalConnection() const;
|
||||
|
||||
bool isHandshake() const;
|
||||
bool isConnecting() const;
|
||||
bool isQueued() const;
|
||||
bool isOnParole() const;
|
||||
bool isSeed() const;
|
||||
|
||||
bool optimisticUnchoke() const;
|
||||
bool isSnubbed() const;
|
||||
bool isUploadOnly() const;
|
||||
bool isEndgameMode() const;
|
||||
bool isHolepunched() const;
|
||||
|
||||
bool useI2PSocket() const;
|
||||
bool useUTPSocket() const;
|
||||
bool useSSLSocket() const;
|
||||
|
||||
bool isRC4Encrypted() const;
|
||||
bool isPlaintextEncrypted() const;
|
||||
|
||||
PeerAddress address() const;
|
||||
QString client() const;
|
||||
qreal progress() const;
|
||||
int payloadUpSpeed() const;
|
||||
int payloadDownSpeed() const;
|
||||
qlonglong totalUpload() const;
|
||||
qlonglong totalDownload() const;
|
||||
QBitArray pieces() const;
|
||||
QString connectionType() const;
|
||||
QString country() const;
|
||||
|
||||
private:
|
||||
libtorrent::peer_info m_nativeInfo;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // BITTORRENT_PEERINFO_H
|
||||
96
src/core/bittorrent/private/bandwidthscheduler.cpp
Normal file
96
src/core/bittorrent/private/bandwidthscheduler.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2010 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include <QTime>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "core/preferences.h"
|
||||
#include "bandwidthscheduler.h"
|
||||
|
||||
BandwidthScheduler::BandwidthScheduler(QObject *parent)
|
||||
: QTimer(parent)
|
||||
{
|
||||
Q_ASSERT(Preferences::instance()->isSchedulerEnabled());
|
||||
// Single shot, we call start() again manually
|
||||
setSingleShot(true);
|
||||
// Connect Signals/Slots
|
||||
connect(this, SIGNAL(timeout()), this, SLOT(start()));
|
||||
}
|
||||
|
||||
void BandwidthScheduler::start()
|
||||
{
|
||||
const Preferences* const pref = Preferences::instance();
|
||||
Q_ASSERT(pref->isSchedulerEnabled());
|
||||
bool alt_bw_enabled = pref->isAltBandwidthEnabled();
|
||||
|
||||
QTime start = pref->getSchedulerStartTime();
|
||||
QTime end = pref->getSchedulerEndTime();
|
||||
QTime now = QTime::currentTime();
|
||||
int sched_days = pref->getSchedulerDays();
|
||||
int day = QDateTime::currentDateTime().toLocalTime().date().dayOfWeek();
|
||||
bool new_mode = false;
|
||||
bool reverse = false;
|
||||
|
||||
if (start > end) {
|
||||
QTime temp = start;
|
||||
start = end;
|
||||
end = temp;
|
||||
reverse = true;
|
||||
}
|
||||
|
||||
if ((start <= now) && (end >= now)) {
|
||||
switch(sched_days) {
|
||||
case EVERY_DAY:
|
||||
new_mode = true;
|
||||
break;
|
||||
case WEEK_ENDS:
|
||||
if ((day == 6) || (day == 7))
|
||||
new_mode = true;
|
||||
break;
|
||||
case WEEK_DAYS:
|
||||
if ((day != 6) && (day != 7))
|
||||
new_mode = true;
|
||||
break;
|
||||
default:
|
||||
if (day == (sched_days - 2))
|
||||
new_mode = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (reverse)
|
||||
new_mode = !new_mode;
|
||||
|
||||
if (new_mode != alt_bw_enabled)
|
||||
emit switchToAlternativeMode(new_mode);
|
||||
|
||||
// Timeout regularly to accomodate for external system clock changes
|
||||
// eg from the user or from a timesync utility
|
||||
QTimer::start(1500);
|
||||
}
|
||||
50
src/core/bittorrent/private/bandwidthscheduler.h
Normal file
50
src/core/bittorrent/private/bandwidthscheduler.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2010 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#ifndef BANDWIDTHSCHEDULER_H
|
||||
#define BANDWIDTHSCHEDULER_H
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
class BandwidthScheduler : public QTimer
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BandwidthScheduler(QObject *parent = 0);
|
||||
|
||||
public slots:
|
||||
void start();
|
||||
|
||||
signals:
|
||||
void switchToAlternativeMode(bool alternative);
|
||||
};
|
||||
|
||||
#endif // BANDWIDTHSCHEDULER_H
|
||||
439
src/core/bittorrent/private/filterparserthread.cpp
Normal file
439
src/core/bittorrent/private/filterparserthread.cpp
Normal file
@@ -0,0 +1,439 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libt.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include <QFile>
|
||||
#include <QHostAddress>
|
||||
#include <QDataStream>
|
||||
#include <QStringList>
|
||||
|
||||
#include <libtorrent/session.hpp>
|
||||
#include <libtorrent/ip_filter.hpp>
|
||||
|
||||
#include "core/logger.h"
|
||||
#include "filterparserthread.h"
|
||||
|
||||
namespace libt = libtorrent;
|
||||
|
||||
FilterParserThread::FilterParserThread(libt::session *s, QObject *parent)
|
||||
: QThread(parent)
|
||||
, m_session(s)
|
||||
, m_abort(false)
|
||||
{
|
||||
}
|
||||
|
||||
FilterParserThread::~FilterParserThread()
|
||||
{
|
||||
m_abort = true;
|
||||
wait();
|
||||
}
|
||||
|
||||
// Parser for eMule ip filter in DAT format
|
||||
int FilterParserThread::parseDATFilterFile(QString m_filePath, libt::ip_filter &filter)
|
||||
{
|
||||
int ruleCount = 0;
|
||||
QFile file(m_filePath);
|
||||
if (!file.exists()) return ruleCount;
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
Logger::instance()->addMessage(tr("I/O Error: Could not open ip filer file in read mode."), Log::CRITICAL);
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
unsigned int nbLine = 0;
|
||||
while (!file.atEnd() && !m_abort) {
|
||||
++nbLine;
|
||||
QByteArray line = file.readLine();
|
||||
// Ignoring empty lines
|
||||
line = line.trimmed();
|
||||
if (line.isEmpty()) continue;
|
||||
// Ignoring commented lines
|
||||
if (line.startsWith('#') || line.startsWith("//")) continue;
|
||||
|
||||
// Line should be splitted by commas
|
||||
QList<QByteArray> partsList = line.split(',');
|
||||
const uint nbElem = partsList.size();
|
||||
|
||||
// IP Range should be splitted by a dash
|
||||
QList<QByteArray> IPs = partsList.first().split('-');
|
||||
if (IPs.size() != 2) {
|
||||
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
|
||||
qDebug("Line was %s", line.constData());
|
||||
continue;
|
||||
}
|
||||
|
||||
boost::system::error_code ec;
|
||||
const QString strStartIP = cleanupIPAddress(IPs.at(0));
|
||||
if (strStartIP.isEmpty()) {
|
||||
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
|
||||
qDebug("Start IP of the range is malformated: %s", qPrintable(strStartIP));
|
||||
continue;
|
||||
}
|
||||
libt::address startAddr = libt::address::from_string(qPrintable(strStartIP), ec);
|
||||
if (ec) {
|
||||
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
|
||||
qDebug("Start IP of the range is malformated: %s", qPrintable(strStartIP));
|
||||
continue;
|
||||
}
|
||||
|
||||
const QString strEndIP = cleanupIPAddress(IPs.at(1));
|
||||
if (strEndIP.isEmpty()) {
|
||||
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
|
||||
qDebug("End IP of the range is malformated: %s", qPrintable(strEndIP));
|
||||
continue;
|
||||
}
|
||||
|
||||
libt::address endAddr = libt::address::from_string(qPrintable(strEndIP), ec);
|
||||
if (ec) {
|
||||
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
|
||||
qDebug("End IP of the range is malformated: %s", qPrintable(strEndIP));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (startAddr.is_v4() != endAddr.is_v4()) {
|
||||
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
|
||||
qDebug("One IP is IPv4 and the other is IPv6!");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if there is an access value (apparently not mandatory)
|
||||
int nbAccess = 0;
|
||||
if (nbElem > 1) {
|
||||
// There is possibly one
|
||||
nbAccess = partsList.at(1).trimmed().toInt();
|
||||
}
|
||||
|
||||
if (nbAccess > 127) {
|
||||
// Ignoring this rule because access value is too high
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now Add to the filter
|
||||
try {
|
||||
filter.add_rule(startAddr, endAddr, libt::ip_filter::blocked);
|
||||
++ruleCount;
|
||||
}
|
||||
catch(std::exception &) {
|
||||
qDebug("Bad line in filter file, avoided crash...");
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
// Parser for PeerGuardian ip filter in p2p format
|
||||
int FilterParserThread::parseP2PFilterFile(QString m_filePath, libt::ip_filter &filter)
|
||||
{
|
||||
int ruleCount = 0;
|
||||
QFile file(m_filePath);
|
||||
if (!file.exists()) return ruleCount;
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
Logger::instance()->addMessage(tr("I/O Error: Could not open ip filer file in read mode."), Log::CRITICAL);
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
unsigned int nbLine = 0;
|
||||
while (!file.atEnd() && !m_abort) {
|
||||
++nbLine;
|
||||
QByteArray line = file.readLine().trimmed();
|
||||
if (line.isEmpty()) continue;
|
||||
// Ignoring commented lines
|
||||
if (line.startsWith('#') || line.startsWith("//")) continue;
|
||||
|
||||
// Line is splitted by :
|
||||
QList<QByteArray> partsList = line.split(':');
|
||||
if (partsList.size() < 2) {
|
||||
qDebug("p2p file: line %d is malformed.", nbLine);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get IP range
|
||||
QList<QByteArray> IPs = partsList.last().split('-');
|
||||
if (IPs.size() != 2) {
|
||||
qDebug("p2p file: line %d is malformed.", nbLine);
|
||||
qDebug("line was: %s", line.constData());
|
||||
continue;
|
||||
}
|
||||
|
||||
boost::system::error_code ec;
|
||||
QString strStartIP = cleanupIPAddress(IPs.at(0));
|
||||
if (strStartIP.isEmpty()) {
|
||||
qDebug("p2p file: line %d is malformed.", nbLine);
|
||||
qDebug("Start IP is invalid: %s", qPrintable(strStartIP));
|
||||
continue;
|
||||
}
|
||||
|
||||
libt::address startAddr = libt::address::from_string(qPrintable(strStartIP), ec);
|
||||
if (ec) {
|
||||
qDebug("p2p file: line %d is malformed.", nbLine);
|
||||
qDebug("Start IP is invalid: %s", qPrintable(strStartIP));
|
||||
continue;
|
||||
}
|
||||
|
||||
QString strEndIP = cleanupIPAddress(IPs.at(1));
|
||||
if (strEndIP.isEmpty()) {
|
||||
qDebug("p2p file: line %d is malformed.", nbLine);
|
||||
qDebug("End IP is invalid: %s", qPrintable(strStartIP));
|
||||
continue;
|
||||
}
|
||||
|
||||
libt::address endAddr = libt::address::from_string(qPrintable(strEndIP), ec);
|
||||
if (ec) {
|
||||
qDebug("p2p file: line %d is malformed.", nbLine);
|
||||
qDebug("End IP is invalid: %s", qPrintable(strStartIP));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (startAddr.is_v4() != endAddr.is_v4()) {
|
||||
qDebug("p2p file: line %d is malformed.", nbLine);
|
||||
qDebug("Line was: %s", line.constData());
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
filter.add_rule(startAddr, endAddr, libt::ip_filter::blocked);
|
||||
++ruleCount;
|
||||
}
|
||||
catch(std::exception &) {
|
||||
qDebug("p2p file: line %d is malformed.", nbLine);
|
||||
qDebug("Line was: %s", line.constData());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
int FilterParserThread::getlineInStream(QDataStream &stream, std::string &name, char delim)
|
||||
{
|
||||
char c;
|
||||
int total_read = 0;
|
||||
int read;
|
||||
do {
|
||||
read = stream.readRawData(&c, 1);
|
||||
total_read += read;
|
||||
if (read > 0) {
|
||||
if (c != delim) {
|
||||
name += c;
|
||||
}
|
||||
else {
|
||||
// Delim found
|
||||
return total_read;
|
||||
}
|
||||
}
|
||||
}
|
||||
while(read > 0);
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
// Parser for PeerGuardian ip filter in p2p format
|
||||
int FilterParserThread::parseP2BFilterFile(QString m_filePath, libt::ip_filter &filter)
|
||||
{
|
||||
int ruleCount = 0;
|
||||
QFile file(m_filePath);
|
||||
if (!file.exists()) return ruleCount;
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
Logger::instance()->addMessage(tr("I/O Error: Could not open ip filer file in read mode."), Log::CRITICAL);
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
QDataStream stream(&file);
|
||||
// Read header
|
||||
char buf[7];
|
||||
unsigned char version;
|
||||
if (!stream.readRawData(buf, sizeof(buf))
|
||||
|| memcmp(buf, "\xFF\xFF\xFF\xFFP2B", 7)
|
||||
|| !stream.readRawData((char*)&version, sizeof(version))) {
|
||||
Logger::instance()->addMessage(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
if ((version == 1) || (version == 2)) {
|
||||
qDebug ("p2b version 1 or 2");
|
||||
unsigned int start, end;
|
||||
|
||||
std::string name;
|
||||
while(getlineInStream(stream, name, '\0') && !m_abort) {
|
||||
if (!stream.readRawData((char*)&start, sizeof(start))
|
||||
|| !stream.readRawData((char*)&end, sizeof(end))) {
|
||||
Logger::instance()->addMessage(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
// Network byte order to Host byte order
|
||||
// asio address_v4 contructor expects it
|
||||
// that way
|
||||
libt::address_v4 first(ntohl(start));
|
||||
libt::address_v4 last(ntohl(end));
|
||||
// Apply to bittorrent session
|
||||
try {
|
||||
filter.add_rule(first, last, libt::ip_filter::blocked);
|
||||
++ruleCount;
|
||||
}
|
||||
catch(std::exception &) {}
|
||||
}
|
||||
}
|
||||
else if (version == 3) {
|
||||
qDebug ("p2b version 3");
|
||||
unsigned int namecount;
|
||||
if (!stream.readRawData((char*)&namecount, sizeof(namecount))) {
|
||||
Logger::instance()->addMessage(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
namecount = ntohl(namecount);
|
||||
// Reading names although, we don't really care about them
|
||||
for (unsigned int i = 0; i < namecount; ++i) {
|
||||
std::string name;
|
||||
if (!getlineInStream(stream, name, '\0')) {
|
||||
Logger::instance()->addMessage(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
if (m_abort) return ruleCount;
|
||||
}
|
||||
|
||||
// Reading the ranges
|
||||
unsigned int rangecount;
|
||||
if (!stream.readRawData((char*)&rangecount, sizeof(rangecount))) {
|
||||
Logger::instance()->addMessage(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
rangecount = ntohl(rangecount);
|
||||
unsigned int name, start, end;
|
||||
for (unsigned int i = 0; i < rangecount; ++i) {
|
||||
if (!stream.readRawData((char*)&name, sizeof(name))
|
||||
|| !stream.readRawData((char*)&start, sizeof(start))
|
||||
|| !stream.readRawData((char*)&end, sizeof(end))) {
|
||||
Logger::instance()->addMessage(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
// Network byte order to Host byte order
|
||||
// asio address_v4 contructor expects it
|
||||
// that way
|
||||
libt::address_v4 first(ntohl(start));
|
||||
libt::address_v4 last(ntohl(end));
|
||||
// Apply to bittorrent session
|
||||
try {
|
||||
filter.add_rule(first, last, libt::ip_filter::blocked);
|
||||
++ruleCount;
|
||||
}
|
||||
catch(std::exception &) {}
|
||||
|
||||
if (m_abort) return ruleCount;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Logger::instance()->addMessage(tr("Parsing Error: The filter file is not a valid PeerGuardian P2B file."), Log::CRITICAL);
|
||||
}
|
||||
|
||||
file.close();
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
// Process ip filter file
|
||||
// Supported formats:
|
||||
// * eMule IP list (DAT): http://wiki.phoenixlabs.org/wiki/DAT_Format
|
||||
// * PeerGuardian Text (P2P): http://wiki.phoenixlabs.org/wiki/P2P_Format
|
||||
// * PeerGuardian Binary (P2B): http://wiki.phoenixlabs.org/wiki/P2B_Format
|
||||
void FilterParserThread::processFilterFile(QString _filePath)
|
||||
{
|
||||
if (isRunning()) {
|
||||
// Already parsing a filter, m_abort first
|
||||
m_abort = true;
|
||||
wait();
|
||||
}
|
||||
|
||||
m_abort = false;
|
||||
m_filePath = _filePath;
|
||||
// Run it
|
||||
start();
|
||||
}
|
||||
|
||||
void FilterParserThread::processFilterList(libt::session *s, const QStringList &IPs)
|
||||
{
|
||||
// First, import current filter
|
||||
libt::ip_filter filter = s->get_ip_filter();
|
||||
foreach (const QString &ip, IPs) {
|
||||
qDebug("Manual ban of peer %s", ip.toLocal8Bit().constData());
|
||||
boost::system::error_code ec;
|
||||
libt::address addr = libt::address::from_string(ip.toLocal8Bit().constData(), ec);
|
||||
Q_ASSERT(!ec);
|
||||
if (!ec)
|
||||
filter.add_rule(addr, addr, libt::ip_filter::blocked);
|
||||
}
|
||||
|
||||
s->set_ip_filter(filter);
|
||||
}
|
||||
|
||||
QString FilterParserThread::cleanupIPAddress(QString _ip)
|
||||
{
|
||||
QHostAddress ip(_ip.trimmed());
|
||||
if (ip.isNull()) return QString();
|
||||
|
||||
return ip.toString();
|
||||
}
|
||||
|
||||
void FilterParserThread::run()
|
||||
{
|
||||
qDebug("Processing filter file");
|
||||
libt::ip_filter filter = m_session->get_ip_filter();
|
||||
int ruleCount = 0;
|
||||
if (m_filePath.endsWith(".p2p", Qt::CaseInsensitive)) {
|
||||
// PeerGuardian p2p file
|
||||
ruleCount = parseP2PFilterFile(m_filePath, filter);
|
||||
}
|
||||
else if (m_filePath.endsWith(".p2b", Qt::CaseInsensitive)) {
|
||||
// PeerGuardian p2b file
|
||||
ruleCount = parseP2BFilterFile(m_filePath, filter);
|
||||
}
|
||||
else if (m_filePath.endsWith(".dat", Qt::CaseInsensitive)) {
|
||||
// eMule DAT format
|
||||
ruleCount = parseDATFilterFile(m_filePath, filter);
|
||||
}
|
||||
|
||||
if (m_abort) return;
|
||||
|
||||
try {
|
||||
m_session->set_ip_filter(filter);
|
||||
emit IPFilterParsed(ruleCount);
|
||||
}
|
||||
catch(std::exception &) {
|
||||
emit IPFilterError();
|
||||
}
|
||||
|
||||
qDebug("IP Filter thread: finished parsing, filter applied");
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -32,38 +32,30 @@
|
||||
#define FILTERPARSERTHREAD_H
|
||||
|
||||
#include <QThread>
|
||||
#include <QDataStream>
|
||||
#include <QStringList>
|
||||
|
||||
namespace libtorrent {
|
||||
class session;
|
||||
struct ip_filter;
|
||||
class QDataStream;
|
||||
class QStringList;
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
class session;
|
||||
struct ip_filter;
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
// P2B Stuff
|
||||
#include <string.h>
|
||||
#ifdef Q_OS_WIN
|
||||
#include <Winsock2.h>
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
// End of P2B stuff
|
||||
|
||||
class FilterParserThread : public QThread {
|
||||
class FilterParserThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FilterParserThread(QObject* parent, libtorrent::session *s);
|
||||
FilterParserThread(libtorrent::session *s, QObject *parent = 0);
|
||||
~FilterParserThread();
|
||||
|
||||
int parseDATFilterFile(QString filePath, libtorrent::ip_filter& filter);
|
||||
int parseP2PFilterFile(QString filePath, libtorrent::ip_filter& filter);
|
||||
int getlineInStream(QDataStream& stream, string& name, char delim);
|
||||
int parseP2BFilterFile(QString filePath, libtorrent::ip_filter& filter);
|
||||
int parseDATFilterFile(QString filePath, libtorrent::ip_filter &filter);
|
||||
int parseP2PFilterFile(QString filePath, libtorrent::ip_filter &filter);
|
||||
int getlineInStream(QDataStream &stream, std::string &name, char delim);
|
||||
int parseP2BFilterFile(QString filePath, libtorrent::ip_filter &filter);
|
||||
void processFilterFile(QString _filePath);
|
||||
static void processFilterList(libtorrent::session *s, const QStringList& IPs);
|
||||
static void processFilterList(libtorrent::session *s, const QStringList &IPs);
|
||||
|
||||
signals:
|
||||
void IPFilterParsed(int ruleCount);
|
||||
@@ -74,9 +66,9 @@ protected:
|
||||
void run();
|
||||
|
||||
private:
|
||||
libtorrent::session *s;
|
||||
bool abort;
|
||||
QString filePath;
|
||||
libtorrent::session *m_session;
|
||||
bool m_abort;
|
||||
QString m_filePath;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // BITTORRENT_FILTERPARSERTHREAD_H
|
||||
83
src/core/bittorrent/private/sessionprivate.h
Normal file
83
src/core/bittorrent/private/sessionprivate.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef SESSIONPRIVATE_H
|
||||
#define SESSIONPRIVATE_H
|
||||
|
||||
class QString;
|
||||
class QUrl;
|
||||
template<typename T> class QList;
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
class entry;
|
||||
}
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class TorrentHandle;
|
||||
class TrackerEntry;
|
||||
}
|
||||
|
||||
struct SessionPrivate
|
||||
{
|
||||
virtual bool isQueueingEnabled() const = 0;
|
||||
virtual bool isTempPathEnabled() const = 0;
|
||||
virtual bool isAppendExtensionEnabled() const = 0;
|
||||
virtual bool useAppendLabelToSavePath() const = 0;
|
||||
#ifndef DISABLE_COUNTRIES_RESOLUTION
|
||||
virtual bool isResolveCountriesEnabled() const = 0;
|
||||
#endif
|
||||
virtual QString defaultSavePath() const = 0;
|
||||
virtual QString tempPath() const = 0;
|
||||
virtual qreal globalMaxRatio() const = 0;
|
||||
|
||||
virtual void handleTorrentRatioLimitChanged(BitTorrent::TorrentHandle *const torrent) = 0;
|
||||
virtual void handleTorrentSavePathChanged(BitTorrent::TorrentHandle *const torrent) = 0;
|
||||
virtual void handleTorrentMetadataReceived(BitTorrent::TorrentHandle *const torrent) = 0;
|
||||
virtual void handleTorrentPaused(BitTorrent::TorrentHandle *const torrent) = 0;
|
||||
virtual void handleTorrentResumed(BitTorrent::TorrentHandle *const torrent) = 0;
|
||||
virtual void handleTorrentChecked(BitTorrent::TorrentHandle *const torrent) = 0;
|
||||
virtual void handleTorrentFinished(BitTorrent::TorrentHandle *const torrent) = 0;
|
||||
virtual void handleTorrentTrackersAdded(BitTorrent::TorrentHandle *const torrent, const QList<BitTorrent::TrackerEntry> &newTrackers) = 0;
|
||||
virtual void handleTorrentTrackersRemoved(BitTorrent::TorrentHandle *const torrent, const QList<BitTorrent::TrackerEntry> &deletedTrackers) = 0;
|
||||
virtual void handleTorrentTrackersChanged(BitTorrent::TorrentHandle *const torrent) = 0;
|
||||
virtual void handleTorrentUrlSeedsAdded(BitTorrent::TorrentHandle *const torrent, const QList<QUrl> &newUrlSeeds) = 0;
|
||||
virtual void handleTorrentUrlSeedsRemoved(BitTorrent::TorrentHandle *const torrent, const QList<QUrl> &urlSeeds) = 0;
|
||||
virtual void handleTorrentResumeDataReady(BitTorrent::TorrentHandle *const torrent, const libtorrent::entry &data) = 0;
|
||||
virtual void handleTorrentResumeDataFailed(BitTorrent::TorrentHandle *const torrent) = 0;
|
||||
virtual void handleTorrentTrackerReply(BitTorrent::TorrentHandle *const torrent, const QString &trackerUrl) = 0;
|
||||
virtual void handleTorrentTrackerWarning(BitTorrent::TorrentHandle *const torrent, const QString &trackerUrl) = 0;
|
||||
virtual void handleTorrentTrackerError(BitTorrent::TorrentHandle *const torrent, const QString &trackerUrl) = 0;
|
||||
virtual void handleTorrentTrackerAuthenticationRequired(BitTorrent::TorrentHandle *const torrent, const QString &trackerUrl) = 0;
|
||||
|
||||
protected:
|
||||
~SessionPrivate() {}
|
||||
};
|
||||
|
||||
#endif // SESSIONPRIVATE_H
|
||||
56
src/core/bittorrent/private/speedmonitor.cpp
Normal file
56
src/core/bittorrent/private/speedmonitor.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2011 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include <QList>
|
||||
#include "speedmonitor.h"
|
||||
|
||||
void SpeedMonitor::addSample(const SpeedSample &sample)
|
||||
{
|
||||
m_speedSamples.push_back(sample);
|
||||
m_sum += sample;
|
||||
if (m_speedSamples.size() > MAX_SAMPLES) {
|
||||
m_sum -= m_speedSamples.front();
|
||||
m_speedSamples.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
SpeedSampleAvg SpeedMonitor::average() const
|
||||
{
|
||||
if (m_speedSamples.empty())
|
||||
return SpeedSampleAvg();
|
||||
|
||||
qreal k = qreal(1.) / m_speedSamples.size();
|
||||
return SpeedSampleAvg(m_sum.download * k, m_sum.upload * k);
|
||||
}
|
||||
|
||||
void SpeedMonitor::reset()
|
||||
{
|
||||
m_sum = SpeedSample();
|
||||
m_speedSamples.clear();
|
||||
}
|
||||
84
src/core/bittorrent/private/speedmonitor.h
Normal file
84
src/core/bittorrent/private/speedmonitor.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2011 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef SPEEDMONITOR_H
|
||||
#define SPEEDMONITOR_H
|
||||
|
||||
template<typename T> class QList;
|
||||
|
||||
template<typename T>
|
||||
struct Sample
|
||||
{
|
||||
Sample()
|
||||
: download()
|
||||
, upload()
|
||||
{
|
||||
}
|
||||
|
||||
Sample(T dl, T ul)
|
||||
: download(dl)
|
||||
, upload(ul)
|
||||
{
|
||||
}
|
||||
|
||||
Sample<T> &operator+=(const Sample<T> &other)
|
||||
{
|
||||
download += other.download;
|
||||
upload += other.upload;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Sample<T> &operator-=(const Sample<T> &other)
|
||||
{
|
||||
download -= other.download;
|
||||
upload -= other.upload;
|
||||
return *this;
|
||||
}
|
||||
|
||||
T download;
|
||||
T upload;
|
||||
};
|
||||
|
||||
typedef Sample<qlonglong> SpeedSample;
|
||||
typedef Sample<qreal> SpeedSampleAvg;
|
||||
|
||||
class SpeedMonitor
|
||||
{
|
||||
public:
|
||||
void addSample(const SpeedSample &sample);
|
||||
SpeedSampleAvg average() const;
|
||||
void reset();
|
||||
|
||||
private:
|
||||
static const int MAX_SAMPLES = 30;
|
||||
QList<SpeedSample> m_speedSamples;
|
||||
SpeedSample m_sum;
|
||||
};
|
||||
|
||||
#endif // SPEEDMONITOR_H
|
||||
115
src/core/bittorrent/private/statistics.cpp
Normal file
115
src/core/bittorrent/private/statistics.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
#include <QDateTime>
|
||||
|
||||
#include <libtorrent/session.hpp>
|
||||
|
||||
#include "core/qinisettings.h"
|
||||
#include "core/preferences.h"
|
||||
#include "core/bittorrent/sessionstatus.h"
|
||||
#include "core/bittorrent/session.h"
|
||||
#include "statistics.h"
|
||||
|
||||
static const qint64 SAVE_INTERVAL = 15 * 60 * 1000;
|
||||
|
||||
namespace libt = libtorrent;
|
||||
using namespace BitTorrent;
|
||||
|
||||
Statistics::Statistics(Session *session)
|
||||
: QObject(session)
|
||||
, m_session(session)
|
||||
, m_sessionUL(0)
|
||||
, m_sessionDL(0)
|
||||
, m_lastWrite(0)
|
||||
, m_dirty(false)
|
||||
{
|
||||
load();
|
||||
connect(&m_timer, SIGNAL(timeout()), this, SLOT(gather()));
|
||||
m_timer.start(60 * 1000);
|
||||
}
|
||||
|
||||
Statistics::~Statistics()
|
||||
{
|
||||
if (m_dirty)
|
||||
m_lastWrite = 0;
|
||||
save();
|
||||
}
|
||||
|
||||
quint64 Statistics::getAlltimeDL() const
|
||||
{
|
||||
return m_alltimeDL + m_sessionDL;
|
||||
}
|
||||
|
||||
quint64 Statistics::getAlltimeUL() const
|
||||
{
|
||||
return m_alltimeUL + m_sessionUL;
|
||||
}
|
||||
|
||||
void Statistics::gather()
|
||||
{
|
||||
SessionStatus ss = m_session->status();
|
||||
if (ss.totalDownload() > m_sessionDL) {
|
||||
m_sessionDL = ss.totalDownload();
|
||||
m_dirty = true;
|
||||
}
|
||||
if (ss.totalUpload() > m_sessionUL) {
|
||||
m_sessionUL = ss.totalUpload();
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
save();
|
||||
}
|
||||
|
||||
void Statistics::save() const
|
||||
{
|
||||
qint64 now = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
if (!m_dirty || ((now - m_lastWrite) < SAVE_INTERVAL))
|
||||
return;
|
||||
|
||||
QIniSettings s("qBittorrent", "qBittorrent-data");
|
||||
QVariantHash v;
|
||||
v.insert("AlltimeDL", m_alltimeDL + m_sessionDL);
|
||||
v.insert("AlltimeUL", m_alltimeUL + m_sessionUL);
|
||||
s.setValue("Stats/AllStats", v);
|
||||
m_dirty = false;
|
||||
m_lastWrite = now;
|
||||
}
|
||||
|
||||
void Statistics::load()
|
||||
{
|
||||
// Temp code. Versions v3.1.4 and v3.1.5 saved the data in the qbittorrent.ini file.
|
||||
// This code reads the data from there, writes it to the new file, and removes the keys
|
||||
// from the old file. This code should be removed after some time has passed.
|
||||
// e.g. When we reach v3.3.0
|
||||
// Don't forget to remove:
|
||||
// 1. Preferences::getStats()
|
||||
// 2. Preferences::removeStats()
|
||||
// 3. #include "core/preferences.h"
|
||||
Preferences* const pref = Preferences::instance();
|
||||
QIniSettings s("qBittorrent", "qBittorrent-data");
|
||||
QVariantHash v = pref->getStats();
|
||||
|
||||
// Let's test if the qbittorrent.ini holds the key
|
||||
if (!v.isEmpty()) {
|
||||
m_dirty = true;
|
||||
|
||||
// If the user has used qbt > 3.1.5 and then reinstalled/used
|
||||
// qbt < 3.1.6, there will be stats in qbittorrent-data.ini too
|
||||
// so we need to merge those 2.
|
||||
if (s.contains("Stats/AllStats")) {
|
||||
QVariantHash tmp = s.value("Stats/AllStats").toHash();
|
||||
v["AlltimeDL"] = v["AlltimeDL"].toULongLong() + tmp["AlltimeDL"].toULongLong();
|
||||
v["AlltimeUL"] = v["AlltimeUL"].toULongLong() + tmp["AlltimeUL"].toULongLong();
|
||||
}
|
||||
}
|
||||
else {
|
||||
v = s.value("Stats/AllStats").toHash();
|
||||
}
|
||||
|
||||
m_alltimeDL = v["AlltimeDL"].toULongLong();
|
||||
m_alltimeUL = v["AlltimeUL"].toULongLong();
|
||||
|
||||
if (m_dirty) {
|
||||
save();
|
||||
pref->removeStats();
|
||||
}
|
||||
}
|
||||
41
src/core/bittorrent/private/statistics.h
Normal file
41
src/core/bittorrent/private/statistics.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef STATISTICS_H
|
||||
#define STATISTICS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
namespace BitTorrent { class Session; }
|
||||
|
||||
class Statistics : QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Statistics)
|
||||
|
||||
public:
|
||||
Statistics(BitTorrent::Session *session);
|
||||
~Statistics();
|
||||
|
||||
quint64 getAlltimeDL() const;
|
||||
quint64 getAlltimeUL() const;
|
||||
|
||||
private slots:
|
||||
void gather();
|
||||
|
||||
private:
|
||||
void save() const;
|
||||
void load();
|
||||
|
||||
private:
|
||||
BitTorrent::Session *m_session;
|
||||
// Will overflow at 15.9 EiB
|
||||
quint64 m_alltimeUL;
|
||||
quint64 m_alltimeDL;
|
||||
qint64 m_sessionUL;
|
||||
qint64 m_sessionDL;
|
||||
mutable qint64 m_lastWrite;
|
||||
mutable bool m_dirty;
|
||||
|
||||
QTimer m_timer;
|
||||
};
|
||||
|
||||
#endif // STATISTICS_H
|
||||
53
src/core/bittorrent/private/torrenthandleprivate.h
Normal file
53
src/core/bittorrent/private/torrenthandleprivate.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef TORRENTHANDLEPRIVATE_H
|
||||
#define TORRENTHANDLEPRIVATE_H
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
class alert;
|
||||
struct torrent_status;
|
||||
}
|
||||
|
||||
struct TorrentHandlePrivate
|
||||
{
|
||||
virtual void handleAlert(libtorrent::alert *) = 0;
|
||||
virtual void handleStateUpdate(const libtorrent::torrent_status &) = 0;
|
||||
virtual void handleDefaultSavePathChanged() = 0;
|
||||
virtual void handleTempPathChanged() = 0;
|
||||
virtual void handleAppendExtensionToggled() = 0;
|
||||
#ifndef DISABLE_COUNTRIES_RESOLUTION
|
||||
virtual void handleResolveCountriesToggled() = 0;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
~TorrentHandlePrivate() {}
|
||||
};
|
||||
|
||||
#endif // TORRENTHANDLEPRIVATE_H
|
||||
2440
src/core/bittorrent/session.cpp
Normal file
2440
src/core/bittorrent/session.cpp
Normal file
File diff suppressed because it is too large
Load Diff
365
src/core/bittorrent/session.h
Normal file
365
src/core/bittorrent/session.h
Normal file
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef BITTORRENT_SESSION_H
|
||||
#define BITTORRENT_SESSION_H
|
||||
|
||||
#include <QFile>
|
||||
#include <QHash>
|
||||
#include <QPointer>
|
||||
#include <QVector>
|
||||
#include <QMutex>
|
||||
#include <QWaitCondition>
|
||||
|
||||
#include "core/tristatebool.h"
|
||||
#include "core/types.h"
|
||||
#include "private/sessionprivate.h"
|
||||
#include "torrentinfo.h"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
class session;
|
||||
struct add_torrent_params;
|
||||
struct pe_settings;
|
||||
struct proxy_settings;
|
||||
struct session_settings;
|
||||
struct session_status;
|
||||
|
||||
class alert;
|
||||
struct torrent_alert;
|
||||
struct state_update_alert;
|
||||
struct stats_alert;
|
||||
struct add_torrent_alert;
|
||||
struct torrent_checked_alert;
|
||||
struct torrent_finished_alert;
|
||||
struct torrent_removed_alert;
|
||||
struct torrent_deleted_alert;
|
||||
struct torrent_paused_alert;
|
||||
struct torrent_resumed_alert;
|
||||
struct save_resume_data_alert;
|
||||
struct save_resume_data_failed_alert;
|
||||
struct file_renamed_alert;
|
||||
struct storage_moved_alert;
|
||||
struct storage_moved_failed_alert;
|
||||
struct metadata_received_alert;
|
||||
struct file_error_alert;
|
||||
struct file_completed_alert;
|
||||
struct tracker_error_alert;
|
||||
struct tracker_reply_alert;
|
||||
struct tracker_warning_alert;
|
||||
struct portmap_error_alert;
|
||||
struct portmap_alert;
|
||||
struct peer_blocked_alert;
|
||||
struct peer_ban_alert;
|
||||
struct fastresume_rejected_alert;
|
||||
struct url_seed_alert;
|
||||
struct listen_succeeded_alert;
|
||||
struct listen_failed_alert;
|
||||
struct external_ip_alert;
|
||||
}
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QTimer;
|
||||
class QStringList;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class FilterParserThread;
|
||||
class BandwidthScheduler;
|
||||
class Statistics;
|
||||
|
||||
typedef QPair<QString, QString> QStringPair;
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class InfoHash;
|
||||
class CacheStatus;
|
||||
class SessionStatus;
|
||||
class TorrentHandle;
|
||||
class Tracker;
|
||||
class MagnetUri;
|
||||
class TrackerEntry;
|
||||
struct AddTorrentData;
|
||||
|
||||
struct AddTorrentParams
|
||||
{
|
||||
QString name;
|
||||
QString label;
|
||||
QString savePath;
|
||||
bool disableTempPath; // e.g. for imported torrents
|
||||
bool sequential;
|
||||
TriStateBool addPaused;
|
||||
QVector<int> filePriorities; // used if TorrentInfo is set
|
||||
bool ignoreShareRatio;
|
||||
bool skipChecking;
|
||||
|
||||
AddTorrentParams();
|
||||
};
|
||||
|
||||
struct TorrentStatusReport
|
||||
{
|
||||
uint nbDownloading;
|
||||
uint nbSeeding;
|
||||
uint nbCompleted;
|
||||
uint nbActive;
|
||||
uint nbInactive;
|
||||
uint nbPaused;
|
||||
uint nbResumed;
|
||||
|
||||
TorrentStatusReport();
|
||||
};
|
||||
|
||||
class Session : public QObject, public SessionPrivate
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Session)
|
||||
|
||||
public:
|
||||
static void initInstance();
|
||||
static void freeInstance();
|
||||
static Session *instance();
|
||||
|
||||
bool isDHTEnabled() const;
|
||||
bool isLSDEnabled() const;
|
||||
bool isPexEnabled() const;
|
||||
bool isQueueingEnabled() const;
|
||||
qreal globalMaxRatio() const;
|
||||
|
||||
TorrentHandle *findTorrent(const InfoHash &hash) const;
|
||||
QHash<InfoHash, TorrentHandle *> torrents() const;
|
||||
bool hasActiveTorrents() const;
|
||||
bool hasUnfinishedTorrents() const;
|
||||
SessionStatus status() const;
|
||||
CacheStatus cacheStatus() const;
|
||||
quint64 getAlltimeDL() const;
|
||||
quint64 getAlltimeUL() const;
|
||||
int downloadRateLimit() const;
|
||||
int uploadRateLimit() const;
|
||||
bool isListening() const;
|
||||
|
||||
void changeSpeedLimitMode(bool alternative);
|
||||
void setDownloadRateLimit(int rate);
|
||||
void setUploadRateLimit(int rate);
|
||||
void setGlobalMaxRatio(qreal ratio);
|
||||
void enableIPFilter(const QString &filterPath, bool force = false);
|
||||
void disableIPFilter();
|
||||
void banIP(const QString &ip);
|
||||
|
||||
bool isKnownTorrent(const InfoHash &hash) const;
|
||||
bool addTorrent(QString source, const AddTorrentParams ¶ms = AddTorrentParams());
|
||||
bool addTorrent(const TorrentInfo &torrentInfo, const AddTorrentParams ¶ms = AddTorrentParams());
|
||||
bool deleteTorrent(const QString &hash, bool deleteLocalFiles = false);
|
||||
bool loadMetadata(const QString &magnetUri);
|
||||
bool cancelLoadMetadata(const InfoHash &hash);
|
||||
|
||||
void recursiveTorrentDownload(const InfoHash &hash);
|
||||
void increaseTorrentsPriority(const QStringList &hashes);
|
||||
void decreaseTorrentsPriority(const QStringList &hashes);
|
||||
void topTorrentsPriority(const QStringList &hashes);
|
||||
void bottomTorrentsPriority(const QStringList &hashes);
|
||||
|
||||
signals:
|
||||
void torrentsUpdated(const BitTorrent::TorrentStatusReport &torrentStatusReport = BitTorrent::TorrentStatusReport());
|
||||
void addTorrentFailed(const QString &error);
|
||||
void torrentAdded(BitTorrent::TorrentHandle *const torrent);
|
||||
void torrentAboutToBeRemoved(BitTorrent::TorrentHandle *const torrent);
|
||||
void torrentStatusUpdated(BitTorrent::TorrentHandle *const torrent);
|
||||
void torrentPaused(BitTorrent::TorrentHandle *const torrent);
|
||||
void torrentResumed(BitTorrent::TorrentHandle *const torrent);
|
||||
void torrentFinished(BitTorrent::TorrentHandle *const torrent);
|
||||
void torrentFinishedChecking(BitTorrent::TorrentHandle *const torrent);
|
||||
void torrentSavePathChanged(BitTorrent::TorrentHandle *const torrent);
|
||||
void allTorrentsFinished();
|
||||
void metadataLoaded(const BitTorrent::TorrentInfo &info);
|
||||
void torrentMetadataLoaded(BitTorrent::TorrentHandle *const torrent);
|
||||
void fullDiskError(BitTorrent::TorrentHandle *const torrent, const QString &msg);
|
||||
void trackerSuccess(BitTorrent::TorrentHandle *const torrent, const QString &tracker);
|
||||
void trackerWarning(BitTorrent::TorrentHandle *const torrent, const QString &tracker);
|
||||
void trackerError(BitTorrent::TorrentHandle *const torrent, const QString &tracker);
|
||||
void trackerAuthenticationRequired(BitTorrent::TorrentHandle *const torrent);
|
||||
void recursiveTorrentDownloadPossible(BitTorrent::TorrentHandle *const torrent);
|
||||
void speedLimitModeChanged(bool alternative);
|
||||
void ipFilterParsed(bool error, int ruleCount);
|
||||
void trackersAdded(BitTorrent::TorrentHandle *const torrent, const QList<BitTorrent::TrackerEntry> &trackers);
|
||||
void trackersRemoved(BitTorrent::TorrentHandle *const torrent, const QList<BitTorrent::TrackerEntry> &trackers);
|
||||
void trackersChanged(BitTorrent::TorrentHandle *const torrent);
|
||||
void trackerlessStateChanged(BitTorrent::TorrentHandle *const torrent, bool trackerless);
|
||||
void downloadFromUrlFailed(const QString &url, const QString &reason);
|
||||
void downloadFromUrlFinished(const QString &url);
|
||||
|
||||
private slots:
|
||||
void configure();
|
||||
void readAlerts();
|
||||
void refresh();
|
||||
void processBigRatios();
|
||||
void generateResumeData(bool final = false);
|
||||
void handleIPFilterParsed(int ruleCount);
|
||||
void handleIPFilterError();
|
||||
void handleDownloadFinished(const QString &url, const QString &filePath);
|
||||
void handleDownloadFailed(const QString &url, const QString &reason);
|
||||
void handleRedirectedToMagnet(const QString &url, const QString &magnetUri);
|
||||
|
||||
private:
|
||||
explicit Session(QObject *parent = 0);
|
||||
~Session();
|
||||
|
||||
bool hasPerTorrentRatioLimit() const;
|
||||
|
||||
void initResumeFolder();
|
||||
void loadState();
|
||||
void saveState();
|
||||
|
||||
// Session configuration
|
||||
void setSessionSettings();
|
||||
void setProxySettings(libtorrent::proxy_settings proxySettings);
|
||||
void adjustLimits();
|
||||
void adjustLimits(libtorrent::session_settings &sessionSettings);
|
||||
void setListeningPort(int port);
|
||||
void setDefaultSavePath(const QString &path);
|
||||
void setDefaultTempPath(const QString &path = QString());
|
||||
void preAllocateAllFiles(bool b);
|
||||
void setMaxConnectionsPerTorrent(int max);
|
||||
void setMaxUploadsPerTorrent(int max);
|
||||
void enableLSD(bool enable);
|
||||
void enableDHT(bool enable);
|
||||
|
||||
void setAppendLabelToSavePath(bool append);
|
||||
void setAppendExtension(bool append);
|
||||
|
||||
void startUpTorrents();
|
||||
bool addTorrent_impl(const AddTorrentData &addData, const MagnetUri &magnetUri,
|
||||
const TorrentInfo &torrentInfo = TorrentInfo(),
|
||||
const QByteArray &fastresumeData = QByteArray());
|
||||
|
||||
void updateRatioTimer();
|
||||
void exportTorrentFile(TorrentHandle *const torrent, TorrentExportFolder folder = TorrentExportFolder::Regular);
|
||||
void exportTorrentFiles(QString path);
|
||||
void saveTorrentResumeData(TorrentHandle *const torrent);
|
||||
|
||||
void handleAlert(libtorrent::alert *a);
|
||||
void dispatchTorrentAlert(libtorrent::alert *a);
|
||||
void handleAddTorrentAlert(libtorrent::add_torrent_alert *p);
|
||||
void handleStateUpdateAlert(libtorrent::state_update_alert *p);
|
||||
void handleMetadataReceivedAlert(libtorrent::metadata_received_alert *p);
|
||||
void handleFileErrorAlert(libtorrent::file_error_alert *p);
|
||||
void handleTorrentRemovedAlert(libtorrent::torrent_removed_alert *p);
|
||||
void handleTorrentDeletedAlert(libtorrent::torrent_deleted_alert *p);
|
||||
void handlePortmapWarningAlert(libtorrent::portmap_error_alert *p);
|
||||
void handlePortmapAlert(libtorrent::portmap_alert *p);
|
||||
void handlePeerBlockedAlert(libtorrent::peer_blocked_alert *p);
|
||||
void handlePeerBanAlert(libtorrent::peer_ban_alert *p);
|
||||
void handleUrlSeedAlert(libtorrent::url_seed_alert *p);
|
||||
void handleListenSucceededAlert(libtorrent::listen_succeeded_alert *p);
|
||||
void handleListenFailedAlert(libtorrent::listen_failed_alert *p);
|
||||
void handleExternalIPAlert(libtorrent::external_ip_alert *p);
|
||||
|
||||
bool isTempPathEnabled() const;
|
||||
bool isAppendExtensionEnabled() const;
|
||||
bool useAppendLabelToSavePath() const;
|
||||
#ifndef DISABLE_COUNTRIES_RESOLUTION
|
||||
bool isResolveCountriesEnabled() const;
|
||||
#endif
|
||||
QString defaultSavePath() const;
|
||||
QString tempPath() const;
|
||||
void handleTorrentRatioLimitChanged(TorrentHandle *const torrent);
|
||||
void handleTorrentSavePathChanged(TorrentHandle *const torrent);
|
||||
void handleTorrentMetadataReceived(TorrentHandle *const torrent);
|
||||
void handleTorrentPaused(TorrentHandle *const torrent);
|
||||
void handleTorrentResumed(TorrentHandle *const torrent);
|
||||
void handleTorrentChecked(TorrentHandle *const torrent);
|
||||
void handleTorrentFinished(TorrentHandle *const torrent);
|
||||
void handleTorrentTrackersAdded(TorrentHandle *const torrent, const QList<TrackerEntry> &newTrackers);
|
||||
void handleTorrentTrackersRemoved(TorrentHandle *const torrent, const QList<TrackerEntry> &deletedTrackers);
|
||||
void handleTorrentTrackersChanged(TorrentHandle *const torrent);
|
||||
void handleTorrentUrlSeedsAdded(TorrentHandle *const torrent, const QList<QUrl> &newUrlSeeds);
|
||||
void handleTorrentUrlSeedsRemoved(TorrentHandle *const torrent, const QList<QUrl> &urlSeeds);
|
||||
void handleTorrentResumeDataReady(TorrentHandle *const torrent, const libtorrent::entry &data);
|
||||
void handleTorrentResumeDataFailed(TorrentHandle *const torrent);
|
||||
void handleTorrentTrackerReply(TorrentHandle *const torrent, const QString &trackerUrl);
|
||||
void handleTorrentTrackerWarning(TorrentHandle *const torrent, const QString &trackerUrl);
|
||||
void handleTorrentTrackerError(TorrentHandle *const torrent, const QString &trackerUrl);
|
||||
void handleTorrentTrackerAuthenticationRequired(TorrentHandle *const torrent, const QString &trackerUrl);
|
||||
|
||||
void saveResumeData();
|
||||
bool writeResumeDataFile(TorrentHandle *const torrent, const libtorrent::entry &data);
|
||||
|
||||
void dispatchAlerts(std::auto_ptr<libtorrent::alert> alertPtr);
|
||||
void getPendingAlerts(QVector<libtorrent::alert *> &out, ulong time = 0);
|
||||
|
||||
// BitTorrent
|
||||
libtorrent::session *m_nativeSession;
|
||||
|
||||
bool m_LSDEnabled;
|
||||
bool m_DHTEnabled;
|
||||
bool m_PeXEnabled;
|
||||
bool m_queueingEnabled;
|
||||
bool m_torrentExportEnabled;
|
||||
bool m_finishedTorrentExportEnabled;
|
||||
bool m_preAllocateAll;
|
||||
qreal m_globalMaxRatio;
|
||||
int m_numResumeData;
|
||||
int m_extraLimit;
|
||||
#ifndef DISABLE_COUNTRIES_RESOLUTION
|
||||
bool m_geoipDBLoaded;
|
||||
bool m_resolveCountries;
|
||||
#endif
|
||||
bool m_appendLabelToSavePath;
|
||||
bool m_appendExtension;
|
||||
uint m_refreshInterval;
|
||||
MaxRatioAction m_highRatioAction;
|
||||
QString m_defaultSavePath;
|
||||
QString m_tempPath;
|
||||
QString m_filterPath;
|
||||
QString m_resumeFolderPath;
|
||||
QFile m_resumeFolderLock;
|
||||
QHash<InfoHash, QString> m_savePathsToRemove;
|
||||
|
||||
QTimer *m_refreshTimer;
|
||||
QTimer *m_bigRatioTimer;
|
||||
QTimer *m_resumeDataTimer;
|
||||
Statistics *m_statistics;
|
||||
// IP filtering
|
||||
QPointer<FilterParserThread> m_filterParser;
|
||||
QPointer<BandwidthScheduler> m_bwScheduler;
|
||||
// Tracker
|
||||
QPointer<Tracker> m_tracker;
|
||||
|
||||
QHash<InfoHash, TorrentInfo> m_loadedMetadata;
|
||||
QHash<InfoHash, TorrentHandle *> m_torrents;
|
||||
QHash<InfoHash, AddTorrentData> m_addingTorrents;
|
||||
QHash<QString, AddTorrentParams> m_downloadedTorrents;
|
||||
|
||||
QMutex m_alertsMutex;
|
||||
QWaitCondition m_alertsWaitCondition;
|
||||
QVector<libtorrent::alert *> m_alerts;
|
||||
|
||||
static Session *m_instance;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // BITTORRENT_SESSION_H
|
||||
96
src/core/bittorrent/sessionstatus.cpp
Normal file
96
src/core/bittorrent/sessionstatus.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include "sessionstatus.h"
|
||||
|
||||
using namespace BitTorrent;
|
||||
|
||||
SessionStatus::SessionStatus(const libtorrent::session_status &nativeStatus)
|
||||
: m_nativeStatus(nativeStatus)
|
||||
{
|
||||
}
|
||||
|
||||
bool SessionStatus::hasIncomingConnections() const
|
||||
{
|
||||
return m_nativeStatus.has_incoming_connections;
|
||||
}
|
||||
|
||||
int SessionStatus::payloadDownloadRate() const
|
||||
{
|
||||
return m_nativeStatus.payload_download_rate;
|
||||
}
|
||||
|
||||
int SessionStatus::payloadUploadRate() const
|
||||
{
|
||||
return m_nativeStatus.payload_upload_rate;
|
||||
}
|
||||
|
||||
qlonglong SessionStatus::totalDownload() const
|
||||
{
|
||||
return m_nativeStatus.total_download;
|
||||
}
|
||||
|
||||
qlonglong SessionStatus::totalUpload() const
|
||||
{
|
||||
return m_nativeStatus.total_upload;
|
||||
}
|
||||
|
||||
qlonglong SessionStatus::totalPayloadDownload() const
|
||||
{
|
||||
return m_nativeStatus.total_payload_download;
|
||||
}
|
||||
|
||||
qlonglong SessionStatus::totalPayloadUpload() const
|
||||
{
|
||||
return m_nativeStatus.total_payload_upload;
|
||||
}
|
||||
|
||||
qlonglong SessionStatus::totalWasted() const
|
||||
{
|
||||
return (m_nativeStatus.total_redundant_bytes + m_nativeStatus.total_failed_bytes);
|
||||
}
|
||||
|
||||
int SessionStatus::diskReadQueue() const
|
||||
{
|
||||
return m_nativeStatus.disk_read_queue;
|
||||
}
|
||||
|
||||
int SessionStatus::diskWriteQueue() const
|
||||
{
|
||||
return m_nativeStatus.disk_write_queue;
|
||||
}
|
||||
|
||||
int SessionStatus::dhtNodes() const
|
||||
{
|
||||
return m_nativeStatus.dht_nodes;
|
||||
}
|
||||
|
||||
int SessionStatus::peersCount() const
|
||||
{
|
||||
return m_nativeStatus.num_peers;
|
||||
}
|
||||
69
src/core/bittorrent/sessionstatus.h
Normal file
69
src/core/bittorrent/sessionstatus.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef BITTORRENT_SESSIONSTATUS_H
|
||||
#define BITTORRENT_SESSIONSTATUS_H
|
||||
|
||||
#include <libtorrent/session_status.hpp>
|
||||
#include <QtGlobal>
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class SessionStatus
|
||||
{
|
||||
public:
|
||||
SessionStatus(const libtorrent::session_status &nativeStatus);
|
||||
|
||||
bool hasIncomingConnections() const;
|
||||
|
||||
// Return current download rate for the BT
|
||||
// session. Payload means that it only take into
|
||||
// account "useful" part of the rate
|
||||
int payloadDownloadRate() const;
|
||||
|
||||
// Return current upload rate for the BT
|
||||
// session. Payload means that it only take into
|
||||
// account "useful" part of the rate
|
||||
int payloadUploadRate() const;
|
||||
|
||||
qlonglong totalDownload() const;
|
||||
qlonglong totalUpload() const;
|
||||
qlonglong totalPayloadDownload() const;
|
||||
qlonglong totalPayloadUpload() const;
|
||||
qlonglong totalWasted() const;
|
||||
int diskReadQueue() const;
|
||||
int diskWriteQueue() const;
|
||||
int dhtNodes() const;
|
||||
int peersCount() const;
|
||||
|
||||
private:
|
||||
libtorrent::session_status m_nativeStatus;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // BITTORRENT_SESSIONSTATUS_H
|
||||
166
src/core/bittorrent/torrentcreatorthread.cpp
Normal file
166
src/core/bittorrent/torrentcreatorthread.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2010 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include <libtorrent/version.hpp>
|
||||
#include <libtorrent/entry.hpp>
|
||||
#include <libtorrent/bencode.hpp>
|
||||
#include <libtorrent/torrent_info.hpp>
|
||||
#include <libtorrent/file.hpp>
|
||||
#include <libtorrent/storage.hpp>
|
||||
#include <libtorrent/hasher.hpp>
|
||||
#include <libtorrent/file_pool.hpp>
|
||||
#include <libtorrent/create_torrent.hpp>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "core/fs_utils.h"
|
||||
#include "core/misc.h"
|
||||
#include "core/utils/string.h"
|
||||
#include "torrentcreatorthread.h"
|
||||
|
||||
namespace libt = libtorrent;
|
||||
using namespace BitTorrent;
|
||||
|
||||
// do not include files and folders whose
|
||||
// name starts with a .
|
||||
bool fileFilter(const std::string &f)
|
||||
{
|
||||
return (libt::filename(f)[0] != '.');
|
||||
}
|
||||
|
||||
TorrentCreatorThread::TorrentCreatorThread(QObject *parent)
|
||||
: QThread(parent)
|
||||
{
|
||||
}
|
||||
|
||||
TorrentCreatorThread::~TorrentCreatorThread()
|
||||
{
|
||||
m_abort = true;
|
||||
wait();
|
||||
}
|
||||
|
||||
void TorrentCreatorThread::create(const QString &inputPath, const QString &savePath, const QStringList &trackers,
|
||||
const QStringList &urlSeeds, const QString &comment, bool isPrivate, int pieceSize)
|
||||
{
|
||||
m_inputPath = fsutils::fromNativePath(inputPath);
|
||||
m_savePath = fsutils::fromNativePath(savePath);
|
||||
if (QFile(m_savePath).exists())
|
||||
fsutils::forceRemove(m_savePath);
|
||||
m_trackers = trackers;
|
||||
m_urlSeeds = urlSeeds;
|
||||
m_comment = comment;
|
||||
m_private = isPrivate;
|
||||
m_pieceSize = pieceSize;
|
||||
m_abort = false;
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
void TorrentCreatorThread::sendProgressSignal(int numHashes, int numPieces)
|
||||
{
|
||||
emit updateProgress(static_cast<int>((numHashes * 100.) / numPieces));
|
||||
}
|
||||
|
||||
void TorrentCreatorThread::abortCreation()
|
||||
{
|
||||
m_abort = true;
|
||||
}
|
||||
|
||||
void TorrentCreatorThread::run()
|
||||
{
|
||||
emit updateProgress(0);
|
||||
|
||||
QString creator_str("qBittorrent " VERSION);
|
||||
try {
|
||||
libt::file_storage fs;
|
||||
// Adding files to the torrent
|
||||
libt::add_files(fs, String::toStdString(fsutils::toNativePath(m_inputPath)), fileFilter);
|
||||
if (m_abort) return;
|
||||
|
||||
libt::create_torrent t(fs, m_pieceSize);
|
||||
|
||||
// Add url seeds
|
||||
foreach (const QString &seed, m_urlSeeds)
|
||||
t.add_url_seed(String::toStdString(seed.trimmed()));
|
||||
|
||||
int tier = 0;
|
||||
bool newline = false;
|
||||
foreach (const QString &tracker, m_trackers) {
|
||||
if (tracker.isEmpty()) {
|
||||
if (newline)
|
||||
continue;
|
||||
++tier;
|
||||
newline = true;
|
||||
continue;
|
||||
}
|
||||
t.add_tracker(String::toStdString(tracker.trimmed()), tier);
|
||||
newline = false;
|
||||
}
|
||||
if (m_abort) return;
|
||||
|
||||
// calculate the hash for all pieces
|
||||
const QString parentPath = fsutils::branchPath(m_inputPath) + "/";
|
||||
libt::set_piece_hashes(t, String::toStdString(fsutils::toNativePath(parentPath)), boost::bind(&TorrentCreatorThread::sendProgressSignal, this, _1, t.num_pieces()));
|
||||
// Set qBittorrent as creator and add user comment to
|
||||
// torrent_info structure
|
||||
t.set_creator(creator_str.toUtf8().constData());
|
||||
t.set_comment(m_comment.toUtf8().constData());
|
||||
// Is private ?
|
||||
t.set_priv(m_private);
|
||||
if (m_abort) return;
|
||||
|
||||
// create the torrent and print it to out
|
||||
qDebug("Saving to %s", qPrintable(m_savePath));
|
||||
#ifdef _MSC_VER
|
||||
wchar_t *savePathW = new wchar_t[m_savePath.length() + 1];
|
||||
int len = fsutils::toNativePath(m_savePath).toWCharArray(savePathW);
|
||||
savePathW[len] = L'\0';
|
||||
std::ofstream outfile(savePathW, std::ios_base::out | std::ios_base::binary);
|
||||
delete[] savePathW;
|
||||
#else
|
||||
std::ofstream outfile(fsutils::toNativePath(m_savePath).toLocal8Bit().constData(), std::ios_base::out | std::ios_base::binary);
|
||||
#endif
|
||||
if (outfile.fail())
|
||||
throw std::exception();
|
||||
|
||||
libt::bencode(std::ostream_iterator<char>(outfile), t.generate());
|
||||
outfile.close();
|
||||
|
||||
emit updateProgress(100);
|
||||
emit creationSuccess(m_savePath, parentPath);
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
emit creationFailure(String::fromStdString(e.what()));
|
||||
}
|
||||
}
|
||||
73
src/core/bittorrent/torrentcreatorthread.h
Normal file
73
src/core/bittorrent/torrentcreatorthread.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2010 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#ifndef BITTORRENT_TORRENTCREATORTHREAD_H
|
||||
#define BITTORRENT_TORRENTCREATORTHREAD_H
|
||||
|
||||
#include <QThread>
|
||||
#include <QStringList>
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class TorrentCreatorThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TorrentCreatorThread(QObject *parent = 0);
|
||||
~TorrentCreatorThread();
|
||||
|
||||
void create(const QString &inputPath, const QString &savePath, const QStringList &trackers,
|
||||
const QStringList &urlSeeds, const QString &comment, bool isPrivate, int pieceSize);
|
||||
void abortCreation();
|
||||
|
||||
protected:
|
||||
void run();
|
||||
|
||||
signals:
|
||||
void creationFailure(const QString &msg);
|
||||
void creationSuccess(const QString &path, const QString &branchPath);
|
||||
void updateProgress(int progress);
|
||||
|
||||
private:
|
||||
void sendProgressSignal(int numHashes, int numPieces);
|
||||
|
||||
QString m_inputPath;
|
||||
QString m_savePath;
|
||||
QStringList m_trackers;
|
||||
QStringList m_urlSeeds;
|
||||
QString m_comment;
|
||||
bool m_private;
|
||||
int m_pieceSize;
|
||||
bool m_abort;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // BITTORRENT_TORRENTCREATORTHREAD_H
|
||||
1887
src/core/bittorrent/torrenthandle.cpp
Normal file
1887
src/core/bittorrent/torrenthandle.cpp
Normal file
File diff suppressed because it is too large
Load Diff
380
src/core/bittorrent/torrenthandle.h
Normal file
380
src/core/bittorrent/torrenthandle.h
Normal file
@@ -0,0 +1,380 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef BITTORRENT_TORRENTHANDLE_H
|
||||
#define BITTORRENT_TORRENTHANDLE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QDateTime>
|
||||
#include <QQueue>
|
||||
#include <QVector>
|
||||
#include <QHash>
|
||||
|
||||
#include <libtorrent/torrent_handle.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include "core/tristatebool.h"
|
||||
#include "private/speedmonitor.h"
|
||||
#include "private/torrenthandleprivate.h"
|
||||
#include "infohash.h"
|
||||
#include "torrentinfo.h"
|
||||
|
||||
class QBitArray;
|
||||
class QStringList;
|
||||
template<typename T, typename U> struct QPair;
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
class alert;
|
||||
struct stats_alert;
|
||||
struct torrent_checked_alert;
|
||||
struct torrent_finished_alert;
|
||||
struct torrent_paused_alert;
|
||||
struct torrent_resumed_alert;
|
||||
struct save_resume_data_alert;
|
||||
struct save_resume_data_failed_alert;
|
||||
struct file_renamed_alert;
|
||||
struct storage_moved_alert;
|
||||
struct storage_moved_failed_alert;
|
||||
struct metadata_received_alert;
|
||||
struct file_completed_alert;
|
||||
struct tracker_error_alert;
|
||||
struct tracker_reply_alert;
|
||||
struct tracker_warning_alert;
|
||||
struct fastresume_rejected_alert;
|
||||
}
|
||||
|
||||
struct SessionPrivate;
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
struct PeerAddress;
|
||||
class Session;
|
||||
class PeerInfo;
|
||||
class TrackerEntry;
|
||||
struct AddTorrentParams;
|
||||
|
||||
struct AddTorrentData
|
||||
{
|
||||
bool resumed;
|
||||
// for both new and resumed torrents
|
||||
QString name;
|
||||
QString label;
|
||||
QString savePath;
|
||||
bool disableTempPath;
|
||||
bool sequential;
|
||||
bool hasSeedStatus;
|
||||
// for new torrents
|
||||
TriStateBool addPaused;
|
||||
QVector<int> filePriorities;
|
||||
bool ignoreShareRatio;
|
||||
// for resumed torrents
|
||||
QDateTime addedTime;
|
||||
qreal ratioLimit;
|
||||
|
||||
AddTorrentData();
|
||||
AddTorrentData(const AddTorrentParams &in);
|
||||
};
|
||||
|
||||
struct TrackerInfo
|
||||
{
|
||||
QString lastMessage;
|
||||
quint32 numPeers;
|
||||
|
||||
TrackerInfo();
|
||||
};
|
||||
|
||||
class TorrentState
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
Unknown = -1,
|
||||
|
||||
Error,
|
||||
|
||||
Uploading,
|
||||
PausedUploading,
|
||||
QueuedUploading,
|
||||
StalledUploading,
|
||||
CheckingUploading,
|
||||
ForcedUploading,
|
||||
|
||||
Allocating,
|
||||
|
||||
DownloadingMetadata,
|
||||
Downloading,
|
||||
PausedDownloading,
|
||||
QueuedDownloading,
|
||||
StalledDownloading,
|
||||
CheckingDownloading,
|
||||
ForcedDownloading
|
||||
};
|
||||
|
||||
TorrentState(int value);
|
||||
|
||||
operator int() const;
|
||||
QString toString() const;
|
||||
|
||||
private:
|
||||
int m_value;
|
||||
};
|
||||
|
||||
class TorrentHandle : public QObject, public TorrentHandlePrivate
|
||||
{
|
||||
Q_DISABLE_COPY(TorrentHandle)
|
||||
|
||||
public:
|
||||
static const qreal USE_GLOBAL_RATIO;
|
||||
static const qreal NO_RATIO_LIMIT;
|
||||
|
||||
static const qreal MAX_RATIO;
|
||||
|
||||
TorrentHandle(Session *session, const libtorrent::torrent_handle &nativeHandle,
|
||||
const AddTorrentData &data);
|
||||
~TorrentHandle();
|
||||
|
||||
bool isValid() const;
|
||||
InfoHash hash() const;
|
||||
QString name() const;
|
||||
QDateTime creationDate() const;
|
||||
QString creator() const;
|
||||
QString comment() const;
|
||||
bool isPrivate() const;
|
||||
qlonglong totalSize() const;
|
||||
qlonglong wantedSize() const;
|
||||
qlonglong completedSize() const;
|
||||
qlonglong incompletedSize() const;
|
||||
qlonglong pieceLength() const;
|
||||
qlonglong wastedSize() const;
|
||||
QString currentTracker() const;
|
||||
QString actualSavePath() const;
|
||||
QString savePath() const;
|
||||
QString rootPath() const;
|
||||
QString savePathParsed() const;
|
||||
int filesCount() const;
|
||||
int piecesCount() const;
|
||||
qreal progress() const;
|
||||
QString label() const;
|
||||
QDateTime addedTime() const;
|
||||
qreal ratioLimit() const;
|
||||
|
||||
QString firstFileSavePath() const;
|
||||
QString filePath(int index) const;
|
||||
QString fileName(int index) const;
|
||||
qlonglong fileSize(int index) const;
|
||||
QStringList absoluteFilePaths() const;
|
||||
QStringList absoluteFilePathsUnwanted() const;
|
||||
QPair<int, int> fileExtremityPieces(int index) const;
|
||||
QVector<int> filePriorities() const;
|
||||
|
||||
TorrentInfo info() const;
|
||||
bool isSeed() const;
|
||||
bool isPaused() const;
|
||||
bool isResumed() const;
|
||||
bool isQueued() const;
|
||||
bool isForced() const;
|
||||
bool isChecking() const;
|
||||
bool isDownloading() const;
|
||||
bool isUploading() const;
|
||||
bool isCompleted() const;
|
||||
bool isActive() const;
|
||||
bool isInactive() const;
|
||||
bool isSequentialDownload() const;
|
||||
bool hasFirstLastPiecePriority() const;
|
||||
TorrentState state() const;
|
||||
bool hasMetadata() const;
|
||||
bool hasMissingFiles() const;
|
||||
bool hasError() const;
|
||||
bool hasFilteredPieces() const;
|
||||
int queuePosition() const;
|
||||
QList<TrackerEntry> trackers() const;
|
||||
QHash<QString, TrackerInfo> trackerInfos() const;
|
||||
QList<QUrl> urlSeeds() const;
|
||||
QString error() const;
|
||||
qlonglong totalDownload() const;
|
||||
qlonglong totalUpload() const;
|
||||
int activeTime() const;
|
||||
int seedingTime() const;
|
||||
qulonglong eta() const;
|
||||
QVector<qreal> filesProgress() const;
|
||||
int seedsCount() const;
|
||||
int peersCount() const;
|
||||
int leechsCount() const;
|
||||
int completeCount() const;
|
||||
int incompleteCount() const;
|
||||
QDateTime lastSeenComplete() const;
|
||||
QDateTime completedTime() const;
|
||||
int timeSinceUpload() const;
|
||||
int timeSinceDownload() const;
|
||||
int downloadLimit() const;
|
||||
int uploadLimit() const;
|
||||
bool superSeeding() const;
|
||||
QList<PeerInfo> peers() const;
|
||||
QBitArray pieces() const;
|
||||
QBitArray downloadingPieces() const;
|
||||
QVector<int> pieceAvailability() const;
|
||||
qreal distributedCopies() const;
|
||||
qreal maxRatio(bool *usesGlobalRatio = 0) const;
|
||||
qreal realRatio() const;
|
||||
int uploadPayloadRate() const;
|
||||
int downloadPayloadRate() const;
|
||||
int totalPayloadUpload() const;
|
||||
int totalPayloadDownload() const;
|
||||
int connectionsCount() const;
|
||||
int connectionsLimit() const;
|
||||
qlonglong nextAnnounce() const;
|
||||
|
||||
void setName(const QString &name);
|
||||
void setLabel(const QString &label);
|
||||
void setSequentialDownload(bool b);
|
||||
void toggleSequentialDownload();
|
||||
void toggleFirstLastPiecePriority();
|
||||
void setFirstLastPiecePriority(bool b);
|
||||
void pause();
|
||||
void resume(bool forced = false);
|
||||
void move(QString path);
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
void forceReannounce();
|
||||
#else
|
||||
void forceReannounce(int index = -1);
|
||||
#endif
|
||||
void forceDHTAnnounce();
|
||||
void forceRecheck();
|
||||
void setTrackerLogin(const QString &username, const QString &password);
|
||||
void renameFile(int index, const QString &name);
|
||||
bool saveTorrentFile(const QString &path);
|
||||
void prioritizeFiles(const QVector<int> &priorities);
|
||||
void setFilePriority(int index, int priority);
|
||||
void setRatioLimit(qreal limit);
|
||||
void setUploadLimit(int limit);
|
||||
void setDownloadLimit(int limit);
|
||||
void setSuperSeeding(bool enable);
|
||||
void flushCache();
|
||||
void addTrackers(const QList<TrackerEntry> &trackers);
|
||||
void replaceTrackers(QList<TrackerEntry> trackers);
|
||||
void addUrlSeeds(const QList<QUrl> &urlSeeds);
|
||||
void removeUrlSeeds(const QList<QUrl> &urlSeeds);
|
||||
bool connectPeer(const PeerAddress &peerAddress);
|
||||
|
||||
QString toMagnetUri() const;
|
||||
|
||||
bool needSaveResumeData() const;
|
||||
void saveResumeData();
|
||||
|
||||
libtorrent::torrent_handle nativeHandle() const;
|
||||
|
||||
private:
|
||||
typedef boost::function<void ()> MoveStorageTrigger;
|
||||
|
||||
void initialize();
|
||||
void updateStatus();
|
||||
void updateStatus(const libtorrent::torrent_status &nativeStatus);
|
||||
void updateState();
|
||||
void updateTorrentInfo();
|
||||
|
||||
void handleAlert(libtorrent::alert *a);
|
||||
void handleStateUpdate(const libtorrent::torrent_status &nativeStatus);
|
||||
void handleDefaultSavePathChanged();
|
||||
void handleTempPathChanged();
|
||||
void handleAppendExtensionToggled();
|
||||
#ifndef DISABLE_COUNTRIES_RESOLUTION
|
||||
void handleResolveCountriesToggled();
|
||||
#endif
|
||||
|
||||
void handleStorageMovedAlert(libtorrent::storage_moved_alert *p);
|
||||
void handleStorageMovedFailedAlert(libtorrent::storage_moved_failed_alert *p);
|
||||
void handleTrackerReplyAlert(libtorrent::tracker_reply_alert *p);
|
||||
void handleTrackerWarningAlert(libtorrent::tracker_warning_alert *p);
|
||||
void handleTrackerErrorAlert(libtorrent::tracker_error_alert *p);
|
||||
void handleTorrentCheckedAlert(libtorrent::torrent_checked_alert *p);
|
||||
void handleTorrentFinishedAlert(libtorrent::torrent_finished_alert *p);
|
||||
void handleTorrentPausedAlert(libtorrent::torrent_paused_alert *p);
|
||||
void handleTorrentResumedAlert(libtorrent::torrent_resumed_alert *p);
|
||||
void handleSaveResumeDataAlert(libtorrent::save_resume_data_alert *p);
|
||||
void handleSaveResumeDataFailedAlert(libtorrent::save_resume_data_failed_alert *p);
|
||||
void handleFastResumeRejectedAlert(libtorrent::fastresume_rejected_alert *p);
|
||||
void handleFileRenamedAlert(libtorrent::file_renamed_alert *p);
|
||||
void handleFileCompletedAlert(libtorrent::file_completed_alert *p);
|
||||
void handleMetadataReceivedAlert(libtorrent::metadata_received_alert *p);
|
||||
void handleStatsAlert(libtorrent::stats_alert *p);
|
||||
|
||||
bool isMoveInProgress() const;
|
||||
bool useTempPath() const;
|
||||
QString nativeActualSavePath() const;
|
||||
|
||||
void resolveCountries(bool b);
|
||||
void adjustSavePath();
|
||||
void adjustActualSavePath();
|
||||
void moveStorage(const QString &newPath);
|
||||
void appendExtensionsToIncompleteFiles();
|
||||
void removeExtensionsFromIncompleteFiles();
|
||||
bool addTracker(const TrackerEntry &tracker);
|
||||
bool addUrlSeed(const QUrl &urlSeed);
|
||||
bool removeUrlSeed(const QUrl &urlSeed);
|
||||
|
||||
SessionPrivate *const m_session;
|
||||
libtorrent::torrent_handle m_nativeHandle;
|
||||
libtorrent::torrent_status m_nativeStatus;
|
||||
TorrentState m_state;
|
||||
TorrentInfo m_torrentInfo;
|
||||
SpeedMonitor m_speedMonitor;
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
QString m_nativeName;
|
||||
QString m_nativeSavePath;
|
||||
#endif
|
||||
|
||||
InfoHash m_hash;
|
||||
|
||||
QString m_oldPath;
|
||||
QString m_newPath;
|
||||
// m_queuedPath is where files should be moved to,
|
||||
// when current moving is completed
|
||||
QString m_queuedPath;
|
||||
QQueue<MoveStorageTrigger> m_moveStorageTriggers;
|
||||
|
||||
// Persistent data
|
||||
QString m_name;
|
||||
QDateTime m_addedTime;
|
||||
QString m_savePath;
|
||||
QString m_label;
|
||||
bool m_hasSeedStatus;
|
||||
qreal m_ratioLimit;
|
||||
bool m_tempPathDisabled;
|
||||
bool m_hasMissingFiles;
|
||||
|
||||
bool m_useDefaultSavePath;
|
||||
bool m_pauseAfterRecheck;
|
||||
bool m_needSaveResumeData;
|
||||
QHash<QString, TrackerInfo> m_trackerInfos;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // BITTORRENT_TORRENTHANDLE_H
|
||||
230
src/core/bittorrent/torrentinfo.cpp
Normal file
230
src/core/bittorrent/torrentinfo.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QUrl>
|
||||
#include <QDateTime>
|
||||
|
||||
#include <libtorrent/error_code.hpp>
|
||||
#include <libtorrent/magnet_uri.hpp>
|
||||
|
||||
#include "core/misc.h"
|
||||
#include "core/fs_utils.h"
|
||||
#include "core/utils/string.h"
|
||||
#include "infohash.h"
|
||||
#include "trackerentry.h"
|
||||
#include "torrentinfo.h"
|
||||
|
||||
namespace libt = libtorrent;
|
||||
using namespace BitTorrent;
|
||||
|
||||
TorrentInfo::TorrentInfo(boost::intrusive_ptr<const libt::torrent_info> nativeInfo)
|
||||
: m_nativeInfo(const_cast<libt::torrent_info *>(nativeInfo.get()))
|
||||
{
|
||||
}
|
||||
|
||||
TorrentInfo::TorrentInfo(const TorrentInfo &other)
|
||||
: m_nativeInfo(other.m_nativeInfo)
|
||||
{
|
||||
}
|
||||
|
||||
TorrentInfo &TorrentInfo::operator=(const TorrentInfo &other)
|
||||
{
|
||||
m_nativeInfo = other.m_nativeInfo;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TorrentInfo TorrentInfo::loadFromFile(const QString &path, QString &error)
|
||||
{
|
||||
error.clear();
|
||||
libt::error_code ec;
|
||||
TorrentInfo info(new libt::torrent_info(String::toStdString(fsutils::toNativePath(path)), ec));
|
||||
if (ec) {
|
||||
error = QString::fromUtf8(ec.message().c_str());
|
||||
qDebug("Cannot load .torrent file: %s", qPrintable(error));
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
TorrentInfo TorrentInfo::loadFromFile(const QString &path)
|
||||
{
|
||||
QString error;
|
||||
return loadFromFile(path, error);
|
||||
}
|
||||
|
||||
bool TorrentInfo::isValid() const
|
||||
{
|
||||
return (m_nativeInfo && m_nativeInfo->is_valid() && (m_nativeInfo->num_files() > 0));
|
||||
}
|
||||
|
||||
InfoHash TorrentInfo::hash() const
|
||||
{
|
||||
if (!isValid()) return InfoHash();
|
||||
return m_nativeInfo->info_hash();
|
||||
}
|
||||
|
||||
QString TorrentInfo::name() const
|
||||
{
|
||||
if (!isValid()) return QString();
|
||||
return String::fromStdString(m_nativeInfo->name());
|
||||
}
|
||||
|
||||
QDateTime TorrentInfo::creationDate() const
|
||||
{
|
||||
if (!isValid()) return QDateTime();
|
||||
boost::optional<time_t> t = m_nativeInfo->creation_date();
|
||||
return t ? QDateTime::fromTime_t(*t) : QDateTime();
|
||||
}
|
||||
|
||||
QString TorrentInfo::creator() const
|
||||
{
|
||||
if (!isValid()) return QString();
|
||||
return String::fromStdString(m_nativeInfo->creator());
|
||||
}
|
||||
|
||||
QString TorrentInfo::comment() const
|
||||
{
|
||||
if (!isValid()) return QString();
|
||||
return String::fromStdString(m_nativeInfo->comment());
|
||||
}
|
||||
|
||||
bool TorrentInfo::isPrivate() const
|
||||
{
|
||||
if (!isValid()) return false;
|
||||
return m_nativeInfo->priv();
|
||||
}
|
||||
|
||||
qlonglong TorrentInfo::totalSize() const
|
||||
{
|
||||
if (!isValid()) return -1;
|
||||
return m_nativeInfo->total_size();
|
||||
}
|
||||
|
||||
int TorrentInfo::filesCount() const
|
||||
{
|
||||
if (!isValid()) return -1;
|
||||
return m_nativeInfo->num_files();
|
||||
}
|
||||
|
||||
int TorrentInfo::pieceLength() const
|
||||
{
|
||||
if (!isValid()) return -1;
|
||||
return m_nativeInfo->piece_length();
|
||||
}
|
||||
|
||||
int TorrentInfo::piecesCount() const
|
||||
{
|
||||
if (!isValid()) return -1;
|
||||
return m_nativeInfo->num_pieces();
|
||||
}
|
||||
|
||||
QString TorrentInfo::filePath(int index) const
|
||||
{
|
||||
if (!isValid()) return QString();
|
||||
return fsutils::fromNativePath(String::fromStdString(m_nativeInfo->files().file_path(index)));
|
||||
}
|
||||
|
||||
QStringList TorrentInfo::filePaths() const
|
||||
{
|
||||
QStringList list;
|
||||
for (int i = 0; i < filesCount(); ++i)
|
||||
list << filePath(i);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
QString TorrentInfo::fileName(int index) const
|
||||
{
|
||||
return fsutils::fileName(filePath(index));
|
||||
}
|
||||
|
||||
QString TorrentInfo::origFilePath(int index) const
|
||||
{
|
||||
if (!isValid()) return QString();
|
||||
return fsutils::fromNativePath(String::fromStdString(m_nativeInfo->orig_files().file_path(index)));
|
||||
}
|
||||
|
||||
qlonglong TorrentInfo::fileSize(int index) const
|
||||
{
|
||||
if (!isValid()) return -1;
|
||||
return m_nativeInfo->files().file_size(index);
|
||||
}
|
||||
|
||||
qlonglong TorrentInfo::fileOffset(int index) const
|
||||
{
|
||||
if (!isValid()) return -1;
|
||||
return m_nativeInfo->file_at(index).offset;
|
||||
}
|
||||
|
||||
QList<TrackerEntry> TorrentInfo::trackers() const
|
||||
{
|
||||
if (!isValid()) return QList<TrackerEntry>();
|
||||
|
||||
QList<TrackerEntry> trackers;
|
||||
foreach (const libt::announce_entry &tracker, m_nativeInfo->trackers())
|
||||
trackers.append(tracker);
|
||||
|
||||
return trackers;
|
||||
}
|
||||
|
||||
QList<QUrl> TorrentInfo::urlSeeds() const
|
||||
{
|
||||
if (!isValid()) return QList<QUrl>();
|
||||
|
||||
QList<QUrl> urlSeeds;
|
||||
foreach (const libt::web_seed_entry &webSeed, m_nativeInfo->web_seeds())
|
||||
if (webSeed.type == libt::web_seed_entry::url_seed)
|
||||
urlSeeds.append(QUrl(webSeed.url.c_str()));
|
||||
|
||||
return urlSeeds;
|
||||
}
|
||||
|
||||
QByteArray TorrentInfo::metadata() const
|
||||
{
|
||||
if (!isValid()) return QByteArray();
|
||||
return QByteArray(m_nativeInfo->metadata().get(), m_nativeInfo->metadata_size());
|
||||
}
|
||||
|
||||
QString TorrentInfo::toMagnetUri() const
|
||||
{
|
||||
if (!isValid()) return QString();
|
||||
return String::fromStdString(libt::make_magnet_uri(*m_nativeInfo));
|
||||
}
|
||||
|
||||
void TorrentInfo::renameFile(uint index, const QString &newPath)
|
||||
{
|
||||
if (!isValid()) return;
|
||||
m_nativeInfo->rename_file(index, String::toStdString(newPath));
|
||||
}
|
||||
|
||||
boost::intrusive_ptr<libtorrent::torrent_info> TorrentInfo::nativeInfo() const
|
||||
{
|
||||
return m_nativeInfo;
|
||||
}
|
||||
88
src/core/bittorrent/torrentinfo.h
Normal file
88
src/core/bittorrent/torrentinfo.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef BITTORRENT_TORRENTINFO_H
|
||||
#define BITTORRENT_TORRENTINFO_H
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <libtorrent/torrent_info.hpp>
|
||||
|
||||
class QString;
|
||||
class QUrl;
|
||||
class QDateTime;
|
||||
class QStringList;
|
||||
class QByteArray;
|
||||
template<typename T> class QList;
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class InfoHash;
|
||||
class TrackerEntry;
|
||||
|
||||
class TorrentInfo
|
||||
{
|
||||
public:
|
||||
explicit TorrentInfo(boost::intrusive_ptr<const libtorrent::torrent_info> nativeInfo = boost::intrusive_ptr<const libtorrent::torrent_info>());
|
||||
TorrentInfo(const TorrentInfo &other);
|
||||
|
||||
static TorrentInfo loadFromFile(const QString &path, QString &error);
|
||||
static TorrentInfo loadFromFile(const QString &path);
|
||||
|
||||
TorrentInfo &operator=(const TorrentInfo &other);
|
||||
|
||||
bool isValid() const;
|
||||
InfoHash hash() const;
|
||||
QString name() const;
|
||||
QDateTime creationDate() const;
|
||||
QString creator() const;
|
||||
QString comment() const;
|
||||
bool isPrivate() const;
|
||||
qlonglong totalSize() const;
|
||||
int filesCount() const;
|
||||
int pieceLength() const;
|
||||
int piecesCount() const;
|
||||
QString filePath(int index) const;
|
||||
QStringList filePaths() const;
|
||||
QString fileName(int index) const;
|
||||
QString origFilePath(int index) const;
|
||||
qlonglong fileSize(int index) const;
|
||||
qlonglong fileOffset(int index) const;
|
||||
QList<TrackerEntry> trackers() const;
|
||||
QList<QUrl> urlSeeds() const;
|
||||
QByteArray metadata() const;
|
||||
QString toMagnetUri() const;
|
||||
|
||||
void renameFile(uint index, const QString &newPath);
|
||||
boost::intrusive_ptr<libtorrent::torrent_info> nativeInfo() const;
|
||||
|
||||
private:
|
||||
boost::intrusive_ptr<libtorrent::torrent_info> m_nativeInfo;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // BITTORRENT_TORRENTINFO_H
|
||||
@@ -31,59 +31,68 @@
|
||||
|
||||
#include <vector>
|
||||
#include <libtorrent/bencode.hpp>
|
||||
#include <libtorrent/entry.hpp>
|
||||
|
||||
#include "preferences.h"
|
||||
#include "http/server.h"
|
||||
#include "qtracker.h"
|
||||
#include "core/preferences.h"
|
||||
#include "core/http/server.h"
|
||||
#include "core/utils/string.h"
|
||||
#include "tracker.h"
|
||||
|
||||
// QPeer
|
||||
bool QPeer::operator!=(const QPeer &other) const
|
||||
// static limits
|
||||
static const int MAX_TORRENTS = 100;
|
||||
static const int MAX_PEERS_PER_TORRENT = 1000;
|
||||
static const int ANNOUNCE_INTERVAL = 1800; // 30min
|
||||
|
||||
using namespace BitTorrent;
|
||||
|
||||
// Peer
|
||||
bool Peer::operator!=(const Peer &other) const
|
||||
{
|
||||
return qhash() != other.qhash();
|
||||
return uid() != other.uid();
|
||||
}
|
||||
|
||||
bool QPeer::operator==(const QPeer &other) const
|
||||
bool Peer::operator==(const Peer &other) const
|
||||
{
|
||||
return qhash() == other.qhash();
|
||||
return uid() == other.uid();
|
||||
}
|
||||
|
||||
QString QPeer::qhash() const
|
||||
QString Peer::uid() const
|
||||
{
|
||||
return ip + ":" + QString::number(port);
|
||||
}
|
||||
|
||||
libtorrent::entry QPeer::toEntry(bool no_peer_id) const
|
||||
libtorrent::entry Peer::toEntry(bool noPeerId) const
|
||||
{
|
||||
libtorrent::entry::dictionary_type peer_map;
|
||||
if (!no_peer_id)
|
||||
peer_map["id"] = libtorrent::entry(peer_id.toStdString());
|
||||
peer_map["ip"] = libtorrent::entry(ip.toStdString());
|
||||
peer_map["port"] = libtorrent::entry(port);
|
||||
libtorrent::entry::dictionary_type peerMap;
|
||||
if (!noPeerId)
|
||||
peerMap["id"] = libtorrent::entry(String::toStdString(peerId));
|
||||
peerMap["ip"] = libtorrent::entry(String::toStdString(ip));
|
||||
peerMap["port"] = libtorrent::entry(port);
|
||||
|
||||
return libtorrent::entry(peer_map);
|
||||
return libtorrent::entry(peerMap);
|
||||
}
|
||||
|
||||
// QTracker
|
||||
// Tracker
|
||||
|
||||
QTracker::QTracker(QObject *parent)
|
||||
Tracker::Tracker(QObject *parent)
|
||||
: Http::ResponseBuilder(parent)
|
||||
, m_server(new Http::Server(this, this))
|
||||
{
|
||||
}
|
||||
|
||||
QTracker::~QTracker()
|
||||
Tracker::~Tracker()
|
||||
{
|
||||
if (m_server->isListening())
|
||||
qDebug("Shutting down the embedded tracker...");
|
||||
// TODO: Store the torrent list
|
||||
}
|
||||
|
||||
bool QTracker::start()
|
||||
bool Tracker::start()
|
||||
{
|
||||
const int listen_port = Preferences::instance()->getTrackerPort();
|
||||
const int listenPort = Preferences::instance()->getTrackerPort();
|
||||
|
||||
if (m_server->isListening()) {
|
||||
if (m_server->serverPort() == listen_port) {
|
||||
if (m_server->serverPort() == listenPort) {
|
||||
// Already listening on the right port, just return
|
||||
return true;
|
||||
}
|
||||
@@ -93,21 +102,21 @@ bool QTracker::start()
|
||||
|
||||
qDebug("Starting the embedded tracker...");
|
||||
// Listen on the predefined port
|
||||
return m_server->listen(QHostAddress::Any, listen_port);
|
||||
return m_server->listen(QHostAddress::Any, listenPort);
|
||||
}
|
||||
|
||||
Http::Response QTracker::processRequest(const Http::Request &request, const Http::Environment &env)
|
||||
Http::Response Tracker::processRequest(const Http::Request &request, const Http::Environment &env)
|
||||
{
|
||||
clear(); // clear response
|
||||
|
||||
//qDebug("QTracker received the following request:\n%s", qPrintable(parser.toString()));
|
||||
//qDebug("Tracker received the following request:\n%s", qPrintable(parser.toString()));
|
||||
// Is request a GET request?
|
||||
if (request.method != "GET") {
|
||||
qDebug("QTracker: Unsupported HTTP request: %s", qPrintable(request.method));
|
||||
qDebug("Tracker: Unsupported HTTP request: %s", qPrintable(request.method));
|
||||
status(100, "Invalid request type");
|
||||
}
|
||||
else if (!request.path.startsWith("/announce", Qt::CaseInsensitive)) {
|
||||
qDebug("QTracker: Unrecognized path: %s", qPrintable(request.path));
|
||||
qDebug("Tracker: Unrecognized path: %s", qPrintable(request.path));
|
||||
status(100, "Invalid request type");
|
||||
}
|
||||
else {
|
||||
@@ -120,85 +129,85 @@ Http::Response QTracker::processRequest(const Http::Request &request, const Http
|
||||
return response();
|
||||
}
|
||||
|
||||
void QTracker::respondToAnnounceRequest()
|
||||
void Tracker::respondToAnnounceRequest()
|
||||
{
|
||||
const QStringMap &gets = m_request.gets;
|
||||
TrackerAnnounceRequest annonce_req;
|
||||
TrackerAnnounceRequest annonceReq;
|
||||
|
||||
// IP
|
||||
annonce_req.peer.ip = m_env.clientAddress.toString();
|
||||
annonceReq.peer.ip = m_env.clientAddress.toString();
|
||||
|
||||
// 1. Get info_hash
|
||||
if (!gets.contains("info_hash")) {
|
||||
qDebug("QTracker: Missing info_hash");
|
||||
qDebug("Tracker: Missing info_hash");
|
||||
status(101, "Missing info_hash");
|
||||
return;
|
||||
}
|
||||
annonce_req.info_hash = gets.value("info_hash");
|
||||
annonceReq.infoHash = gets.value("info_hash");
|
||||
// info_hash cannot be longer than 20 bytes
|
||||
/*if (annonce_req.info_hash.toLatin1().length() > 20) {
|
||||
qDebug("QTracker: Info_hash is not 20 byte long: %s (%d)", qPrintable(annonce_req.info_hash), annonce_req.info_hash.toLatin1().length());
|
||||
qDebug("Tracker: Info_hash is not 20 byte long: %s (%d)", qPrintable(annonce_req.info_hash), annonce_req.info_hash.toLatin1().length());
|
||||
status(150, "Invalid infohash");
|
||||
return;
|
||||
}*/
|
||||
|
||||
// 2. Get peer ID
|
||||
if (!gets.contains("peer_id")) {
|
||||
qDebug("QTracker: Missing peer_id");
|
||||
qDebug("Tracker: Missing peer_id");
|
||||
status(102, "Missing peer_id");
|
||||
return;
|
||||
}
|
||||
annonce_req.peer.peer_id = gets.value("peer_id");
|
||||
annonceReq.peer.peerId = gets.value("peer_id");
|
||||
// peer_id cannot be longer than 20 bytes
|
||||
/*if (annonce_req.peer.peer_id.length() > 20) {
|
||||
qDebug("QTracker: peer_id is not 20 byte long: %s", qPrintable(annonce_req.peer.peer_id));
|
||||
qDebug("Tracker: peer_id is not 20 byte long: %s", qPrintable(annonce_req.peer.peer_id));
|
||||
status(151, "Invalid peerid");
|
||||
return;
|
||||
}*/
|
||||
|
||||
// 3. Get port
|
||||
if (!gets.contains("port")) {
|
||||
qDebug("QTracker: Missing port");
|
||||
qDebug("Tracker: Missing port");
|
||||
status(103, "Missing port");
|
||||
return;
|
||||
}
|
||||
bool ok = false;
|
||||
annonce_req.peer.port = gets.value("port").toInt(&ok);
|
||||
if (!ok || annonce_req.peer.port < 1 || annonce_req.peer.port > 65535) {
|
||||
qDebug("QTracker: Invalid port number (%d)", annonce_req.peer.port);
|
||||
annonceReq.peer.port = gets.value("port").toInt(&ok);
|
||||
if (!ok || annonceReq.peer.port < 1 || annonceReq.peer.port > 65535) {
|
||||
qDebug("Tracker: Invalid port number (%d)", annonceReq.peer.port);
|
||||
status(103, "Missing port");
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. Get event
|
||||
annonce_req.event = "";
|
||||
annonceReq.event = "";
|
||||
if (gets.contains("event")) {
|
||||
annonce_req.event = gets.value("event");
|
||||
qDebug("QTracker: event is %s", qPrintable(annonce_req.event));
|
||||
annonceReq.event = gets.value("event");
|
||||
qDebug("Tracker: event is %s", qPrintable(annonceReq.event));
|
||||
}
|
||||
|
||||
// 5. Get numwant
|
||||
annonce_req.numwant = 50;
|
||||
annonceReq.numwant = 50;
|
||||
if (gets.contains("numwant")) {
|
||||
int tmp = gets.value("numwant").toInt();
|
||||
if (tmp > 0) {
|
||||
qDebug("QTracker: numwant = %d", tmp);
|
||||
annonce_req.numwant = tmp;
|
||||
qDebug("Tracker: numwant = %d", tmp);
|
||||
annonceReq.numwant = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// 6. no_peer_id (extension)
|
||||
annonce_req.no_peer_id = false;
|
||||
annonceReq.noPeerId = false;
|
||||
if (gets.contains("no_peer_id"))
|
||||
annonce_req.no_peer_id = true;
|
||||
annonceReq.noPeerId = true;
|
||||
|
||||
// 7. TODO: support "compact" extension
|
||||
|
||||
// Done parsing, now let's reply
|
||||
if (m_torrents.contains(annonce_req.info_hash)) {
|
||||
if (annonce_req.event == "stopped") {
|
||||
qDebug("QTracker: Peer stopped downloading, deleting it from the list");
|
||||
m_torrents[annonce_req.info_hash].remove(annonce_req.peer.qhash());
|
||||
if (m_torrents.contains(annonceReq.infoHash)) {
|
||||
if (annonceReq.event == "stopped") {
|
||||
qDebug("Tracker: Peer stopped downloading, deleting it from the list");
|
||||
m_torrents[annonceReq.infoHash].remove(annonceReq.peer.uid());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -210,36 +219,36 @@ void QTracker::respondToAnnounceRequest()
|
||||
}
|
||||
}
|
||||
// Register the user
|
||||
PeerList peers = m_torrents.value(annonce_req.info_hash);
|
||||
PeerList peers = m_torrents.value(annonceReq.infoHash);
|
||||
if (peers.size() == MAX_PEERS_PER_TORRENT) {
|
||||
// Too many peers, remove a random one
|
||||
peers.erase(peers.begin());
|
||||
}
|
||||
peers[annonce_req.peer.qhash()] = annonce_req.peer;
|
||||
m_torrents[annonce_req.info_hash] = peers;
|
||||
peers[annonceReq.peer.uid()] = annonceReq.peer;
|
||||
m_torrents[annonceReq.infoHash] = peers;
|
||||
|
||||
// Reply
|
||||
replyWithPeerList(annonce_req);
|
||||
replyWithPeerList(annonceReq);
|
||||
}
|
||||
|
||||
void QTracker::replyWithPeerList(const TrackerAnnounceRequest &annonce_req)
|
||||
void Tracker::replyWithPeerList(const TrackerAnnounceRequest &annonceReq)
|
||||
{
|
||||
// Prepare the entry for bencoding
|
||||
libtorrent::entry::dictionary_type reply_dict;
|
||||
reply_dict["interval"] = libtorrent::entry(ANNOUNCE_INTERVAL);
|
||||
QList<QPeer> peers = m_torrents.value(annonce_req.info_hash).values();
|
||||
libtorrent::entry::list_type peer_list;
|
||||
foreach (const QPeer &p, peers) {
|
||||
libtorrent::entry::dictionary_type replyDict;
|
||||
replyDict["interval"] = libtorrent::entry(ANNOUNCE_INTERVAL);
|
||||
QList<Peer> peers = m_torrents.value(annonceReq.infoHash).values();
|
||||
libtorrent::entry::list_type peerList;
|
||||
foreach (const Peer &p, peers) {
|
||||
//if (p != annonce_req.peer)
|
||||
peer_list.push_back(p.toEntry(annonce_req.no_peer_id));
|
||||
peerList.push_back(p.toEntry(annonceReq.noPeerId));
|
||||
}
|
||||
reply_dict["peers"] = libtorrent::entry(peer_list);
|
||||
libtorrent::entry reply_entry(reply_dict);
|
||||
replyDict["peers"] = libtorrent::entry(peerList);
|
||||
libtorrent::entry replyEntry(replyDict);
|
||||
// bencode
|
||||
std::vector<char> buf;
|
||||
libtorrent::bencode(std::back_inserter(buf), reply_entry);
|
||||
libtorrent::bencode(std::back_inserter(buf), replyEntry);
|
||||
QByteArray reply(&buf[0], static_cast<int>(buf.size()));
|
||||
qDebug("QTracker: reply with the following bencoded data:\n %s", reply.constData());
|
||||
qDebug("Tracker: reply with the following bencoded data:\n %s", reply.constData());
|
||||
|
||||
// HTTP reply
|
||||
print(reply, Http::CONTENT_TYPE_TXT);
|
||||
103
src/core/bittorrent/tracker.h
Normal file
103
src/core/bittorrent/tracker.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2010 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#ifndef BITTORRENT_TRACKER_H
|
||||
#define BITTORRENT_TRACKER_H
|
||||
|
||||
#include <QHash>
|
||||
#include "core/http/types.h"
|
||||
#include "core/http/responsebuilder.h"
|
||||
#include "core/http/irequesthandler.h"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
class entry;
|
||||
}
|
||||
|
||||
namespace Http
|
||||
{
|
||||
class Server;
|
||||
}
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
struct Peer
|
||||
{
|
||||
QString ip;
|
||||
QString peerId;
|
||||
int port;
|
||||
|
||||
bool operator!=(const Peer &other) const;
|
||||
bool operator==(const Peer &other) const;
|
||||
QString uid() const;
|
||||
libtorrent::entry toEntry(bool noPeerId) const;
|
||||
};
|
||||
|
||||
struct TrackerAnnounceRequest
|
||||
{
|
||||
QString infoHash;
|
||||
QString event;
|
||||
int numwant;
|
||||
Peer peer;
|
||||
// Extensions
|
||||
bool noPeerId;
|
||||
};
|
||||
|
||||
typedef QHash<QString, Peer> PeerList;
|
||||
typedef QHash<QString, PeerList> TorrentList;
|
||||
|
||||
/* Basic Bittorrent tracker implementation in Qt */
|
||||
/* Following http://wiki.theory.org/BitTorrent_Tracker_Protocol */
|
||||
class Tracker : public Http::ResponseBuilder, public Http::IRequestHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Tracker)
|
||||
|
||||
public:
|
||||
explicit Tracker(QObject *parent = 0);
|
||||
~Tracker();
|
||||
|
||||
bool start();
|
||||
Http::Response processRequest(const Http::Request &request, const Http::Environment &env);
|
||||
|
||||
private:
|
||||
void respondToAnnounceRequest();
|
||||
void replyWithPeerList(const TrackerAnnounceRequest &annonceReq);
|
||||
|
||||
Http::Server *m_server;
|
||||
TorrentList m_torrents;
|
||||
|
||||
Http::Request m_request;
|
||||
Http::Environment m_env;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // BITTORRENT_TRACKER_H
|
||||
93
src/core/bittorrent/trackerentry.cpp
Normal file
93
src/core/bittorrent/trackerentry.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "core/misc.h"
|
||||
#include "core/utils/string.h"
|
||||
#include "trackerentry.h"
|
||||
|
||||
using namespace BitTorrent;
|
||||
|
||||
TrackerEntry::TrackerEntry(const QString &url)
|
||||
: m_nativeEntry(libtorrent::announce_entry(String::toStdString(url)))
|
||||
{
|
||||
}
|
||||
|
||||
TrackerEntry::TrackerEntry(const libtorrent::announce_entry &nativeEntry)
|
||||
: m_nativeEntry(nativeEntry)
|
||||
{
|
||||
}
|
||||
|
||||
TrackerEntry::TrackerEntry(const TrackerEntry &other)
|
||||
: m_nativeEntry(other.m_nativeEntry)
|
||||
{
|
||||
}
|
||||
|
||||
QString TrackerEntry::url() const
|
||||
{
|
||||
return String::fromStdString(m_nativeEntry.url);
|
||||
}
|
||||
|
||||
int TrackerEntry::tier() const
|
||||
{
|
||||
return m_nativeEntry.tier;
|
||||
}
|
||||
|
||||
TrackerEntry::Status TrackerEntry::status() const
|
||||
{
|
||||
if (m_nativeEntry.verified)
|
||||
return Working;
|
||||
else if ((m_nativeEntry.fails == 0) && m_nativeEntry.updating)
|
||||
return Updating;
|
||||
else if (m_nativeEntry.fails == 0)
|
||||
return NotContacted;
|
||||
else
|
||||
return NotWorking;
|
||||
}
|
||||
|
||||
void TrackerEntry::setTier(int value)
|
||||
{
|
||||
m_nativeEntry.tier = value;
|
||||
}
|
||||
|
||||
TrackerEntry &TrackerEntry::operator=(const TrackerEntry &other)
|
||||
{
|
||||
this->m_nativeEntry = other.m_nativeEntry;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool TrackerEntry::operator==(const TrackerEntry &other)
|
||||
{
|
||||
return (QUrl(url()) == QUrl(other.url()));
|
||||
}
|
||||
|
||||
libtorrent::announce_entry TrackerEntry::nativeEntry() const
|
||||
{
|
||||
return m_nativeEntry;
|
||||
}
|
||||
68
src/core/bittorrent/trackerentry.h
Normal file
68
src/core/bittorrent/trackerentry.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef BITTORRENT_TRACKERENTRY_H
|
||||
#define BITTORRENT_TRACKERENTRY_H
|
||||
|
||||
#include <libtorrent/torrent_info.hpp>
|
||||
|
||||
class QString;
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class TrackerEntry
|
||||
{
|
||||
public:
|
||||
enum Status
|
||||
{
|
||||
NotContacted,
|
||||
Working,
|
||||
Updating,
|
||||
NotWorking
|
||||
};
|
||||
|
||||
TrackerEntry(const QString &url);
|
||||
TrackerEntry(const libtorrent::announce_entry &nativeEntry);
|
||||
TrackerEntry(const TrackerEntry &other);
|
||||
|
||||
QString url() const;
|
||||
int tier() const;
|
||||
Status status() const;
|
||||
|
||||
void setTier(int value);
|
||||
TrackerEntry &operator=(const TrackerEntry &other);
|
||||
bool operator==(const TrackerEntry &other);
|
||||
|
||||
libtorrent::announce_entry nativeEntry() const;
|
||||
|
||||
private:
|
||||
libtorrent::announce_entry m_nativeEntry;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // BITTORRENT_TRACKERENTRY_H
|
||||
@@ -1,16 +1,13 @@
|
||||
include(qtlibtorrent/qtlibtorrent.pri)
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/types.h \
|
||||
$$PWD/misc.h \
|
||||
$$PWD/fs_utils.h \
|
||||
$$PWD/downloadthread.h \
|
||||
$$PWD/torrentpersistentdata.h \
|
||||
$$PWD/tristatebool.h \
|
||||
$$PWD/filesystemwatcher.h \
|
||||
$$PWD/scannedfoldersmodel.h \
|
||||
$$PWD/qinisettings.h \
|
||||
$$PWD/logger.h \
|
||||
$$PWD/preferences.h \
|
||||
$$PWD/qtracker.h \
|
||||
$$PWD/iconprovider.h \
|
||||
$$PWD/http/irequesthandler.h \
|
||||
$$PWD/http/connection.h \
|
||||
$$PWD/http/requestparser.h \
|
||||
@@ -19,24 +16,66 @@ HEADERS += \
|
||||
$$PWD/http/types.h \
|
||||
$$PWD/http/responsebuilder.h \
|
||||
$$PWD/net/dnsupdater.h \
|
||||
$$PWD/net/downloadmanager.h \
|
||||
$$PWD/net/downloadhandler.h \
|
||||
$$PWD/net/portforwarder.h \
|
||||
$$PWD/net/reverseresolution.h \
|
||||
$$PWD/net/smtp.h
|
||||
$$PWD/net/smtp.h \
|
||||
$$PWD/bittorrent/infohash.h \
|
||||
$$PWD/bittorrent/session.h \
|
||||
$$PWD/bittorrent/sessionstatus.h \
|
||||
$$PWD/bittorrent/cachestatus.h \
|
||||
$$PWD/bittorrent/magneturi.h \
|
||||
$$PWD/bittorrent/torrentinfo.h \
|
||||
$$PWD/bittorrent/torrenthandle.h \
|
||||
$$PWD/bittorrent/peerinfo.h \
|
||||
$$PWD/bittorrent/trackerentry.h \
|
||||
$$PWD/bittorrent/tracker.h \
|
||||
$$PWD/bittorrent/torrentcreatorthread.h \
|
||||
$$PWD/bittorrent/private/sessionprivate.h \
|
||||
$$PWD/bittorrent/private/torrenthandleprivate.h \
|
||||
$$PWD/bittorrent/private/speedmonitor.h \
|
||||
$$PWD/bittorrent/private/bandwidthscheduler.h \
|
||||
$$PWD/bittorrent/private/filterparserthread.h \
|
||||
$$PWD/bittorrent/private/statistics.h \
|
||||
$$PWD/utils/string.h \
|
||||
$$PWD/torrentfilter.h \
|
||||
$$PWD/scanfoldersmodel.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/downloadthread.cpp \
|
||||
$$PWD/scannedfoldersmodel.cpp \
|
||||
$$PWD/torrentpersistentdata.cpp \
|
||||
$$PWD/filesystemwatcher.cpp \
|
||||
$$PWD/misc.cpp \
|
||||
$$PWD/fs_utils.cpp \
|
||||
$$PWD/tristatebool.cpp \
|
||||
$$PWD/filesystemwatcher.cpp \
|
||||
$$PWD/logger.cpp \
|
||||
$$PWD/preferences.cpp \
|
||||
$$PWD/qtracker.cpp \
|
||||
$$PWD/iconprovider.cpp \
|
||||
$$PWD/http/connection.cpp \
|
||||
$$PWD/http/requestparser.cpp \
|
||||
$$PWD/http/responsegenerator.cpp \
|
||||
$$PWD/http/server.cpp \
|
||||
$$PWD/http/responsebuilder.cpp \
|
||||
$$PWD/net/dnsupdater.cpp \
|
||||
$$PWD/net/downloadmanager.cpp \
|
||||
$$PWD/net/downloadhandler.cpp \
|
||||
$$PWD/net/portforwarder.cpp \
|
||||
$$PWD/net/reverseresolution.cpp \
|
||||
$$PWD/net/smtp.cpp
|
||||
$$PWD/net/smtp.cpp \
|
||||
$$PWD/bittorrent/infohash.cpp \
|
||||
$$PWD/bittorrent/session.cpp \
|
||||
$$PWD/bittorrent/sessionstatus.cpp \
|
||||
$$PWD/bittorrent/cachestatus.cpp \
|
||||
$$PWD/bittorrent/magneturi.cpp \
|
||||
$$PWD/bittorrent/torrentinfo.cpp \
|
||||
$$PWD/bittorrent/torrenthandle.cpp \
|
||||
$$PWD/bittorrent/peerinfo.cpp \
|
||||
$$PWD/bittorrent/trackerentry.cpp \
|
||||
$$PWD/bittorrent/tracker.cpp \
|
||||
$$PWD/bittorrent/torrentcreatorthread.cpp \
|
||||
$$PWD/bittorrent/private/speedmonitor.cpp \
|
||||
$$PWD/bittorrent/private/bandwidthscheduler.cpp \
|
||||
$$PWD/bittorrent/private/filterparserthread.cpp \
|
||||
$$PWD/bittorrent/private/statistics.cpp \
|
||||
$$PWD/utils/string.cpp \
|
||||
$$PWD/torrentfilter.cpp \
|
||||
$$PWD/scanfoldersmodel.cpp
|
||||
|
||||
@@ -12,8 +12,10 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "fs_utils.h"
|
||||
#include "misc.h"
|
||||
#include "core/preferences.h"
|
||||
#include "core/bittorrent/torrentinfo.h"
|
||||
#include "core/bittorrent/magneturi.h"
|
||||
#include "filesystemwatcher.h"
|
||||
|
||||
#ifndef CIFS_MAGIC_NUMBER
|
||||
#define CIFS_MAGIC_NUMBER 0xFF534D42
|
||||
@@ -30,8 +32,6 @@
|
||||
const int WATCH_INTERVAL = 10000; // 10 sec
|
||||
const int MAX_PARTIAL_RETRIES = 5;
|
||||
|
||||
#include "filesystemwatcher.h"
|
||||
|
||||
FileSystemWatcher::FileSystemWatcher(QObject *parent)
|
||||
: QFileSystemWatcher(parent)
|
||||
{
|
||||
@@ -149,7 +149,7 @@ void FileSystemWatcher::processPartialTorrents()
|
||||
if (!QFile::exists(torrentPath)) {
|
||||
m_partialTorrents.remove(torrentPath);
|
||||
}
|
||||
else if (fsutils::isValidTorrentFile(torrentPath)) {
|
||||
else if (BitTorrent::TorrentInfo::loadFromFile(torrentPath).isValid()) {
|
||||
noLongerPartial << torrentPath;
|
||||
m_partialTorrents.remove(torrentPath);
|
||||
}
|
||||
@@ -197,11 +197,11 @@ void FileSystemWatcher::addTorrentsFromDir(const QDir &dir, QStringList &torrent
|
||||
if (fileAbsPath.endsWith(".magnet")) {
|
||||
QFile f(fileAbsPath);
|
||||
if (f.open(QIODevice::ReadOnly)
|
||||
&& !misc::magnetUriToHash(QString::fromLocal8Bit(f.readAll())).isEmpty()) {
|
||||
&& !BitTorrent::MagnetUri(QString::fromLocal8Bit(f.readAll())).isValid()) {
|
||||
torrents << fileAbsPath;
|
||||
}
|
||||
}
|
||||
else if (fsutils::isValidTorrentFile(fileAbsPath)) {
|
||||
else if (BitTorrent::TorrentInfo::loadFromFile(fileAbsPath).isValid()) {
|
||||
torrents << fileAbsPath;
|
||||
}
|
||||
else if (!m_partialTorrents.contains(fileAbsPath)) {
|
||||
|
||||
@@ -25,7 +25,7 @@ public:
|
||||
void removePath(const QString &path);
|
||||
|
||||
signals:
|
||||
void torrentsAdded(QStringList &pathList);
|
||||
void torrentsAdded(const QStringList &pathList);
|
||||
|
||||
protected slots:
|
||||
void scanLocalFolder(QString path);
|
||||
|
||||
@@ -36,11 +36,7 @@
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QSettings>
|
||||
#ifdef DISABLE_GUI
|
||||
#include <QCoreApplication>
|
||||
#else
|
||||
#include <QApplication>
|
||||
#endif
|
||||
#include <libtorrent/torrent_info.hpp>
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
@@ -110,17 +106,6 @@ QString fsutils::folderName(const QString& file_path) {
|
||||
return path.left(slash_index);
|
||||
}
|
||||
|
||||
bool fsutils::isValidTorrentFile(const QString& torrent_path) {
|
||||
try {
|
||||
boost::intrusive_ptr<libtorrent::torrent_info> t = new torrent_info(fsutils::toNativePath(torrent_path).toUtf8().constData());
|
||||
if (!t->is_valid() || t->num_files() == 0)
|
||||
return false;
|
||||
} catch(std::exception&) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an empty folder tree.
|
||||
*
|
||||
@@ -233,38 +218,6 @@ bool fsutils::sameFiles(const QString& path1, const QString& path2) {
|
||||
return same;
|
||||
}
|
||||
|
||||
QString fsutils::updateLabelInSavePath(const QString& defaultSavePath, const QString& save_path, const QString& old_label, const QString& new_label) {
|
||||
if (old_label == new_label) return fsutils::fromNativePath(save_path);
|
||||
QString defaultPath = fsutils::fromNativePath(defaultSavePath);
|
||||
QString path = fsutils::fromNativePath(save_path);
|
||||
qDebug("UpdateLabelInSavePath(%s, %s, %s)", qPrintable(path), qPrintable(old_label), qPrintable(new_label));
|
||||
if (!path.startsWith(defaultPath)) return path;
|
||||
QString new_save_path = path;
|
||||
new_save_path.remove(defaultPath);
|
||||
QStringList path_parts = new_save_path.split("/", QString::SkipEmptyParts);
|
||||
if (path_parts.empty()) {
|
||||
if (!new_label.isEmpty())
|
||||
path_parts << new_label;
|
||||
} else {
|
||||
if (old_label.isEmpty() || path_parts.first() != old_label) {
|
||||
if (path_parts.first() != new_label)
|
||||
path_parts.prepend(new_label);
|
||||
} else {
|
||||
if (new_label.isEmpty()) {
|
||||
path_parts.removeAt(0);
|
||||
} else {
|
||||
if (path_parts.first() != new_label)
|
||||
path_parts.replace(0, new_label);
|
||||
}
|
||||
}
|
||||
}
|
||||
new_save_path = defaultPath;
|
||||
if (!new_save_path.endsWith("/")) new_save_path += "/";
|
||||
new_save_path += path_parts.join("/");
|
||||
qDebug("New save path is %s", qPrintable(new_save_path));
|
||||
return new_save_path;
|
||||
}
|
||||
|
||||
QString fsutils::toValidFileSystemName(QString filename) {
|
||||
qDebug("toValidFSName: %s", qPrintable(filename));
|
||||
const QRegExp regex("[\\\\/:?\"*<>|]");
|
||||
@@ -513,15 +466,6 @@ QString fsutils::searchEngineLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
QString fsutils::BTBackupLocation() {
|
||||
const QString location = fsutils::expandPathAbs(QDesktopServicesDataLocation()
|
||||
+ "BT_backup");
|
||||
QDir locationDir(location);
|
||||
if (!locationDir.exists())
|
||||
locationDir.mkpath(locationDir.absolutePath());
|
||||
return location;
|
||||
}
|
||||
|
||||
QString fsutils::cacheLocation() {
|
||||
QString location = fsutils::expandPathAbs(QDesktopServicesCacheLocation());
|
||||
QDir locationDir(location);
|
||||
|
||||
@@ -46,7 +46,6 @@ namespace fsutils
|
||||
QString folderName(const QString& file_path);
|
||||
qint64 computePathSize(const QString& path);
|
||||
bool sameFiles(const QString& path1, const QString& path2);
|
||||
QString updateLabelInSavePath(const QString &defaultSavePath, const QString &save_path, const QString& old_label, const QString& new_label);
|
||||
QString toValidFileSystemName(QString filename);
|
||||
bool isValidFileSystemName(const QString& filename);
|
||||
long long freeDiskSpaceOnPath(QString path);
|
||||
@@ -54,7 +53,6 @@ namespace fsutils
|
||||
bool sameFileNames(const QString& first, const QString& second);
|
||||
QString expandPath(const QString& path);
|
||||
QString expandPathAbs(const QString& path);
|
||||
bool isValidTorrentFile(const QString& path);
|
||||
bool smartRemoveEmptyFolderTree(const QString& dir_path);
|
||||
bool forceRemove(const QString& file_path);
|
||||
|
||||
@@ -64,7 +62,6 @@ namespace fsutils
|
||||
QString QDesktopServicesDownloadLocation();
|
||||
/* End of Qt4 code */
|
||||
QString searchEngineLocation();
|
||||
QString BTBackupLocation();
|
||||
QString cacheLocation();
|
||||
|
||||
}
|
||||
|
||||
64
src/core/iconprovider.cpp
Normal file
64
src/core/iconprovider.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2011 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include <QString>
|
||||
#include "iconprovider.h"
|
||||
|
||||
IconProvider::IconProvider(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
IconProvider::~IconProvider() {}
|
||||
|
||||
void IconProvider::initInstance()
|
||||
{
|
||||
if (!m_instance)
|
||||
m_instance = new IconProvider;
|
||||
}
|
||||
|
||||
void IconProvider::freeInstance()
|
||||
{
|
||||
if (m_instance) {
|
||||
delete m_instance;
|
||||
m_instance = 0;
|
||||
}
|
||||
}
|
||||
|
||||
IconProvider *IconProvider::instance()
|
||||
{
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
QString IconProvider::getIconPath(const QString &iconId)
|
||||
{
|
||||
return ":/icons/oxygen/" + iconId + ".png";
|
||||
}
|
||||
|
||||
IconProvider *IconProvider::m_instance = 0;
|
||||
55
src/core/iconprovider.h
Normal file
55
src/core/iconprovider.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2011 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef ICONPROVIDER_H
|
||||
#define ICONPROVIDER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class QString;
|
||||
|
||||
class IconProvider : public QObject
|
||||
{
|
||||
Q_DISABLE_COPY(IconProvider)
|
||||
|
||||
public:
|
||||
static void initInstance();
|
||||
static void freeInstance();
|
||||
static IconProvider *instance();
|
||||
|
||||
virtual QString getIconPath(const QString &iconId);
|
||||
|
||||
protected:
|
||||
explicit IconProvider(QObject *parent = 0);
|
||||
~IconProvider();
|
||||
|
||||
static IconProvider *m_instance;
|
||||
};
|
||||
|
||||
#endif // ICONPROVIDER_H
|
||||
@@ -44,15 +44,18 @@ Logger::Logger()
|
||||
|
||||
Logger::~Logger() {}
|
||||
|
||||
Logger * Logger::instance()
|
||||
Logger *Logger::instance()
|
||||
{
|
||||
if (!m_instance)
|
||||
m_instance = new Logger;
|
||||
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
void Logger::drop()
|
||||
void Logger::initInstance()
|
||||
{
|
||||
if (!m_instance)
|
||||
m_instance = new Logger;
|
||||
}
|
||||
|
||||
void Logger::freeInstance()
|
||||
{
|
||||
if (m_instance) {
|
||||
delete m_instance;
|
||||
|
||||
@@ -53,9 +53,9 @@ class Logger : public QObject
|
||||
Q_DISABLE_COPY(Logger)
|
||||
|
||||
public:
|
||||
static Logger* instance();
|
||||
static void drop();
|
||||
~Logger();
|
||||
static void initInstance();
|
||||
static void freeInstance();
|
||||
static Logger *instance();
|
||||
|
||||
void addMessage(const QString &message, const Log::MsgType &type = Log::NORMAL);
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
@@ -72,6 +72,8 @@ signals:
|
||||
|
||||
private:
|
||||
Logger();
|
||||
~Logger();
|
||||
|
||||
static Logger* m_instance;
|
||||
QVector<Log::Msg> m_messages;
|
||||
QVector<Log::Peer> m_peers;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -28,8 +28,6 @@
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <QUrl>
|
||||
@@ -71,14 +69,7 @@ const int UNLEN = 256;
|
||||
#endif
|
||||
#endif // DISABLE_GUI
|
||||
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
#include <libtorrent/peer_id.hpp>
|
||||
#else
|
||||
#include <libtorrent/sha1_hash.hpp>
|
||||
#endif
|
||||
#include <libtorrent/magnet_uri.hpp>
|
||||
|
||||
using namespace libtorrent;
|
||||
#include "misc.h"
|
||||
|
||||
static struct { const char *source; const char *comment; } units[] = {
|
||||
QT_TRANSLATE_NOOP3("misc", "B", "bytes"),
|
||||
@@ -88,35 +79,8 @@ static struct { const char *source; const char *comment; } units[] = {
|
||||
QT_TRANSLATE_NOOP3("misc", "TiB", "tebibytes (1024 gibibytes)")
|
||||
};
|
||||
|
||||
QString misc::toQString(const std::string &str)
|
||||
{
|
||||
return QString::fromLocal8Bit(str.c_str());
|
||||
}
|
||||
|
||||
QString misc::toQString(const char* str)
|
||||
{
|
||||
return QString::fromLocal8Bit(str);
|
||||
}
|
||||
|
||||
QString misc::toQStringU(const std::string &str)
|
||||
{
|
||||
return QString::fromUtf8(str.c_str());
|
||||
}
|
||||
|
||||
QString misc::toQStringU(const char* str)
|
||||
{
|
||||
return QString::fromUtf8(str);
|
||||
}
|
||||
|
||||
QString misc::toQString(const libtorrent::sha1_hash &hash)
|
||||
{
|
||||
char out[41];
|
||||
libtorrent::to_hex((char const*)&hash[0], libtorrent::sha1_hash::size, out);
|
||||
return QString(out);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
void misc::shutdownComputer(shutDownAction action)
|
||||
void misc::shutdownComputer(ShutDownAction action)
|
||||
{
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) && defined(QT_DBUS_LIB)
|
||||
// Use dbus to power off / suspend the system
|
||||
@@ -378,28 +342,6 @@ QString misc::bcLinkToMagnet(QString bc_link)
|
||||
return magnet;
|
||||
}
|
||||
|
||||
QString misc::magnetUriToName(const QString& magnet_uri)
|
||||
{
|
||||
add_torrent_params p;
|
||||
error_code ec;
|
||||
parse_magnet_uri(magnet_uri.toUtf8().constData(), p, ec);
|
||||
|
||||
if (ec)
|
||||
return QString::null;
|
||||
return toQStringU(p.name);
|
||||
}
|
||||
|
||||
QString misc::magnetUriToHash(const QString& magnet_uri)
|
||||
{
|
||||
add_torrent_params p;
|
||||
error_code ec;
|
||||
parse_magnet_uri(magnet_uri.toUtf8().constData(), p, ec);
|
||||
|
||||
if (ec)
|
||||
return QString::null;
|
||||
return toQString(p.info_hash);
|
||||
}
|
||||
|
||||
// Take a number of seconds and return an user-friendly
|
||||
// time duration like "1d 2h 10m".
|
||||
QString misc::userFriendlyDuration(qlonglong seconds)
|
||||
@@ -530,11 +472,6 @@ QString misc::parseHtmlLinks(const QString &raw_text)
|
||||
return result;
|
||||
}
|
||||
|
||||
QString misc::toQString(time_t t)
|
||||
{
|
||||
return QDateTime::fromTime_t(t).toString(Qt::DefaultLocaleLongDate);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
bool misc::naturalSort(QString left, QString right, bool &result) // uses lessThan comparison
|
||||
{ // Return value indicates if functions was successful
|
||||
@@ -624,18 +561,6 @@ bool misc::slowEquals(const QByteArray &a, const QByteArray &b)
|
||||
return (diff == 0);
|
||||
}
|
||||
|
||||
void misc::loadBencodedFile(const QString &filename, std::vector<char> &buffer, libtorrent::lazy_entry &entry, libtorrent::error_code &ec)
|
||||
{
|
||||
QFile file(filename);
|
||||
if (!file.open(QIODevice::ReadOnly)) return;
|
||||
const qint64 content_size = file.bytesAvailable();
|
||||
if (content_size <= 0) return;
|
||||
buffer.resize(content_size);
|
||||
file.read(&buffer[0], content_size);
|
||||
// bdecode
|
||||
lazy_bdecode(&buffer[0], &buffer[0] + buffer.size(), entry, ec);
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Trick to get a portable sleep() function
|
||||
class SleeperThread: public QThread {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -39,37 +39,18 @@
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QUrl>
|
||||
#ifndef DISABLE_GUI
|
||||
#include <QIcon>
|
||||
#endif
|
||||
|
||||
#include <libtorrent/version.hpp>
|
||||
#include <libtorrent/error_code.hpp>
|
||||
|
||||
namespace libtorrent {
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
class big_number;
|
||||
typedef big_number sha1_hash;
|
||||
#else
|
||||
class sha1_hash;
|
||||
#endif
|
||||
struct lazy_entry;
|
||||
}
|
||||
namespace BitTorrent { class TorrentHandle; }
|
||||
|
||||
const qlonglong MAX_ETA = 8640000;
|
||||
enum shutDownAction { NO_SHUTDOWN, SHUTDOWN_COMPUTER, SUSPEND_COMPUTER, HIBERNATE_COMPUTER };
|
||||
enum ShutDownAction { NO_SHUTDOWN, SHUTDOWN_COMPUTER, SUSPEND_COMPUTER, HIBERNATE_COMPUTER };
|
||||
|
||||
/* Miscellaneaous functions that can be useful */
|
||||
namespace misc
|
||||
{
|
||||
QString toQString(const std::string &str);
|
||||
QString toQString(const char* str);
|
||||
QString toQStringU(const std::string &str);
|
||||
QString toQStringU(const char* str);
|
||||
QString toQString(const libtorrent::sha1_hash &hash);
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
void shutdownComputer(shutDownAction action = SHUTDOWN_COMPUTER);
|
||||
void shutdownComputer(ShutDownAction action = SHUTDOWN_COMPUTER);
|
||||
#endif
|
||||
|
||||
QString parseHtmlLinks(const QString &raw_text);
|
||||
@@ -87,8 +68,7 @@ namespace misc
|
||||
// value must be given in bytes
|
||||
QString friendlyUnit(qreal val, bool is_speed = false);
|
||||
bool isPreviewable(const QString& extension);
|
||||
QString magnetUriToName(const QString& magnet_uri);
|
||||
QString magnetUriToHash(const QString& magnet_uri);
|
||||
|
||||
QString bcLinkToMagnet(QString bc_link);
|
||||
// Take a number of seconds and return an user-friendly
|
||||
// time duration like "1d 2h 10m".
|
||||
@@ -100,7 +80,6 @@ namespace misc
|
||||
QList<int> intListfromStringList(const QStringList &l);
|
||||
QList<bool> boolListfromStringList(const QStringList &l);
|
||||
|
||||
QString toQString(time_t t);
|
||||
QString accurateDoubleToString(const double &n, const int &precision);
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
@@ -110,8 +89,6 @@ namespace misc
|
||||
// Implements constant-time comparison to protect against timing attacks
|
||||
// Taken from https://crackstation.net/hashing-security.htm
|
||||
bool slowEquals(const QByteArray &a, const QByteArray &b);
|
||||
void loadBencodedFile(const QString &filename, std::vector<char> &buffer, libtorrent::lazy_entry &entry, libtorrent::error_code &ec);
|
||||
|
||||
void msleep(unsigned long msecs);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,12 +33,13 @@
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkProxy>
|
||||
#include <QNetworkCookie>
|
||||
#include <QUrl>
|
||||
#include <QDebug>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include "fs_utils.h"
|
||||
#include "misc.h"
|
||||
#include "core/fs_utils.h"
|
||||
#include "core/misc.h"
|
||||
#include "downloadmanager.h"
|
||||
#include "downloadhandler.h"
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
class QUrl;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Net
|
||||
|
||||
160
src/core/net/portforwarder.cpp
Normal file
160
src/core/net/portforwarder.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <libtorrent/session.hpp>
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
#include <libtorrent/upnp.hpp>
|
||||
#include <libtorrent/natpmp.hpp>
|
||||
#endif
|
||||
|
||||
#include "core/logger.h"
|
||||
#include "core/preferences.h"
|
||||
#include "portforwarder.h"
|
||||
|
||||
namespace libt = libtorrent;
|
||||
using namespace Net;
|
||||
|
||||
PortForwarder::PortForwarder(libtorrent::session *provider, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_active(false)
|
||||
, m_provider(provider)
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
, m_upnp(0)
|
||||
, m_natpmp(0)
|
||||
#endif
|
||||
{
|
||||
configure();
|
||||
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure()));
|
||||
}
|
||||
|
||||
PortForwarder::~PortForwarder()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void PortForwarder::initInstance(libtorrent::session *const provider)
|
||||
{
|
||||
if (!m_instance)
|
||||
m_instance = new PortForwarder(provider);
|
||||
}
|
||||
|
||||
void PortForwarder::freeInstance()
|
||||
{
|
||||
if (m_instance) {
|
||||
delete m_instance;
|
||||
m_instance = 0;
|
||||
}
|
||||
}
|
||||
|
||||
PortForwarder *PortForwarder::instance()
|
||||
{
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
void PortForwarder::addPort(qint16 port)
|
||||
{
|
||||
if (!m_mappedPorts.contains(port)) {
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
m_mappedPorts.insert(port, qMakePair(0, 0));
|
||||
#else
|
||||
m_mappedPorts.insert(port, 0);
|
||||
#endif
|
||||
if (m_active) {
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
m_mappedPorts[port].first = m_upnp->add_mapping(libt::upnp::tcp, port, port);
|
||||
m_mappedPorts[port].second = m_natpmp->add_mapping(libt::natpmp::tcp, port, port);
|
||||
#else
|
||||
m_mappedPorts[port] = m_provider->add_port_mapping(libt::session::tcp, port, port);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PortForwarder::deletePort(qint16 port)
|
||||
{
|
||||
if (m_mappedPorts.contains(port)) {
|
||||
if (m_active) {
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
m_upnp->delete_mapping(m_mappedPorts[port].first);
|
||||
m_natpmp->delete_mapping(m_mappedPorts[port].second);
|
||||
#else
|
||||
m_provider->delete_port_mapping(m_mappedPorts[port]);
|
||||
#endif
|
||||
}
|
||||
m_mappedPorts.remove(port);
|
||||
}
|
||||
}
|
||||
|
||||
void PortForwarder::configure()
|
||||
{
|
||||
bool enable = Preferences::instance()->isUPnPEnabled();
|
||||
if (m_active != enable) {
|
||||
if (enable)
|
||||
start();
|
||||
else
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
void PortForwarder::start()
|
||||
{
|
||||
qDebug("Enabling UPnP / NAT-PMP");
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
m_upnp = m_provider->start_upnp();
|
||||
m_natpmp = m_provider->start_natpmp();
|
||||
foreach (qint16 port, m_mappedPorts.keys()) {
|
||||
m_mappedPorts[port].first = m_upnp->add_mapping(libt::upnp::tcp, port, port);
|
||||
m_mappedPorts[port].second = m_natpmp->add_mapping(libt::natpmp::tcp, port, port);
|
||||
}
|
||||
#else
|
||||
m_provider->start_upnp();
|
||||
m_provider->start_natpmp();
|
||||
foreach (qint16 port, m_mappedPorts.keys())
|
||||
m_mappedPorts[port] = m_provider->add_port_mapping(libt::session::tcp, port, port);
|
||||
#endif
|
||||
m_active = true;
|
||||
Logger::instance()->addMessage(tr("UPnP / NAT-PMP support [ON]"), Log::INFO);
|
||||
}
|
||||
|
||||
void PortForwarder::stop()
|
||||
{
|
||||
qDebug("Disabling UPnP / NAT-PMP");
|
||||
m_provider->stop_upnp();
|
||||
m_provider->stop_natpmp();
|
||||
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
m_upnp = 0;
|
||||
m_natpmp = 0;
|
||||
#endif
|
||||
m_active = false;
|
||||
Logger::instance()->addMessage(tr("UPnP / NAT-PMP support [OFF]"), Log::INFO);
|
||||
}
|
||||
|
||||
PortForwarder *PortForwarder::m_instance = 0;
|
||||
84
src/core/net/portforwarder.h
Normal file
84
src/core/net/portforwarder.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef NET_PORTFORWARDER_H
|
||||
#define NET_PORTFORWARDER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QHash>
|
||||
#include <libtorrent/version.hpp>
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
class upnp;
|
||||
class natpmp;
|
||||
#endif
|
||||
class session;
|
||||
}
|
||||
|
||||
namespace Net
|
||||
{
|
||||
class PortForwarder : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(PortForwarder)
|
||||
|
||||
public:
|
||||
static void initInstance(libtorrent::session *const provider);
|
||||
static void freeInstance();
|
||||
static PortForwarder *instance();
|
||||
|
||||
void addPort(qint16 port);
|
||||
void deletePort(qint16 port);
|
||||
|
||||
private slots:
|
||||
void configure();
|
||||
|
||||
private:
|
||||
explicit PortForwarder(libtorrent::session *const provider, QObject *parent = 0);
|
||||
~PortForwarder();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
bool m_active;
|
||||
libtorrent::session *m_provider;
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
libtorrent::upnp *m_upnp;
|
||||
libtorrent::natpmp *m_natpmp;
|
||||
QHash<qint16, QPair<int, int> > m_mappedPorts;
|
||||
#else
|
||||
QHash<qint16, int> m_mappedPorts;
|
||||
#endif
|
||||
|
||||
static PortForwarder *m_instance;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NET_PORTFORWARDER_H
|
||||
@@ -116,15 +116,18 @@ Preferences::~Preferences()
|
||||
save();
|
||||
}
|
||||
|
||||
Preferences * Preferences::instance()
|
||||
Preferences *Preferences::instance()
|
||||
{
|
||||
if (!m_instance)
|
||||
m_instance = new Preferences;
|
||||
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
void Preferences::drop()
|
||||
void Preferences::initInstance()
|
||||
{
|
||||
if (!m_instance)
|
||||
m_instance = new Preferences;
|
||||
}
|
||||
|
||||
void Preferences::freeInstance()
|
||||
{
|
||||
if (m_instance) {
|
||||
delete m_instance;
|
||||
@@ -132,12 +135,11 @@ void Preferences::drop()
|
||||
}
|
||||
}
|
||||
|
||||
void Preferences::save()
|
||||
bool Preferences::save()
|
||||
{
|
||||
QReadLocker locker(&lock);
|
||||
|
||||
if (!dirty)
|
||||
return;
|
||||
if (!dirty) return false;
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
// QSettings delete the file before writing it out. This can result in problems
|
||||
@@ -160,7 +162,7 @@ void Preferences::save()
|
||||
settings->sync(); // Important to get error status
|
||||
if (settings->status() == QSettings::AccessError) {
|
||||
delete settings;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
QString new_path = settings->fileName();
|
||||
delete settings;
|
||||
@@ -173,7 +175,7 @@ void Preferences::save()
|
||||
delete settings;
|
||||
#endif
|
||||
|
||||
emit changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
const QVariant Preferences::value(const QString &key, const QVariant &defaultValue) const
|
||||
@@ -950,12 +952,12 @@ void Preferences::setGlobalMaxRatio(qreal ratio)
|
||||
setValue("Preferences/Bittorrent/MaxRatio", ratio);
|
||||
}
|
||||
|
||||
int Preferences::getMaxRatioAction() const
|
||||
MaxRatioAction Preferences::getMaxRatioAction() const
|
||||
{
|
||||
return value("Preferences/Bittorrent/MaxRatioAction", PAUSE_ACTION).toInt();
|
||||
return value("Preferences/Bittorrent/MaxRatioAction", MaxRatioAction::Pause).toInt();
|
||||
}
|
||||
|
||||
void Preferences::setMaxRatioAction(int act)
|
||||
void Preferences::setMaxRatioAction(MaxRatioAction act)
|
||||
{
|
||||
setValue("Preferences/Bittorrent/MaxRatioAction", act);
|
||||
}
|
||||
@@ -2477,3 +2479,9 @@ void Preferences::setHostNameCookies(const QString &host_name, const QList<QByte
|
||||
hosts_table.insert(host_name, raw_cookies);
|
||||
setValue("Rss/hosts_cookies", hosts_table);
|
||||
}
|
||||
|
||||
void Preferences::apply()
|
||||
{
|
||||
if (save())
|
||||
emit changed();
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@
|
||||
|
||||
#include <libtorrent/version.hpp>
|
||||
|
||||
#include "core/types.h"
|
||||
|
||||
enum scheduler_days
|
||||
{
|
||||
EVERY_DAY,
|
||||
@@ -57,12 +59,6 @@ enum scheduler_days
|
||||
SUN
|
||||
};
|
||||
|
||||
enum maxRatioAction
|
||||
{
|
||||
PAUSE_ACTION,
|
||||
REMOVE_ACTION
|
||||
};
|
||||
|
||||
namespace Proxy
|
||||
{
|
||||
enum ProxyType
|
||||
@@ -101,7 +97,9 @@ class Preferences: public QObject
|
||||
Q_DISABLE_COPY(Preferences)
|
||||
|
||||
private:
|
||||
explicit Preferences();
|
||||
Preferences();
|
||||
~Preferences();
|
||||
|
||||
static Preferences* m_instance;
|
||||
QHash<QString, QVariant> m_data;
|
||||
int m_randomPort;
|
||||
@@ -111,16 +109,16 @@ private:
|
||||
const QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
|
||||
void setValue(const QString &key, const QVariant &value);
|
||||
|
||||
private slots:
|
||||
bool save();
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
|
||||
public slots:
|
||||
void save();
|
||||
|
||||
public:
|
||||
static void initInstance();
|
||||
static void freeInstance();
|
||||
static Preferences* instance();
|
||||
static void drop();
|
||||
~Preferences();
|
||||
|
||||
// General options
|
||||
QString getLocale() const;
|
||||
@@ -276,8 +274,8 @@ public:
|
||||
void setEncryptionSetting(int val);
|
||||
qreal getGlobalMaxRatio() const;
|
||||
void setGlobalMaxRatio(qreal ratio);
|
||||
int getMaxRatioAction() const;
|
||||
void setMaxRatioAction(int act);
|
||||
MaxRatioAction getMaxRatioAction() const;
|
||||
void setMaxRatioAction(MaxRatioAction act);
|
||||
|
||||
// IP Filter
|
||||
bool isFilteringEnabled() const;
|
||||
@@ -536,6 +534,8 @@ public slots:
|
||||
void setStatusFilterState(bool checked);
|
||||
void setLabelFilterState(bool checked);
|
||||
void setTrackerFilterState(bool checked);
|
||||
|
||||
void apply();
|
||||
};
|
||||
|
||||
#endif // PREFERENCES_H
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
#ifndef BANDWIDTHSCHEDULER_H
|
||||
#define BANDWIDTHSCHEDULER_H
|
||||
|
||||
#include <QTimer>
|
||||
#include <QTime>
|
||||
#include <QDateTime>
|
||||
#include "core/preferences.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
class BandwidthScheduler: public QTimer {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BandwidthScheduler(QObject *parent): QTimer(parent) {
|
||||
Q_ASSERT(Preferences::instance()->isSchedulerEnabled());
|
||||
// Signal shot, we call start() again manually
|
||||
setSingleShot(true);
|
||||
// Connect Signals/Slots
|
||||
connect(this, SIGNAL(timeout()), this, SLOT(start()));
|
||||
}
|
||||
|
||||
public slots:
|
||||
void start() {
|
||||
const Preferences* const pref = Preferences::instance();
|
||||
Q_ASSERT(pref->isSchedulerEnabled());
|
||||
bool alt_bw_enabled = pref->isAltBandwidthEnabled();
|
||||
|
||||
QTime start = pref->getSchedulerStartTime();
|
||||
QTime end = pref->getSchedulerEndTime();
|
||||
QTime now = QTime::currentTime();
|
||||
int sched_days = pref->getSchedulerDays();
|
||||
int day = QDateTime::currentDateTime().toLocalTime().date().dayOfWeek();
|
||||
bool new_mode = false;
|
||||
bool reverse = false;
|
||||
|
||||
if (start > end) {
|
||||
QTime temp = start;
|
||||
start = end;
|
||||
end = temp;
|
||||
reverse = true;
|
||||
}
|
||||
|
||||
if (start <= now && end >= now) {
|
||||
switch(sched_days) {
|
||||
case EVERY_DAY:
|
||||
new_mode = true;
|
||||
break;
|
||||
case WEEK_ENDS:
|
||||
if (day == 6 || day == 7)
|
||||
new_mode = true;
|
||||
break;
|
||||
case WEEK_DAYS:
|
||||
if (day != 6 && day != 7)
|
||||
new_mode = true;
|
||||
break;
|
||||
default:
|
||||
if (day == sched_days - 2)
|
||||
new_mode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (reverse)
|
||||
new_mode = !new_mode;
|
||||
|
||||
if (new_mode != alt_bw_enabled)
|
||||
emit switchToAlternativeMode(new_mode);
|
||||
|
||||
// Timeout regularly to accomodate for external system clock changes
|
||||
// eg from the user or from a timesync utility
|
||||
QTimer::start(1500);
|
||||
}
|
||||
|
||||
signals:
|
||||
void switchToAlternativeMode(bool alternative);
|
||||
};
|
||||
|
||||
#endif // BANDWIDTHSCHEDULER_H
|
||||
@@ -1,394 +0,0 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "filterparserthread.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QHostAddress>
|
||||
|
||||
#include <libtorrent/session.hpp>
|
||||
#include <libtorrent/ip_filter.hpp>
|
||||
|
||||
FilterParserThread::FilterParserThread(QObject* parent, libtorrent::session *s) : QThread(parent), s(s), abort(false) {
|
||||
|
||||
}
|
||||
|
||||
FilterParserThread::~FilterParserThread() {
|
||||
abort = true;
|
||||
wait();
|
||||
}
|
||||
|
||||
// Parser for eMule ip filter in DAT format
|
||||
int FilterParserThread::parseDATFilterFile(QString filePath, libtorrent::ip_filter& filter) {
|
||||
int ruleCount = 0;
|
||||
QFile file(filePath);
|
||||
if (file.exists()) {
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl;
|
||||
return ruleCount;
|
||||
}
|
||||
unsigned int nbLine = 0;
|
||||
while (!file.atEnd() && !abort) {
|
||||
++nbLine;
|
||||
QByteArray line = file.readLine();
|
||||
// Ignoring empty lines
|
||||
line = line.trimmed();
|
||||
if (line.isEmpty()) continue;
|
||||
// Ignoring commented lines
|
||||
if (line.startsWith('#') || line.startsWith("//")) continue;
|
||||
|
||||
// Line should be splitted by commas
|
||||
QList<QByteArray> partsList = line.split(',');
|
||||
const uint nbElem = partsList.size();
|
||||
|
||||
// IP Range should be splitted by a dash
|
||||
QList<QByteArray> IPs = partsList.first().split('-');
|
||||
if (IPs.size() != 2) {
|
||||
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
|
||||
qDebug("Line was %s", line.constData());
|
||||
continue;
|
||||
}
|
||||
|
||||
boost::system::error_code ec;
|
||||
const QString strStartIP = cleanupIPAddress(IPs.at(0));
|
||||
if (strStartIP.isEmpty()) {
|
||||
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
|
||||
qDebug("Start IP of the range is malformated: %s", qPrintable(strStartIP));
|
||||
continue;
|
||||
}
|
||||
libtorrent::address startAddr = libtorrent::address::from_string(qPrintable(strStartIP), ec);
|
||||
if (ec) {
|
||||
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
|
||||
qDebug("Start IP of the range is malformated: %s", qPrintable(strStartIP));
|
||||
continue;
|
||||
}
|
||||
const QString strEndIP = cleanupIPAddress(IPs.at(1));
|
||||
if (strEndIP.isEmpty()) {
|
||||
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
|
||||
qDebug("End IP of the range is malformated: %s", qPrintable(strEndIP));
|
||||
continue;
|
||||
}
|
||||
libtorrent::address endAddr = libtorrent::address::from_string(qPrintable(strEndIP), ec);
|
||||
if (ec) {
|
||||
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
|
||||
qDebug("End IP of the range is malformated: %s", qPrintable(strEndIP));
|
||||
continue;
|
||||
}
|
||||
if (startAddr.is_v4() != endAddr.is_v4()) {
|
||||
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
|
||||
qDebug("One IP is IPv4 and the other is IPv6!");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if there is an access value (apparently not mandatory)
|
||||
int nbAccess = 0;
|
||||
if (nbElem > 1) {
|
||||
// There is possibly one
|
||||
nbAccess = partsList.at(1).trimmed().toInt();
|
||||
}
|
||||
|
||||
if (nbAccess > 127) {
|
||||
// Ignoring this rule because access value is too high
|
||||
continue;
|
||||
}
|
||||
// Now Add to the filter
|
||||
try {
|
||||
filter.add_rule(startAddr, endAddr, libtorrent::ip_filter::blocked);
|
||||
++ruleCount;
|
||||
}catch(exception) {
|
||||
qDebug("Bad line in filter file, avoided crash...");
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
// Parser for PeerGuardian ip filter in p2p format
|
||||
int FilterParserThread::parseP2PFilterFile(QString filePath, libtorrent::ip_filter& filter) {
|
||||
int ruleCount = 0;
|
||||
QFile file(filePath);
|
||||
if (file.exists()) {
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl;
|
||||
return ruleCount;
|
||||
}
|
||||
unsigned int nbLine = 0;
|
||||
while (!file.atEnd() && !abort) {
|
||||
++nbLine;
|
||||
QByteArray line = file.readLine().trimmed();
|
||||
if (line.isEmpty()) continue;
|
||||
// Ignoring commented lines
|
||||
if (line.startsWith('#') || line.startsWith("//")) continue;
|
||||
// Line is splitted by :
|
||||
QList<QByteArray> partsList = line.split(':');
|
||||
if (partsList.size() < 2) {
|
||||
qDebug("p2p file: line %d is malformed.", nbLine);
|
||||
continue;
|
||||
}
|
||||
// Get IP range
|
||||
QList<QByteArray> IPs = partsList.last().split('-');
|
||||
if (IPs.size() != 2) {
|
||||
qDebug("p2p file: line %d is malformed.", nbLine);
|
||||
qDebug("line was: %s", line.constData());
|
||||
continue;
|
||||
}
|
||||
boost::system::error_code ec;
|
||||
QString strStartIP = cleanupIPAddress(IPs.at(0));
|
||||
if (strStartIP.isEmpty()) {
|
||||
qDebug("p2p file: line %d is malformed.", nbLine);
|
||||
qDebug("Start IP is invalid: %s", qPrintable(strStartIP));
|
||||
continue;
|
||||
}
|
||||
libtorrent::address startAddr = libtorrent::address::from_string(qPrintable(strStartIP), ec);
|
||||
if (ec) {
|
||||
qDebug("p2p file: line %d is malformed.", nbLine);
|
||||
qDebug("Start IP is invalid: %s", qPrintable(strStartIP));
|
||||
continue;
|
||||
}
|
||||
QString strEndIP = cleanupIPAddress(IPs.at(1));
|
||||
if (strEndIP.isEmpty()) {
|
||||
qDebug("p2p file: line %d is malformed.", nbLine);
|
||||
qDebug("End IP is invalid: %s", qPrintable(strStartIP));
|
||||
continue;
|
||||
}
|
||||
libtorrent::address endAddr = libtorrent::address::from_string(qPrintable(strEndIP), ec);
|
||||
if (ec) {
|
||||
qDebug("p2p file: line %d is malformed.", nbLine);
|
||||
qDebug("End IP is invalid: %s", qPrintable(strStartIP));
|
||||
continue;
|
||||
}
|
||||
if (startAddr.is_v4() != endAddr.is_v4()) {
|
||||
qDebug("p2p file: line %d is malformed.", nbLine);
|
||||
qDebug("Line was: %s", line.constData());
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
filter.add_rule(startAddr, endAddr, libtorrent::ip_filter::blocked);
|
||||
++ruleCount;
|
||||
} catch(std::exception&) {
|
||||
qDebug("p2p file: line %d is malformed.", nbLine);
|
||||
qDebug("Line was: %s", line.constData());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
int FilterParserThread::getlineInStream(QDataStream& stream, string& name, char delim) {
|
||||
char c;
|
||||
int total_read = 0;
|
||||
int read;
|
||||
do {
|
||||
read = stream.readRawData(&c, 1);
|
||||
total_read += read;
|
||||
if (read > 0) {
|
||||
if (c != delim) {
|
||||
name += c;
|
||||
} else {
|
||||
// Delim found
|
||||
return total_read;
|
||||
}
|
||||
}
|
||||
} while(read > 0);
|
||||
return total_read;
|
||||
}
|
||||
|
||||
// Parser for PeerGuardian ip filter in p2p format
|
||||
int FilterParserThread::parseP2BFilterFile(QString filePath, libtorrent::ip_filter& filter) {
|
||||
int ruleCount = 0;
|
||||
QFile file(filePath);
|
||||
if (file.exists()) {
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl;
|
||||
return ruleCount;
|
||||
}
|
||||
QDataStream stream(&file);
|
||||
// Read header
|
||||
char buf[7];
|
||||
unsigned char version;
|
||||
if (
|
||||
!stream.readRawData(buf, sizeof(buf)) ||
|
||||
memcmp(buf, "\xFF\xFF\xFF\xFFP2B", 7) ||
|
||||
!stream.readRawData((char*)&version, sizeof(version))
|
||||
) {
|
||||
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
if (version==1 || version==2) {
|
||||
qDebug ("p2b version 1 or 2");
|
||||
unsigned int start, end;
|
||||
|
||||
string name;
|
||||
while(getlineInStream(stream, name, '\0') && !abort) {
|
||||
if (
|
||||
!stream.readRawData((char*)&start, sizeof(start)) ||
|
||||
!stream.readRawData((char*)&end, sizeof(end))
|
||||
) {
|
||||
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
|
||||
return ruleCount;
|
||||
}
|
||||
// Network byte order to Host byte order
|
||||
// asio address_v4 contructor expects it
|
||||
// that way
|
||||
libtorrent::address_v4 first(ntohl(start));
|
||||
libtorrent::address_v4 last(ntohl(end));
|
||||
// Apply to bittorrent session
|
||||
try {
|
||||
filter.add_rule(first, last, libtorrent::ip_filter::blocked);
|
||||
++ruleCount;
|
||||
} catch(std::exception&) {}
|
||||
}
|
||||
}
|
||||
else if (version==3) {
|
||||
qDebug ("p2b version 3");
|
||||
unsigned int namecount;
|
||||
if (!stream.readRawData((char*)&namecount, sizeof(namecount))) {
|
||||
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
|
||||
return ruleCount;
|
||||
}
|
||||
namecount=ntohl(namecount);
|
||||
// Reading names although, we don't really care about them
|
||||
for (unsigned int i=0; i<namecount; i++) {
|
||||
string name;
|
||||
if (!getlineInStream(stream, name, '\0')) {
|
||||
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
|
||||
return ruleCount;
|
||||
}
|
||||
if (abort) return ruleCount;
|
||||
}
|
||||
// Reading the ranges
|
||||
unsigned int rangecount;
|
||||
if (!stream.readRawData((char*)&rangecount, sizeof(rangecount))) {
|
||||
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
|
||||
return ruleCount;
|
||||
}
|
||||
rangecount=ntohl(rangecount);
|
||||
|
||||
unsigned int name, start, end;
|
||||
|
||||
for (unsigned int i=0; i<rangecount; i++) {
|
||||
if (
|
||||
!stream.readRawData((char*)&name, sizeof(name)) ||
|
||||
!stream.readRawData((char*)&start, sizeof(start)) ||
|
||||
!stream.readRawData((char*)&end, sizeof(end))
|
||||
) {
|
||||
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
|
||||
return ruleCount;
|
||||
}
|
||||
// Network byte order to Host byte order
|
||||
// asio address_v4 contructor expects it
|
||||
// that way
|
||||
libtorrent::address_v4 first(ntohl(start));
|
||||
libtorrent::address_v4 last(ntohl(end));
|
||||
// Apply to bittorrent session
|
||||
try {
|
||||
filter.add_rule(first, last, libtorrent::ip_filter::blocked);
|
||||
++ruleCount;
|
||||
} catch(std::exception&) {}
|
||||
if (abort) return ruleCount;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
|
||||
return ruleCount;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
return ruleCount;
|
||||
}
|
||||
|
||||
// Process ip filter file
|
||||
// Supported formats:
|
||||
// * eMule IP list (DAT): http://wiki.phoenixlabs.org/wiki/DAT_Format
|
||||
// * PeerGuardian Text (P2P): http://wiki.phoenixlabs.org/wiki/P2P_Format
|
||||
// * PeerGuardian Binary (P2B): http://wiki.phoenixlabs.org/wiki/P2B_Format
|
||||
void FilterParserThread::processFilterFile(QString _filePath) {
|
||||
if (isRunning()) {
|
||||
// Already parsing a filter, abort first
|
||||
abort = true;
|
||||
wait();
|
||||
}
|
||||
abort = false;
|
||||
filePath = _filePath;
|
||||
// Run it
|
||||
start();
|
||||
}
|
||||
|
||||
void FilterParserThread::processFilterList(libtorrent::session *s, const QStringList& IPs) {
|
||||
// First, import current filter
|
||||
libtorrent::ip_filter filter = s->get_ip_filter();
|
||||
foreach (const QString &ip, IPs) {
|
||||
qDebug("Manual ban of peer %s", ip.toLocal8Bit().constData());
|
||||
boost::system::error_code ec;
|
||||
libtorrent::address addr = libtorrent::address::from_string(ip.toLocal8Bit().constData(), ec);
|
||||
Q_ASSERT(!ec);
|
||||
if (!ec)
|
||||
filter.add_rule(addr, addr, libtorrent::ip_filter::blocked);
|
||||
}
|
||||
s->set_ip_filter(filter);
|
||||
}
|
||||
|
||||
QString FilterParserThread::cleanupIPAddress(QString _ip) {
|
||||
QHostAddress ip(_ip.trimmed());
|
||||
if (ip.isNull()) {
|
||||
return QString();
|
||||
}
|
||||
return ip.toString();
|
||||
}
|
||||
|
||||
void FilterParserThread::run() {
|
||||
qDebug("Processing filter file");
|
||||
libtorrent::ip_filter filter = s->get_ip_filter();
|
||||
int ruleCount = 0;
|
||||
if (filePath.endsWith(".p2p", Qt::CaseInsensitive)) {
|
||||
// PeerGuardian p2p file
|
||||
ruleCount = parseP2PFilterFile(filePath, filter);
|
||||
} else {
|
||||
if (filePath.endsWith(".p2b", Qt::CaseInsensitive)) {
|
||||
// PeerGuardian p2b file
|
||||
ruleCount = parseP2BFilterFile(filePath, filter);
|
||||
} else {
|
||||
// Default: eMule DAT format
|
||||
ruleCount = parseDATFilterFile(filePath, filter);
|
||||
}
|
||||
}
|
||||
if (abort)
|
||||
return;
|
||||
try {
|
||||
s->set_ip_filter(filter);
|
||||
emit IPFilterParsed(ruleCount);
|
||||
} catch(std::exception&) {
|
||||
emit IPFilterError();
|
||||
}
|
||||
qDebug("IP Filter thread: finished parsing, filter applied");
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,352 +0,0 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
#ifndef __BITTORRENT_H__
|
||||
#define __BITTORRENT_H__
|
||||
|
||||
#include <QMap>
|
||||
#include <QHash>
|
||||
#include <QUrl>
|
||||
#include <QStringList>
|
||||
#include <QPointer>
|
||||
#include <QTimer>
|
||||
#include <QNetworkCookie>
|
||||
|
||||
#include <libtorrent/version.hpp>
|
||||
|
||||
#include "qtorrenthandle.h"
|
||||
#include "trackerinfos.h"
|
||||
#include "core/misc.h"
|
||||
|
||||
#ifndef DISABLE_GUI
|
||||
#include "rssdownloadrule.h"
|
||||
#endif
|
||||
|
||||
namespace libtorrent {
|
||||
struct add_torrent_params;
|
||||
struct pe_settings;
|
||||
struct proxy_settings;
|
||||
class session;
|
||||
struct session_status;
|
||||
|
||||
class alert;
|
||||
struct torrent_finished_alert;
|
||||
struct save_resume_data_alert;
|
||||
struct file_renamed_alert;
|
||||
struct torrent_deleted_alert;
|
||||
struct storage_moved_alert;
|
||||
struct storage_moved_failed_alert;
|
||||
struct metadata_received_alert;
|
||||
struct file_error_alert;
|
||||
struct file_completed_alert;
|
||||
struct torrent_paused_alert;
|
||||
struct tracker_error_alert;
|
||||
struct tracker_reply_alert;
|
||||
struct tracker_warning_alert;
|
||||
struct portmap_error_alert;
|
||||
struct portmap_alert;
|
||||
struct peer_blocked_alert;
|
||||
struct peer_ban_alert;
|
||||
struct fastresume_rejected_alert;
|
||||
struct url_seed_alert;
|
||||
struct listen_succeeded_alert;
|
||||
struct listen_failed_alert;
|
||||
struct torrent_checked_alert;
|
||||
struct external_ip_alert;
|
||||
struct state_update_alert;
|
||||
struct stats_alert;
|
||||
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
class upnp;
|
||||
class natpmp;
|
||||
#endif
|
||||
}
|
||||
|
||||
class DownloadThread;
|
||||
class FilterParserThread;
|
||||
class BandwidthScheduler;
|
||||
class ScanFoldersModel;
|
||||
class TorrentSpeedMonitor;
|
||||
class TorrentStatistics;
|
||||
class QAlertDispatcher;
|
||||
|
||||
enum TorrentExportFolder {
|
||||
RegularTorrentExportFolder,
|
||||
FinishedTorrentExportFolder
|
||||
};
|
||||
|
||||
class QTracker;
|
||||
|
||||
class QBtSession : public QObject {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(QBtSession)
|
||||
|
||||
public:
|
||||
static const qreal MAX_RATIO;
|
||||
|
||||
private:
|
||||
explicit QBtSession();
|
||||
static QBtSession* m_instance;
|
||||
|
||||
public:
|
||||
static QBtSession* instance();
|
||||
static void drop();
|
||||
~QBtSession();
|
||||
QTorrentHandle getTorrentHandle(const QString &hash) const;
|
||||
std::vector<libtorrent::torrent_handle> getTorrents() const;
|
||||
qreal getPayloadDownloadRate() const;
|
||||
qreal getPayloadUploadRate() const;
|
||||
libtorrent::session_status getSessionStatus() const;
|
||||
int getListenPort() const;
|
||||
qreal getRealRatio(const libtorrent::torrent_status &status) const;
|
||||
QHash<QString, TrackerInfos> getTrackersInfo(const QString &hash) const;
|
||||
bool hasActiveTorrents() const;
|
||||
bool hasDownloadingTorrents() const;
|
||||
//int getMaximumActiveDownloads() const;
|
||||
//int getMaximumActiveTorrents() const;
|
||||
inline libtorrent::session* getSession() const { return s; }
|
||||
inline bool useTemporaryFolder() const { return !defaultTempPath.isEmpty(); }
|
||||
inline QString getDefaultSavePath() const { return defaultSavePath; }
|
||||
inline ScanFoldersModel* getScanFoldersModel() const { return m_scanFolders; }
|
||||
inline bool isDHTEnabled() const { return DHTEnabled; }
|
||||
inline bool isLSDEnabled() const { return LSDEnabled; }
|
||||
inline bool isPexEnabled() const { return PeXEnabled; }
|
||||
inline bool isQueueingEnabled() const { return queueingEnabled; }
|
||||
quint64 getAlltimeDL() const;
|
||||
quint64 getAlltimeUL() const;
|
||||
void postTorrentUpdate();
|
||||
|
||||
public slots:
|
||||
QTorrentHandle addTorrent(QString path, bool fromScanDir = false, QString from_url = QString(), bool resumed = false, bool imported = false);
|
||||
QTorrentHandle addMagnetUri(QString magnet_uri, bool resumed=false, bool fromScanDir=false, const QString &filePath=QString());
|
||||
void loadSessionState();
|
||||
void saveSessionState();
|
||||
void downloadFromUrl(const QString &url, const QList<QNetworkCookie>& cookies = QList<QNetworkCookie>());
|
||||
void deleteTorrent(const QString &hash, bool delete_local_files = false);
|
||||
void startUpTorrents();
|
||||
void recheckTorrent(const QString &hash);
|
||||
void useAlternativeSpeedsLimit(bool alternative);
|
||||
qlonglong getETA(const QString& hash, const libtorrent::torrent_status &status) const;
|
||||
/* Needed by Web UI */
|
||||
void pauseAllTorrents();
|
||||
void pauseTorrent(const QString &hash);
|
||||
void resumeTorrent(const QString &hash, const bool force = false);
|
||||
void resumeAllTorrents();
|
||||
/* End Web UI */
|
||||
void preAllocateAllFiles(bool b);
|
||||
void saveFastResumeData();
|
||||
void enableIPFilter(const QString &filter_path, bool force=false);
|
||||
void disableIPFilter();
|
||||
void setQueueingEnabled(bool enable);
|
||||
void handleDownloadFailure(QString url, QString reason);
|
||||
void handleMagnetRedirect(const QString &url_new, const QString &url_old);
|
||||
#ifndef DISABLE_GUI
|
||||
void downloadUrlAndSkipDialog(QString url, QString save_path=QString(), QString label=QString(),
|
||||
const QList<QNetworkCookie>& cookies = QList<QNetworkCookie>(),
|
||||
const RssDownloadRule::AddPausedState &aps = RssDownloadRule::USE_GLOBAL);
|
||||
#else
|
||||
void downloadUrlAndSkipDialog(QString url, QString save_path=QString(), QString label=QString(),
|
||||
const QList<QNetworkCookie>& cookies = QList<QNetworkCookie>());
|
||||
#endif
|
||||
// Session configuration - Setters
|
||||
void setListeningPort(int port);
|
||||
void setMaxConnectionsPerTorrent(int max);
|
||||
void setMaxUploadsPerTorrent(int max);
|
||||
void setDownloadRateLimit(long rate);
|
||||
void setUploadRateLimit(long rate);
|
||||
void setGlobalMaxRatio(qreal ratio);
|
||||
qreal getGlobalMaxRatio() const { return global_ratio_limit; }
|
||||
void setMaxRatioPerTorrent(const QString &hash, qreal ratio);
|
||||
qreal getMaxRatioPerTorrent(const QString &hash, bool *usesGlobalRatio) const;
|
||||
void removeRatioPerTorrent(const QString &hash);
|
||||
void setDefaultSavePath(const QString &savepath);
|
||||
void setDefaultTempPath(const QString &temppath);
|
||||
void setAppendLabelToSavePath(bool append);
|
||||
void appendLabelToTorrentSavePath(const QTorrentHandle &h);
|
||||
void changeLabelInTorrentSavePath(const QTorrentHandle &h, QString old_label, QString new_label);
|
||||
void appendqBextensionToTorrent(const QTorrentHandle &h, bool append);
|
||||
void setAppendqBExtension(bool append);
|
||||
void setDownloadLimit(QString hash, long val);
|
||||
void setUploadLimit(QString hash, long val);
|
||||
void enableUPnP(bool b);
|
||||
void enableLSD(bool b);
|
||||
void enableDHT(bool b);
|
||||
void processDownloadedFile(QString, QString);
|
||||
#ifndef DISABLE_GUI
|
||||
void addMagnetSkipAddDlg(const QString& uri, const QString& save_path = QString(), const QString& label = QString(),
|
||||
const RssDownloadRule::AddPausedState &aps = RssDownloadRule::USE_GLOBAL, const QString &uri_old = QString());
|
||||
#else
|
||||
void addMagnetSkipAddDlg(const QString& uri, const QString& save_path = QString(), const QString& label = QString(), const QString &uri_old = QString());
|
||||
#endif
|
||||
void addMagnetInteractive(const QString& uri);
|
||||
void downloadFromURLList(const QStringList& urls);
|
||||
void banIP(QString ip);
|
||||
void recursiveTorrentDownload(const QTorrentHandle &h);
|
||||
void unhideMagnet(const QString &hash);
|
||||
void addTrackersAndUrlSeeds(const QString &hash, const QStringList &trackers, const QStringList& urlSeeds);
|
||||
|
||||
private:
|
||||
void applyEncryptionSettings(libtorrent::pe_settings se);
|
||||
void setProxySettings(libtorrent::proxy_settings proxySettings);
|
||||
void setSessionSettings(const libtorrent::session_settings &sessionSettings);
|
||||
QString getSavePath(const QString &hash, bool fromScanDir = false, QString filePath = QString::null, bool imported = false);
|
||||
bool loadFastResumeData(const QString &hash, std::vector<char> &buf);
|
||||
void loadTorrentSettings(QTorrentHandle &h);
|
||||
void loadTorrentTempData(QTorrentHandle &h, QString savePath, bool magnet);
|
||||
void initializeAddTorrentParams(const QString &hash, libtorrent::add_torrent_params &p);
|
||||
void updateRatioTimer();
|
||||
void recoverPersistentData(const QString &hash, const std::vector<char> &buf);
|
||||
void backupPersistentData(const QString &hash, boost::shared_ptr<libtorrent::entry> data);
|
||||
void handleAlert(libtorrent::alert* a);
|
||||
void handleTorrentFinishedAlert(libtorrent::torrent_finished_alert* p);
|
||||
void handleSaveResumeDataAlert(libtorrent::save_resume_data_alert* p);
|
||||
void handleFileRenamedAlert(libtorrent::file_renamed_alert* p);
|
||||
void handleTorrentDeletedAlert(libtorrent::torrent_deleted_alert* p);
|
||||
void handleStorageMovedAlert(libtorrent::storage_moved_alert* p);
|
||||
void handleStorageMovedFailedAlert(libtorrent::storage_moved_failed_alert* p);
|
||||
void handleMetadataReceivedAlert(libtorrent::metadata_received_alert* p);
|
||||
void handleFileErrorAlert(libtorrent::file_error_alert* p);
|
||||
void handleFileCompletedAlert(libtorrent::file_completed_alert* p);
|
||||
void handleTorrentPausedAlert(libtorrent::torrent_paused_alert* p);
|
||||
void handleTrackerErrorAlert(libtorrent::tracker_error_alert* p);
|
||||
void handleTrackerReplyAlert(libtorrent::tracker_reply_alert* p);
|
||||
void handleTrackerWarningAlert(libtorrent::tracker_warning_alert* p);
|
||||
void handlePortmapWarningAlert(libtorrent::portmap_error_alert* p);
|
||||
void handlePortmapAlert(libtorrent::portmap_alert* p);
|
||||
void handlePeerBlockedAlert(libtorrent::peer_blocked_alert* p);
|
||||
void handlePeerBanAlert(libtorrent::peer_ban_alert* p);
|
||||
void handleFastResumeRejectedAlert(libtorrent::fastresume_rejected_alert* p);
|
||||
void handleUrlSeedAlert(libtorrent::url_seed_alert* p);
|
||||
void handleListenSucceededAlert(libtorrent::listen_succeeded_alert *p);
|
||||
void handleListenFailedAlert(libtorrent::listen_failed_alert *p);
|
||||
void handleTorrentCheckedAlert(libtorrent::torrent_checked_alert* p);
|
||||
void handleExternalIPAlert(libtorrent::external_ip_alert *p);
|
||||
void handleStateUpdateAlert(libtorrent::state_update_alert *p);
|
||||
void handleStatsAlert(libtorrent::stats_alert *p);
|
||||
|
||||
private slots:
|
||||
void addTorrentsFromScanFolder(QStringList&);
|
||||
void readAlerts();
|
||||
void processBigRatios();
|
||||
void exportTorrentFiles(QString path);
|
||||
void saveTempFastResumeData();
|
||||
void sendNotificationEmail(const QTorrentHandle &h);
|
||||
void autoRunExternalProgram(const QTorrentHandle &h);
|
||||
void mergeTorrents(const QTorrentHandle &h, const boost::intrusive_ptr<libtorrent::torrent_info> t);
|
||||
void mergeTorrents(const QTorrentHandle &h, const QString &magnet_uri);
|
||||
void mergeTorrents_impl(const QTorrentHandle &h, const QStringList &trackers, const QStringList& urlSeeds);
|
||||
void exportTorrentFile(const QTorrentHandle &h, TorrentExportFolder folder = RegularTorrentExportFolder);
|
||||
void handleIPFilterParsed(int ruleCount);
|
||||
void handleIPFilterError();
|
||||
void configureSession();
|
||||
|
||||
signals:
|
||||
void addedTorrent(const QTorrentHandle& h);
|
||||
void torrentAboutToBeRemoved(const QTorrentHandle &h);
|
||||
void pausedTorrent(const QTorrentHandle& h);
|
||||
void resumedTorrent(const QTorrentHandle& h);
|
||||
void finishedTorrent(const QTorrentHandle& h);
|
||||
void fullDiskError(const QTorrentHandle& h, QString msg);
|
||||
void trackerSuccess(const QString &hash, const QString &tracker);
|
||||
void trackerError(const QString &hash, const QString &tracker);
|
||||
void trackerWarning(const QString &hash, const QString &tracker);
|
||||
void trackerAuthenticationRequired(const QTorrentHandle& h);
|
||||
void newDownloadedTorrent(QString path, QString url);
|
||||
void newDownloadedTorrentFromRss(QString url);
|
||||
void newMagnetLink(const QString& link);
|
||||
void updateFileSize(const QString &hash);
|
||||
void downloadFromUrlFailure(QString url, QString reason);
|
||||
void torrentFinishedChecking(const QTorrentHandle& h);
|
||||
void metadataReceived(const QTorrentHandle &h);
|
||||
void savePathChanged(const QTorrentHandle &h);
|
||||
void alternativeSpeedsModeChanged(bool alternative);
|
||||
void recursiveTorrentDownloadPossible(const QTorrentHandle &h);
|
||||
void ipFilterParsed(bool error, int ruleCount);
|
||||
void metadataReceivedHidden(const QTorrentHandle &h);
|
||||
void stateUpdate(const std::vector<libtorrent::torrent_status> &statuses);
|
||||
void statsReceived(const libtorrent::stats_alert&);
|
||||
void trackersAdded(const QStringList &trackers, const QString &hash);
|
||||
void trackerlessChange(bool trackerless, const QString &hash);
|
||||
void reloadTrackersAndUrlSeeds(const QTorrentHandle &h);
|
||||
|
||||
private:
|
||||
// Bittorrent
|
||||
libtorrent::session *s;
|
||||
QPointer<BandwidthScheduler> bd_scheduler;
|
||||
QMap<QUrl, QPair<QString, QString> > savepathLabel_fromurl; // Use QMap for compatibility with Qt < 4.7: qHash(QUrl)
|
||||
#ifndef DISABLE_GUI
|
||||
QMap<QUrl, RssDownloadRule::AddPausedState> addpaused_fromurl;
|
||||
#endif
|
||||
QHash<QString, QHash<QString, TrackerInfos> > trackersInfos;
|
||||
QHash<QString, QString> savePathsToRemove;
|
||||
QStringList torrentsToPausedAfterChecking;
|
||||
QTimer resumeDataTimer;
|
||||
// Ratio
|
||||
QPointer<QTimer> BigRatioTimer;
|
||||
// HTTP
|
||||
DownloadThread* downloader;
|
||||
// File System
|
||||
ScanFoldersModel *m_scanFolders;
|
||||
// Settings
|
||||
bool preAllocateAll;
|
||||
qreal global_ratio_limit;
|
||||
int high_ratio_action;
|
||||
bool LSDEnabled;
|
||||
bool DHTEnabled;
|
||||
bool PeXEnabled;
|
||||
bool queueingEnabled;
|
||||
bool appendLabelToSavePath;
|
||||
bool m_torrentExportEnabled;
|
||||
bool m_finishedTorrentExportEnabled;
|
||||
bool appendqBExtension;
|
||||
QString defaultSavePath;
|
||||
QString defaultTempPath;
|
||||
// IP filtering
|
||||
QPointer<FilterParserThread> filterParser;
|
||||
QString filterPath;
|
||||
QList<QUrl> url_skippingDlg;
|
||||
// GeoIP
|
||||
#ifndef DISABLE_GUI
|
||||
bool geoipDBLoaded;
|
||||
bool resolve_countries;
|
||||
#endif
|
||||
// Tracker
|
||||
QPointer<QTracker> m_tracker;
|
||||
TorrentSpeedMonitor *m_speedMonitor;
|
||||
shutDownAction m_shutdownAct;
|
||||
// Port forwarding
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
libtorrent::upnp *m_upnp;
|
||||
libtorrent::natpmp *m_natpmp;
|
||||
#endif
|
||||
QAlertDispatcher* m_alertDispatcher;
|
||||
TorrentStatistics* m_torrentStatistics;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,17 +0,0 @@
|
||||
INCLUDEPATH += $$PWD
|
||||
|
||||
HEADERS += $$PWD/qbtsession.h \
|
||||
$$PWD/qtorrenthandle.h \
|
||||
$$PWD/bandwidthscheduler.h \
|
||||
$$PWD/trackerinfos.h \
|
||||
$$PWD/torrentspeedmonitor.h \
|
||||
$$PWD/filterparserthread.h \
|
||||
$$PWD/alertdispatcher.h \
|
||||
$$PWD/torrentstatistics.h
|
||||
|
||||
SOURCES += $$PWD/qbtsession.cpp \
|
||||
$$PWD/qtorrenthandle.cpp \
|
||||
$$PWD/torrentspeedmonitor.cpp \
|
||||
$$PWD/alertdispatcher.cpp \
|
||||
$$PWD/torrentstatistics.cpp \
|
||||
$$PWD/filterparserthread.cpp
|
||||
@@ -1,856 +0,0 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QByteArray>
|
||||
#include <math.h>
|
||||
#include "core/fs_utils.h"
|
||||
#include "core/misc.h"
|
||||
#include "core/preferences.h"
|
||||
#include "qtorrenthandle.h"
|
||||
#include "core/torrentpersistentdata.h"
|
||||
#include "qbtsession.h"
|
||||
#include <libtorrent/version.hpp>
|
||||
#include <libtorrent/magnet_uri.hpp>
|
||||
#include <libtorrent/torrent_info.hpp>
|
||||
#include <libtorrent/bencode.hpp>
|
||||
#include <libtorrent/entry.hpp>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
using namespace libtorrent;
|
||||
using namespace std;
|
||||
|
||||
static QPair<int, int> get_file_extremity_pieces(const torrent_info& t, int file_index)
|
||||
{
|
||||
const int num_pieces = t.num_pieces();
|
||||
const int piece_size = t.piece_length();
|
||||
const file_entry& file = t.file_at(file_index);
|
||||
|
||||
// Determine the first and last piece of the file
|
||||
int first_piece = floor((file.offset + 1) / (float) piece_size);
|
||||
Q_ASSERT(first_piece >= 0 && first_piece < num_pieces);
|
||||
|
||||
int num_pieces_in_file = ceil(file.size / (float) piece_size);
|
||||
int last_piece = first_piece + num_pieces_in_file - 1;
|
||||
Q_ASSERT(last_piece >= 0 && last_piece < num_pieces);
|
||||
|
||||
return qMakePair(first_piece, last_piece);
|
||||
}
|
||||
|
||||
QTorrentHandle::QTorrentHandle(const torrent_handle& h): torrent_handle(h)
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// Getters
|
||||
//
|
||||
|
||||
QString QTorrentHandle::hash() const
|
||||
{
|
||||
return misc::toQString(torrent_handle::info_hash());
|
||||
}
|
||||
|
||||
QString QTorrentHandle::name() const
|
||||
{
|
||||
QString name = TorrentPersistentData::instance()->getName(hash());
|
||||
if (name.isEmpty()) {
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
name = misc::toQStringU(torrent_handle::name());
|
||||
#else
|
||||
name = misc::toQStringU(status(query_name).name);
|
||||
#endif
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
QString QTorrentHandle::creation_date() const
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
boost::optional<time_t> t = torrent_handle::get_torrent_info().creation_date();
|
||||
#else
|
||||
boost::optional<time_t> t = torrent_handle::torrent_file()->creation_date();
|
||||
#endif
|
||||
return t ? misc::toQString(*t) : "";
|
||||
}
|
||||
|
||||
qlonglong QTorrentHandle::creation_date_unix() const
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
boost::optional<time_t> t = torrent_handle::get_torrent_info().creation_date();
|
||||
#else
|
||||
boost::optional<time_t> t = torrent_handle::torrent_file()->creation_date();
|
||||
#endif
|
||||
return t ? *t : -1;
|
||||
}
|
||||
|
||||
QString QTorrentHandle::current_tracker() const
|
||||
{
|
||||
return misc::toQString(status(0x0).current_tracker);
|
||||
}
|
||||
|
||||
bool QTorrentHandle::is_paused() const
|
||||
{
|
||||
return is_paused(status(0x0));
|
||||
}
|
||||
|
||||
bool QTorrentHandle::is_queued() const
|
||||
{
|
||||
return is_queued(status(0x0));
|
||||
}
|
||||
|
||||
size_type QTorrentHandle::total_size() const
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
return torrent_handle::get_torrent_info().total_size();
|
||||
#else
|
||||
return torrent_handle::torrent_file()->total_size();
|
||||
#endif
|
||||
}
|
||||
|
||||
size_type QTorrentHandle::piece_length() const
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
return torrent_handle::get_torrent_info().piece_length();
|
||||
#else
|
||||
return torrent_handle::torrent_file()->piece_length();
|
||||
#endif
|
||||
}
|
||||
|
||||
int QTorrentHandle::num_pieces() const
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
return torrent_handle::get_torrent_info().num_pieces();
|
||||
#else
|
||||
return torrent_handle::torrent_file()->num_pieces();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool QTorrentHandle::first_last_piece_first() const
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
torrent_info const* t = &get_torrent_info();
|
||||
#else
|
||||
boost::intrusive_ptr<torrent_info const> t = torrent_file();
|
||||
#endif
|
||||
|
||||
// Get int first media file
|
||||
int index = 0;
|
||||
for (index = 0; index < t->num_files(); ++index) {
|
||||
QString path = misc::toQStringU(t->file_at(index).path);
|
||||
const QString ext = fsutils::fileExtension(path);
|
||||
if (misc::isPreviewable(ext) && torrent_handle::file_priority(index) > 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (index >= t->num_files()) // No media file
|
||||
return false;
|
||||
|
||||
QPair<int, int> extremities = get_file_extremity_pieces(*t, index);
|
||||
|
||||
return (torrent_handle::piece_priority(extremities.first) == 7)
|
||||
&& (torrent_handle::piece_priority(extremities.second) == 7);
|
||||
}
|
||||
|
||||
QString QTorrentHandle::save_path() const
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
return fsutils::fromNativePath(misc::toQStringU(torrent_handle::save_path()));
|
||||
#else
|
||||
return fsutils::fromNativePath(misc::toQStringU(status(torrent_handle::query_save_path).save_path));
|
||||
#endif
|
||||
}
|
||||
|
||||
QString QTorrentHandle::save_path_parsed() const
|
||||
{
|
||||
QString p;
|
||||
if (has_metadata() && num_files() == 1) {
|
||||
p = firstFileSavePath();
|
||||
}
|
||||
else {
|
||||
p = fsutils::fromNativePath(TorrentPersistentData::instance()->getSavePath(hash()));
|
||||
if (p.isEmpty())
|
||||
p = save_path();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
QStringList QTorrentHandle::url_seeds() const
|
||||
{
|
||||
QStringList res;
|
||||
try {
|
||||
const std::set<std::string> existing_seeds = torrent_handle::url_seeds();
|
||||
|
||||
std::set<std::string>::const_iterator it = existing_seeds.begin();
|
||||
std::set<std::string>::const_iterator itend = existing_seeds.end();
|
||||
for (; it != itend; ++it) {
|
||||
qDebug("URL Seed: %s", it->c_str());
|
||||
res << misc::toQString(*it);
|
||||
}
|
||||
} catch(std::exception &e) {
|
||||
std::cout << "ERROR: Failed to convert the URL seed" << std::endl;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// get the size of the torrent without the filtered files
|
||||
size_type QTorrentHandle::actual_size() const
|
||||
{
|
||||
return status(query_accurate_download_counters).total_wanted;
|
||||
}
|
||||
|
||||
bool QTorrentHandle::has_filtered_pieces() const
|
||||
{
|
||||
const std::vector<int> piece_priorities = torrent_handle::piece_priorities();
|
||||
foreach (const int priority, piece_priorities)
|
||||
if (priority == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int QTorrentHandle::num_files() const
|
||||
{
|
||||
if (!has_metadata())
|
||||
return -1;
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
return torrent_handle::get_torrent_info().num_files();
|
||||
#else
|
||||
return torrent_handle::torrent_file()->num_files();
|
||||
#endif
|
||||
}
|
||||
|
||||
QString QTorrentHandle::filename_at(unsigned int index) const
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
Q_ASSERT(index < (unsigned int)torrent_handle::get_torrent_info().num_files());
|
||||
#else
|
||||
Q_ASSERT(index < (unsigned int)torrent_handle::torrent_file()->num_files());
|
||||
#endif
|
||||
return fsutils::fileName(filepath_at(index));
|
||||
}
|
||||
|
||||
size_type QTorrentHandle::filesize_at(unsigned int index) const
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
Q_ASSERT(index < (unsigned int)torrent_handle::get_torrent_info().num_files());
|
||||
return torrent_handle::get_torrent_info().files().file_size(index);
|
||||
#else
|
||||
Q_ASSERT(index < (unsigned int)torrent_handle::torrent_file()->num_files());
|
||||
return torrent_handle::torrent_file()->files().file_size(index);
|
||||
#endif
|
||||
}
|
||||
|
||||
QString QTorrentHandle::filepath_at(unsigned int index) const
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
return filepath_at(torrent_handle::get_torrent_info(), index);
|
||||
#else
|
||||
return filepath_at(*torrent_handle::torrent_file(), index);
|
||||
#endif
|
||||
}
|
||||
|
||||
QString QTorrentHandle::orig_filepath_at(unsigned int index) const
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
return fsutils::fromNativePath(misc::toQStringU(torrent_handle::get_torrent_info().orig_files().file_path(index)));
|
||||
#else
|
||||
return fsutils::fromNativePath(misc::toQStringU(torrent_handle::torrent_file()->orig_files().file_path(index)));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
torrent_status::state_t QTorrentHandle::state() const
|
||||
{
|
||||
return status(0x0).state;
|
||||
}
|
||||
|
||||
QString QTorrentHandle::creator() const
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
return misc::toQStringU(torrent_handle::get_torrent_info().creator());
|
||||
#else
|
||||
return misc::toQStringU(torrent_handle::torrent_file()->creator());
|
||||
#endif
|
||||
}
|
||||
|
||||
QString QTorrentHandle::comment() const
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
return misc::toQStringU(torrent_handle::get_torrent_info().comment());
|
||||
#else
|
||||
return misc::toQStringU(torrent_handle::torrent_file()->comment());
|
||||
#endif
|
||||
}
|
||||
|
||||
bool QTorrentHandle::is_checking() const
|
||||
{
|
||||
return is_checking(status(0x0));
|
||||
}
|
||||
|
||||
// Return a list of absolute paths corresponding
|
||||
// to all files in a torrent
|
||||
QStringList QTorrentHandle::absolute_files_path() const
|
||||
{
|
||||
QDir saveDir(save_path());
|
||||
QStringList res;
|
||||
for (int i = 0; i<num_files(); ++i)
|
||||
res << fsutils::expandPathAbs(saveDir.absoluteFilePath(filepath_at(i)));
|
||||
return res;
|
||||
}
|
||||
|
||||
QStringList QTorrentHandle::absolute_files_path_uneeded() const
|
||||
{
|
||||
QDir saveDir(save_path());
|
||||
QStringList res;
|
||||
std::vector<int> fp = torrent_handle::file_priorities();
|
||||
for (uint i = 0; i < fp.size(); ++i) {
|
||||
if (fp[i] == 0) {
|
||||
const QString file_path = fsutils::expandPathAbs(saveDir.absoluteFilePath(filepath_at(i)));
|
||||
if (file_path.contains(".unwanted"))
|
||||
res << file_path;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool QTorrentHandle::has_missing_files() const
|
||||
{
|
||||
const QStringList paths = absolute_files_path();
|
||||
foreach (const QString &path, paths)
|
||||
if (!QFile::exists(path)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int QTorrentHandle::queue_position() const
|
||||
{
|
||||
return queue_position(status(0x0));
|
||||
}
|
||||
|
||||
bool QTorrentHandle::is_seed() const
|
||||
{
|
||||
// Affected by bug http://code.rasterbar.com/libtorrent/ticket/402
|
||||
//return torrent_handle::is_seed();
|
||||
// May suffer from approximation problems
|
||||
//return (progress() == 1.);
|
||||
// This looks safe
|
||||
return is_seed(status(0x0));
|
||||
}
|
||||
|
||||
bool QTorrentHandle::is_sequential_download() const
|
||||
{
|
||||
return status(0x0).sequential_download;
|
||||
}
|
||||
|
||||
bool QTorrentHandle::priv() const
|
||||
{
|
||||
if (!has_metadata())
|
||||
return false;
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
return torrent_handle::get_torrent_info().priv();
|
||||
#else
|
||||
return torrent_handle::torrent_file()->priv();
|
||||
#endif
|
||||
}
|
||||
|
||||
QString QTorrentHandle::firstFileSavePath() const
|
||||
{
|
||||
Q_ASSERT(has_metadata());
|
||||
QString fsave_path = fsutils::fromNativePath(TorrentPersistentData::instance()->getSavePath(hash()));
|
||||
if (fsave_path.isEmpty())
|
||||
fsave_path = save_path();
|
||||
if (!fsave_path.endsWith("/"))
|
||||
fsave_path += "/";
|
||||
fsave_path += filepath_at(0);
|
||||
// Remove .!qB extension
|
||||
if (fsave_path.endsWith(".!qB", Qt::CaseInsensitive))
|
||||
fsave_path.chop(4);
|
||||
return fsave_path;
|
||||
}
|
||||
|
||||
QString QTorrentHandle::root_path() const
|
||||
{
|
||||
if (num_files() < 2)
|
||||
return save_path();
|
||||
QString first_filepath = filepath_at(0);
|
||||
const int slashIndex = first_filepath.indexOf("/");
|
||||
if (slashIndex >= 0)
|
||||
return QDir(save_path()).absoluteFilePath(first_filepath.left(slashIndex));
|
||||
return save_path();
|
||||
}
|
||||
|
||||
bool QTorrentHandle::has_error() const
|
||||
{
|
||||
return has_error(status(0x0));
|
||||
}
|
||||
|
||||
QString QTorrentHandle::error() const
|
||||
{
|
||||
return misc::toQString(status(0x0).error);
|
||||
}
|
||||
|
||||
void QTorrentHandle::downloading_pieces(bitfield &bf) const
|
||||
{
|
||||
std::vector<partial_piece_info> queue;
|
||||
torrent_handle::get_download_queue(queue);
|
||||
|
||||
std::vector<partial_piece_info>::const_iterator it = queue.begin();
|
||||
std::vector<partial_piece_info>::const_iterator itend = queue.end();
|
||||
for (; it!= itend; ++it)
|
||||
bf.set_bit(it->piece_index);
|
||||
return;
|
||||
}
|
||||
|
||||
bool QTorrentHandle::has_metadata() const
|
||||
{
|
||||
return status(0x0).has_metadata;
|
||||
}
|
||||
|
||||
void QTorrentHandle::file_progress(std::vector<size_type>& fp) const
|
||||
{
|
||||
torrent_handle::file_progress(fp, torrent_handle::piece_granularity);
|
||||
}
|
||||
|
||||
QTorrentState QTorrentHandle::torrentState() const
|
||||
{
|
||||
QTorrentState state = QTorrentState::Unknown;
|
||||
libtorrent::torrent_status s = status(torrent_handle::query_accurate_download_counters);
|
||||
|
||||
if (is_paused(s)) {
|
||||
if (has_error(s))
|
||||
state = QTorrentState::Error;
|
||||
else
|
||||
state = is_seed(s) ? QTorrentState::PausedUploading : QTorrentState::PausedDownloading;
|
||||
}
|
||||
else {
|
||||
if (QBtSession::instance()->isQueueingEnabled() && is_queued(s)) {
|
||||
state = is_seed(s) ? QTorrentState::QueuedUploading : QTorrentState::QueuedDownloading;
|
||||
}
|
||||
else {
|
||||
switch (s.state) {
|
||||
case torrent_status::finished:
|
||||
case torrent_status::seeding:
|
||||
state = s.upload_payload_rate > 0 ? QTorrentState::Uploading : QTorrentState::StalledUploading;
|
||||
break;
|
||||
case torrent_status::allocating:
|
||||
case torrent_status::checking_files:
|
||||
case torrent_status::queued_for_checking:
|
||||
case torrent_status::checking_resume_data:
|
||||
state = is_seed(s) ? QTorrentState::CheckingUploading : QTorrentState::CheckingDownloading;
|
||||
break;
|
||||
case torrent_status::downloading:
|
||||
case torrent_status::downloading_metadata:
|
||||
state = s.download_payload_rate > 0 ? QTorrentState::Downloading : QTorrentState::StalledDownloading;
|
||||
break;
|
||||
default:
|
||||
qWarning("Unrecognized torrent status, should not happen!!! status was %d", this->state());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
qulonglong QTorrentHandle::eta() const
|
||||
{
|
||||
libtorrent::torrent_status s = status(torrent_handle::query_accurate_download_counters);
|
||||
return QBtSession::instance()->getETA(hash(), s);
|
||||
}
|
||||
|
||||
void QTorrentHandle::toggleSequentialDownload()
|
||||
{
|
||||
if (is_valid() && has_metadata()) {
|
||||
bool was_sequential = is_sequential_download();
|
||||
set_sequential_download(!was_sequential);
|
||||
if (!was_sequential)
|
||||
prioritize_first_last_piece(true);
|
||||
}
|
||||
}
|
||||
|
||||
void QTorrentHandle::toggleFirstLastPiecePrio()
|
||||
{
|
||||
if (is_valid() && has_metadata())
|
||||
prioritize_first_last_piece(!first_last_piece_first());
|
||||
}
|
||||
|
||||
bool QTorrentHandle::is_forced() const
|
||||
{
|
||||
return is_forced(status(0x0));
|
||||
}
|
||||
|
||||
//
|
||||
// Setters
|
||||
//
|
||||
|
||||
void QTorrentHandle::pause() const
|
||||
{
|
||||
torrent_handle::auto_managed(false);
|
||||
torrent_handle::pause();
|
||||
if (!TorrentPersistentData::instance()->getHasMissingFiles(this->hash()))
|
||||
torrent_handle::save_resume_data();
|
||||
}
|
||||
|
||||
void QTorrentHandle::resume(const bool force) const
|
||||
{
|
||||
if (has_error())
|
||||
torrent_handle::clear_error();
|
||||
torrent_handle::set_upload_mode(false);
|
||||
|
||||
const QString torrent_hash = hash();
|
||||
TorrentPersistentData* const TorPersistent = TorrentPersistentData::instance();
|
||||
bool has_persistant_error = TorPersistent->hasError(torrent_hash);
|
||||
TorPersistent->setErrorState(torrent_hash, false);
|
||||
bool temp_path_enabled = Preferences::instance()->isTempPathEnabled();
|
||||
if (has_persistant_error && temp_path_enabled) {
|
||||
// Torrent was supposed to be seeding, checking again in final destination
|
||||
qDebug("Resuming a torrent with error...");
|
||||
const QString final_save_path = TorPersistent->getSavePath(torrent_hash);
|
||||
qDebug("Torrent final path is: %s", qPrintable(final_save_path));
|
||||
if (!final_save_path.isEmpty())
|
||||
move_storage(final_save_path);
|
||||
}
|
||||
torrent_handle::auto_managed(!force);
|
||||
torrent_handle::resume();
|
||||
if (has_persistant_error && temp_path_enabled)
|
||||
// Force recheck
|
||||
torrent_handle::force_recheck();
|
||||
}
|
||||
|
||||
void QTorrentHandle::remove_url_seed(const QString& seed) const
|
||||
{
|
||||
torrent_handle::remove_url_seed(seed.toStdString());
|
||||
}
|
||||
|
||||
void QTorrentHandle::add_url_seed(const QString& seed) const
|
||||
{
|
||||
const std::string str_seed = seed.toStdString();
|
||||
qDebug("calling torrent_handle::add_url_seed(%s)", str_seed.c_str());
|
||||
torrent_handle::add_url_seed(str_seed);
|
||||
}
|
||||
|
||||
void QTorrentHandle::set_tracker_login(const QString& username, const QString& password) const
|
||||
{
|
||||
torrent_handle::set_tracker_login(std::string(username.toLocal8Bit().constData()), std::string(password.toLocal8Bit().constData()));
|
||||
}
|
||||
|
||||
void QTorrentHandle::move_storage(const QString& new_path) const
|
||||
{
|
||||
QString hashstr = hash();
|
||||
|
||||
if (TorrentTempData::isMoveInProgress(hashstr)) {
|
||||
qDebug("enqueue move storage to %s", qPrintable(new_path));
|
||||
TorrentTempData::enqueueMove(hashstr, new_path);
|
||||
}
|
||||
else {
|
||||
QString old_path = save_path();
|
||||
|
||||
qDebug("move storage: %s to %s", qPrintable(old_path), qPrintable(new_path));
|
||||
|
||||
if (QDir(old_path) == QDir(new_path))
|
||||
return;
|
||||
|
||||
TorrentTempData::startMove(hashstr, old_path, new_path);
|
||||
|
||||
// Create destination directory if necessary
|
||||
// or move_storage() will fail...
|
||||
QDir().mkpath(new_path);
|
||||
// Actually move the storage
|
||||
torrent_handle::move_storage(fsutils::toNativePath(new_path).toUtf8().constData());
|
||||
}
|
||||
}
|
||||
|
||||
bool QTorrentHandle::save_torrent_file(const QString& path) const
|
||||
{
|
||||
if (!has_metadata()) return false;
|
||||
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
torrent_info const* t = &get_torrent_info();
|
||||
#else
|
||||
boost::intrusive_ptr<torrent_info const> t = torrent_file();
|
||||
#endif
|
||||
|
||||
entry meta = bdecode(t->metadata().get(),
|
||||
t->metadata().get() + t->metadata_size());
|
||||
entry torrent_entry(entry::dictionary_t);
|
||||
torrent_entry["info"] = meta;
|
||||
if (!torrent_handle::trackers().empty())
|
||||
torrent_entry["announce"] = torrent_handle::trackers().front().url;
|
||||
|
||||
vector<char> out;
|
||||
bencode(back_inserter(out), torrent_entry);
|
||||
QFile torrent_file(path);
|
||||
if (!out.empty() && torrent_file.open(QIODevice::WriteOnly)) {
|
||||
torrent_file.write(&out[0], out.size());
|
||||
torrent_file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void QTorrentHandle::file_priority(int index, int priority) const
|
||||
{
|
||||
vector<int> priorities = torrent_handle::file_priorities();
|
||||
if (priorities[index] != priority) {
|
||||
priorities[index] = priority;
|
||||
prioritize_files(priorities);
|
||||
}
|
||||
}
|
||||
|
||||
void QTorrentHandle::prioritize_files(const vector<int> &files) const
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
torrent_info const& info = torrent_handle::get_torrent_info();
|
||||
#else
|
||||
boost::intrusive_ptr<torrent_info const> info_ptr = torrent_handle::torrent_file();
|
||||
torrent_info const& info = *info_ptr;
|
||||
#endif
|
||||
if ((int)files.size() != info.num_files()) return;
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
bool was_seed = is_seed();
|
||||
qDebug() << Q_FUNC_INFO << "Changing files priorities...";
|
||||
torrent_handle::prioritize_files(files);
|
||||
qDebug() << Q_FUNC_INFO << "Moving unwanted files to .unwanted folder and conversely...";
|
||||
|
||||
QString spath = save_path();
|
||||
|
||||
for (uint i = 0; i < files.size(); ++i) {
|
||||
QString filepath = filepath_at(info, i);
|
||||
// Move unwanted files to a .unwanted subfolder
|
||||
if (files[i] == 0) {
|
||||
QString old_abspath = QDir(spath).absoluteFilePath(filepath);
|
||||
QString parent_abspath = fsutils::branchPath(old_abspath);
|
||||
// Make sure the file does not already exists
|
||||
if (QDir(parent_abspath).dirName() != ".unwanted") {
|
||||
QString unwanted_abspath = parent_abspath + "/.unwanted";
|
||||
QString new_abspath = unwanted_abspath + "/" + fsutils::fileName(filepath);
|
||||
qDebug() << "Unwanted path is" << unwanted_abspath;
|
||||
if (QFile::exists(new_abspath)) {
|
||||
qWarning() << "File" << new_abspath << "already exists at destination.";
|
||||
continue;
|
||||
}
|
||||
bool created = QDir().mkpath(unwanted_abspath);
|
||||
#ifdef Q_OS_WIN
|
||||
qDebug() << "unwanted folder was created:" << created;
|
||||
if (created) {
|
||||
// Hide the folder on Windows
|
||||
qDebug() << "Hiding folder (Windows)";
|
||||
wstring win_path = fsutils::toNativePath(unwanted_abspath).toStdWString();
|
||||
DWORD dwAttrs = GetFileAttributesW(win_path.c_str());
|
||||
bool ret = SetFileAttributesW(win_path.c_str(), dwAttrs | FILE_ATTRIBUTE_HIDDEN);
|
||||
Q_ASSERT(ret != 0); Q_UNUSED(ret);
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(created);
|
||||
#endif
|
||||
QString parent_path = fsutils::branchPath(filepath);
|
||||
if (!parent_path.isEmpty() && !parent_path.endsWith("/"))
|
||||
parent_path += "/";
|
||||
rename_file(i, parent_path + ".unwanted/" + fsutils::fileName(filepath));
|
||||
}
|
||||
}
|
||||
// Move wanted files back to their original folder
|
||||
if (files[i] > 0) {
|
||||
QString parent_relpath = fsutils::branchPath(filepath);
|
||||
if (QDir(parent_relpath).dirName() == ".unwanted") {
|
||||
QString old_name = fsutils::fileName(filepath);
|
||||
QString new_relpath = fsutils::branchPath(parent_relpath);
|
||||
if (new_relpath.isEmpty())
|
||||
rename_file(i, old_name);
|
||||
else
|
||||
rename_file(i, QDir(new_relpath).filePath(old_name));
|
||||
// Remove .unwanted directory if empty
|
||||
qDebug() << "Attempting to remove .unwanted folder at " << QDir(spath + "/" + new_relpath).absoluteFilePath(".unwanted");
|
||||
QDir(spath + "/" + new_relpath).rmdir(".unwanted");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (was_seed && !is_seed()) {
|
||||
qDebug() << "Torrent is no longer SEEDING";
|
||||
// Save seed status
|
||||
TorrentPersistentData::instance()->saveSeedStatus(*this);
|
||||
// Move to temp folder if necessary
|
||||
const Preferences* const pref = Preferences::instance();
|
||||
if (pref->isTempPathEnabled()) {
|
||||
QString tmp_path = pref->getTempPath();
|
||||
qDebug() << "tmp folder is enabled, move torrent to " << tmp_path << " from " << spath;
|
||||
move_storage(tmp_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QTorrentHandle::prioritize_first_last_piece(int file_index, bool b) const
|
||||
{
|
||||
// Determine the priority to set
|
||||
int prio = b ? 7 : torrent_handle::file_priority(file_index);
|
||||
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
torrent_info const* tf = &get_torrent_info();
|
||||
#else
|
||||
boost::intrusive_ptr<torrent_info const> tf = torrent_file();
|
||||
#endif
|
||||
|
||||
QPair<int, int> extremities = get_file_extremity_pieces(*tf, file_index);
|
||||
piece_priority(extremities.first, prio);
|
||||
piece_priority(extremities.second, prio);
|
||||
}
|
||||
|
||||
void QTorrentHandle::prioritize_first_last_piece(bool b) const
|
||||
{
|
||||
if (!has_metadata()) return;
|
||||
// Download first and last pieces first for all media files in the torrent
|
||||
const uint nbfiles = num_files();
|
||||
for (uint index = 0; index < nbfiles; ++index) {
|
||||
const QString path = filepath_at(index);
|
||||
const QString ext = fsutils::fileExtension(path);
|
||||
if (misc::isPreviewable(ext) && torrent_handle::file_priority(index) > 0) {
|
||||
qDebug() << "File" << path << "is previewable, toggle downloading of first/last pieces first";
|
||||
prioritize_first_last_piece(index, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QTorrentHandle::rename_file(int index, const QString& name) const
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << index << name;
|
||||
torrent_handle::rename_file(index, std::string(fsutils::toNativePath(name).toUtf8().constData()));
|
||||
}
|
||||
|
||||
//
|
||||
// Operators
|
||||
//
|
||||
|
||||
bool QTorrentHandle::operator ==(const QTorrentHandle& new_h) const
|
||||
{
|
||||
return info_hash() == new_h.info_hash();
|
||||
}
|
||||
|
||||
bool QTorrentHandle::is_paused(const libtorrent::torrent_status &status)
|
||||
{
|
||||
return status.paused && !status.auto_managed;
|
||||
}
|
||||
|
||||
int QTorrentHandle::queue_position(const libtorrent::torrent_status &status)
|
||||
{
|
||||
if (status.queue_position < 0)
|
||||
return -1;
|
||||
return status.queue_position + 1;
|
||||
}
|
||||
|
||||
bool QTorrentHandle::is_queued(const libtorrent::torrent_status &status)
|
||||
{
|
||||
return status.paused && status.auto_managed;
|
||||
}
|
||||
|
||||
bool QTorrentHandle::is_seed(const libtorrent::torrent_status &status)
|
||||
{
|
||||
return status.state == torrent_status::finished
|
||||
|| status.state == torrent_status::seeding;
|
||||
}
|
||||
|
||||
bool QTorrentHandle::is_checking(const libtorrent::torrent_status &status)
|
||||
{
|
||||
return status.state == torrent_status::checking_files
|
||||
|| status.state == torrent_status::checking_resume_data;
|
||||
}
|
||||
|
||||
bool QTorrentHandle::has_error(const libtorrent::torrent_status &status)
|
||||
{
|
||||
return status.paused && !status.error.empty();
|
||||
}
|
||||
|
||||
float QTorrentHandle::progress(const libtorrent::torrent_status &status)
|
||||
{
|
||||
if (!status.total_wanted)
|
||||
return 0.;
|
||||
if (status.total_wanted_done == status.total_wanted)
|
||||
return 1.;
|
||||
float progress = (float) status.total_wanted_done / (float) status.total_wanted;
|
||||
Q_ASSERT(progress >= 0.f && progress <= 1.f);
|
||||
return progress;
|
||||
}
|
||||
|
||||
QString QTorrentHandle::filepath_at(const libtorrent::torrent_info &info, unsigned int index)
|
||||
{
|
||||
return fsutils::fromNativePath(misc::toQStringU(info.files().file_path(index)));
|
||||
|
||||
}
|
||||
|
||||
bool QTorrentHandle::is_forced(const libtorrent::torrent_status &status)
|
||||
{
|
||||
return !status.paused && !status.auto_managed;
|
||||
}
|
||||
|
||||
|
||||
QTorrentState::QTorrentState(int value)
|
||||
: m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
QString QTorrentState::toString() const
|
||||
{
|
||||
switch (m_value) {
|
||||
case Error:
|
||||
return "error";
|
||||
case Uploading:
|
||||
return "uploading";
|
||||
case PausedUploading:
|
||||
return "pausedUP";
|
||||
case QueuedUploading:
|
||||
return "queuedUP";
|
||||
case StalledUploading:
|
||||
return "stalledUP";
|
||||
case CheckingUploading:
|
||||
return "checkingUP";
|
||||
case Downloading:
|
||||
return "downloading";
|
||||
case PausedDownloading:
|
||||
return "pausedDL";
|
||||
case QueuedDownloading:
|
||||
return "queuedDL";
|
||||
case StalledDownloading:
|
||||
return "stalledDL";
|
||||
case CheckingDownloading:
|
||||
return "checkingDL";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
QTorrentState::operator int() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#ifndef QTORRENTHANDLE_H
|
||||
#define QTORRENTHANDLE_H
|
||||
|
||||
#include <libtorrent/torrent_handle.hpp>
|
||||
|
||||
#include <QString>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QStringList;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class QTorrentState
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
Unknown = -1,
|
||||
|
||||
Error,
|
||||
|
||||
Uploading,
|
||||
PausedUploading,
|
||||
QueuedUploading,
|
||||
StalledUploading,
|
||||
CheckingUploading,
|
||||
|
||||
Downloading,
|
||||
PausedDownloading,
|
||||
QueuedDownloading,
|
||||
StalledDownloading,
|
||||
CheckingDownloading
|
||||
};
|
||||
|
||||
QTorrentState(int value);
|
||||
|
||||
operator int() const;
|
||||
QString toString() const;
|
||||
|
||||
private:
|
||||
int m_value;
|
||||
};
|
||||
|
||||
// A wrapper for torrent_handle in libtorrent
|
||||
// to interact well with Qt types
|
||||
class QTorrentHandle: public libtorrent::torrent_handle
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//
|
||||
// Constructors
|
||||
//
|
||||
|
||||
QTorrentHandle() {}
|
||||
explicit QTorrentHandle(const libtorrent::torrent_handle& h);
|
||||
|
||||
//
|
||||
// Getters
|
||||
//
|
||||
QString hash() const;
|
||||
QString name() const;
|
||||
QString current_tracker() const;
|
||||
bool is_paused() const;
|
||||
bool has_filtered_pieces() const;
|
||||
libtorrent::size_type total_size() const;
|
||||
libtorrent::size_type piece_length() const;
|
||||
int num_pieces() const;
|
||||
QString save_path() const;
|
||||
QString save_path_parsed() const;
|
||||
QStringList url_seeds() const;
|
||||
libtorrent::size_type actual_size() const;
|
||||
int num_files() const;
|
||||
int queue_position() const;
|
||||
bool is_queued() const;
|
||||
QString filename_at(unsigned int index) const;
|
||||
libtorrent::size_type filesize_at(unsigned int index) const;
|
||||
QString filepath_at(unsigned int index) const;
|
||||
QString orig_filepath_at(unsigned int index) const;
|
||||
libtorrent::torrent_status::state_t state() const;
|
||||
QString creator() const;
|
||||
QString comment() const;
|
||||
QStringList absolute_files_path() const;
|
||||
QStringList absolute_files_path_uneeded() const;
|
||||
bool has_missing_files() const;
|
||||
bool is_seed() const;
|
||||
bool is_checking() const;
|
||||
bool is_sequential_download() const;
|
||||
QString creation_date() const;
|
||||
qlonglong creation_date_unix() const;
|
||||
bool priv() const;
|
||||
bool first_last_piece_first() const;
|
||||
QString root_path() const;
|
||||
QString firstFileSavePath() const;
|
||||
bool has_error() const;
|
||||
QString error() const;
|
||||
void downloading_pieces(libtorrent::bitfield& bf) const;
|
||||
bool has_metadata() const;
|
||||
void file_progress(std::vector<libtorrent::size_type>& fp) const;
|
||||
QTorrentState torrentState() const;
|
||||
qulonglong eta() const;
|
||||
void toggleSequentialDownload();
|
||||
void toggleFirstLastPiecePrio();
|
||||
bool is_forced() const;
|
||||
|
||||
//
|
||||
// Setters
|
||||
//
|
||||
void pause() const;
|
||||
void resume(const bool force = false) const;
|
||||
void remove_url_seed(const QString& seed) const;
|
||||
void add_url_seed(const QString& seed) const;
|
||||
void set_tracker_login(const QString& username, const QString& password) const;
|
||||
void move_storage(const QString& path) const;
|
||||
void prioritize_first_last_piece(bool b) const;
|
||||
void rename_file(int index, const QString& name) const;
|
||||
bool save_torrent_file(const QString& path) const;
|
||||
void prioritize_files(const std::vector<int>& files) const;
|
||||
void file_priority(int index, int priority) const;
|
||||
|
||||
//
|
||||
// Operators
|
||||
//
|
||||
bool operator ==(const QTorrentHandle& new_h) const;
|
||||
|
||||
static bool is_paused(const libtorrent::torrent_status &status);
|
||||
static int queue_position(const libtorrent::torrent_status &status);
|
||||
static bool is_queued(const libtorrent::torrent_status &status);
|
||||
static bool is_seed(const libtorrent::torrent_status &status);
|
||||
static bool is_checking(const libtorrent::torrent_status &status);
|
||||
static bool has_error(const libtorrent::torrent_status &status);
|
||||
static float progress(const libtorrent::torrent_status &status);
|
||||
static QString filepath_at(const libtorrent::torrent_info &info, unsigned int index);
|
||||
static bool is_forced(const libtorrent::torrent_status &status);
|
||||
|
||||
private:
|
||||
void prioritize_first_last_piece(int file_index, bool b) const;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2010 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#ifndef QTRACKER_H
|
||||
#define QTRACKER_H
|
||||
|
||||
#include <libtorrent/entry.hpp>
|
||||
#include <QHash>
|
||||
#include "http/types.h"
|
||||
#include "http/responsebuilder.h"
|
||||
#include "http/irequesthandler.h"
|
||||
|
||||
struct QPeer
|
||||
{
|
||||
QString ip;
|
||||
QString peer_id;
|
||||
int port;
|
||||
|
||||
bool operator!=(const QPeer &other) const;
|
||||
bool operator==(const QPeer &other) const;
|
||||
QString qhash() const;
|
||||
libtorrent::entry toEntry(bool no_peer_id) const;
|
||||
};
|
||||
|
||||
struct TrackerAnnounceRequest
|
||||
{
|
||||
QString info_hash;
|
||||
QString event;
|
||||
int numwant;
|
||||
QPeer peer;
|
||||
// Extensions
|
||||
bool no_peer_id;
|
||||
};
|
||||
|
||||
// static limits
|
||||
const int MAX_TORRENTS = 100;
|
||||
const int MAX_PEERS_PER_TORRENT = 1000;
|
||||
const int ANNOUNCE_INTERVAL = 1800; // 30min
|
||||
|
||||
typedef QHash<QString, QPeer> PeerList;
|
||||
typedef QHash<QString, PeerList> TorrentList;
|
||||
|
||||
namespace Http { class Server; }
|
||||
|
||||
/* Basic Bittorrent tracker implementation in Qt */
|
||||
/* Following http://wiki.theory.org/BitTorrent_Tracker_Protocol */
|
||||
class QTracker : public Http::ResponseBuilder, public Http::IRequestHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(QTracker)
|
||||
|
||||
public:
|
||||
explicit QTracker(QObject *parent = 0);
|
||||
~QTracker();
|
||||
|
||||
bool start();
|
||||
Http::Response processRequest(const Http::Request &request, const Http::Environment &env);
|
||||
|
||||
private:
|
||||
void respondToAnnounceRequest();
|
||||
void replyWithPeerList(const TrackerAnnounceRequest &annonce_req);
|
||||
|
||||
Http::Server *m_server;
|
||||
TorrentList m_torrents;
|
||||
|
||||
Http::Request m_request;
|
||||
Http::Environment m_env;
|
||||
};
|
||||
|
||||
#endif // QTRACKER_H
|
||||
@@ -38,7 +38,8 @@
|
||||
#include "fs_utils.h"
|
||||
#include "preferences.h"
|
||||
#include "filesystemwatcher.h"
|
||||
#include "scannedfoldersmodel.h"
|
||||
#include "bittorrent/session.h"
|
||||
#include "scanfoldersmodel.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -67,11 +68,26 @@ public:
|
||||
|
||||
ScanFoldersModel *ScanFoldersModel::m_instance = 0;
|
||||
|
||||
ScanFoldersModel *ScanFoldersModel::instance(QObject *parent)
|
||||
bool ScanFoldersModel::initInstance(QObject *parent)
|
||||
{
|
||||
//Q_ASSERT(!parent != !m_instance);
|
||||
if (!m_instance)
|
||||
if (!m_instance) {
|
||||
m_instance = new ScanFoldersModel(parent);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ScanFoldersModel::freeInstance()
|
||||
{
|
||||
if (m_instance) {
|
||||
delete m_instance;
|
||||
m_instance = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ScanFoldersModel *ScanFoldersModel::instance()
|
||||
{
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
@@ -79,6 +95,8 @@ ScanFoldersModel::ScanFoldersModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
, m_fsWatcher(0)
|
||||
{
|
||||
configure();
|
||||
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure()));
|
||||
}
|
||||
|
||||
ScanFoldersModel::~ScanFoldersModel()
|
||||
@@ -153,7 +171,7 @@ ScanFoldersModel::PathStatus ScanFoldersModel::addPath(const QString &path, bool
|
||||
|
||||
if (!m_fsWatcher) {
|
||||
m_fsWatcher = new FileSystemWatcher(this);
|
||||
connect(m_fsWatcher, SIGNAL(torrentsAdded(QStringList&)), this, SIGNAL(torrentsAdded(QStringList&)));
|
||||
connect(m_fsWatcher, SIGNAL(torrentsAdded(const QStringList &)), this, SLOT(addTorrentsToSession(const QStringList &)));
|
||||
}
|
||||
|
||||
beginInsertRows(QModelIndex(), rowCount(), rowCount());
|
||||
@@ -231,3 +249,47 @@ void ScanFoldersModel::makePersistent()
|
||||
pref->setScanDirs(paths);
|
||||
pref->setDownloadInScanDirs(downloadInFolderInfo);
|
||||
}
|
||||
|
||||
void ScanFoldersModel::configure()
|
||||
{
|
||||
Preferences *const pref = Preferences::instance();
|
||||
|
||||
int i = 0;
|
||||
QList<bool> downloadInDirList = pref->getDownloadInScanDirs();
|
||||
foreach (const QString &dir, pref->getScanDirs()) {
|
||||
bool downloadInDir = downloadInDirList.value(i, false);
|
||||
addPath(dir, downloadInDir);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void ScanFoldersModel::addTorrentsToSession(const QStringList &pathList)
|
||||
{
|
||||
foreach (const QString &file, pathList) {
|
||||
qDebug("File %s added", qPrintable(file));
|
||||
if (file.endsWith(".magnet")) {
|
||||
QFile f(file);
|
||||
if (f.open(QIODevice::ReadOnly)) {
|
||||
BitTorrent::Session::instance()->addTorrent(QString::fromLocal8Bit(f.readAll()));
|
||||
f.remove();
|
||||
}
|
||||
else {
|
||||
qDebug("Failed to open magnet file: %s", qPrintable(f.errorString()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
BitTorrent::AddTorrentParams params;
|
||||
if (downloadInTorrentFolder(file))
|
||||
params.savePath = QFileInfo(file).dir().path();
|
||||
|
||||
BitTorrent::TorrentInfo torrentInfo = BitTorrent::TorrentInfo::loadFromFile(file);
|
||||
if (torrentInfo.isValid()) {
|
||||
BitTorrent::Session::instance()->addTorrent(torrentInfo, params);
|
||||
fsutils::forceRemove(file);
|
||||
}
|
||||
else {
|
||||
qDebug("Ignoring incomplete torrent file: %s", qPrintable(file));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,8 +28,8 @@
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#ifndef SCANNEDFOLDERSMODEL_H
|
||||
#define SCANNEDFOLDERSMODEL_H
|
||||
#ifndef SCANFOLDERSMODEL_H
|
||||
#define SCANFOLDERSMODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QList>
|
||||
@@ -55,14 +55,15 @@ public:
|
||||
AlreadyInList
|
||||
};
|
||||
|
||||
static ScanFoldersModel *instance(QObject *parent = 0);
|
||||
virtual ~ScanFoldersModel();
|
||||
static bool initInstance(QObject *parent = 0);
|
||||
static void freeInstance();
|
||||
static ScanFoldersModel *instance();
|
||||
|
||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
|
||||
// TODO: removePaths(); singular version becomes private helper functions;
|
||||
// also: remove functions should take modelindexes
|
||||
@@ -74,12 +75,14 @@ public:
|
||||
bool downloadInTorrentFolder(const QString &filePath) const;
|
||||
void makePersistent();
|
||||
|
||||
signals:
|
||||
// The absolute paths of new torrent files in the scanned directories.
|
||||
void torrentsAdded(QStringList &pathList);
|
||||
private slots:
|
||||
void configure();
|
||||
void addTorrentsToSession(const QStringList &pathList);
|
||||
|
||||
private:
|
||||
explicit ScanFoldersModel(QObject *parent = 0);
|
||||
~ScanFoldersModel();
|
||||
|
||||
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
|
||||
static ScanFoldersModel *m_instance;
|
||||
class PathData;
|
||||
@@ -89,4 +92,4 @@ private:
|
||||
FileSystemWatcher *m_fsWatcher;
|
||||
};
|
||||
|
||||
#endif // SCANNEDFOLDERSMODEL_H
|
||||
#endif // SCANFOLDERSMODEL_H
|
||||
159
src/core/torrentfilter.cpp
Normal file
159
src/core/torrentfilter.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include "bittorrent/torrenthandle.h"
|
||||
#include "torrentfilter.h"
|
||||
|
||||
const QString TorrentFilter::AnyLabel;
|
||||
const QStringSet TorrentFilter::AnyHash = (QStringSet() << QString());
|
||||
|
||||
const TorrentFilter TorrentFilter::DownloadingTorrent(TorrentFilter::Downloading);
|
||||
const TorrentFilter TorrentFilter::SeedingTorrent(TorrentFilter::Seeding);
|
||||
const TorrentFilter TorrentFilter::CompletedTorrent(TorrentFilter::Completed);
|
||||
const TorrentFilter TorrentFilter::PausedTorrent(TorrentFilter::Paused);
|
||||
const TorrentFilter TorrentFilter::ResumedTorrent(TorrentFilter::Resumed);
|
||||
const TorrentFilter TorrentFilter::ActiveTorrent(TorrentFilter::Active);
|
||||
const TorrentFilter TorrentFilter::InactiveTorrent(TorrentFilter::Inactive);
|
||||
|
||||
using BitTorrent::TorrentHandle;
|
||||
using BitTorrent::TorrentState;
|
||||
|
||||
TorrentFilter::TorrentFilter()
|
||||
: m_type(All)
|
||||
{
|
||||
}
|
||||
|
||||
TorrentFilter::TorrentFilter(Type type, QStringSet hashSet, QString label)
|
||||
: m_type(type)
|
||||
, m_label(label)
|
||||
, m_hashSet(hashSet)
|
||||
{
|
||||
}
|
||||
|
||||
TorrentFilter::TorrentFilter(QString filter, QStringSet hashSet, QString label)
|
||||
: m_type(All)
|
||||
, m_label(label)
|
||||
, m_hashSet(hashSet)
|
||||
{
|
||||
setTypeByName(filter);
|
||||
}
|
||||
|
||||
bool TorrentFilter::setType(Type type)
|
||||
{
|
||||
if (m_type != type) {
|
||||
m_type = type;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TorrentFilter::setTypeByName(const QString &filter)
|
||||
{
|
||||
Type type = All;
|
||||
|
||||
if (filter == "downloading")
|
||||
type = Downloading;
|
||||
else if (filter == "seeding")
|
||||
type = Seeding;
|
||||
else if (filter == "completed")
|
||||
type = Completed;
|
||||
else if (filter == "paused")
|
||||
type = Paused;
|
||||
else if (filter == "resumed")
|
||||
type = Resumed;
|
||||
else if (filter == "active")
|
||||
type = Active;
|
||||
else if (filter == "inactive")
|
||||
type = Inactive;
|
||||
|
||||
return setType(type);
|
||||
}
|
||||
|
||||
bool TorrentFilter::setHashSet(const QStringSet &hashSet)
|
||||
{
|
||||
if (m_hashSet != hashSet) {
|
||||
m_hashSet = hashSet;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TorrentFilter::setLabel(const QString &label)
|
||||
{
|
||||
if (m_label != label) {
|
||||
m_label = label;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TorrentFilter::match(TorrentHandle *const torrent) const
|
||||
{
|
||||
if (!torrent) return false;
|
||||
|
||||
return (matchState(torrent) && matchHash(torrent) && matchLabel(torrent));
|
||||
}
|
||||
|
||||
bool TorrentFilter::matchState(BitTorrent::TorrentHandle *const torrent) const
|
||||
{
|
||||
switch (m_type) {
|
||||
case All:
|
||||
return true;
|
||||
case Downloading:
|
||||
return torrent->isDownloading();
|
||||
case Seeding:
|
||||
return torrent->isUploading();
|
||||
case Completed:
|
||||
return torrent->isCompleted();
|
||||
case Paused:
|
||||
return torrent->isPaused();
|
||||
case Resumed:
|
||||
return torrent->isResumed();
|
||||
case Active:
|
||||
return torrent->isActive();
|
||||
case Inactive:
|
||||
return torrent->isInactive();
|
||||
default: // All
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool TorrentFilter::matchHash(BitTorrent::TorrentHandle *const torrent) const
|
||||
{
|
||||
if (m_hashSet == AnyHash) return true;
|
||||
else return m_hashSet.contains(torrent->hash());
|
||||
}
|
||||
|
||||
bool TorrentFilter::matchLabel(BitTorrent::TorrentHandle *const torrent) const
|
||||
{
|
||||
if (m_label == AnyLabel) return true;
|
||||
else return (torrent->label() == m_label);
|
||||
}
|
||||
93
src/core/torrentfilter.h
Normal file
93
src/core/torrentfilter.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef TORRENTFILTER_H
|
||||
#define TORRENTFILTER_H
|
||||
|
||||
#include <QString>
|
||||
#include <QSet>
|
||||
|
||||
typedef QSet<QString> QStringSet;
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
|
||||
class TorrentHandle;
|
||||
class TorrentState;
|
||||
|
||||
}
|
||||
|
||||
class TorrentFilter
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
All,
|
||||
Downloading,
|
||||
Seeding,
|
||||
Completed,
|
||||
Resumed,
|
||||
Paused,
|
||||
Active,
|
||||
Inactive
|
||||
};
|
||||
|
||||
static const QString AnyLabel;
|
||||
static const QStringSet AnyHash;
|
||||
|
||||
static const TorrentFilter DownloadingTorrent;
|
||||
static const TorrentFilter SeedingTorrent;
|
||||
static const TorrentFilter CompletedTorrent;
|
||||
static const TorrentFilter PausedTorrent;
|
||||
static const TorrentFilter ResumedTorrent;
|
||||
static const TorrentFilter ActiveTorrent;
|
||||
static const TorrentFilter InactiveTorrent;
|
||||
|
||||
TorrentFilter();
|
||||
// label: pass empty string for "no label" or null string (QString()) for "any label"
|
||||
TorrentFilter(Type type, QStringSet hashSet = AnyHash, QString label = AnyLabel);
|
||||
TorrentFilter(QString filter, QStringSet hashSet = AnyHash, QString label = AnyLabel);
|
||||
|
||||
bool setType(Type type);
|
||||
bool setTypeByName(const QString &filter);
|
||||
bool setHashSet(const QStringSet &hashSet);
|
||||
bool setLabel(const QString &label);
|
||||
|
||||
bool match(BitTorrent::TorrentHandle *const torrent) const;
|
||||
|
||||
private:
|
||||
bool matchState(BitTorrent::TorrentHandle *const torrent) const;
|
||||
bool matchHash(BitTorrent::TorrentHandle *const torrent) const;
|
||||
bool matchLabel(BitTorrent::TorrentHandle *const torrent) const;
|
||||
|
||||
Type m_type;
|
||||
QString m_label;
|
||||
QStringSet m_hashSet;
|
||||
};
|
||||
|
||||
#endif // TORRENTFILTER_H
|
||||
@@ -1,527 +0,0 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include "torrentpersistentdata.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QVariant>
|
||||
|
||||
#include "qinisettings.h"
|
||||
#include "misc.h"
|
||||
#include "qtorrenthandle.h"
|
||||
|
||||
#include <libtorrent/magnet_uri.hpp>
|
||||
|
||||
QHash<QString, TorrentTempData::TorrentData> TorrentTempData::data = QHash<QString, TorrentTempData::TorrentData>();
|
||||
QHash<QString, TorrentTempData::TorrentMoveState> TorrentTempData::torrentMoveStates = QHash<QString, TorrentTempData::TorrentMoveState>();
|
||||
QHash<QString, bool> HiddenData::data = QHash<QString, bool>();
|
||||
unsigned int HiddenData::metadata_counter = 0;
|
||||
TorrentPersistentData* TorrentPersistentData::m_instance = 0;
|
||||
|
||||
TorrentTempData::TorrentData::TorrentData()
|
||||
: sequential(false)
|
||||
, seed(false)
|
||||
, add_paused(Preferences::instance()->addTorrentsInPause())
|
||||
{
|
||||
}
|
||||
|
||||
TorrentTempData::TorrentMoveState::TorrentMoveState(QString oldPath, QString newPath)
|
||||
: oldPath(oldPath)
|
||||
, newPath(newPath)
|
||||
{
|
||||
}
|
||||
|
||||
bool TorrentTempData::hasTempData(const QString &hash)
|
||||
{
|
||||
return data.contains(hash);
|
||||
}
|
||||
|
||||
void TorrentTempData::deleteTempData(const QString &hash)
|
||||
{
|
||||
data.remove(hash);
|
||||
}
|
||||
|
||||
void TorrentTempData::setFilesPriority(const QString &hash, const std::vector<int> &pp)
|
||||
{
|
||||
data[hash].files_priority = pp;
|
||||
}
|
||||
|
||||
void TorrentTempData::setFilesPath(const QString &hash, const QStringList &path_list)
|
||||
{
|
||||
data[hash].path_list = path_list;
|
||||
}
|
||||
|
||||
void TorrentTempData::setSavePath(const QString &hash, const QString &save_path)
|
||||
{
|
||||
data[hash].save_path = save_path;
|
||||
}
|
||||
|
||||
void TorrentTempData::setLabel(const QString &hash, const QString &label)
|
||||
{
|
||||
data[hash].label = label;
|
||||
}
|
||||
|
||||
void TorrentTempData::setSequential(const QString &hash, const bool &sequential)
|
||||
{
|
||||
data[hash].sequential = sequential;
|
||||
}
|
||||
|
||||
bool TorrentTempData::isSequential(const QString &hash)
|
||||
{
|
||||
return data.value(hash).sequential;
|
||||
}
|
||||
|
||||
void TorrentTempData::setSeedingMode(const QString &hash, const bool &seed)
|
||||
{
|
||||
data[hash].seed = seed;
|
||||
}
|
||||
|
||||
bool TorrentTempData::isSeedingMode(const QString &hash)
|
||||
{
|
||||
return data.value(hash).seed;
|
||||
}
|
||||
|
||||
QString TorrentTempData::getSavePath(const QString &hash)
|
||||
{
|
||||
return data.value(hash).save_path;
|
||||
}
|
||||
|
||||
QStringList TorrentTempData::getFilesPath(const QString &hash)
|
||||
{
|
||||
return data.value(hash).path_list;
|
||||
}
|
||||
|
||||
QString TorrentTempData::getLabel(const QString &hash)
|
||||
{
|
||||
return data.value(hash).label;
|
||||
}
|
||||
|
||||
void TorrentTempData::getFilesPriority(const QString &hash, std::vector<int> &fp)
|
||||
{
|
||||
fp = data.value(hash).files_priority;
|
||||
}
|
||||
|
||||
bool TorrentTempData::isMoveInProgress(const QString &hash)
|
||||
{
|
||||
return torrentMoveStates.find(hash) != torrentMoveStates.end();
|
||||
}
|
||||
|
||||
void TorrentTempData::enqueueMove(const QString &hash, const QString &queuedPath)
|
||||
{
|
||||
QHash<QString, TorrentMoveState>::iterator i = torrentMoveStates.find(hash);
|
||||
if (i == torrentMoveStates.end()) {
|
||||
Q_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
i->queuedPath = queuedPath;
|
||||
}
|
||||
|
||||
void TorrentTempData::startMove(const QString &hash, const QString &oldPath, const QString& newPath)
|
||||
{
|
||||
QHash<QString, TorrentMoveState>::iterator i = torrentMoveStates.find(hash);
|
||||
if (i != torrentMoveStates.end()) {
|
||||
Q_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
torrentMoveStates.insert(hash, TorrentMoveState(oldPath, newPath));
|
||||
}
|
||||
|
||||
void TorrentTempData::finishMove(const QString &hash)
|
||||
{
|
||||
QHash<QString, TorrentMoveState>::iterator i = torrentMoveStates.find(hash);
|
||||
if (i == torrentMoveStates.end()) {
|
||||
Q_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
torrentMoveStates.erase(i);
|
||||
}
|
||||
|
||||
QString TorrentTempData::getOldPath(const QString &hash)
|
||||
{
|
||||
QHash<QString, TorrentMoveState>::iterator i = torrentMoveStates.find(hash);
|
||||
if (i == torrentMoveStates.end()) {
|
||||
Q_ASSERT(false);
|
||||
return QString();
|
||||
}
|
||||
return i->oldPath;
|
||||
}
|
||||
|
||||
QString TorrentTempData::getNewPath(const QString &hash)
|
||||
{
|
||||
QHash<QString, TorrentMoveState>::iterator i = torrentMoveStates.find(hash);
|
||||
if (i == torrentMoveStates.end()) {
|
||||
Q_ASSERT(false);
|
||||
return QString();
|
||||
}
|
||||
return i->newPath;
|
||||
}
|
||||
|
||||
QString TorrentTempData::getQueuedPath(const QString &hash)
|
||||
{
|
||||
QHash<QString, TorrentMoveState>::iterator i = torrentMoveStates.find(hash);
|
||||
if (i == torrentMoveStates.end()) {
|
||||
Q_ASSERT(false);
|
||||
return QString();
|
||||
}
|
||||
return i->queuedPath;
|
||||
}
|
||||
|
||||
void TorrentTempData::setAddPaused(const QString &hash, const bool &paused)
|
||||
{
|
||||
data[hash].add_paused = paused;
|
||||
}
|
||||
|
||||
bool TorrentTempData::isAddPaused(const QString &hash)
|
||||
{
|
||||
return data.value(hash).add_paused;
|
||||
}
|
||||
|
||||
void HiddenData::addData(const QString &hash)
|
||||
{
|
||||
data[hash] = false;
|
||||
}
|
||||
|
||||
bool HiddenData::hasData(const QString &hash)
|
||||
{
|
||||
return data.contains(hash);
|
||||
}
|
||||
|
||||
void HiddenData::deleteData(const QString &hash)
|
||||
{
|
||||
if (data.value(hash, false))
|
||||
metadata_counter--;
|
||||
data.remove(hash);
|
||||
}
|
||||
|
||||
int HiddenData::getSize()
|
||||
{
|
||||
return data.size();
|
||||
}
|
||||
|
||||
int HiddenData::getDownloadingSize()
|
||||
{
|
||||
return data.size() - metadata_counter;
|
||||
}
|
||||
|
||||
void HiddenData::gotMetadata(const QString &hash)
|
||||
{
|
||||
if (!data.contains(hash))
|
||||
return;
|
||||
data[hash] = true;
|
||||
metadata_counter++;
|
||||
}
|
||||
|
||||
TorrentPersistentData::TorrentPersistentData()
|
||||
: m_data(QIniSettings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")).value("torrents").toHash())
|
||||
, dirty(false)
|
||||
{
|
||||
timer.setSingleShot(true);
|
||||
timer.setInterval(5 * 1000);
|
||||
connect(&timer, SIGNAL(timeout()), SLOT(save()));
|
||||
}
|
||||
|
||||
TorrentPersistentData::~TorrentPersistentData()
|
||||
{
|
||||
save();
|
||||
}
|
||||
|
||||
void TorrentPersistentData::save()
|
||||
{
|
||||
if (!dirty)
|
||||
return;
|
||||
|
||||
QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
|
||||
settings.setValue("torrents", m_data);
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
const QVariant TorrentPersistentData::value(const QString &key, const QVariant &defaultValue) const
|
||||
{
|
||||
QReadLocker locker(&lock);
|
||||
return m_data.value(key, defaultValue);
|
||||
}
|
||||
|
||||
void TorrentPersistentData::setValue(const QString &key, const QVariant &value)
|
||||
{
|
||||
QWriteLocker locker(&lock);
|
||||
if (m_data.value(key) == value)
|
||||
return;
|
||||
dirty = true;
|
||||
timer.start();
|
||||
m_data.insert(key, value);
|
||||
}
|
||||
|
||||
TorrentPersistentData* TorrentPersistentData::instance()
|
||||
{
|
||||
if (!m_instance)
|
||||
m_instance = new TorrentPersistentData;
|
||||
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
void TorrentPersistentData::drop()
|
||||
{
|
||||
if (m_instance) {
|
||||
delete m_instance;
|
||||
m_instance = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool TorrentPersistentData::isKnownTorrent(QString hash) const
|
||||
{
|
||||
QReadLocker locker(&lock);
|
||||
return m_data.contains(hash);
|
||||
}
|
||||
|
||||
QStringList TorrentPersistentData::knownTorrents() const
|
||||
{
|
||||
QReadLocker locker(&lock);
|
||||
return m_data.keys();
|
||||
}
|
||||
|
||||
void TorrentPersistentData::setRatioLimit(const QString &hash, const qreal &ratio)
|
||||
{
|
||||
QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
torrent["max_ratio"] = ratio;
|
||||
setValue(hash, torrent);
|
||||
}
|
||||
|
||||
qreal TorrentPersistentData::getRatioLimit(const QString &hash) const
|
||||
{
|
||||
const QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
return torrent.value("max_ratio", USE_GLOBAL_RATIO).toReal();
|
||||
}
|
||||
|
||||
bool TorrentPersistentData::hasPerTorrentRatioLimit() const
|
||||
{
|
||||
QReadLocker locker(&lock);
|
||||
QHash<QString, QVariant>::ConstIterator it = m_data.constBegin();
|
||||
QHash<QString, QVariant>::ConstIterator itend = m_data.constEnd();
|
||||
for (; it != itend; ++it)
|
||||
if (it.value().toHash().value("max_ratio", USE_GLOBAL_RATIO).toReal() >= 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void TorrentPersistentData::setAddedDate(const QString &hash, const QDateTime &time)
|
||||
{
|
||||
QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
if (!torrent.contains("add_date")) {
|
||||
torrent["add_date"] = time;
|
||||
setValue(hash, torrent);
|
||||
}
|
||||
}
|
||||
|
||||
QDateTime TorrentPersistentData::getAddedDate(const QString &hash) const
|
||||
{
|
||||
const QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
QDateTime dt = torrent.value("add_date").toDateTime();
|
||||
if (!dt.isValid())
|
||||
dt = QDateTime::currentDateTime();
|
||||
return dt;
|
||||
}
|
||||
|
||||
void TorrentPersistentData::setErrorState(const QString &hash, const bool has_error)
|
||||
{
|
||||
QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
torrent["has_error"] = has_error;
|
||||
setValue(hash, torrent);
|
||||
}
|
||||
|
||||
bool TorrentPersistentData::hasError(const QString &hash) const
|
||||
{
|
||||
const QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
return torrent.value("has_error", false).toBool();
|
||||
}
|
||||
|
||||
QDateTime TorrentPersistentData::getSeedDate(const QString &hash) const
|
||||
{
|
||||
const QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
return torrent.value("seed_date").toDateTime();
|
||||
}
|
||||
|
||||
void TorrentPersistentData::deletePersistentData(const QString &hash)
|
||||
{
|
||||
QWriteLocker locker(&lock);
|
||||
if (m_data.contains(hash)) {
|
||||
m_data.remove(hash);
|
||||
dirty = true;
|
||||
timer.start();
|
||||
}
|
||||
}
|
||||
|
||||
void TorrentPersistentData::saveTorrentPersistentData(const QTorrentHandle &h, const QString &save_path, const bool is_magnet)
|
||||
{
|
||||
Q_ASSERT(h.is_valid());
|
||||
QString hash = h.hash();
|
||||
qDebug("Saving persistent data for %s", qPrintable(hash));
|
||||
// Save persistent data
|
||||
QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
torrent["is_magnet"] = is_magnet;
|
||||
if (is_magnet)
|
||||
torrent["magnet_uri"] = misc::toQString(make_magnet_uri(h));
|
||||
torrent["seed"] = h.is_seed();
|
||||
torrent["priority"] = h.queue_position();
|
||||
if (save_path.isEmpty()) {
|
||||
qDebug("TorrentPersistantData: save path is %s", qPrintable(h.save_path()));
|
||||
torrent["save_path"] = h.save_path();
|
||||
}
|
||||
else {
|
||||
qDebug("TorrentPersistantData: overriding save path is %s", qPrintable(save_path));
|
||||
torrent["save_path"] = save_path; // Override torrent save path (e.g. because it is a temp dir)
|
||||
}
|
||||
// Label
|
||||
torrent["label"] = TorrentTempData::getLabel(hash);
|
||||
// Save data
|
||||
setValue(hash, torrent);
|
||||
qDebug("TorrentPersistentData: Saving save_path %s, hash: %s", qPrintable(h.save_path()), qPrintable(hash));
|
||||
// Set Added date
|
||||
setAddedDate(hash, QDateTime::currentDateTime());
|
||||
// Finally, remove temp data
|
||||
TorrentTempData::deleteTempData(hash);
|
||||
}
|
||||
|
||||
void TorrentPersistentData::saveSavePath(const QString &hash, const QString &save_path)
|
||||
{
|
||||
Q_ASSERT(!hash.isEmpty());
|
||||
qDebug("TorrentPersistentData::saveSavePath(%s)", qPrintable(save_path));
|
||||
QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
torrent["save_path"] = save_path;
|
||||
setValue(hash, torrent);
|
||||
qDebug("TorrentPersistentData: Saving save_path: %s, hash: %s", qPrintable(save_path), qPrintable(hash));
|
||||
}
|
||||
|
||||
void TorrentPersistentData::saveLabel(const QString &hash, const QString &label)
|
||||
{
|
||||
Q_ASSERT(!hash.isEmpty());
|
||||
QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
torrent["label"] = label;
|
||||
setValue(hash, torrent);
|
||||
}
|
||||
|
||||
void TorrentPersistentData::saveName(const QString &hash, const QString &name)
|
||||
{
|
||||
Q_ASSERT(!hash.isEmpty());
|
||||
QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
torrent["name"] = name;
|
||||
setValue(hash, torrent);
|
||||
}
|
||||
|
||||
void TorrentPersistentData::savePriority(const QTorrentHandle &h)
|
||||
{
|
||||
QString hash = h.hash();
|
||||
QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
torrent["priority"] = h.queue_position();
|
||||
setValue(hash, torrent);
|
||||
}
|
||||
|
||||
void TorrentPersistentData::savePriority(const QString &hash, const int &queue_pos)
|
||||
{
|
||||
QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
torrent["priority"] = queue_pos;
|
||||
setValue(hash, torrent);
|
||||
}
|
||||
|
||||
void TorrentPersistentData::saveSeedStatus(const QTorrentHandle &h)
|
||||
{
|
||||
QString hash = h.hash();
|
||||
QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
bool was_seed = torrent.value("seed", false).toBool();
|
||||
if (was_seed != h.is_seed()) {
|
||||
torrent["seed"] = !was_seed;
|
||||
setValue(hash, torrent);
|
||||
}
|
||||
}
|
||||
|
||||
void TorrentPersistentData::saveSeedStatus(const QString &hash, const bool seedStatus)
|
||||
{
|
||||
QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
torrent["seed"] = seedStatus;
|
||||
setValue(hash, torrent);
|
||||
}
|
||||
|
||||
void TorrentPersistentData::setHasMissingFiles(const QString& hash, bool missing)
|
||||
{
|
||||
QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
torrent["has_missing_files"] = missing;
|
||||
setValue(hash, torrent);
|
||||
}
|
||||
|
||||
QString TorrentPersistentData::getSavePath(const QString &hash) const
|
||||
{
|
||||
const QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
//qDebug("TorrentPersistentData: getSavePath %s", data["save_path"].toString().toLocal8Bit().data());
|
||||
return torrent.value("save_path").toString();
|
||||
}
|
||||
|
||||
QString TorrentPersistentData::getLabel(const QString &hash) const
|
||||
{
|
||||
const QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
return torrent.value("label", "").toString();
|
||||
}
|
||||
|
||||
QString TorrentPersistentData::getName(const QString &hash) const
|
||||
{
|
||||
const QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
return torrent.value("name", "").toString();
|
||||
}
|
||||
|
||||
int TorrentPersistentData::getPriority(const QString &hash) const
|
||||
{
|
||||
const QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
return torrent.value("priority", -1).toInt();
|
||||
}
|
||||
|
||||
bool TorrentPersistentData::isSeed(const QString &hash) const
|
||||
{
|
||||
const QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
return torrent.value("seed", false).toBool();
|
||||
}
|
||||
|
||||
bool TorrentPersistentData::isMagnet(const QString &hash) const
|
||||
{
|
||||
const QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
return torrent.value("is_magnet", false).toBool();
|
||||
}
|
||||
|
||||
QString TorrentPersistentData::getMagnetUri(const QString &hash) const
|
||||
{
|
||||
const QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
Q_ASSERT(torrent.value("is_magnet", false).toBool());
|
||||
return torrent.value("magnet_uri").toString();
|
||||
}
|
||||
|
||||
bool TorrentPersistentData::getHasMissingFiles(const QString& hash)
|
||||
{
|
||||
QHash<QString, QVariant> torrent = value(hash).toHash();
|
||||
return torrent.value("has_missing_files").toBool();
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#ifndef TORRENTPERSISTENTDATA_H
|
||||
#define TORRENTPERSISTENTDATA_H
|
||||
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
#include <QReadWriteLock>
|
||||
#include <vector>
|
||||
#include "preferences.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QDateTime;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class QTorrentHandle;
|
||||
|
||||
class TorrentTempData
|
||||
{
|
||||
// This class stores strings w/o modifying separators
|
||||
public:
|
||||
static bool hasTempData(const QString &hash);
|
||||
static void deleteTempData(const QString &hash);
|
||||
static void setFilesPriority(const QString &hash, const std::vector<int> &pp);
|
||||
static void setFilesPath(const QString &hash, const QStringList &path_list);
|
||||
static void setSavePath(const QString &hash, const QString &save_path);
|
||||
static void setLabel(const QString &hash, const QString &label);
|
||||
static void setSequential(const QString &hash, const bool &sequential);
|
||||
static bool isSequential(const QString &hash);
|
||||
static void setSeedingMode(const QString &hash, const bool &seed);
|
||||
static bool isSeedingMode(const QString &hash);
|
||||
static QString getSavePath(const QString &hash);
|
||||
static QStringList getFilesPath(const QString &hash);
|
||||
static QString getLabel(const QString &hash);
|
||||
static void getFilesPriority(const QString &hash, std::vector<int> &fp);
|
||||
static bool isMoveInProgress(const QString &hash);
|
||||
static void enqueueMove(const QString &hash, const QString &queuedPath);
|
||||
static void startMove(const QString &hash, const QString &oldPath, const QString& newPath);
|
||||
static void finishMove(const QString &hash);
|
||||
static QString getOldPath(const QString &hash);
|
||||
static QString getNewPath(const QString &hash);
|
||||
static QString getQueuedPath(const QString &hash);
|
||||
static void setAddPaused(const QString &hash, const bool &paused);
|
||||
static bool isAddPaused(const QString &hash);
|
||||
|
||||
private:
|
||||
struct TorrentData
|
||||
{
|
||||
TorrentData();
|
||||
std::vector<int> files_priority;
|
||||
QStringList path_list;
|
||||
QString save_path;
|
||||
QString label;
|
||||
bool sequential;
|
||||
bool seed;
|
||||
bool add_paused;
|
||||
};
|
||||
|
||||
struct TorrentMoveState
|
||||
{
|
||||
TorrentMoveState(QString oldPath, QString newPath);
|
||||
// the moving occurs from oldPath to newPath
|
||||
// queuedPath is where files should be moved to, when current moving is completed
|
||||
QString oldPath;
|
||||
QString newPath;
|
||||
QString queuedPath;
|
||||
};
|
||||
|
||||
static QHash<QString, TorrentData> data;
|
||||
static QHash<QString, TorrentMoveState> torrentMoveStates;
|
||||
};
|
||||
|
||||
class HiddenData
|
||||
{
|
||||
public:
|
||||
static void addData(const QString &hash);
|
||||
static bool hasData(const QString &hash);
|
||||
static void deleteData(const QString &hash);
|
||||
static int getSize();
|
||||
static int getDownloadingSize();
|
||||
static void gotMetadata(const QString &hash);
|
||||
|
||||
private:
|
||||
static QHash<QString, bool> data;
|
||||
static unsigned int metadata_counter;
|
||||
};
|
||||
|
||||
class TorrentPersistentData: QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(TorrentPersistentData)
|
||||
|
||||
public:
|
||||
enum RatioLimit
|
||||
{
|
||||
USE_GLOBAL_RATIO = -2,
|
||||
NO_RATIO_LIMIT = -1
|
||||
};
|
||||
|
||||
static TorrentPersistentData* instance();
|
||||
static void drop();
|
||||
~TorrentPersistentData();
|
||||
|
||||
bool isKnownTorrent(QString hash) const;
|
||||
QStringList knownTorrents() const;
|
||||
void setRatioLimit(const QString &hash, const qreal &ratio);
|
||||
qreal getRatioLimit(const QString &hash) const;
|
||||
bool hasPerTorrentRatioLimit() const;
|
||||
void setAddedDate(const QString &hash, const QDateTime &time);
|
||||
QDateTime getAddedDate(const QString &hash) const;
|
||||
void setErrorState(const QString &hash, const bool has_error);
|
||||
bool hasError(const QString &hash) const;
|
||||
QDateTime getSeedDate(const QString &hash) const;
|
||||
void deletePersistentData(const QString &hash);
|
||||
void saveTorrentPersistentData(const QTorrentHandle &h, const QString &save_path = QString::null, const bool is_magnet = false);
|
||||
|
||||
// Setters
|
||||
void saveSavePath(const QString &hash, const QString &save_path);
|
||||
void saveLabel(const QString &hash, const QString &label);
|
||||
void saveName(const QString &hash, const QString &name);
|
||||
void savePriority(const QTorrentHandle &h);
|
||||
void savePriority(const QString &hash, const int &queue_pos);
|
||||
void saveSeedStatus(const QTorrentHandle &h);
|
||||
void saveSeedStatus(const QString &hash, const bool seedStatus);
|
||||
void setHasMissingFiles(const QString &hash, bool missing);
|
||||
|
||||
// Getters
|
||||
QString getSavePath(const QString &hash) const;
|
||||
QString getLabel(const QString &hash) const;
|
||||
QString getName(const QString &hash) const;
|
||||
int getPriority(const QString &hash) const;
|
||||
bool isSeed(const QString &hash) const;
|
||||
bool isMagnet(const QString &hash) const;
|
||||
QString getMagnetUri(const QString &hash) const;
|
||||
bool getHasMissingFiles(const QString& hash);
|
||||
public slots:
|
||||
void save();
|
||||
|
||||
private:
|
||||
TorrentPersistentData();
|
||||
static TorrentPersistentData* m_instance;
|
||||
QHash<QString, QVariant> m_data;
|
||||
bool dirty;
|
||||
QTimer timer;
|
||||
mutable QReadWriteLock lock;
|
||||
const QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
|
||||
void setValue(const QString &key, const QVariant &value);
|
||||
|
||||
};
|
||||
|
||||
#endif // TORRENTPERSISTENTDATA_H
|
||||
60
src/core/tristatebool.cpp
Normal file
60
src/core/tristatebool.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include "tristatebool.h"
|
||||
|
||||
TriStateBool::TriStateBool()
|
||||
: m_value(Undefined)
|
||||
{
|
||||
}
|
||||
|
||||
TriStateBool::TriStateBool(bool b)
|
||||
{
|
||||
m_value = (b ? True : False);
|
||||
}
|
||||
|
||||
TriStateBool::TriStateBool(TriStateBool::ValueType value)
|
||||
: m_value(Undefined)
|
||||
{
|
||||
switch (value) {
|
||||
case Undefined:
|
||||
case True:
|
||||
case False:
|
||||
m_value = value;
|
||||
}
|
||||
}
|
||||
|
||||
TriStateBool::operator bool() const
|
||||
{
|
||||
return (m_value == True);
|
||||
}
|
||||
|
||||
TriStateBool::operator ValueType() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
53
src/core/tristatebool.h
Normal file
53
src/core/tristatebool.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef TRISTATEBOOL_H
|
||||
#define TRISTATEBOOL_H
|
||||
|
||||
class TriStateBool
|
||||
{
|
||||
public:
|
||||
enum ValueType
|
||||
{
|
||||
Undefined = -1,
|
||||
False = 0,
|
||||
True = 1
|
||||
};
|
||||
|
||||
TriStateBool();
|
||||
TriStateBool(bool b);
|
||||
TriStateBool(ValueType value);
|
||||
|
||||
operator ValueType() const;
|
||||
operator bool() const;
|
||||
|
||||
private:
|
||||
ValueType m_value;
|
||||
};
|
||||
|
||||
#endif // TRISTATEBOOL_H
|
||||
63
src/core/types.h
Normal file
63
src/core/types.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
#define BEGIN_SCOPED_ENUM(name) class name\
|
||||
{\
|
||||
int m_val;\
|
||||
\
|
||||
public:\
|
||||
name() {}\
|
||||
name(int val) : m_val(val) {}\
|
||||
operator int() const { return m_val; }\
|
||||
operator QVariant() const { return m_val; }\
|
||||
\
|
||||
enum
|
||||
|
||||
#define END_SCOPED_ENUM ; };
|
||||
|
||||
|
||||
BEGIN_SCOPED_ENUM(MaxRatioAction)
|
||||
{
|
||||
Pause,
|
||||
Remove
|
||||
}
|
||||
END_SCOPED_ENUM
|
||||
|
||||
BEGIN_SCOPED_ENUM(TorrentExportFolder)
|
||||
{
|
||||
Regular,
|
||||
Finished
|
||||
}
|
||||
END_SCOPED_ENUM
|
||||
|
||||
#endif // TYPES_H
|
||||
43
src/core/utils/string.cpp
Normal file
43
src/core/utils/string.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include "string.h"
|
||||
|
||||
QString String::fromStdString(const std::string &str)
|
||||
{
|
||||
return QString::fromUtf8(str.c_str());
|
||||
}
|
||||
|
||||
std::string String::toStdString(const QString &str)
|
||||
{
|
||||
QByteArray utf8 = str.toUtf8();
|
||||
return std::string(utf8.constData(), utf8.length());
|
||||
}
|
||||
43
src/core/utils/string.h
Normal file
43
src/core/utils/string.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef UTILS_STRING_H
|
||||
#define UTILS_STRING_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class QString;
|
||||
|
||||
namespace String
|
||||
{
|
||||
QString fromStdString(const std::string &str);
|
||||
std::string toStdString(const QString &str);
|
||||
}
|
||||
|
||||
#endif // UTILS_STRING_H
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2012 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -34,9 +34,12 @@
|
||||
#include "torrentcontentmodel.h"
|
||||
#include "torrentcontentfiltermodel.h"
|
||||
#include "core/preferences.h"
|
||||
#include "core/torrentpersistentdata.h"
|
||||
#include "qbtsession.h"
|
||||
#include "iconprovider.h"
|
||||
#include "core/net/downloadmanager.h"
|
||||
#include "core/net/downloadhandler.h"
|
||||
#include "core/bittorrent/session.h"
|
||||
#include "core/bittorrent/magneturi.h"
|
||||
#include "core/bittorrent/torrentinfo.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "core/fs_utils.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
#include "messageboxraised.h"
|
||||
@@ -47,18 +50,13 @@
|
||||
#include <QUrl>
|
||||
#include <QMenu>
|
||||
#include <QFileDialog>
|
||||
#include <libtorrent/version.hpp>
|
||||
|
||||
using namespace libtorrent;
|
||||
|
||||
AddNewTorrentDialog::AddNewTorrentDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::AddNewTorrentDialog)
|
||||
, m_contentModel(0)
|
||||
, m_contentDelegate(0)
|
||||
, m_isMagnet(false)
|
||||
, m_hasMetadata(false)
|
||||
, m_hasRenamedFile(false)
|
||||
, m_oldIndex(0)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
@@ -123,22 +121,115 @@ void AddNewTorrentDialog::saveState()
|
||||
pref->setAddNewTorrentDialogExpanded(ui->adv_button->isChecked());
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::showTorrent(const QString &torrent_path, const QString& from_url, QWidget *parent)
|
||||
void AddNewTorrentDialog::show(QString source, QWidget *parent)
|
||||
{
|
||||
if (source.startsWith("bc://bt/", Qt::CaseInsensitive)) {
|
||||
qDebug("Converting bc link to magnet link");
|
||||
source = misc::bcLinkToMagnet(source);
|
||||
}
|
||||
|
||||
AddNewTorrentDialog *dlg = new AddNewTorrentDialog(parent);
|
||||
if (dlg->loadTorrent(torrent_path, from_url))
|
||||
dlg->open();
|
||||
else
|
||||
delete dlg;
|
||||
|
||||
if (misc::isUrl(source)) {
|
||||
// Launch downloader
|
||||
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl(source, 10485760 /* 10MB */);
|
||||
connect(handler, SIGNAL(downloadFinished(QString, QString)), dlg, SLOT(handleDownloadFinished(QString, QString)));
|
||||
connect(handler, SIGNAL(downloadFailed(QString, QString)), dlg, SLOT(handleDownloadFailed(QString, QString)));
|
||||
connect(handler, SIGNAL(redirectedToMagnet(QString, QString)), dlg, SLOT(handleRedirectedToMagnet(QString, QString)));
|
||||
}
|
||||
else {
|
||||
bool ok = false;
|
||||
if (source.startsWith("magnet:", Qt::CaseInsensitive))
|
||||
ok = dlg->loadMagnet(source);
|
||||
else
|
||||
ok = dlg->loadTorrent(source);
|
||||
|
||||
if (ok)
|
||||
dlg->open();
|
||||
else
|
||||
delete dlg;
|
||||
}
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::showMagnet(const QString& link, QWidget *parent)
|
||||
bool AddNewTorrentDialog::loadTorrent(const QString& torrent_path)
|
||||
{
|
||||
AddNewTorrentDialog *dlg = new AddNewTorrentDialog(parent);
|
||||
if (dlg->loadMagnet(link))
|
||||
dlg->open();
|
||||
if (torrent_path.startsWith("file://", Qt::CaseInsensitive))
|
||||
m_filePath = QUrl::fromEncoded(torrent_path.toLocal8Bit()).toLocalFile();
|
||||
else
|
||||
delete dlg;
|
||||
m_filePath = torrent_path;
|
||||
|
||||
if (!QFile::exists(m_filePath)) {
|
||||
MessageBoxRaised::critical(0, tr("I/O Error"), tr("The torrent file does not exist."));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_hasMetadata = true;
|
||||
QString error;
|
||||
m_torrentInfo = BitTorrent::TorrentInfo::loadFromFile(m_filePath, error);
|
||||
if (!m_torrentInfo.isValid()) {
|
||||
MessageBoxRaised::critical(0, tr("Invalid torrent"), tr("Failed to load the torrent: %1").arg(error));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_hash = m_torrentInfo.hash();
|
||||
|
||||
// Prevent showing the dialog if download is already present
|
||||
if (BitTorrent::Session::instance()->isKnownTorrent(m_hash)) {
|
||||
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(m_hash);
|
||||
if (torrent) {
|
||||
torrent->addTrackers(m_torrentInfo.trackers());
|
||||
torrent->addUrlSeeds(m_torrentInfo.urlSeeds());
|
||||
MessageBoxRaised::information(0, tr("Already in download list"), tr("Torrent is already in download list. Trackers were merged."), QMessageBox::Ok);
|
||||
}
|
||||
else {
|
||||
MessageBoxRaised::critical(0, tr("Cannot add torrent"), tr("Cannot add this torrent. Perhaps it is already in adding state."), QMessageBox::Ok);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ui->lblhash->setText(m_hash);
|
||||
setupTreeview();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AddNewTorrentDialog::loadMagnet(const QString &magnet_uri)
|
||||
{
|
||||
BitTorrent::MagnetUri magnet(magnet_uri);
|
||||
if (!magnet.isValid()) {
|
||||
MessageBoxRaised::critical(0, tr("Invalid magnet link"), tr("This magnet link was not recognized"));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_hash = magnet.hash();
|
||||
// Prevent showing the dialog if download is already present
|
||||
if (BitTorrent::Session::instance()->isKnownTorrent(m_hash)) {
|
||||
BitTorrent::TorrentHandle *const torrent = BitTorrent::Session::instance()->findTorrent(m_hash);
|
||||
if (torrent) {
|
||||
torrent->addTrackers(magnet.trackers());
|
||||
torrent->addUrlSeeds(magnet.urlSeeds());
|
||||
MessageBoxRaised::information(0, tr("Already in download list"), tr("Magnet link is already in download list. Trackers were merged."), QMessageBox::Ok);
|
||||
}
|
||||
else {
|
||||
MessageBoxRaised::critical(0, tr("Cannot add torrent"), tr("Cannot add this torrent. Perhaps it is already in adding."), QMessageBox::Ok);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(metadataLoaded(BitTorrent::TorrentInfo)), SLOT(updateMetadata(BitTorrent::TorrentInfo)));
|
||||
|
||||
// Set dialog title
|
||||
QString torrent_name = magnet.name();
|
||||
setWindowTitle(torrent_name.isEmpty() ? tr("Magnet link") : torrent_name);
|
||||
|
||||
setupTreeview();
|
||||
// Set dialog position
|
||||
setdialogPosition();
|
||||
|
||||
BitTorrent::Session::instance()->loadMetadata(magnet_uri);
|
||||
setMetadataProgressIndicator(true, tr("Retrieving metadata..."));
|
||||
ui->lblhash->setText(m_hash);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::showEvent(QShowEvent *event)
|
||||
@@ -158,7 +249,7 @@ void AddNewTorrentDialog::showAdvancedSettings(bool show)
|
||||
ui->adv_button->setText(QString::fromUtf8("▲"));
|
||||
ui->settings_group->setVisible(true);
|
||||
ui->info_group->setVisible(true);
|
||||
if (m_hasMetadata && (m_torrentInfo->num_files() > 1)) {
|
||||
if (m_hasMetadata && (m_torrentInfo.filesCount() > 1)) {
|
||||
ui->content_tree->setVisible(true);
|
||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
}
|
||||
@@ -178,83 +269,6 @@ void AddNewTorrentDialog::showAdvancedSettings(bool show)
|
||||
relayout();
|
||||
}
|
||||
|
||||
bool AddNewTorrentDialog::loadTorrent(const QString& torrent_path, const QString& from_url)
|
||||
{
|
||||
m_isMagnet = false;
|
||||
m_url = from_url;
|
||||
if (torrent_path.startsWith("file://", Qt::CaseInsensitive))
|
||||
m_filePath = QUrl::fromEncoded(torrent_path.toLocal8Bit()).toLocalFile();
|
||||
else
|
||||
m_filePath = torrent_path;
|
||||
|
||||
if (!QFile::exists(m_filePath)) {
|
||||
MessageBoxRaised::critical(0, tr("I/O Error"), tr("The torrent file does not exist."));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_hasMetadata = true;
|
||||
|
||||
try {
|
||||
std::vector<char> buffer;
|
||||
lazy_entry entry;
|
||||
libtorrent::error_code ec;
|
||||
misc::loadBencodedFile(m_filePath, buffer, entry, ec);
|
||||
m_torrentInfo = new torrent_info(entry);
|
||||
m_hash = misc::toQString(m_torrentInfo->info_hash());
|
||||
}
|
||||
catch(const std::exception& e) {
|
||||
MessageBoxRaised::critical(0, tr("Invalid torrent"), tr("Failed to load the torrent: %1").arg(misc::toQStringU(e.what())));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prevent showing the dialog if download is already present
|
||||
if (QBtSession::instance()->getTorrentHandle(m_hash).is_valid()) {
|
||||
MessageBoxRaised::information(0, tr("Already in download list"), tr("Torrent is already in download list. Merging trackers."), QMessageBox::Ok);
|
||||
QBtSession::instance()->addTorrent(m_filePath, false, m_url);;
|
||||
return false;
|
||||
}
|
||||
|
||||
ui->lblhash->setText(m_hash);
|
||||
setupTreeview();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AddNewTorrentDialog::loadMagnet(const QString &magnet_uri)
|
||||
{
|
||||
connect(QBtSession::instance(), SIGNAL(metadataReceivedHidden(const QTorrentHandle &)), SLOT(updateMetadata(const QTorrentHandle &)));
|
||||
m_isMagnet = true;
|
||||
m_url = magnet_uri;
|
||||
m_hash = misc::magnetUriToHash(m_url);
|
||||
if (m_hash.isEmpty()) {
|
||||
MessageBoxRaised::critical(0, tr("Invalid magnet link"), tr("This magnet link was not recognized"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prevent showing the dialog if download is already present
|
||||
if (QBtSession::instance()->getTorrentHandle(m_hash).is_valid()) {
|
||||
MessageBoxRaised::information(0, tr("Already in download list"), tr("Magnet link is already in download list. Merging trackers."), QMessageBox::Ok);
|
||||
QBtSession::instance()->addMagnetUri(m_url, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set dialog title
|
||||
QString torrent_name = misc::magnetUriToName(m_url);
|
||||
setWindowTitle(torrent_name.isEmpty() ? tr("Magnet link") : torrent_name);
|
||||
|
||||
setupTreeview();
|
||||
// Set dialog position
|
||||
setdialogPosition();
|
||||
|
||||
// Override save path
|
||||
TorrentTempData::setSavePath(m_hash, QString(QDir::tempPath() + "/" + m_hash));
|
||||
HiddenData::addData(m_hash);
|
||||
QBtSession::instance()->addMagnetUri(m_url, false);
|
||||
setMetadataProgressIndicator(true, tr("Retrieving metadata..."));
|
||||
ui->lblhash->setText(m_hash);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::saveSavePathHistory() const
|
||||
{
|
||||
QDir selected_save_path(ui->save_path_combo->itemData(ui->save_path_combo->currentIndex()).toString());
|
||||
@@ -279,7 +293,7 @@ void AddNewTorrentDialog::saveSavePathHistory() const
|
||||
int AddNewTorrentDialog::indexOfSavePath(const QString &save_path)
|
||||
{
|
||||
QDir saveDir(save_path);
|
||||
for(int i = 0; i<ui->save_path_combo->count() - 1; ++i)
|
||||
for(int i = 0; i < ui->save_path_combo->count(); ++i)
|
||||
if (QDir(ui->save_path_combo->itemData(i).toString()) == saveDir)
|
||||
return i;
|
||||
return -1;
|
||||
@@ -287,7 +301,7 @@ int AddNewTorrentDialog::indexOfSavePath(const QString &save_path)
|
||||
|
||||
void AddNewTorrentDialog::updateFileNameInSavePaths(const QString &new_filename)
|
||||
{
|
||||
for(int i = 0; i<ui->save_path_combo->count() - 1; ++i) {
|
||||
for(int i = 0; i < ui->save_path_combo->count(); ++i) {
|
||||
const QDir folder(ui->save_path_combo->itemData(i).toString());
|
||||
ui->save_path_combo->setItemText(i, fsutils::toNativePath(folder.absoluteFilePath(new_filename)));
|
||||
}
|
||||
@@ -300,14 +314,14 @@ void AddNewTorrentDialog::updateDiskSpaceLabel()
|
||||
|
||||
if (m_hasMetadata) {
|
||||
if (m_contentModel) {
|
||||
const std::vector<int> priorities = m_contentModel->model()->getFilesPriorities();
|
||||
Q_ASSERT(priorities.size() == (uint) m_torrentInfo->num_files());
|
||||
for (uint i = 0; i<priorities.size(); ++i)
|
||||
const QVector<int> priorities = m_contentModel->model()->getFilePriorities();
|
||||
Q_ASSERT(priorities.size() == m_torrentInfo.filesCount());
|
||||
for (int i = 0; i < priorities.size(); ++i)
|
||||
if (priorities[i] > 0)
|
||||
torrent_size += m_torrentInfo->files().file_size(i);
|
||||
torrent_size += m_torrentInfo.fileSize(i);
|
||||
}
|
||||
else {
|
||||
torrent_size = m_torrentInfo->total_size();
|
||||
torrent_size = m_torrentInfo.totalSize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,7 +352,7 @@ void AddNewTorrentDialog::browseButton_clicked()
|
||||
QString cur_save_path = ui->save_path_combo->itemText(m_oldIndex);
|
||||
QString new_path, old_filename, new_filename;
|
||||
|
||||
if (m_torrentInfo && m_torrentInfo->num_files() == 1) {
|
||||
if (m_torrentInfo.isValid() && (m_torrentInfo.filesCount() == 1)) {
|
||||
old_filename = fsutils::fileName(cur_save_path);
|
||||
new_path = QFileDialog::getSaveFileName(this, tr("Choose save path"), cur_save_path, QString(), 0, QFileDialog::DontConfirmOverwrite);
|
||||
if (!new_path.isEmpty())
|
||||
@@ -367,8 +381,7 @@ void AddNewTorrentDialog::browseButton_clicked()
|
||||
}
|
||||
// Update file name in all save_paths
|
||||
if (!new_filename.isEmpty() && !fsutils::sameFileNames(old_filename, new_filename)) {
|
||||
m_hasRenamedFile = true;
|
||||
m_filesPath[0] = new_filename;
|
||||
m_torrentInfo.renameFile(0, new_filename);
|
||||
updateFileNameInSavePaths(new_filename);
|
||||
}
|
||||
|
||||
@@ -415,7 +428,7 @@ void AddNewTorrentDialog::renameSelectedFile()
|
||||
if (m_contentModel->itemType(index) == TorrentContentModelItem::FileType) {
|
||||
// File renaming
|
||||
const int file_index = m_contentModel->getFileIndex(index);
|
||||
QString old_name = fsutils::fromNativePath(m_filesPath.at(file_index));
|
||||
QString old_name = fsutils::fromNativePath(m_torrentInfo.filePath(file_index));
|
||||
qDebug("Old name: %s", qPrintable(old_name));
|
||||
QStringList path_items = old_name.split("/");
|
||||
path_items.removeLast();
|
||||
@@ -428,9 +441,9 @@ void AddNewTorrentDialog::renameSelectedFile()
|
||||
new_name = fsutils::expandPath(new_name);
|
||||
qDebug("New name: %s", qPrintable(new_name));
|
||||
// Check if that name is already used
|
||||
for (int i = 0; i<m_torrentInfo->num_files(); ++i) {
|
||||
for (int i = 0; i < m_torrentInfo.filesCount(); ++i) {
|
||||
if (i == file_index) continue;
|
||||
if (fsutils::sameFileNames(m_filesPath.at(i), new_name)) {
|
||||
if (fsutils::sameFileNames(m_torrentInfo.filePath(i), new_name)) {
|
||||
// Display error message
|
||||
MessageBoxRaised::warning(this, tr("The file could not be renamed"),
|
||||
tr("This name is already in use in this folder. Please use a different name."),
|
||||
@@ -439,9 +452,7 @@ void AddNewTorrentDialog::renameSelectedFile()
|
||||
}
|
||||
}
|
||||
qDebug("Renaming %s to %s", qPrintable(old_name), qPrintable(new_name));
|
||||
// Rename file in files_path
|
||||
m_filesPath.replace(file_index, new_name);
|
||||
m_hasRenamedFile = true;
|
||||
m_torrentInfo.renameFile(file_index, new_name);
|
||||
// Rename in torrent files model too
|
||||
m_contentModel->setData(index, new_name_last);
|
||||
}
|
||||
@@ -460,8 +471,8 @@ void AddNewTorrentDialog::renameSelectedFile()
|
||||
QString new_path = path_items.join("/");
|
||||
if (!new_path.endsWith("/")) new_path += "/";
|
||||
// Check for overwriting
|
||||
for (int i = 0; i<m_torrentInfo->num_files(); ++i) {
|
||||
const QString ¤t_name = m_filesPath.at(i);
|
||||
for (int i = 0; i < m_torrentInfo.filesCount(); ++i) {
|
||||
const QString ¤t_name = m_torrentInfo.filePath(i);
|
||||
#if defined(Q_OS_UNIX) || defined(Q_WS_QWS)
|
||||
if (current_name.startsWith(new_path, Qt::CaseSensitive)) {
|
||||
#else
|
||||
@@ -474,18 +485,17 @@ void AddNewTorrentDialog::renameSelectedFile()
|
||||
}
|
||||
}
|
||||
// Replace path in all files
|
||||
for (int i = 0; i<m_torrentInfo->num_files(); ++i) {
|
||||
const QString ¤t_name = m_filesPath.at(i);
|
||||
for (int i = 0; i < m_torrentInfo.filesCount(); ++i) {
|
||||
const QString ¤t_name = m_torrentInfo.filePath(i);
|
||||
if (current_name.startsWith(old_path)) {
|
||||
QString new_name = current_name;
|
||||
new_name.replace(0, old_path.length(), new_path);
|
||||
new_name = fsutils::expandPath(new_name);
|
||||
qDebug("Rename %s to %s", qPrintable(current_name), qPrintable(new_name));
|
||||
// Rename in files_path
|
||||
m_filesPath.replace(i, new_name);
|
||||
m_torrentInfo.renameFile(i, new_name);
|
||||
}
|
||||
}
|
||||
m_hasRenamedFile = true;
|
||||
|
||||
// Rename folder in torrent files model too
|
||||
m_contentModel->setData(index, new_name_last);
|
||||
}
|
||||
@@ -524,8 +534,8 @@ void AddNewTorrentDialog::displayContentTreeMenu(const QPoint&)
|
||||
QMenu myFilesLlistMenu;
|
||||
const QModelIndexList selectedRows = ui->content_tree->selectionModel()->selectedRows(0);
|
||||
QAction *actRename = 0;
|
||||
if (selectedRows.size() == 1 && m_torrentInfo->num_files() > 1) {
|
||||
actRename = myFilesLlistMenu.addAction(IconProvider::instance()->getIcon("edit-rename"), tr("Rename..."));
|
||||
if ((selectedRows.size() == 1) && (m_torrentInfo.filesCount() > 1)) {
|
||||
actRename = myFilesLlistMenu.addAction(GuiIconProvider::instance()->getIcon("edit-rename"), tr("Rename..."));
|
||||
myFilesLlistMenu.addSeparator();
|
||||
}
|
||||
QMenu subMenu;
|
||||
@@ -564,85 +574,78 @@ void AddNewTorrentDialog::displayContentTreeMenu(const QPoint&)
|
||||
|
||||
void AddNewTorrentDialog::accept()
|
||||
{
|
||||
if (m_isMagnet)
|
||||
disconnect(this, SLOT(updateMetadata(const QTorrentHandle &)));
|
||||
if (!m_hasMetadata)
|
||||
disconnect(this, SLOT(updateMetadata(const BitTorrent::TorrentInfo &)));
|
||||
|
||||
Preferences *const pref = Preferences::instance();
|
||||
BitTorrent::AddTorrentParams params;
|
||||
|
||||
Preferences* const pref = Preferences::instance();
|
||||
// Save Temporary data about torrent
|
||||
QString save_path = ui->save_path_combo->itemData(ui->save_path_combo->currentIndex()).toString();
|
||||
TorrentTempData::setSavePath(m_hash, save_path);
|
||||
if (ui->skip_check_cb->isChecked())
|
||||
// TODO: Check if destination actually exists
|
||||
TorrentTempData::setSeedingMode(m_hash, true);
|
||||
params.skipChecking = true;
|
||||
|
||||
// Label
|
||||
const QString label = ui->label_combo->currentText();
|
||||
if (!label.isEmpty())
|
||||
TorrentTempData::setLabel(m_hash, label);
|
||||
params.label = ui->label_combo->currentText();
|
||||
|
||||
// Save file priorities
|
||||
if (m_contentModel)
|
||||
TorrentTempData::setFilesPriority(m_hash, m_contentModel->model()->getFilesPriorities());
|
||||
params.filePriorities = m_contentModel->model()->getFilePriorities();
|
||||
|
||||
// Rename files if necessary
|
||||
if (m_hasRenamedFile)
|
||||
TorrentTempData::setFilesPath(m_hash, m_filesPath);
|
||||
|
||||
TorrentTempData::setAddPaused(m_hash, !ui->start_torrent_cb->isChecked());
|
||||
|
||||
// Add torrent
|
||||
if (m_isMagnet)
|
||||
QBtSession::instance()->unhideMagnet(m_hash);
|
||||
else
|
||||
QBtSession::instance()->addTorrent(m_filePath, false, m_url);
|
||||
params.addPaused = !ui->start_torrent_cb->isChecked();
|
||||
|
||||
saveSavePathHistory();
|
||||
// Save settings
|
||||
pref->useAdditionDialog(!ui->never_show_cb->isChecked());
|
||||
|
||||
QString savePath = ui->save_path_combo->itemData(ui->save_path_combo->currentIndex()).toString();
|
||||
if (ui->default_save_path_cb->isChecked()) {
|
||||
pref->setSavePath(ui->save_path_combo->itemData(ui->save_path_combo->currentIndex()).toString());
|
||||
QBtSession::instance()->setDefaultSavePath(pref->getSavePath());
|
||||
pref->setSavePath(savePath);
|
||||
pref->apply();
|
||||
}
|
||||
else {
|
||||
// if we don't use default save path...
|
||||
if (QDir(savePath) != QDir(pref->getSavePath()))
|
||||
params.savePath = savePath;
|
||||
}
|
||||
|
||||
// Add torrent
|
||||
if (!m_hasMetadata)
|
||||
BitTorrent::Session::instance()->addTorrent(m_hash, params);
|
||||
else
|
||||
BitTorrent::Session::instance()->addTorrent(m_torrentInfo, params);
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::reject()
|
||||
{
|
||||
if (m_isMagnet) {
|
||||
disconnect(this, SLOT(updateMetadata(const QTorrentHandle &)));
|
||||
if (!m_hasMetadata) {
|
||||
disconnect(this, SLOT(updateMetadata(BitTorrent::TorrentInfo)));
|
||||
setMetadataProgressIndicator(false);
|
||||
QBtSession::instance()->deleteTorrent(m_hash, true);
|
||||
BitTorrent::Session::instance()->cancelLoadMetadata(m_hash);
|
||||
}
|
||||
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::updateMetadata(const QTorrentHandle &h)
|
||||
void AddNewTorrentDialog::updateMetadata(const BitTorrent::TorrentInfo &info)
|
||||
{
|
||||
try {
|
||||
if (h.hash() != m_hash)
|
||||
return;
|
||||
if (info.hash() != m_hash) return;
|
||||
|
||||
disconnect(this, SLOT(updateMetadata(const QTorrentHandle &)));
|
||||
Q_ASSERT(h.has_metadata());
|
||||
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
m_torrentInfo = new torrent_info(h.get_torrent_info());
|
||||
#else
|
||||
m_torrentInfo = new torrent_info(*h.torrent_file());
|
||||
#endif
|
||||
|
||||
// Good to go
|
||||
m_hasMetadata = true;
|
||||
setMetadataProgressIndicator(true, tr("Parsing metadata..."));
|
||||
|
||||
// Update UI
|
||||
setupTreeview();
|
||||
setMetadataProgressIndicator(false, tr("Metadata retrieval complete"));
|
||||
} catch (invalid_handle&) {
|
||||
MessageBoxRaised::critical(0, tr("I/O Error"), ("Unknown error."));
|
||||
setMetadataProgressIndicator(false, tr("Unknown error"));
|
||||
disconnect(this, SLOT(updateMetadata(BitTorrent::TorrentInfo)));
|
||||
if (!info.isValid()) {
|
||||
MessageBoxRaised::critical(0, tr("I/O Error"), ("Invalid metadata."));
|
||||
setMetadataProgressIndicator(false, tr("Invalid metadata"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Good to go
|
||||
m_torrentInfo = info;
|
||||
m_hasMetadata = true;
|
||||
setMetadataProgressIndicator(true, tr("Parsing metadata..."));
|
||||
|
||||
// Update UI
|
||||
setupTreeview();
|
||||
setMetadataProgressIndicator(false, tr("Metadata retrieval complete"));
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText)
|
||||
@@ -661,21 +664,15 @@ void AddNewTorrentDialog::setupTreeview()
|
||||
}
|
||||
else {
|
||||
// Set dialog title
|
||||
setWindowTitle(misc::toQStringU(m_torrentInfo->name()));
|
||||
setWindowTitle(m_torrentInfo.name());
|
||||
|
||||
// Set torrent information
|
||||
QString comment = misc::toQString(m_torrentInfo->comment());
|
||||
QString comment = m_torrentInfo.comment();
|
||||
ui->comment_lbl->setText(comment.replace('\n', ' '));
|
||||
ui->date_lbl->setText(m_torrentInfo->creation_date() ? misc::toQString(*m_torrentInfo->creation_date()) : tr("Not available"));
|
||||
|
||||
file_storage const& fs = m_torrentInfo->files();
|
||||
|
||||
// Populate m_filesList
|
||||
for (int i = 0; i < fs.num_files(); ++i)
|
||||
m_filesPath << misc::toQStringU(fs.file_path(i));
|
||||
ui->date_lbl->setText(!m_torrentInfo.creationDate().isNull() ? m_torrentInfo.creationDate().toString(Qt::DefaultLocaleLongDate) : tr("Not available"));
|
||||
|
||||
// Prepare content tree
|
||||
if (fs.num_files() > 1) {
|
||||
if (m_torrentInfo.filesCount() > 1) {
|
||||
m_contentModel = new TorrentContentFilterModel(this);
|
||||
connect(m_contentModel->model(), SIGNAL(filteredFilesChanged()), SLOT(updateDiskSpaceLabel()));
|
||||
ui->content_tree->setModel(m_contentModel);
|
||||
@@ -686,7 +683,7 @@ void AddNewTorrentDialog::setupTreeview()
|
||||
connect(ui->content_tree, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(displayContentTreeMenu(const QPoint &)));
|
||||
|
||||
// List files in torrent
|
||||
m_contentModel->model()->setupModelData(*m_torrentInfo);
|
||||
m_contentModel->model()->setupModelData(m_torrentInfo);
|
||||
if (!m_headerState.isEmpty())
|
||||
ui->content_tree->header()->restoreState(m_headerState);
|
||||
|
||||
@@ -695,8 +692,8 @@ void AddNewTorrentDialog::setupTreeview()
|
||||
}
|
||||
else {
|
||||
// Update save paths (append file name to them)
|
||||
QString single_file_relpath = misc::toQStringU(fs.file_path(0));
|
||||
for (int i = 0; i<ui->save_path_combo->count() - 1; ++i)
|
||||
QString single_file_relpath = m_torrentInfo.filePath(0);
|
||||
for (int i = 0; i < ui->save_path_combo->count(); ++i)
|
||||
ui->save_path_combo->setItemText(i, fsutils::toNativePath(QDir(ui->save_path_combo->itemText(i)).absoluteFilePath(single_file_relpath)));
|
||||
}
|
||||
}
|
||||
@@ -706,3 +703,27 @@ void AddNewTorrentDialog::setupTreeview()
|
||||
// Set dialog position
|
||||
setdialogPosition();
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::handleDownloadFailed(const QString &url, const QString &reason)
|
||||
{
|
||||
MessageBoxRaised::critical(0, tr("Download Error"), QString("Cannot download %1: %2").arg(url).arg(reason));
|
||||
this->deleteLater();
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::handleRedirectedToMagnet(const QString &url, const QString &magnetUri)
|
||||
{
|
||||
Q_UNUSED(url)
|
||||
if (loadMagnet(magnetUri))
|
||||
open();
|
||||
else
|
||||
this->deleteLater();
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::handleDownloadFinished(const QString &url, const QString &filePath)
|
||||
{
|
||||
Q_UNUSED(url)
|
||||
if (loadTorrent(filePath))
|
||||
open();
|
||||
else
|
||||
this->deleteLater();
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
#include <QDialog>
|
||||
#include <QUrl>
|
||||
|
||||
#include <libtorrent/torrent_info.hpp>
|
||||
#include "qtorrenthandle.h"
|
||||
#include "core/bittorrent/infohash.h"
|
||||
#include "core/bittorrent/torrentinfo.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
@@ -54,8 +54,7 @@ class AddNewTorrentDialog: public QDialog
|
||||
public:
|
||||
~AddNewTorrentDialog();
|
||||
|
||||
static void showTorrent(const QString& torrent_path, const QString& from_url, QWidget *parent = 0);
|
||||
static void showMagnet(const QString& torrent_link, QWidget *parent = 0);
|
||||
static void show(QString source, QWidget *parent = 0);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event);
|
||||
@@ -68,8 +67,11 @@ private slots:
|
||||
void relayout();
|
||||
void renameSelectedFile();
|
||||
void setdialogPosition();
|
||||
void updateMetadata(const QTorrentHandle& h);
|
||||
void updateMetadata(const BitTorrent::TorrentInfo &info);
|
||||
void browseButton_clicked();
|
||||
void handleDownloadFailed(const QString &url, const QString &reason);
|
||||
void handleRedirectedToMagnet(const QString &url, const QString &magnetUri);
|
||||
void handleDownloadFinished(const QString &url, const QString &filePath);
|
||||
|
||||
protected slots:
|
||||
virtual void accept();
|
||||
@@ -77,7 +79,7 @@ protected slots:
|
||||
|
||||
private:
|
||||
explicit AddNewTorrentDialog(QWidget *parent = 0);
|
||||
bool loadTorrent(const QString& torrent_path, const QString& from_url);
|
||||
bool loadTorrent(const QString& torrent_path);
|
||||
bool loadMagnet(const QString& magnet_uri);
|
||||
void loadSavePathHistory();
|
||||
void saveSavePathHistory() const;
|
||||
@@ -92,14 +94,10 @@ private:
|
||||
Ui::AddNewTorrentDialog *ui;
|
||||
TorrentContentFilterModel *m_contentModel;
|
||||
PropListDelegate *m_contentDelegate;
|
||||
bool m_isMagnet;
|
||||
bool m_hasMetadata;
|
||||
QString m_filePath;
|
||||
QString m_url;
|
||||
QString m_hash;
|
||||
boost::intrusive_ptr<libtorrent::torrent_info> m_torrentInfo;
|
||||
QStringList m_filesPath;
|
||||
bool m_hasRenamedFile;
|
||||
BitTorrent::InfoHash m_hash;
|
||||
BitTorrent::TorrentInfo m_torrentInfo;
|
||||
QShortcut *editHotkey;
|
||||
QByteArray m_headerState;
|
||||
int m_oldIndex;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <QLineEdit>
|
||||
#include <QComboBox>
|
||||
#include <QNetworkInterface>
|
||||
#include <libtorrent/version.hpp>
|
||||
|
||||
#include "core/preferences.h"
|
||||
|
||||
enum AdvSettingsCols {PROPERTY, VALUE};
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#include <QPushButton>
|
||||
#include "ui_confirmdeletiondlg.h"
|
||||
#include "core/preferences.h"
|
||||
#include "iconprovider.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "core/misc.h"
|
||||
|
||||
class DeletionConfirmationDlg : public QDialog, private Ui::confirmDeletionDlg {
|
||||
@@ -49,9 +49,9 @@ class DeletionConfirmationDlg : public QDialog, private Ui::confirmDeletionDlg {
|
||||
else
|
||||
label->setText(tr("Are you sure you want to delete these %1 torrents from the transfer list?", "Are you sure you want to delete these 5 torrents from the transfer list?").arg(QString::number(size)));
|
||||
// Icons
|
||||
lbl_warn->setPixmap(IconProvider::instance()->getIcon("dialog-warning").pixmap(lbl_warn->height()));
|
||||
lbl_warn->setPixmap(GuiIconProvider::instance()->getIcon("dialog-warning").pixmap(lbl_warn->height()));
|
||||
lbl_warn->setFixedWidth(lbl_warn->height());
|
||||
rememberBtn->setIcon(IconProvider::instance()->getIcon("object-locked"));
|
||||
rememberBtn->setIcon(GuiIconProvider::instance()->getIcon("object-locked"));
|
||||
|
||||
move(misc::screenCenter(this));
|
||||
checkPermDelete->setChecked(Preferences::instance()->deleteTorrentFilesAsDefault());
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include "executionlog.h"
|
||||
#include "ui_executionlog.h"
|
||||
#include "core/logger.h"
|
||||
#include "iconprovider.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "loglistwidget.h"
|
||||
|
||||
ExecutionLog::ExecutionLog(QWidget *parent)
|
||||
@@ -47,8 +47,8 @@ ExecutionLog::ExecutionLog(QWidget *parent)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->tabConsole->setTabIcon(0, IconProvider::instance()->getIcon("view-calendar-journal"));
|
||||
ui->tabConsole->setTabIcon(1, IconProvider::instance()->getIcon("view-filter"));
|
||||
ui->tabConsole->setTabIcon(0, GuiIconProvider::instance()->getIcon("view-calendar-journal"));
|
||||
ui->tabConsole->setTabIcon(1, GuiIconProvider::instance()->getIcon("view-filter"));
|
||||
ui->tabGeneral->layout()->addWidget(m_msgList);
|
||||
ui->tabBan->layout()->addWidget(m_peerList);
|
||||
|
||||
|
||||
@@ -183,21 +183,21 @@ const char * country_name[253] =
|
||||
"Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey",
|
||||
"Saint Barthelemy","Saint Martin"};
|
||||
|
||||
QString GeoIPManager::CountryISOCodeToName(const char* iso) {
|
||||
if (iso[0] == 0) return "N/A";
|
||||
QString GeoIPManager::CountryISOCodeToName(const QString &iso) {
|
||||
if (iso.isEmpty()) return "N/A";
|
||||
|
||||
for (uint i = 0; i < num_countries; ++i) {
|
||||
if (iso[0] == country_code[i][0] && iso[1] == country_code[i][1]) {
|
||||
if (iso == country_code[i]) {
|
||||
return QLatin1String(country_name[i]);
|
||||
}
|
||||
}
|
||||
qDebug("GeoIPManager: Country name resolution failed for: %c%c", iso[0], iso[1]);
|
||||
qDebug("GeoIPManager: Country name resolution failed for: %s", qPrintable(iso));
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
// http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm
|
||||
QIcon GeoIPManager::CountryISOCodeToIcon(const char* iso) {
|
||||
if (iso[0] == 0 || iso[0] == '!') return QIcon();
|
||||
const QString isoStr = QString(QByteArray(iso, 2)).toLower();
|
||||
return QIcon(":/icons/flags/"+isoStr+".png");
|
||||
QIcon GeoIPManager::CountryISOCodeToIcon(const QString &iso) {
|
||||
if (iso.isEmpty() || (iso[0] == '!')) return QIcon();
|
||||
return QIcon(":/icons/flags/" + iso.toLower() + ".png");
|
||||
}
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@ class GeoIPManager : public QObject {
|
||||
|
||||
public:
|
||||
static void loadDatabase(libtorrent::session *s);
|
||||
static QIcon CountryISOCodeToIcon(const char* iso);
|
||||
static QString CountryISOCodeToName(const char* iso);
|
||||
static QIcon CountryISOCodeToIcon(const QString &iso);
|
||||
static QString CountryISOCodeToName(const QString &iso);
|
||||
|
||||
private:
|
||||
static QString geoipFolder(bool embedded=false);
|
||||
|
||||
@@ -3,7 +3,6 @@ INCLUDEPATH += $$PWD
|
||||
include(lineedit/lineedit.pri)
|
||||
include(properties/properties.pri)
|
||||
include(rss/rss.pri)
|
||||
include(torrentcreator/torrentcreator.pri)
|
||||
include(geoip/geoip.pri)
|
||||
include(powermanagement/powermanagement.pri)
|
||||
unix:!macx:dbus: include(qtnotify/qtnotify.pri)
|
||||
@@ -32,18 +31,18 @@ HEADERS += \
|
||||
$$PWD/hidabletabwidget.h \
|
||||
$$PWD/torrentimportdlg.h \
|
||||
$$PWD/executionlog.h \
|
||||
$$PWD/iconprovider.h \
|
||||
$$PWD/guiiconprovider.h \
|
||||
$$PWD/updownratiodlg.h \
|
||||
$$PWD/loglistwidget.h \
|
||||
$$PWD/addnewtorrentdialog.h \
|
||||
$$PWD/autoexpandabledialog.h \
|
||||
$$PWD/statsdialog.h \
|
||||
$$PWD/messageboxraised.h \
|
||||
$$PWD/torrentfilterenum.h \
|
||||
$$PWD/options_imp.h \
|
||||
$$PWD/advancedsettings.h \
|
||||
$$PWD/shutdownconfirm.h \
|
||||
$$PWD/torrentmodel.h
|
||||
$$PWD/torrentmodel.h \
|
||||
$$PWD/torrentcreatordlg.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/mainwindow.cpp \
|
||||
@@ -62,7 +61,7 @@ SOURCES += \
|
||||
$$PWD/executionlog.cpp \
|
||||
$$PWD/speedlimitdlg.cpp \
|
||||
$$PWD/previewselect.cpp \
|
||||
$$PWD/iconprovider.cpp \
|
||||
$$PWD/guiiconprovider.cpp \
|
||||
$$PWD/updownratiodlg.cpp \
|
||||
$$PWD/loglistwidget.cpp \
|
||||
$$PWD/addnewtorrentdialog.cpp \
|
||||
@@ -73,7 +72,8 @@ SOURCES += \
|
||||
$$PWD/trackerlogin.cpp \
|
||||
$$PWD/options_imp.cpp \
|
||||
$$PWD/shutdownconfirm.cpp \
|
||||
$$PWD/torrentmodel.cpp
|
||||
$$PWD/torrentmodel.cpp \
|
||||
$$PWD/torrentcreatordlg.cpp
|
||||
|
||||
win32|macx {
|
||||
HEADERS += $$PWD/programupdater.h
|
||||
@@ -94,6 +94,7 @@ FORMS += \
|
||||
$$PWD/addnewtorrentdialog.ui \
|
||||
$$PWD/autoexpandabledialog.ui \
|
||||
$$PWD/statsdialog.ui \
|
||||
$$PWD/options.ui
|
||||
$$PWD/options.ui \
|
||||
$$PWD/createtorrent.ui
|
||||
|
||||
RESOURCES += $$PWD/about.qrc
|
||||
|
||||
125
src/gui/guiiconprovider.cpp
Normal file
125
src/gui/guiiconprovider.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2011 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#include "guiiconprovider.h"
|
||||
#include "core/preferences.h"
|
||||
|
||||
#include <QIcon>
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#endif
|
||||
|
||||
GuiIconProvider::GuiIconProvider(QObject *parent)
|
||||
: IconProvider(parent)
|
||||
{
|
||||
configure();
|
||||
connect(Preferences::instance(), SIGNAL(changed()), SLOT(configure()));
|
||||
}
|
||||
|
||||
GuiIconProvider::~GuiIconProvider() {}
|
||||
|
||||
void GuiIconProvider::initInstance()
|
||||
{
|
||||
if (!m_instance)
|
||||
m_instance = new GuiIconProvider;
|
||||
}
|
||||
|
||||
GuiIconProvider *GuiIconProvider::instance()
|
||||
{
|
||||
return static_cast<GuiIconProvider *>(m_instance);
|
||||
}
|
||||
|
||||
QIcon GuiIconProvider::getIcon(const QString &iconId)
|
||||
{
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
||||
if (m_useSystemTheme) {
|
||||
QIcon icon = QIcon::fromTheme(iconId, QIcon(IconProvider::getIconPath(iconId)));
|
||||
icon = generateDifferentSizes(icon);
|
||||
return icon;
|
||||
}
|
||||
#endif
|
||||
return QIcon(IconProvider::getIconPath(iconId));
|
||||
}
|
||||
|
||||
// Makes sure the icon is at least available in 16px and 24px size
|
||||
// It scales the icon from the theme if necessary
|
||||
// Otherwise, the UI looks broken if the icon is not available
|
||||
// in the correct size.
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
||||
QIcon GuiIconProvider::generateDifferentSizes(const QIcon &icon)
|
||||
{
|
||||
QIcon newIcon;
|
||||
QList<QSize> requiredSizes;
|
||||
requiredSizes << QSize(16, 16) << QSize(24, 24) << QSize(32, 32);
|
||||
QList<QIcon::Mode> modes;
|
||||
modes << QIcon::Normal << QIcon::Active << QIcon::Selected << QIcon::Disabled;
|
||||
foreach (const QSize &size, requiredSizes) {
|
||||
foreach (QIcon::Mode mode, modes) {
|
||||
QPixmap pixoff = icon.pixmap(size, mode, QIcon::Off);
|
||||
if (pixoff.height() > size.height())
|
||||
pixoff = pixoff.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
newIcon.addPixmap(pixoff, mode, QIcon::Off);
|
||||
QPixmap pixon = icon.pixmap(size, mode, QIcon::On);
|
||||
if (pixon.height() > size.height())
|
||||
pixon = pixoff.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
newIcon.addPixmap(pixon, mode, QIcon::On);
|
||||
}
|
||||
}
|
||||
|
||||
return newIcon;
|
||||
}
|
||||
#endif
|
||||
|
||||
QString GuiIconProvider::getIconPath(const QString &iconId)
|
||||
{
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
||||
if (m_useSystemTheme) {
|
||||
QString path = QDir::temp().absoluteFilePath(iconId + ".png");
|
||||
if (!QFile::exists(path)) {
|
||||
const QIcon icon = QIcon::fromTheme(iconId);
|
||||
if (!icon.isNull())
|
||||
icon.pixmap(32).save(path);
|
||||
else
|
||||
path = IconProvider::getIconPath(iconId);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
#endif
|
||||
return IconProvider::getIconPath(iconId);
|
||||
}
|
||||
|
||||
|
||||
void GuiIconProvider::configure()
|
||||
{
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
||||
m_useSystemTheme = Preferences::instance()->useSystemIconTheme();
|
||||
#endif
|
||||
}
|
||||
62
src/gui/guiiconprovider.h
Normal file
62
src/gui/guiiconprovider.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2011 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give permission to
|
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||
* and distribute the linked executables. You must obey the GNU General Public
|
||||
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*/
|
||||
|
||||
#ifndef GUIICONPROVIDER_H
|
||||
#define GUIICONPROVIDER_H
|
||||
|
||||
#include "core/iconprovider.h"
|
||||
|
||||
class QIcon;
|
||||
|
||||
class GuiIconProvider : public IconProvider
|
||||
{
|
||||
Q_DISABLE_COPY(GuiIconProvider)
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static void initInstance();
|
||||
static GuiIconProvider *instance();
|
||||
|
||||
QIcon getIcon(const QString &iconId);
|
||||
QString getIconPath(const QString &iconId);
|
||||
|
||||
private slots:
|
||||
void configure();
|
||||
|
||||
private:
|
||||
explicit GuiIconProvider(QObject *parent = 0);
|
||||
~GuiIconProvider();
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
||||
QIcon generateDifferentSizes(const QIcon &icon);
|
||||
|
||||
bool m_useSystemTheme;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // GUIICONPROVIDER_H
|
||||
@@ -35,7 +35,7 @@
|
||||
#include <QRegExp>
|
||||
#include <QAction>
|
||||
#include "loglistwidget.h"
|
||||
#include "iconprovider.h"
|
||||
#include "guiiconprovider.h"
|
||||
|
||||
LogListWidget::LogListWidget(int max_lines, QWidget *parent) :
|
||||
QListWidget(parent),
|
||||
@@ -44,8 +44,8 @@ LogListWidget::LogListWidget(int max_lines, QWidget *parent) :
|
||||
// Allow multiple selections
|
||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
// Context menu
|
||||
QAction *copyAct = new QAction(IconProvider::instance()->getIcon("edit-copy"), tr("Copy"), this);
|
||||
QAction *clearAct = new QAction(IconProvider::instance()->getIcon("edit-clear"), tr("Clear"), this);
|
||||
QAction *copyAct = new QAction(GuiIconProvider::instance()->getIcon("edit-copy"), tr("Copy"), this);
|
||||
QAction *clearAct = new QAction(GuiIconProvider::instance()->getIcon("edit-clear"), tr("Clear"), this);
|
||||
connect(copyAct, SIGNAL(triggered()), SLOT(copySelection()));
|
||||
connect(clearAct, SIGNAL(triggered()), SLOT(clearLog()));
|
||||
addAction(copyAct);
|
||||
|
||||
@@ -55,7 +55,9 @@
|
||||
#include "addnewtorrentdialog.h"
|
||||
#include "searchengine.h"
|
||||
#include "rss_imp.h"
|
||||
#include "qbtsession.h"
|
||||
#include "core/bittorrent/session.h"
|
||||
#include "core/bittorrent/sessionstatus.h"
|
||||
#include "core/bittorrent/torrenthandle.h"
|
||||
#include "about_imp.h"
|
||||
#include "trackerlogin.h"
|
||||
#include "options_imp.h"
|
||||
@@ -63,7 +65,6 @@
|
||||
#include "core/preferences.h"
|
||||
#include "trackerlist.h"
|
||||
#include "peerlistwidget.h"
|
||||
#include "core/torrentpersistentdata.h"
|
||||
#include "transferlistfilterswidget.h"
|
||||
#include "propertieswidget.h"
|
||||
#include "statusbar.h"
|
||||
@@ -71,11 +72,9 @@
|
||||
#include "torrentimportdlg.h"
|
||||
#include "torrentmodel.h"
|
||||
#include "executionlog.h"
|
||||
#include "iconprovider.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "core/logger.h"
|
||||
#ifndef DISABLE_GUI
|
||||
#include "autoexpandabledialog.h"
|
||||
#endif
|
||||
#ifdef Q_OS_MAC
|
||||
void qt_mac_set_dock_menu(QMenu *menu);
|
||||
#endif
|
||||
@@ -86,13 +85,10 @@ void qt_mac_set_dock_menu(QMenu *menu);
|
||||
#endif
|
||||
#include "powermanagement.h"
|
||||
#ifdef Q_OS_WIN
|
||||
#include "core/downloadthread.h"
|
||||
#include "core/net/downloadmanager.h"
|
||||
#include "core/net/downloadhandler.h"
|
||||
#endif
|
||||
|
||||
#include <libtorrent/session.hpp>
|
||||
|
||||
using namespace libtorrent;
|
||||
|
||||
#define TIME_TRAY_BALLOON 5000
|
||||
#define PREVENT_SUSPEND_INTERVAL 60000
|
||||
|
||||
@@ -128,32 +124,32 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
|
||||
addToolbarContextMenu();
|
||||
|
||||
actionOpen->setIcon(IconProvider::instance()->getIcon("list-add"));
|
||||
actionDownload_from_URL->setIcon(IconProvider::instance()->getIcon("insert-link"));
|
||||
actionOpen->setIcon(GuiIconProvider::instance()->getIcon("list-add"));
|
||||
actionDownload_from_URL->setIcon(GuiIconProvider::instance()->getIcon("insert-link"));
|
||||
actionSet_upload_limit->setIcon(QIcon(QString::fromUtf8(":/icons/skin/seeding.png")));
|
||||
actionSet_download_limit->setIcon(QIcon(QString::fromUtf8(":/icons/skin/download.png")));
|
||||
actionSet_global_upload_limit->setIcon(QIcon(QString::fromUtf8(":/icons/skin/seeding.png")));
|
||||
actionSet_global_download_limit->setIcon(QIcon(QString::fromUtf8(":/icons/skin/download.png")));
|
||||
actionCreate_torrent->setIcon(IconProvider::instance()->getIcon("document-edit"));
|
||||
actionAbout->setIcon(IconProvider::instance()->getIcon("help-about"));
|
||||
actionStatistics->setIcon(IconProvider::instance()->getIcon("view-statistics"));
|
||||
actionBugReport->setIcon(IconProvider::instance()->getIcon("tools-report-bug"));
|
||||
actionDecreasePriority->setIcon(IconProvider::instance()->getIcon("go-down"));
|
||||
actionBottomPriority->setIcon(IconProvider::instance()->getIcon("go-bottom"));
|
||||
actionDelete->setIcon(IconProvider::instance()->getIcon("list-remove"));
|
||||
actionDocumentation->setIcon(IconProvider::instance()->getIcon("help-contents"));
|
||||
actionDonate_money->setIcon(IconProvider::instance()->getIcon("wallet-open"));
|
||||
actionExit->setIcon(IconProvider::instance()->getIcon("application-exit"));
|
||||
actionIncreasePriority->setIcon(IconProvider::instance()->getIcon("go-up"));
|
||||
actionTopPriority->setIcon(IconProvider::instance()->getIcon("go-top"));
|
||||
actionLock_qBittorrent->setIcon(IconProvider::instance()->getIcon("object-locked"));
|
||||
actionOptions->setIcon(IconProvider::instance()->getIcon("preferences-system"));
|
||||
actionPause->setIcon(IconProvider::instance()->getIcon("media-playback-pause"));
|
||||
actionPause_All->setIcon(IconProvider::instance()->getIcon("media-playback-pause"));
|
||||
actionStart->setIcon(IconProvider::instance()->getIcon("media-playback-start"));
|
||||
actionStart_All->setIcon(IconProvider::instance()->getIcon("media-playback-start"));
|
||||
action_Import_Torrent->setIcon(IconProvider::instance()->getIcon("document-import"));
|
||||
menuAuto_Shutdown_on_downloads_completion->setIcon(IconProvider::instance()->getIcon("application-exit"));
|
||||
actionCreate_torrent->setIcon(GuiIconProvider::instance()->getIcon("document-edit"));
|
||||
actionAbout->setIcon(GuiIconProvider::instance()->getIcon("help-about"));
|
||||
actionStatistics->setIcon(GuiIconProvider::instance()->getIcon("view-statistics"));
|
||||
actionBugReport->setIcon(GuiIconProvider::instance()->getIcon("tools-report-bug"));
|
||||
actionDecreasePriority->setIcon(GuiIconProvider::instance()->getIcon("go-down"));
|
||||
actionBottomPriority->setIcon(GuiIconProvider::instance()->getIcon("go-bottom"));
|
||||
actionDelete->setIcon(GuiIconProvider::instance()->getIcon("list-remove"));
|
||||
actionDocumentation->setIcon(GuiIconProvider::instance()->getIcon("help-contents"));
|
||||
actionDonate_money->setIcon(GuiIconProvider::instance()->getIcon("wallet-open"));
|
||||
actionExit->setIcon(GuiIconProvider::instance()->getIcon("application-exit"));
|
||||
actionIncreasePriority->setIcon(GuiIconProvider::instance()->getIcon("go-up"));
|
||||
actionTopPriority->setIcon(GuiIconProvider::instance()->getIcon("go-top"));
|
||||
actionLock_qBittorrent->setIcon(GuiIconProvider::instance()->getIcon("object-locked"));
|
||||
actionOptions->setIcon(GuiIconProvider::instance()->getIcon("preferences-system"));
|
||||
actionPause->setIcon(GuiIconProvider::instance()->getIcon("media-playback-pause"));
|
||||
actionPause_All->setIcon(GuiIconProvider::instance()->getIcon("media-playback-pause"));
|
||||
actionStart->setIcon(GuiIconProvider::instance()->getIcon("media-playback-start"));
|
||||
actionStart_All->setIcon(GuiIconProvider::instance()->getIcon("media-playback-start"));
|
||||
action_Import_Torrent->setIcon(GuiIconProvider::instance()->getIcon("document-import"));
|
||||
menuAuto_Shutdown_on_downloads_completion->setIcon(GuiIconProvider::instance()->getIcon("application-exit"));
|
||||
|
||||
QMenu *startAllMenu = new QMenu(this);
|
||||
startAllMenu->addAction(actionStart_All);
|
||||
@@ -169,14 +165,13 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
actionLock_qBittorrent->setMenu(lockMenu);
|
||||
|
||||
// Creating Bittorrent session
|
||||
connect(QBtSession::instance(), SIGNAL(fullDiskError(QTorrentHandle, QString)), this, SLOT(fullDiskError(QTorrentHandle, QString)));
|
||||
connect(QBtSession::instance(), SIGNAL(finishedTorrent(QTorrentHandle)), this, SLOT(finishedTorrent(QTorrentHandle)));
|
||||
connect(QBtSession::instance(), SIGNAL(trackerAuthenticationRequired(QTorrentHandle)), this, SLOT(trackerAuthenticationRequired(QTorrentHandle)));
|
||||
connect(QBtSession::instance(), SIGNAL(newDownloadedTorrent(QString, QString)), this, SLOT(processDownloadedFiles(QString, QString)));
|
||||
connect(QBtSession::instance(), SIGNAL(newMagnetLink(QString)), this, SLOT(processNewMagnetLink(QString)));
|
||||
connect(QBtSession::instance(), SIGNAL(downloadFromUrlFailure(QString, QString)), this, SLOT(handleDownloadFromUrlFailure(QString, QString)));
|
||||
connect(QBtSession::instance(), SIGNAL(alternativeSpeedsModeChanged(bool)), this, SLOT(updateAltSpeedsBtn(bool)));
|
||||
connect(QBtSession::instance(), SIGNAL(recursiveTorrentDownloadPossible(QTorrentHandle)), this, SLOT(askRecursiveTorrentDownloadConfirmation(QTorrentHandle)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(fullDiskError(BitTorrent::TorrentHandle *const, QString)), this, SLOT(fullDiskError(BitTorrent::TorrentHandle *const, QString)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(addTorrentFailed(const QString &)), this, SLOT(addTorrentFailed(const QString &)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(torrentFinished(BitTorrent::TorrentHandle *const)), this, SLOT(finishedTorrent(BitTorrent::TorrentHandle *const)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(trackerAuthenticationRequired(BitTorrent::TorrentHandle *const)), this, SLOT(trackerAuthenticationRequired(BitTorrent::TorrentHandle *const)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(downloadFromUrlFailed(QString, QString)), this, SLOT(handleDownloadFromUrlFailure(QString, QString)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(speedLimitModeChanged(bool)), this, SLOT(updateAltSpeedsBtn(bool)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(recursiveTorrentDownloadPossible(BitTorrent::TorrentHandle *const)), this, SLOT(askRecursiveTorrentDownloadConfirmation(BitTorrent::TorrentHandle *const)));
|
||||
|
||||
qDebug("create tabWidget");
|
||||
tabs = new HidableTabWidget(this);
|
||||
@@ -200,7 +195,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
toolBar->insertWidget(searchFilterAct, spacer);
|
||||
|
||||
// Transfer List tab
|
||||
transferList = new TransferListWidget(hSplitter, this, QBtSession::instance());
|
||||
transferList = new TransferListWidget(hSplitter, this);
|
||||
properties = new PropertiesWidget(hSplitter, this, transferList);
|
||||
transferListFilters = new TransferListFiltersWidget(vSplitter, transferList);
|
||||
hSplitter->addWidget(transferList);
|
||||
@@ -209,20 +204,18 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
vSplitter->addWidget(hSplitter);
|
||||
vSplitter->setCollapsible(0, true);
|
||||
vSplitter->setCollapsible(1, false);
|
||||
tabs->addTab(vSplitter, IconProvider::instance()->getIcon("folder-remote"), tr("Transfers"));
|
||||
tabs->addTab(vSplitter, GuiIconProvider::instance()->getIcon("folder-remote"), tr("Transfers"));
|
||||
|
||||
connect(search_filter, SIGNAL(textChanged(QString)), transferList, SLOT(applyNameFilter(QString)));
|
||||
connect(hSplitter, SIGNAL(splitterMoved(int, int)), this, SLOT(writeSettings()));
|
||||
connect(vSplitter, SIGNAL(splitterMoved(int, int)), this, SLOT(writeSettings()));
|
||||
connect(properties, SIGNAL(trackersAdded(const QStringList &, const QString &)), transferListFilters, SLOT(addTrackers(const QStringList &, const QString &)));
|
||||
connect(properties, SIGNAL(trackersRemoved(const QStringList &, const QString &)), transferListFilters, SLOT(removeTrackers(const QStringList &, const QString &)));
|
||||
connect(properties, SIGNAL(trackerlessChange(bool, const QString &)), transferListFilters, SLOT(changeTrackerless(bool, const QString &)));
|
||||
connect(QBtSession::instance(), SIGNAL(trackersAdded(const QStringList &, const QString &)), transferListFilters, SLOT(addTrackers(const QStringList &, const QString &)));
|
||||
connect(QBtSession::instance(), SIGNAL(trackerlessChange(bool, const QString &)), transferListFilters, SLOT(changeTrackerless(bool, const QString &)));
|
||||
connect(QBtSession::instance(), SIGNAL(reloadTrackersAndUrlSeeds(const QTorrentHandle &)), properties, SLOT(loadTrackers(const QTorrentHandle &)));
|
||||
connect(QBtSession::instance(), SIGNAL(trackerSuccess(const QString &, const QString &)), transferListFilters, SIGNAL(trackerSuccess(const QString &, const QString &)));
|
||||
connect(QBtSession::instance(), SIGNAL(trackerError(const QString &, const QString &)), transferListFilters, SIGNAL(trackerError(const QString &, const QString &)));
|
||||
connect(QBtSession::instance(), SIGNAL(trackerWarning(const QString &, const QString &)), transferListFilters, SIGNAL(trackerWarning(const QString &, const QString &)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(trackersChanged(BitTorrent::TorrentHandle *const)), properties, SLOT(loadTrackers(BitTorrent::TorrentHandle *const)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(trackersAdded(BitTorrent::TorrentHandle *const, const QList<BitTorrent::TrackerEntry> &)), transferListFilters, SLOT(addTrackers(BitTorrent::TorrentHandle *const, const QList<BitTorrent::TrackerEntry> &)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(trackersRemoved(BitTorrent::TorrentHandle *const, const QList<BitTorrent::TrackerEntry> &)), transferListFilters, SLOT(removeTrackers(BitTorrent::TorrentHandle *const, const QList<BitTorrent::TrackerEntry> &)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(trackerlessStateChanged(BitTorrent::TorrentHandle *const, bool)), transferListFilters, SLOT(changeTrackerless(BitTorrent::TorrentHandle *const, bool)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(trackerSuccess(BitTorrent::TorrentHandle *const, const QString &)), transferListFilters, SLOT(trackerSuccess(BitTorrent::TorrentHandle *const, const QString &)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(trackerError(BitTorrent::TorrentHandle *const, const QString &)), transferListFilters, SLOT(trackerError(BitTorrent::TorrentHandle *const, const QString &)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(trackerWarning(BitTorrent::TorrentHandle *const, const QString &)), transferListFilters, SLOT(trackerWarning(BitTorrent::TorrentHandle *const, const QString &)));
|
||||
|
||||
vboxLayout->addWidget(tabs);
|
||||
|
||||
@@ -231,9 +224,9 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
|
||||
// Transfer list slots
|
||||
connect(actionStart, SIGNAL(triggered()), transferList, SLOT(startSelectedTorrents()));
|
||||
connect(actionStart_All, SIGNAL(triggered()), QBtSession::instance(), SLOT(resumeAllTorrents()));
|
||||
connect(actionStart_All, SIGNAL(triggered()), transferList, SLOT(resumeAllTorrents()));
|
||||
connect(actionPause, SIGNAL(triggered()), transferList, SLOT(pauseSelectedTorrents()));
|
||||
connect(actionPause_All, SIGNAL(triggered()), QBtSession::instance(), SLOT(pauseAllTorrents()));
|
||||
connect(actionPause_All, SIGNAL(triggered()), transferList, SLOT(pauseAllTorrents()));
|
||||
connect(actionDelete, SIGNAL(triggered()), transferList, SLOT(deleteSelectedTorrents()));
|
||||
connect(actionTopPriority, SIGNAL(triggered()), transferList, SLOT(topPrioSelectedTorrents()));
|
||||
connect(actionIncreasePriority, SIGNAL(triggered()), transferList, SLOT(increasePrioSelectedTorrents()));
|
||||
@@ -258,10 +251,8 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
// Configure BT session according to options
|
||||
loadPreferences(false);
|
||||
|
||||
// Start connection checking timer
|
||||
guiUpdater = new QTimer(this);
|
||||
connect(guiUpdater, SIGNAL(timeout()), this, SLOT(updateGUI()));
|
||||
guiUpdater->start(2000);
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(torrentsUpdated()), this, SLOT(updateGUI()));
|
||||
|
||||
// Accept drag 'n drops
|
||||
setAcceptDrops(true);
|
||||
createKeyboardShortcuts();
|
||||
@@ -516,7 +507,7 @@ void MainWindow::displayRSSTab(bool enable)
|
||||
if (!rssWidget) {
|
||||
rssWidget = new RSSImp(tabs);
|
||||
int index_tab = tabs->addTab(rssWidget, tr("RSS"));
|
||||
tabs->setTabIcon(index_tab, IconProvider::instance()->getIcon("application-rss+xml"));
|
||||
tabs->setTabIcon(index_tab, GuiIconProvider::instance()->getIcon("application-rss+xml"));
|
||||
}
|
||||
}
|
||||
else if (rssWidget) {
|
||||
@@ -532,7 +523,7 @@ void MainWindow::displaySearchTab(bool enable)
|
||||
// RSS tab
|
||||
if (!searchEngine) {
|
||||
searchEngine = new SearchEngine(this);
|
||||
tabs->insertTab(1, searchEngine, IconProvider::instance()->getIcon("edit-find"), tr("Search"));
|
||||
tabs->insertTab(1, searchEngine, GuiIconProvider::instance()->getIcon("edit-find"), tr("Search"));
|
||||
}
|
||||
}
|
||||
else if (searchEngine) {
|
||||
@@ -595,7 +586,6 @@ void MainWindow::cleanup()
|
||||
writeSettings();
|
||||
|
||||
delete executable_watcher;
|
||||
guiUpdater->stop();
|
||||
if (systrayCreator)
|
||||
systrayCreator->stop();
|
||||
if (preventTimer)
|
||||
@@ -643,18 +633,21 @@ void MainWindow::balloonClicked()
|
||||
activateWindow();
|
||||
}
|
||||
|
||||
// called when a torrent has finished
|
||||
void MainWindow::finishedTorrent(const QTorrentHandle& h) const
|
||||
void MainWindow::addTorrentFailed(const QString &error) const
|
||||
{
|
||||
if (TorrentPersistentData::instance()->isSeed(h.hash()))
|
||||
showNotificationBaloon(tr("Download completion"), tr("%1 has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(h.name()));
|
||||
showNotificationBaloon(tr("Error"), tr("Failed to add torrent: %1").arg(error));
|
||||
}
|
||||
|
||||
// called when a torrent has finished
|
||||
void MainWindow::finishedTorrent(BitTorrent::TorrentHandle *const torrent) const
|
||||
{
|
||||
showNotificationBaloon(tr("Download completion"), tr("%1 has finished downloading.", "e.g: xxx.avi has finished downloading.").arg(torrent->name()));
|
||||
}
|
||||
|
||||
// Notification when disk is full
|
||||
void MainWindow::fullDiskError(const QTorrentHandle& h, QString msg) const
|
||||
void MainWindow::fullDiskError(BitTorrent::TorrentHandle *const torrent, QString msg) const
|
||||
{
|
||||
if (!h.is_valid()) return;
|
||||
showNotificationBaloon(tr("I/O Error", "i.e: Input/Output Error"), tr("An I/O error occurred for torrent %1.\n Reason: %2", "e.g: An error occurred for torrent xxx.avi.\n Reason: disk is full.").arg(h.name()).arg(msg));
|
||||
showNotificationBaloon(tr("I/O Error", "i.e: Input/Output Error"), tr("An I/O error occurred for torrent %1.\n Reason: %2", "e.g: An error occurred for torrent xxx.avi.\n Reason: disk is full.").arg(torrent->name()).arg(msg));
|
||||
}
|
||||
|
||||
void MainWindow::createKeyboardShortcuts()
|
||||
@@ -709,28 +702,21 @@ void MainWindow::displayRSSTab() const
|
||||
|
||||
// End of keyboard shortcuts slots
|
||||
|
||||
void MainWindow::askRecursiveTorrentDownloadConfirmation(const QTorrentHandle &h)
|
||||
void MainWindow::askRecursiveTorrentDownloadConfirmation(BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
Preferences* const pref = Preferences::instance();
|
||||
if (pref->recursiveDownloadDisabled()) return;
|
||||
// Get Torrent name
|
||||
QString torrent_name;
|
||||
try {
|
||||
torrent_name = h.name();
|
||||
} catch(invalid_handle&) {
|
||||
return;
|
||||
}
|
||||
QString torrent_name = torrent->name();
|
||||
QMessageBox confirmBox(QMessageBox::Question, tr("Recursive download confirmation"), tr("The torrent %1 contains torrent files, do you want to proceed with their download?").arg(torrent_name));
|
||||
QPushButton *yes = confirmBox.addButton(tr("Yes"), QMessageBox::YesRole);
|
||||
/*QPushButton *no = */ confirmBox.addButton(tr("No"), QMessageBox::NoRole);
|
||||
QPushButton *never = confirmBox.addButton(tr("Never"), QMessageBox::NoRole);
|
||||
confirmBox.exec();
|
||||
if (confirmBox.clickedButton() == 0) return;
|
||||
if (confirmBox.clickedButton() == yes) {
|
||||
QBtSession::instance()->recursiveTorrentDownload(h);
|
||||
return;
|
||||
}
|
||||
if (confirmBox.clickedButton() == never)
|
||||
|
||||
if (confirmBox.clickedButton() == yes)
|
||||
BitTorrent::Session::instance()->recursiveTorrentDownload(torrent->hash());
|
||||
else if (confirmBox.clickedButton() == never)
|
||||
pref->disableRecursiveDownload();
|
||||
}
|
||||
|
||||
@@ -744,11 +730,11 @@ void MainWindow::on_actionSet_global_upload_limit_triggered()
|
||||
{
|
||||
qDebug("actionSet_global_upload_limit_triggered");
|
||||
bool ok;
|
||||
int cur_limit = QBtSession::instance()->getSession()->settings().upload_rate_limit;
|
||||
int cur_limit = BitTorrent::Session::instance()->uploadRateLimit();
|
||||
const long new_limit = SpeedLimitDialog::askSpeedLimit(&ok, tr("Global Upload Speed Limit"), cur_limit);
|
||||
if (ok) {
|
||||
qDebug("Setting global upload rate limit to %.1fKb/s", new_limit / 1024.);
|
||||
QBtSession::instance()->setUploadRateLimit(new_limit);
|
||||
BitTorrent::Session::instance()->setUploadRateLimit(new_limit);
|
||||
if (new_limit <= 0)
|
||||
Preferences::instance()->setGlobalUploadLimit(-1);
|
||||
else
|
||||
@@ -760,11 +746,11 @@ void MainWindow::on_actionSet_global_download_limit_triggered()
|
||||
{
|
||||
qDebug("actionSet_global_download_limit_triggered");
|
||||
bool ok;
|
||||
int cur_limit = QBtSession::instance()->getSession()->settings().download_rate_limit;
|
||||
int cur_limit = BitTorrent::Session::instance()->downloadRateLimit();
|
||||
const long new_limit = SpeedLimitDialog::askSpeedLimit(&ok, tr("Global Download Speed Limit"), cur_limit);
|
||||
if (ok) {
|
||||
qDebug("Setting global download rate limit to %.1fKb/s", new_limit / 1024.);
|
||||
QBtSession::instance()->setDownloadRateLimit(new_limit);
|
||||
BitTorrent::Session::instance()->setDownloadRateLimit(new_limit);
|
||||
if (new_limit <= 0)
|
||||
Preferences::instance()->setGlobalDownloadLimit(-1);
|
||||
else
|
||||
@@ -904,7 +890,7 @@ void MainWindow::closeEvent(QCloseEvent *e)
|
||||
return;
|
||||
}
|
||||
|
||||
if (pref->confirmOnExit() && QBtSession::instance()->hasActiveTorrents()) {
|
||||
if (pref->confirmOnExit() && BitTorrent::Session::instance()->hasActiveTorrents()) {
|
||||
if (e->spontaneous() || force_exit) {
|
||||
if (!isVisible())
|
||||
show();
|
||||
@@ -941,13 +927,10 @@ void MainWindow::closeEvent(QCloseEvent *e)
|
||||
// Display window to create a torrent
|
||||
void MainWindow::on_actionCreate_torrent_triggered()
|
||||
{
|
||||
if (createTorrentDlg) {
|
||||
if (createTorrentDlg)
|
||||
createTorrentDlg->setFocus();
|
||||
}
|
||||
else {
|
||||
else
|
||||
createTorrentDlg = new TorrentCreatorDlg(this);
|
||||
connect(createTorrentDlg, SIGNAL(torrent_to_seed(QString)), this, SLOT(addTorrent(QString)));
|
||||
}
|
||||
}
|
||||
|
||||
bool MainWindow::event(QEvent * e)
|
||||
@@ -1015,33 +998,15 @@ void MainWindow::dropEvent(QDropEvent *event)
|
||||
else {
|
||||
files = event->mimeData()->text().split(QString::fromUtf8("\n"));
|
||||
}
|
||||
|
||||
// Add file to download list
|
||||
Preferences* const pref = Preferences::instance();
|
||||
const bool useTorrentAdditionDialog = pref->useAdditionDialog();
|
||||
const bool useTorrentAdditionDialog = Preferences::instance()->useAdditionDialog();
|
||||
foreach (QString file, files) {
|
||||
qDebug("Dropped file %s on download list", qPrintable(file));
|
||||
if (misc::isUrl(file)) {
|
||||
QBtSession::instance()->downloadFromUrl(file);
|
||||
continue;
|
||||
}
|
||||
// Bitcomet or Magnet link
|
||||
if (file.startsWith("bc://bt/", Qt::CaseInsensitive)) {
|
||||
qDebug("Converting bc link to magnet link");
|
||||
file = misc::bcLinkToMagnet(file);
|
||||
}
|
||||
if (file.startsWith("magnet:", Qt::CaseInsensitive)) {
|
||||
if (useTorrentAdditionDialog)
|
||||
AddNewTorrentDialog::showMagnet(file, this);
|
||||
else
|
||||
QBtSession::instance()->addMagnetUri(file);
|
||||
}
|
||||
else {
|
||||
// Local file
|
||||
if (useTorrentAdditionDialog)
|
||||
AddNewTorrentDialog::showTorrent(file, QString(), this);
|
||||
else
|
||||
QBtSession::instance()->addTorrent(file);
|
||||
}
|
||||
if (useTorrentAdditionDialog)
|
||||
AddNewTorrentDialog::show(file, this);
|
||||
else
|
||||
BitTorrent::Session::instance()->addTorrent(file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1067,22 +1032,22 @@ void MainWindow::on_actionOpen_triggered()
|
||||
Preferences* const pref = Preferences::instance();
|
||||
// Open File Open Dialog
|
||||
// Note: it is possible to select more than one file
|
||||
const QStringList pathsList = QFileDialog::getOpenFileNames(0,
|
||||
tr("Open Torrent Files"), pref->getMainLastDir(),
|
||||
tr("Torrent Files") + QString::fromUtf8(" (*.torrent)"));
|
||||
if (!pathsList.empty()) {
|
||||
const uint listSize = pathsList.size();
|
||||
for (uint i = 0; i<listSize; ++i) {
|
||||
if (pref->useAdditionDialog())
|
||||
AddNewTorrentDialog::showTorrent(pathsList.at(i), QString(), this);
|
||||
else
|
||||
QBtSession::instance()->addTorrent(pathsList.at(i));
|
||||
}
|
||||
// Save last dir to remember it
|
||||
QStringList top_dir = fsutils::fromNativePath(pathsList.at(0)).split("/");
|
||||
top_dir.removeLast();
|
||||
pref->setMainLastDir(fsutils::fromNativePath(top_dir.join("/")));
|
||||
const QStringList pathsList =
|
||||
QFileDialog::getOpenFileNames(0, tr("Open Torrent Files"), pref->getMainLastDir(),
|
||||
tr("Torrent Files") + QString::fromUtf8(" (*.torrent)"));
|
||||
const bool useTorrentAdditionDialog = Preferences::instance()->useAdditionDialog();
|
||||
foreach (QString file, pathsList) {
|
||||
qDebug("Dropped file %s on download list", qPrintable(file));
|
||||
if (useTorrentAdditionDialog)
|
||||
AddNewTorrentDialog::show(file, this);
|
||||
else
|
||||
BitTorrent::Session::instance()->addTorrent(file);
|
||||
}
|
||||
|
||||
// Save last dir to remember it
|
||||
QStringList top_dir = fsutils::fromNativePath(pathsList.at(0)).split("/");
|
||||
top_dir.removeLast();
|
||||
pref->setMainLastDir(fsutils::fromNativePath(top_dir.join("/")));
|
||||
}
|
||||
|
||||
void MainWindow::activate()
|
||||
@@ -1094,29 +1059,6 @@ void MainWindow::activate()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::addTorrent(QString path)
|
||||
{
|
||||
QBtSession::instance()->addTorrent(path);
|
||||
}
|
||||
|
||||
void MainWindow::processDownloadedFiles(QString path, QString url)
|
||||
{
|
||||
Preferences* const pref = Preferences::instance();
|
||||
if (pref->useAdditionDialog())
|
||||
AddNewTorrentDialog::showTorrent(path, url, this);
|
||||
else
|
||||
QBtSession::instance()->addTorrent(path, false, url);
|
||||
}
|
||||
|
||||
void MainWindow::processNewMagnetLink(const QString& link)
|
||||
{
|
||||
Preferences* const pref = Preferences::instance();
|
||||
if (pref->useAdditionDialog())
|
||||
AddNewTorrentDialog::showMagnet(link, this);
|
||||
else
|
||||
QBtSession::instance()->addMagnetUri(link);
|
||||
}
|
||||
|
||||
void MainWindow::optionsSaved()
|
||||
{
|
||||
loadPreferences();
|
||||
@@ -1175,8 +1117,6 @@ void MainWindow::loadPreferences(bool configure_session)
|
||||
m_pwr->setActivityState(false);
|
||||
}
|
||||
|
||||
const uint new_refreshInterval = pref->getRefreshInterval();
|
||||
transferList->setRefreshInterval(new_refreshInterval);
|
||||
transferList->setAlternatingRowColors(pref->useAlternatingRowColors());
|
||||
properties->getFilesList()->setAlternatingRowColors(pref->useAlternatingRowColors());
|
||||
properties->getTrackerList()->setAlternatingRowColors(pref->useAlternatingRowColors());
|
||||
@@ -1209,11 +1149,6 @@ void MainWindow::loadPreferences(bool configure_session)
|
||||
// Torrent properties
|
||||
properties->reloadPreferences();
|
||||
|
||||
// Icon provider
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
||||
IconProvider::instance()->useSystemIconTheme(pref->useSystemIconTheme());
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||
if (pref->isUpdateCheckEnabled())
|
||||
checkProgramUpdate();
|
||||
@@ -1224,7 +1159,7 @@ void MainWindow::loadPreferences(bool configure_session)
|
||||
qDebug("GUI settings loaded");
|
||||
}
|
||||
|
||||
void MainWindow::addUnauthenticatedTracker(const QPair<QTorrentHandle,QString> &tracker)
|
||||
void MainWindow::addUnauthenticatedTracker(const QPair<BitTorrent::TorrentHandle *const, QString> &tracker)
|
||||
{
|
||||
// Trackers whose authentication was cancelled
|
||||
if (unauthenticated_trackers.indexOf(tracker) < 0)
|
||||
@@ -1232,16 +1167,18 @@ void MainWindow::addUnauthenticatedTracker(const QPair<QTorrentHandle,QString> &
|
||||
}
|
||||
|
||||
// Called when a tracker requires authentication
|
||||
void MainWindow::trackerAuthenticationRequired(const QTorrentHandle& h)
|
||||
void MainWindow::trackerAuthenticationRequired(BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
if (unauthenticated_trackers.indexOf(QPair<QTorrentHandle,QString>(h, h.current_tracker())) < 0)
|
||||
if (unauthenticated_trackers.indexOf(QPair<BitTorrent::TorrentHandle *const, QString>(torrent, torrent->currentTracker())) < 0)
|
||||
// Tracker login
|
||||
new trackerLogin(this, h);
|
||||
new trackerLogin(this, torrent);
|
||||
}
|
||||
|
||||
// Check connection status and display right icon
|
||||
void MainWindow::updateGUI()
|
||||
{
|
||||
BitTorrent::SessionStatus status = BitTorrent::Session::instance()->status();
|
||||
|
||||
// update global informations
|
||||
if (systrayIcon) {
|
||||
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC))
|
||||
@@ -1249,21 +1186,21 @@ void MainWindow::updateGUI()
|
||||
html += "qBittorrent";
|
||||
html += "</div>";
|
||||
html += "<div style='vertical-align: baseline; height: 18px;'>";
|
||||
html += "<img src=':/icons/skin/download.png'/> " + tr("DL speed: %1", "e.g: Download speed: 10 KiB/s").arg(misc::friendlyUnit(QBtSession::instance()->getPayloadDownloadRate(), true));
|
||||
html += "<img src=':/icons/skin/download.png'/> " + tr("DL speed: %1", "e.g: Download speed: 10 KiB/s").arg(misc::friendlyUnit(status.payloadDownloadRate(), true));
|
||||
html += "</div>";
|
||||
html += "<div style='vertical-align: baseline; height: 18px;'>";
|
||||
html += "<img src=':/icons/skin/seeding.png'/> " + tr("UP speed: %1", "e.g: Upload speed: 10 KiB/s").arg(misc::friendlyUnit(QBtSession::instance()->getPayloadUploadRate(), true));
|
||||
html += "<img src=':/icons/skin/seeding.png'/> " + tr("UP speed: %1", "e.g: Upload speed: 10 KiB/s").arg(misc::friendlyUnit(status.payloadUploadRate(), true));
|
||||
html += "</div>";
|
||||
#else
|
||||
// OSes such as Windows do not support html here
|
||||
QString html = tr("DL speed: %1", "e.g: Download speed: 10 KiB/s").arg(misc::friendlyUnit(QBtSession::instance()->getPayloadDownloadRate(), true));
|
||||
QString html = tr("DL speed: %1", "e.g: Download speed: 10 KiB/s").arg(misc::friendlyUnit(status.payloadDownloadRate(), true));
|
||||
html += "\n";
|
||||
html += tr("UP speed: %1", "e.g: Upload speed: 10 KiB/s").arg(misc::friendlyUnit(QBtSession::instance()->getPayloadUploadRate(), true));
|
||||
html += tr("UP speed: %1", "e.g: Upload speed: 10 KiB/s").arg(misc::friendlyUnit(status.payloadUploadRate(), true));
|
||||
#endif
|
||||
systrayIcon->setToolTip(html); // tray icon
|
||||
}
|
||||
if (displaySpeedInTitle)
|
||||
setWindowTitle(tr("[D: %1, U: %2] qBittorrent %3", "D = Download; U = Upload; %3 is qBittorrent version").arg(misc::friendlyUnit(QBtSession::instance()->getPayloadDownloadRate(), true)).arg(misc::friendlyUnit(QBtSession::instance()->getPayloadUploadRate(), true)).arg(QString::fromUtf8(VERSION)));
|
||||
setWindowTitle(tr("[D: %1, U: %2] qBittorrent %3", "D = Download; U = Upload; %3 is qBittorrent version").arg(misc::friendlyUnit(status.payloadDownloadRate(), true)).arg(misc::friendlyUnit(status.payloadUploadRate(), true)).arg(QString::fromUtf8(VERSION)));
|
||||
}
|
||||
|
||||
void MainWindow::showNotificationBaloon(QString title, QString msg) const
|
||||
@@ -1302,26 +1239,16 @@ void MainWindow::showNotificationBaloon(QString title, QString msg) const
|
||||
|
||||
void MainWindow::downloadFromURLList(const QStringList& url_list)
|
||||
{
|
||||
Preferences* const pref = Preferences::instance();
|
||||
const bool useTorrentAdditionDialog = pref->useAdditionDialog();
|
||||
const bool useTorrentAdditionDialog = Preferences::instance()->useAdditionDialog();
|
||||
foreach (QString url, url_list) {
|
||||
if (url.startsWith("bc://bt/", Qt::CaseInsensitive)) {
|
||||
qDebug("Converting bc link to magnet link");
|
||||
url = misc::bcLinkToMagnet(url);
|
||||
}
|
||||
if ((url.size() == 40 && !url.contains(QRegExp("[^0-9A-Fa-f]")))
|
||||
|| (url.size() == 32 && !url.contains(QRegExp("[^2-7A-Za-z]"))))
|
||||
url = "magnet:?xt=urn:btih:" + url;
|
||||
if (url.startsWith("magnet:", Qt::CaseInsensitive)) {
|
||||
if (useTorrentAdditionDialog)
|
||||
AddNewTorrentDialog::showMagnet(url, this);
|
||||
else
|
||||
QBtSession::instance()->addMagnetUri(url);
|
||||
}
|
||||
else if (url.startsWith("http://", Qt::CaseInsensitive) || url.startsWith("https://", Qt::CaseInsensitive)
|
||||
|| url.startsWith("ftp://", Qt::CaseInsensitive)) {
|
||||
QBtSession::instance()->downloadFromUrl(url);
|
||||
}
|
||||
|
||||
if (useTorrentAdditionDialog)
|
||||
AddNewTorrentDialog::show(url, this);
|
||||
else
|
||||
BitTorrent::Session::instance()->addTorrent(url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1549,7 +1476,7 @@ void MainWindow::on_actionExecution_Logs_triggered(bool checked)
|
||||
Q_ASSERT(!m_executionLog);
|
||||
m_executionLog = new ExecutionLog(tabs);
|
||||
int index_tab = tabs->addTab(m_executionLog, tr("Execution Log"));
|
||||
tabs->setTabIcon(index_tab, IconProvider::instance()->getIcon("view-calendar-journal"));
|
||||
tabs->setTabIcon(index_tab, GuiIconProvider::instance()->getIcon("view-calendar-journal"));
|
||||
}
|
||||
else if (m_executionLog) {
|
||||
delete m_executionLog;
|
||||
@@ -1583,7 +1510,7 @@ void MainWindow::on_actionAutoShutdown_system_toggled(bool enabled)
|
||||
|
||||
void MainWindow::checkForActiveTorrents()
|
||||
{
|
||||
m_pwr->setActivityState(transferList->getSourceModel()->inhibitSystem());
|
||||
m_pwr->setActivityState(BitTorrent::Session::instance()->hasActiveTorrents());
|
||||
}
|
||||
|
||||
QIcon MainWindow::getSystrayIcon() const
|
||||
@@ -1650,21 +1577,20 @@ void MainWindow::installPython()
|
||||
{
|
||||
setCursor(QCursor(Qt::WaitCursor));
|
||||
// Download python
|
||||
DownloadThread *pydownloader = new DownloadThread(this);
|
||||
connect(pydownloader, SIGNAL(downloadFinished(QString,QString)), this, SLOT(pythonDownloadSuccess(QString,QString)));
|
||||
connect(pydownloader, SIGNAL(downloadFailure(QString,QString)), this, SLOT(pythonDownloadFailure(QString,QString)));
|
||||
pydownloader->downloadUrl("http://python.org/ftp/python/2.7.3/python-2.7.3.msi");
|
||||
Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl("http://python.org/ftp/python/2.7.3/python-2.7.3.msi");
|
||||
connect(handler, SIGNAL(downloadFinished(QString, QString)), this, SLOT(pythonDownloadSuccess(QString, QString)));
|
||||
connect(handler, SIGNAL(downloadFailed(QString, QString)), this, SLOT(pythonDownloadFailure(QString, QString)));
|
||||
}
|
||||
|
||||
void MainWindow::pythonDownloadSuccess(QString url, QString file_path)
|
||||
void MainWindow::pythonDownloadSuccess(const QString &url, const QString &filePath)
|
||||
{
|
||||
Q_UNUSED(url)
|
||||
setCursor(QCursor(Qt::ArrowCursor));
|
||||
Q_UNUSED(url);
|
||||
QFile::rename(file_path, file_path + ".msi");
|
||||
QFile::rename(filePath, filePath + ".msi");
|
||||
QProcess installer;
|
||||
qDebug("Launching Python installer in passive mode...");
|
||||
|
||||
installer.start("msiexec.exe /passive /i " + fsutils::toNativePath(file_path) + ".msi");
|
||||
installer.start("msiexec.exe /passive /i " + fsutils::toNativePath(filePath) + ".msi");
|
||||
// Wait for setup to complete
|
||||
installer.waitForFinished();
|
||||
|
||||
@@ -1672,21 +1598,19 @@ void MainWindow::pythonDownloadSuccess(QString url, QString file_path)
|
||||
qDebug("Installer stderr: %s", installer.readAllStandardError().data());
|
||||
qDebug("Setup should be complete!");
|
||||
// Delete temp file
|
||||
fsutils::forceRemove(file_path);
|
||||
fsutils::forceRemove(filePath);
|
||||
// Reload search engine
|
||||
has_python = addPythonPathToEnv();
|
||||
if (has_python) {
|
||||
actionSearch_engine->setChecked(true);
|
||||
displaySearchTab(true);
|
||||
}
|
||||
sender()->deleteLater();
|
||||
}
|
||||
|
||||
void MainWindow::pythonDownloadFailure(QString url, QString error)
|
||||
void MainWindow::pythonDownloadFailure(const QString &url, const QString &error)
|
||||
{
|
||||
Q_UNUSED(url);
|
||||
Q_UNUSED(url)
|
||||
setCursor(QCursor(Qt::ArrowCursor));
|
||||
QMessageBox::warning(this, tr("Download error"), tr("Python setup could not be downloaded, reason: %1.\nPlease install it manually.").arg(error));
|
||||
sender()->deleteLater();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -35,10 +35,8 @@
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QPointer>
|
||||
#include "ui_mainwindow.h"
|
||||
#include "qtorrenthandle.h"
|
||||
#include "statsdialog.h"
|
||||
|
||||
class QBtSession;
|
||||
class downloadFromURL;
|
||||
class SearchEngine;
|
||||
class RSSImp;
|
||||
@@ -64,6 +62,11 @@ class QTabWidget;
|
||||
class QTimer;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class TorrentHandle;
|
||||
}
|
||||
|
||||
class MainWindow: public QMainWindow, private Ui::MainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -79,7 +82,7 @@ public:
|
||||
PropertiesWidget *getProperties() const { return properties; }
|
||||
|
||||
public slots:
|
||||
void trackerAuthenticationRequired(const QTorrentHandle& h);
|
||||
void trackerAuthenticationRequired(BitTorrent::TorrentHandle *const torrent);
|
||||
void setTabText(int index, QString text) const;
|
||||
void showNotificationBaloon(QString title, QString msg) const;
|
||||
void downloadFromURLList(const QStringList& urls);
|
||||
@@ -101,7 +104,7 @@ protected slots:
|
||||
void readSettings();
|
||||
void on_actionExit_triggered();
|
||||
void createTrayIcon();
|
||||
void fullDiskError(const QTorrentHandle& h, QString msg) const;
|
||||
void fullDiskError(BitTorrent::TorrentHandle *const torrent, QString msg) const;
|
||||
void handleDownloadFromUrlFailure(QString, QString) const;
|
||||
void createSystrayDelayed();
|
||||
void tab_changed(int);
|
||||
@@ -125,12 +128,10 @@ protected slots:
|
||||
void on_actionOpen_triggered();
|
||||
void updateGUI();
|
||||
void loadPreferences(bool configure_session = true);
|
||||
void addTorrent(QString path);
|
||||
void addUnauthenticatedTracker(const QPair<QTorrentHandle,QString> &tracker);
|
||||
void processDownloadedFiles(QString path, QString url);
|
||||
void processNewMagnetLink(const QString& link);
|
||||
void finishedTorrent(const QTorrentHandle& h) const;
|
||||
void askRecursiveTorrentDownloadConfirmation(const QTorrentHandle &h);
|
||||
void addUnauthenticatedTracker(const QPair<BitTorrent::TorrentHandle *const, QString> &tracker);
|
||||
void addTorrentFailed(const QString &error) const;
|
||||
void finishedTorrent(BitTorrent::TorrentHandle *const torrent) const;
|
||||
void askRecursiveTorrentDownloadConfirmation(BitTorrent::TorrentHandle *const torrent);
|
||||
// Options slots
|
||||
void on_actionOptions_triggered();
|
||||
void optionsSaved();
|
||||
@@ -156,18 +157,17 @@ private:
|
||||
void installPython();
|
||||
|
||||
private slots:
|
||||
void pythonDownloadSuccess(QString url, QString file_path);
|
||||
void pythonDownloadFailure(QString url, QString error);
|
||||
void pythonDownloadSuccess(const QString &url, const QString &filePath);
|
||||
void pythonDownloadFailure(const QString &url, const QString &error);
|
||||
#endif
|
||||
void addToolbarContextMenu();
|
||||
|
||||
private:
|
||||
QFileSystemWatcher *executable_watcher;
|
||||
// Bittorrent
|
||||
QList<QPair<QTorrentHandle,QString> > unauthenticated_trackers; // Still needed?
|
||||
QList<QPair<BitTorrent::TorrentHandle *const, QString> > unauthenticated_trackers; // Still needed?
|
||||
// GUI related
|
||||
bool m_posInitialized;
|
||||
QTimer *guiUpdater;
|
||||
QTabWidget *tabs;
|
||||
StatusBar *status_bar;
|
||||
QPointer<options_imp> options;
|
||||
|
||||
@@ -45,9 +45,9 @@
|
||||
#include "core/preferences.h"
|
||||
#include "core/fs_utils.h"
|
||||
#include "advancedsettings.h"
|
||||
#include "core/scannedfoldersmodel.h"
|
||||
#include "qbtsession.h"
|
||||
#include "iconprovider.h"
|
||||
#include "core/scanfoldersmodel.h"
|
||||
#include "core/bittorrent/session.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "core/net/dnsupdater.h"
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
@@ -55,8 +55,6 @@
|
||||
#include <QSslCertificate>
|
||||
#endif
|
||||
|
||||
using namespace libtorrent;
|
||||
|
||||
// Constructor
|
||||
options_imp::options_imp(QWidget *parent):
|
||||
QDialog(parent), m_refreshingIpFilter(false) {
|
||||
@@ -65,18 +63,18 @@ options_imp::options_imp(QWidget *parent):
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
setModal(true);
|
||||
// Icons
|
||||
tabSelection->item(TAB_UI)->setIcon(IconProvider::instance()->getIcon("preferences-desktop"));
|
||||
tabSelection->item(TAB_BITTORRENT)->setIcon(IconProvider::instance()->getIcon("preferences-system-network"));
|
||||
tabSelection->item(TAB_CONNECTION)->setIcon(IconProvider::instance()->getIcon("network-wired"));
|
||||
tabSelection->item(TAB_DOWNLOADS)->setIcon(IconProvider::instance()->getIcon("download"));
|
||||
tabSelection->item(TAB_SPEED)->setIcon(IconProvider::instance()->getIcon("chronometer"));
|
||||
tabSelection->item(TAB_UI)->setIcon(GuiIconProvider::instance()->getIcon("preferences-desktop"));
|
||||
tabSelection->item(TAB_BITTORRENT)->setIcon(GuiIconProvider::instance()->getIcon("preferences-system-network"));
|
||||
tabSelection->item(TAB_CONNECTION)->setIcon(GuiIconProvider::instance()->getIcon("network-wired"));
|
||||
tabSelection->item(TAB_DOWNLOADS)->setIcon(GuiIconProvider::instance()->getIcon("download"));
|
||||
tabSelection->item(TAB_SPEED)->setIcon(GuiIconProvider::instance()->getIcon("chronometer"));
|
||||
#ifndef DISABLE_WEBUI
|
||||
tabSelection->item(TAB_WEBUI)->setIcon(IconProvider::instance()->getIcon("network-server"));
|
||||
tabSelection->item(TAB_WEBUI)->setIcon(GuiIconProvider::instance()->getIcon("network-server"));
|
||||
#else
|
||||
tabSelection->item(TAB_WEBUI)->setHidden(true);
|
||||
#endif
|
||||
tabSelection->item(TAB_ADVANCED)->setIcon(IconProvider::instance()->getIcon("preferences-other"));
|
||||
IpFilterRefreshBtn->setIcon(IconProvider::instance()->getIcon("view-refresh"));
|
||||
tabSelection->item(TAB_ADVANCED)->setIcon(GuiIconProvider::instance()->getIcon("preferences-other"));
|
||||
IpFilterRefreshBtn->setIcon(GuiIconProvider::instance()->getIcon("view-refresh"));
|
||||
|
||||
hsplitter->setCollapsible(0, false);
|
||||
hsplitter->setCollapsible(1, false);
|
||||
@@ -494,7 +492,7 @@ void options_imp::saveOptions() {
|
||||
advancedSettings->saveAdvancedSettings();
|
||||
// Assume that user changed multiple settings
|
||||
// so it's best to save immediately
|
||||
pref->save();
|
||||
pref->apply();
|
||||
}
|
||||
|
||||
bool options_imp::isFilteringEnabled() const {
|
||||
@@ -1250,9 +1248,9 @@ void options_imp::on_IpFilterRefreshBtn_clicked() {
|
||||
pref->setFilteringEnabled(true);
|
||||
pref->setFilter(getFilter());
|
||||
// Force refresh
|
||||
connect(QBtSession::instance(), SIGNAL(ipFilterParsed(bool, int)), SLOT(handleIPFilterParsed(bool, int)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(ipFilterParsed(bool, int)), SLOT(handleIPFilterParsed(bool, int)));
|
||||
setCursor(QCursor(Qt::WaitCursor));
|
||||
QBtSession::instance()->enableIPFilter(getFilter(), true);
|
||||
BitTorrent::Session::instance()->enableIPFilter(getFilter(), true);
|
||||
}
|
||||
|
||||
void options_imp::handleIPFilterParsed(bool error, int ruleCount)
|
||||
@@ -1264,7 +1262,7 @@ void options_imp::handleIPFilterParsed(bool error, int ruleCount)
|
||||
QMessageBox::information(this, tr("Successfully refreshed"), tr("Successfully parsed the provided IP filter: %1 rules were applied.", "%1 is a number").arg(ruleCount));
|
||||
}
|
||||
m_refreshingIpFilter = false;
|
||||
disconnect(QBtSession::instance(), SIGNAL(ipFilterParsed(bool, int)), this, SLOT(handleIPFilterParsed(bool, int)));
|
||||
disconnect(BitTorrent::Session::instance(), SIGNAL(ipFilterParsed(bool, int)), this, SLOT(handleIPFilterParsed(bool, int)));
|
||||
}
|
||||
|
||||
QString options_imp::languageToLocalizedString(const QLocale &locale)
|
||||
|
||||
@@ -33,16 +33,16 @@
|
||||
#include <QMessageBox>
|
||||
#include <QFile>
|
||||
|
||||
#include <libtorrent/version.hpp>
|
||||
#include <libtorrent/session.hpp>
|
||||
|
||||
#include "core/misc.h"
|
||||
#include "previewlistdelegate.h"
|
||||
#include "previewselect.h"
|
||||
#include "core/fs_utils.h"
|
||||
#include "core/preferences.h"
|
||||
|
||||
PreviewSelect::PreviewSelect(QWidget* parent, QTorrentHandle h): QDialog(parent), h(h) {
|
||||
PreviewSelect::PreviewSelect(QWidget* parent, BitTorrent::TorrentHandle *const torrent)
|
||||
: QDialog(parent)
|
||||
, m_torrent(torrent)
|
||||
{
|
||||
setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
Preferences* const pref = Preferences::instance();
|
||||
@@ -58,11 +58,10 @@ PreviewSelect::PreviewSelect(QWidget* parent, QTorrentHandle h): QDialog(parent)
|
||||
previewList->header()->resizeSection(0, 200);
|
||||
previewList->setAlternatingRowColors(pref->useAlternatingRowColors());
|
||||
// Fill list in
|
||||
std::vector<libtorrent::size_type> fp;
|
||||
h.file_progress(fp);
|
||||
unsigned int nbFiles = h.num_files();
|
||||
for (unsigned int i=0; i<nbFiles; ++i) {
|
||||
QString fileName = h.filename_at(i);
|
||||
QVector<qreal> fp = torrent->filesProgress();
|
||||
uint nbFiles = torrent->filesCount();
|
||||
for (uint i = 0; i < nbFiles; ++i) {
|
||||
QString fileName = torrent->fileName(i);
|
||||
if (fileName.endsWith(".!qB"))
|
||||
fileName.chop(4);
|
||||
QString extension = fsutils::fileExtension(fileName).toUpper();
|
||||
@@ -70,8 +69,8 @@ PreviewSelect::PreviewSelect(QWidget* parent, QTorrentHandle h): QDialog(parent)
|
||||
int row = previewListModel->rowCount();
|
||||
previewListModel->insertRow(row);
|
||||
previewListModel->setData(previewListModel->index(row, NAME), QVariant(fileName));
|
||||
previewListModel->setData(previewListModel->index(row, SIZE), QVariant((qlonglong)h.filesize_at(i)));
|
||||
previewListModel->setData(previewListModel->index(row, PROGRESS), QVariant((double)fp[i]/h.filesize_at(i)));
|
||||
previewListModel->setData(previewListModel->index(row, SIZE), QVariant(torrent->fileSize(i)));
|
||||
previewListModel->setData(previewListModel->index(row, PROGRESS), QVariant(fp[i]));
|
||||
previewListModel->setData(previewListModel->index(row, FILE_INDEX), QVariant(i));
|
||||
}
|
||||
}
|
||||
@@ -105,9 +104,9 @@ void PreviewSelect::on_previewButton_clicked() {
|
||||
QModelIndexList selectedIndexes = previewList->selectionModel()->selectedRows(FILE_INDEX);
|
||||
if (selectedIndexes.size() == 0) return;
|
||||
// Flush data
|
||||
h.flush_cache();
|
||||
m_torrent->flushCache();
|
||||
|
||||
QStringList absolute_paths(h.absolute_files_path());
|
||||
QStringList absolute_paths(m_torrent->absoluteFilePaths());
|
||||
//only one file should be selected
|
||||
QString path = absolute_paths.at(selectedIndexes.at(0).data().toInt());
|
||||
// File
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include <QDialog>
|
||||
#include <QList>
|
||||
#include "ui_preview.h"
|
||||
#include "qtorrenthandle.h"
|
||||
#include "core/bittorrent/torrenthandle.h"
|
||||
|
||||
class PreviewListDelegate;
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
enum PreviewColumn { NAME, SIZE, PROGRESS, FILE_INDEX, NB_COLUMNS };
|
||||
|
||||
public:
|
||||
PreviewSelect(QWidget* parent, QTorrentHandle h);
|
||||
PreviewSelect(QWidget* parent, BitTorrent::TorrentHandle *const torrent);
|
||||
~PreviewSelect();
|
||||
|
||||
signals:
|
||||
@@ -62,8 +62,7 @@ protected slots:
|
||||
private:
|
||||
QStandardItemModel *previewListModel;
|
||||
PreviewListDelegate *listDelegate;
|
||||
QTorrentHandle h;
|
||||
|
||||
BitTorrent::TorrentHandle *const m_torrent;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,28 +28,25 @@
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include "downloadedpiecesbar.h"
|
||||
|
||||
//#include <QDebug>
|
||||
|
||||
DownloadedPiecesBar::DownloadedPiecesBar(QWidget *parent): QWidget(parent)
|
||||
{
|
||||
setFixedHeight(BAR_HEIGHT);
|
||||
|
||||
bg_color = 0xffffff;
|
||||
border_color = palette().color(QPalette::Dark).rgb();
|
||||
piece_color = 0x0000ff;
|
||||
piece_color_dl = 0x00d000;
|
||||
m_bgColor = 0xffffff;
|
||||
m_borderColor = palette().color(QPalette::Dark).rgb();
|
||||
m_pieceColor = 0x0000ff;
|
||||
m_dlPieceColor = 0x00d000;
|
||||
|
||||
updatePieceColors();
|
||||
}
|
||||
|
||||
std::vector<float> DownloadedPiecesBar::bitfieldToFloatVector(const libtorrent::bitfield &vecin, int reqSize)
|
||||
QVector<float> DownloadedPiecesBar::bitfieldToFloatVector(const QBitArray &vecin, int reqSize)
|
||||
{
|
||||
std::vector<float> result(reqSize, 0.0);
|
||||
|
||||
if (vecin.empty())
|
||||
return result;
|
||||
QVector<float> result(reqSize, 0.0);
|
||||
if (vecin.isEmpty()) return result;
|
||||
|
||||
const float ratio = vecin.size() / (float)reqSize;
|
||||
|
||||
@@ -154,18 +151,18 @@ void DownloadedPiecesBar::updateImage()
|
||||
// qDebug() << "updateImage";
|
||||
QImage image2(width() - 2, 1, QImage::Format_RGB888);
|
||||
|
||||
if (pieces.empty()) {
|
||||
if (m_pieces.isEmpty()) {
|
||||
image2.fill(0xffffff);
|
||||
image = image2;
|
||||
m_image = image2;
|
||||
update();
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<float> scaled_pieces = bitfieldToFloatVector(pieces, image2.width());
|
||||
std::vector<float> scaled_pieces_dl = bitfieldToFloatVector(pieces_dl, image2.width());
|
||||
QVector<float> scaled_pieces = bitfieldToFloatVector(m_pieces, image2.width());
|
||||
QVector<float> scaled_pieces_dl = bitfieldToFloatVector(m_downloadedPieces, image2.width());
|
||||
|
||||
// filling image
|
||||
for (unsigned int x = 0; x < scaled_pieces.size(); ++x)
|
||||
for (int x = 0; x < scaled_pieces.size(); ++x)
|
||||
{
|
||||
float pieces2_val = scaled_pieces.at(x);
|
||||
float pieces2_val_dl = scaled_pieces_dl.at(x);
|
||||
@@ -174,23 +171,23 @@ void DownloadedPiecesBar::updateImage()
|
||||
float fill_ratio = pieces2_val + pieces2_val_dl;
|
||||
float ratio = pieces2_val_dl / fill_ratio;
|
||||
|
||||
int mixedColor = mixTwoColors(piece_color, piece_color_dl, ratio);
|
||||
mixedColor = mixTwoColors(bg_color, mixedColor, fill_ratio);
|
||||
int mixedColor = mixTwoColors(m_pieceColor, m_dlPieceColor, ratio);
|
||||
mixedColor = mixTwoColors(m_bgColor, mixedColor, fill_ratio);
|
||||
|
||||
image2.setPixel(x, 0, mixedColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
image2.setPixel(x, 0, piece_colors[pieces2_val * 255]);
|
||||
image2.setPixel(x, 0, m_pieceColors[pieces2_val * 255]);
|
||||
}
|
||||
}
|
||||
image = image2;
|
||||
m_image = image2;
|
||||
}
|
||||
|
||||
void DownloadedPiecesBar::setProgress(const libtorrent::bitfield &bf, const libtorrent::bitfield &bf_dl)
|
||||
void DownloadedPiecesBar::setProgress(const QBitArray &pieces, const QBitArray &downloadedPieces)
|
||||
{
|
||||
pieces = libtorrent::bitfield(bf);
|
||||
pieces_dl = libtorrent::bitfield(bf_dl);
|
||||
m_pieces = pieces;
|
||||
m_downloadedPieces = downloadedPieces;
|
||||
|
||||
updateImage();
|
||||
update();
|
||||
@@ -198,16 +195,16 @@ void DownloadedPiecesBar::setProgress(const libtorrent::bitfield &bf, const libt
|
||||
|
||||
void DownloadedPiecesBar::updatePieceColors()
|
||||
{
|
||||
piece_colors = std::vector<int>(256);
|
||||
m_pieceColors = QVector<int>(256);
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
float ratio = (i / 255.0);
|
||||
piece_colors[i] = mixTwoColors(bg_color, piece_color, ratio);
|
||||
m_pieceColors[i] = mixTwoColors(m_bgColor, m_pieceColor, ratio);
|
||||
}
|
||||
}
|
||||
|
||||
void DownloadedPiecesBar::clear()
|
||||
{
|
||||
image = QImage();
|
||||
m_image = QImage();
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -215,30 +212,30 @@ void DownloadedPiecesBar::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter painter(this);
|
||||
QRect imageRect(1, 1, width() - 2, height() - 2);
|
||||
if (image.isNull())
|
||||
if (m_image.isNull())
|
||||
{
|
||||
painter.setBrush(Qt::white);
|
||||
painter.drawRect(imageRect);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (image.width() != imageRect.width())
|
||||
if (m_image.width() != imageRect.width())
|
||||
updateImage();
|
||||
painter.drawImage(imageRect, image);
|
||||
painter.drawImage(imageRect, m_image);
|
||||
}
|
||||
QPainterPath border;
|
||||
border.addRect(0, 0, width() - 1, height() - 1);
|
||||
|
||||
painter.setPen(border_color);
|
||||
painter.setPen(m_borderColor);
|
||||
painter.drawPath(border);
|
||||
}
|
||||
|
||||
void DownloadedPiecesBar::setColors(int background, int border, int complete, int incomplete)
|
||||
{
|
||||
bg_color = background;
|
||||
border_color = border;
|
||||
piece_color = complete;
|
||||
piece_color_dl = incomplete;
|
||||
m_bgColor = background;
|
||||
m_borderColor = border;
|
||||
m_pieceColor = complete;
|
||||
m_dlPieceColor = incomplete;
|
||||
|
||||
updatePieceColors();
|
||||
updateImage();
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
#include <QWidget>
|
||||
#include <QPainter>
|
||||
#include <QImage>
|
||||
#include <cmath>
|
||||
#include <libtorrent/bitfield.hpp>
|
||||
#include <QBitArray>
|
||||
#include <QVector>
|
||||
|
||||
#define BAR_HEIGHT 18
|
||||
|
||||
@@ -44,28 +44,28 @@ class DownloadedPiecesBar: public QWidget {
|
||||
Q_DISABLE_COPY(DownloadedPiecesBar)
|
||||
|
||||
private:
|
||||
QImage image;
|
||||
QImage m_image;
|
||||
|
||||
// I used values, bacause it should be possible to change colors in runtime
|
||||
|
||||
// background color
|
||||
int bg_color;
|
||||
int m_bgColor;
|
||||
// border color
|
||||
int border_color;
|
||||
int m_borderColor;
|
||||
// complete piece color
|
||||
int piece_color;
|
||||
int m_pieceColor;
|
||||
// incomplete piece color
|
||||
int piece_color_dl;
|
||||
int m_dlPieceColor;
|
||||
// buffered 256 levels gradient from bg_color to piece_color
|
||||
std::vector<int> piece_colors;
|
||||
QVector<int> m_pieceColors;
|
||||
|
||||
// last used bitfields, uses to better resize redraw
|
||||
// TODO: make a diff pieces to new pieces and update only changed pixels, speedup when update > 20x faster
|
||||
libtorrent::bitfield pieces;
|
||||
libtorrent::bitfield pieces_dl;
|
||||
QBitArray m_pieces;
|
||||
QBitArray m_downloadedPieces;
|
||||
|
||||
// scale bitfield vector to float vector
|
||||
std::vector<float> bitfieldToFloatVector(const libtorrent::bitfield &vecin, int reqSize);
|
||||
QVector<float> bitfieldToFloatVector(const QBitArray &vecin, int reqSize);
|
||||
// mix two colors by light model, ratio <0, 1>
|
||||
int mixTwoColors(int &rgb1, int &rgb2, float ratio);
|
||||
// draw new image and replace actual image
|
||||
@@ -74,7 +74,7 @@ private:
|
||||
public:
|
||||
DownloadedPiecesBar(QWidget *parent);
|
||||
|
||||
void setProgress(const libtorrent::bitfield &bf, const libtorrent::bitfield &bf_dl);
|
||||
void setProgress(const QBitArray &m_pieces, const QBitArray &downloadedPieces);
|
||||
void updatePieceColors();
|
||||
void clear();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2006 Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -34,72 +34,62 @@
|
||||
#include <QDialog>
|
||||
#include <QRegExp>
|
||||
#include <QMessageBox>
|
||||
#include <QHostAddress>
|
||||
|
||||
#include "core/bittorrent/peerinfo.h"
|
||||
#include "ui_peer.h"
|
||||
|
||||
#include <libtorrent/socket.hpp>
|
||||
#include <libtorrent/address.hpp>
|
||||
|
||||
#include <boost/version.hpp>
|
||||
#if BOOST_VERSION < 103500
|
||||
#include <libtorrent/asio/ip/tcp.hpp>
|
||||
#else
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#endif
|
||||
|
||||
class PeerAdditionDlg: public QDialog, private Ui::addPeerDialog {
|
||||
Q_OBJECT
|
||||
class PeerAdditionDlg: public QDialog, private Ui::addPeerDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PeerAdditionDlg(QWidget *parent=0): QDialog(parent) {
|
||||
setupUi(this);
|
||||
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(validateInput()));
|
||||
}
|
||||
|
||||
~PeerAdditionDlg() {}
|
||||
|
||||
QString getIP() const {
|
||||
QHostAddress ip(lineIP->text());
|
||||
if (!ip.isNull()) {
|
||||
// QHostAddress::toString() cleans up the IP for libtorrent
|
||||
return ip.toString();
|
||||
PeerAdditionDlg(QWidget *parent=0)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(validateInput()));
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
unsigned short getPort() const {
|
||||
return spinPort->value();
|
||||
}
|
||||
|
||||
static libtorrent::asio::ip::tcp::endpoint askForPeerEndpoint() {
|
||||
libtorrent::asio::ip::tcp::endpoint ep;
|
||||
PeerAdditionDlg dlg;
|
||||
if (dlg.exec() == QDialog::Accepted) {
|
||||
QString ip = dlg.getIP();
|
||||
boost::system::error_code ec;
|
||||
libtorrent::address addr = libtorrent::address::from_string(qPrintable(ip), ec);
|
||||
if (ec) {
|
||||
qDebug("Unable to parse the provided IP: %s", qPrintable(ip));
|
||||
return ep;
|
||||
}
|
||||
qDebug("Provided IP is correct");
|
||||
ep = libtorrent::asio::ip::tcp::endpoint(addr, dlg.getPort());
|
||||
~PeerAdditionDlg()
|
||||
{
|
||||
}
|
||||
|
||||
QHostAddress getAddress() const
|
||||
{
|
||||
return QHostAddress(lineIP->text());
|
||||
}
|
||||
|
||||
ushort getPort() const
|
||||
{
|
||||
return spinPort->value();
|
||||
}
|
||||
|
||||
static BitTorrent::PeerAddress askForPeerAddress()
|
||||
{
|
||||
BitTorrent::PeerAddress addr;
|
||||
|
||||
PeerAdditionDlg dlg;
|
||||
if (dlg.exec() == QDialog::Accepted) {
|
||||
addr.ip = dlg.getAddress();
|
||||
if (addr.ip.isNull())
|
||||
qDebug("Unable to parse the provided IP.");
|
||||
else
|
||||
qDebug("Provided IP is correct");
|
||||
addr.port = dlg.getPort();
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
return ep;
|
||||
}
|
||||
|
||||
|
||||
protected slots:
|
||||
void validateInput() {
|
||||
if (getIP().isEmpty()) {
|
||||
QMessageBox::warning(this, tr("Invalid IP"),
|
||||
tr("The IP you provided is invalid."),
|
||||
QMessageBox::Ok);
|
||||
} else {
|
||||
accept();
|
||||
void validateInput() {
|
||||
if (getAddress().isNull())
|
||||
QMessageBox::warning(this, tr("Invalid IP"), tr("The IP you provided is invalid."), QMessageBox::Ok);
|
||||
else
|
||||
accept();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // PEERADDITION_H
|
||||
|
||||
@@ -37,19 +37,17 @@
|
||||
#include "geoipmanager.h"
|
||||
#include "peeraddition.h"
|
||||
#include "speedlimitdlg.h"
|
||||
#include "iconprovider.h"
|
||||
#include "qtorrenthandle.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "core/bittorrent/torrenthandle.h"
|
||||
#include "core/bittorrent/peerinfo.h"
|
||||
#include "core/logger.h"
|
||||
|
||||
#include <QStandardItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QSet>
|
||||
#include <QHeaderView>
|
||||
#include <QMenu>
|
||||
#include <QClipboard>
|
||||
#include <vector>
|
||||
#include <libtorrent/peer_info.hpp>
|
||||
|
||||
using namespace libtorrent;
|
||||
|
||||
PeerListWidget::PeerListWidget(PropertiesWidget *parent):
|
||||
QTreeView(parent), m_properties(parent), m_displayFlags(false)
|
||||
@@ -149,8 +147,9 @@ void PeerListWidget::showPeerListMenu(const QPoint&)
|
||||
{
|
||||
QMenu menu;
|
||||
bool empty_menu = true;
|
||||
QTorrentHandle h = m_properties->getCurrentTorrent();
|
||||
if (!h.is_valid()) return;
|
||||
BitTorrent::TorrentHandle *const torrent = m_properties->getCurrentTorrent();
|
||||
if (!torrent) return;
|
||||
|
||||
QModelIndexList selectedIndexes = selectionModel()->selectedRows();
|
||||
QStringList selectedPeerIPs;
|
||||
QStringList selectedPeerIPPort;
|
||||
@@ -163,55 +162,34 @@ void PeerListWidget::showPeerListMenu(const QPoint&)
|
||||
}
|
||||
// Add Peer Action
|
||||
QAction *addPeerAct = 0;
|
||||
if (!h.is_queued() && !h.is_checking()) {
|
||||
addPeerAct = menu.addAction(IconProvider::instance()->getIcon("user-group-new"), tr("Add a new peer..."));
|
||||
if (!torrent->isQueued() && !torrent->isChecking()) {
|
||||
addPeerAct = menu.addAction(GuiIconProvider::instance()->getIcon("user-group-new"), tr("Add a new peer..."));
|
||||
empty_menu = false;
|
||||
}
|
||||
// Per Peer Speed limiting actions
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
QAction *upLimitAct = 0;
|
||||
QAction *dlLimitAct = 0;
|
||||
#endif
|
||||
QAction *banAct = 0;
|
||||
QAction *copyPeerAct = 0;
|
||||
if (!selectedPeerIPs.isEmpty()) {
|
||||
copyPeerAct = menu.addAction(IconProvider::instance()->getIcon("edit-copy"), tr("Copy selected"));
|
||||
copyPeerAct = menu.addAction(GuiIconProvider::instance()->getIcon("edit-copy"), tr("Copy selected"));
|
||||
menu.addSeparator();
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
dlLimitAct = menu.addAction(QIcon(":/icons/skin/download.png"), tr("Limit download rate..."));
|
||||
upLimitAct = menu.addAction(QIcon(":/icons/skin/seeding.png"), tr("Limit upload rate..."));
|
||||
menu.addSeparator();
|
||||
#endif
|
||||
banAct = menu.addAction(IconProvider::instance()->getIcon("user-group-delete"), tr("Ban peer permanently"));
|
||||
banAct = menu.addAction(GuiIconProvider::instance()->getIcon("user-group-delete"), tr("Ban peer permanently"));
|
||||
empty_menu = false;
|
||||
}
|
||||
if (empty_menu) return;
|
||||
QAction *act = menu.exec(QCursor::pos());
|
||||
if (act == 0) return;
|
||||
if (act == addPeerAct) {
|
||||
boost::asio::ip::tcp::endpoint ep = PeerAdditionDlg::askForPeerEndpoint();
|
||||
if (ep != boost::asio::ip::tcp::endpoint()) {
|
||||
try {
|
||||
h.connect_peer(ep);
|
||||
BitTorrent::PeerAddress addr = PeerAdditionDlg::askForPeerAddress();
|
||||
if (!addr.ip.isNull()) {
|
||||
if (torrent->connectPeer(addr))
|
||||
QMessageBox::information(0, tr("Peer addition"), tr("The peer was added to this torrent."));
|
||||
} catch(std::exception) {
|
||||
else
|
||||
QMessageBox::critical(0, tr("Peer addition"), tr("The peer could not be added to this torrent."));
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
qDebug("No peer was added");
|
||||
}
|
||||
return;
|
||||
}
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
if (act == upLimitAct) {
|
||||
limitUpRateSelectedPeers(selectedPeerIPs);
|
||||
return;
|
||||
}
|
||||
if (act == dlLimitAct) {
|
||||
limitDlRateSelectedPeers(selectedPeerIPs);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (act == banAct) {
|
||||
banSelectedPeers(selectedPeerIPs);
|
||||
return;
|
||||
@@ -237,84 +215,16 @@ void PeerListWidget::banSelectedPeers(const QStringList& peer_ips)
|
||||
foreach (const QString &ip, peer_ips) {
|
||||
qDebug("Banning peer %s...", ip.toLocal8Bit().data());
|
||||
Logger::instance()->addMessage(tr("Manually banning peer %1...").arg(ip));
|
||||
QBtSession::instance()->banIP(ip);
|
||||
BitTorrent::Session::instance()->banIP(ip);
|
||||
}
|
||||
// Refresh list
|
||||
loadPeers(m_properties->getCurrentTorrent());
|
||||
}
|
||||
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
void PeerListWidget::limitUpRateSelectedPeers(const QStringList& peer_ips)
|
||||
{
|
||||
if (peer_ips.empty())
|
||||
return;
|
||||
QTorrentHandle h = m_properties->getCurrentTorrent();
|
||||
if (!h.is_valid())
|
||||
return;
|
||||
|
||||
bool ok = false;
|
||||
int cur_limit = -1;
|
||||
boost::asio::ip::tcp::endpoint first_ep = m_peerEndpoints.value(peer_ips.first(),
|
||||
boost::asio::ip::tcp::endpoint());
|
||||
if (first_ep != boost::asio::ip::tcp::endpoint())
|
||||
cur_limit = h.get_peer_upload_limit(first_ep);
|
||||
long limit = SpeedLimitDialog::askSpeedLimit(&ok,
|
||||
tr("Upload rate limiting"),
|
||||
cur_limit,
|
||||
Preferences::instance()->getGlobalUploadLimit()*1024.);
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
foreach (const QString &ip, peer_ips) {
|
||||
boost::asio::ip::tcp::endpoint ep = m_peerEndpoints.value(ip, boost::asio::ip::tcp::endpoint());
|
||||
if (ep != boost::asio::ip::tcp::endpoint()) {
|
||||
qDebug("Settings Upload limit of %.1f Kb/s to peer %s", limit/1024., ip.toLocal8Bit().data());
|
||||
try {
|
||||
h.set_peer_upload_limit(ep, limit);
|
||||
} catch(std::exception) {
|
||||
std::cerr << "Impossible to apply upload limit to peer" << std::endl;
|
||||
}
|
||||
} else {
|
||||
qDebug("The selected peer no longer exists...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListWidget::limitDlRateSelectedPeers(const QStringList& peer_ips)
|
||||
{
|
||||
QTorrentHandle h = m_properties->getCurrentTorrent();
|
||||
if (!h.is_valid())
|
||||
return;
|
||||
bool ok = false;
|
||||
int cur_limit = -1;
|
||||
boost::asio::ip::tcp::endpoint first_ep = m_peerEndpoints.value(peer_ips.first(),
|
||||
boost::asio::ip::tcp::endpoint());
|
||||
if (first_ep != boost::asio::ip::tcp::endpoint())
|
||||
cur_limit = h.get_peer_download_limit(first_ep);
|
||||
long limit = SpeedLimitDialog::askSpeedLimit(&ok, tr("Download rate limiting"), cur_limit, Preferences::instance()->getGlobalDownloadLimit()*1024.);
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
foreach (const QString &ip, peer_ips) {
|
||||
boost::asio::ip::tcp::endpoint ep = m_peerEndpoints.value(ip, boost::asio::ip::tcp::endpoint());
|
||||
if (ep != boost::asio::ip::tcp::endpoint()) {
|
||||
qDebug("Settings Download limit of %.1f Kb/s to peer %s", limit/1024., ip.toLocal8Bit().data());
|
||||
try {
|
||||
h.set_peer_download_limit(ep, limit);
|
||||
}catch(std::exception) {
|
||||
std::cerr << "Impossible to apply download limit to peer" << std::endl;
|
||||
}
|
||||
} else {
|
||||
qDebug("The selected peer no longer exists...");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void PeerListWidget::clear() {
|
||||
qDebug("clearing peer list");
|
||||
m_peerItems.clear();
|
||||
m_peerEndpoints.clear();
|
||||
m_peerAddresses.clear();
|
||||
m_missingFlags.clear();
|
||||
int nbrows = m_listModel->rowCount();
|
||||
if (nbrows > 0) {
|
||||
@@ -331,34 +241,28 @@ void PeerListWidget::saveSettings() const {
|
||||
Preferences::instance()->setPeerListState(header()->saveState());
|
||||
}
|
||||
|
||||
void PeerListWidget::loadPeers(const QTorrentHandle &h, bool force_hostname_resolution) {
|
||||
if (!h.is_valid())
|
||||
return;
|
||||
boost::system::error_code ec;
|
||||
libtorrent::torrent_status status = h.status(torrent_handle::query_pieces);
|
||||
std::vector<peer_info> peers;
|
||||
h.get_peer_info(peers);
|
||||
void PeerListWidget::loadPeers(BitTorrent::TorrentHandle *const torrent, bool force_hostname_resolution) {
|
||||
if (!torrent) return;
|
||||
|
||||
QList<BitTorrent::PeerInfo> peers = torrent->peers();
|
||||
QSet<QString> old_peers_set = m_peerItems.keys().toSet();
|
||||
|
||||
std::vector<peer_info>::const_iterator itr = peers.begin();
|
||||
std::vector<peer_info>::const_iterator itrend = peers.end();
|
||||
for ( ; itr != itrend; ++itr) {
|
||||
peer_info peer = *itr;
|
||||
std::string ip_str = peer.ip.address().to_string(ec);
|
||||
if (ec || ip_str.empty())
|
||||
continue;
|
||||
QString peer_ip = misc::toQString(ip_str);
|
||||
foreach (const BitTorrent::PeerInfo &peer, peers) {
|
||||
BitTorrent::PeerAddress addr = peer.address();
|
||||
if (addr.ip.isNull()) continue;
|
||||
|
||||
QString peer_ip = addr.ip.toString();
|
||||
if (m_peerItems.contains(peer_ip)) {
|
||||
// Update existing peer
|
||||
updatePeer(peer_ip, status, peer);
|
||||
updatePeer(peer_ip, torrent, peer);
|
||||
old_peers_set.remove(peer_ip);
|
||||
if (force_hostname_resolution && m_resolver) {
|
||||
m_resolver->resolve(peer_ip);
|
||||
}
|
||||
} else {
|
||||
// Add new peer
|
||||
m_peerItems[peer_ip] = addPeer(peer_ip, status, peer);
|
||||
m_peerEndpoints[peer_ip] = peer.ip;
|
||||
m_peerItems[peer_ip] = addPeer(peer_ip, torrent, peer);
|
||||
m_peerAddresses[peer_ip] = addr;
|
||||
// Resolve peer host name is asked
|
||||
if (m_resolver)
|
||||
m_resolver->resolve(peer_ip);
|
||||
@@ -369,70 +273,70 @@ void PeerListWidget::loadPeers(const QTorrentHandle &h, bool force_hostname_reso
|
||||
while(it.hasNext()) {
|
||||
const QString& ip = it.next();
|
||||
m_missingFlags.remove(ip);
|
||||
m_peerEndpoints.remove(ip);
|
||||
m_peerAddresses.remove(ip);
|
||||
QStandardItem *item = m_peerItems.take(ip);
|
||||
m_listModel->removeRow(item->row());
|
||||
}
|
||||
}
|
||||
|
||||
QStandardItem* PeerListWidget::addPeer(const QString& ip, const libtorrent::torrent_status &status, const peer_info& peer) {
|
||||
QStandardItem* PeerListWidget::addPeer(const QString& ip, BitTorrent::TorrentHandle *const torrent, const BitTorrent::PeerInfo &peer) {
|
||||
int row = m_listModel->rowCount();
|
||||
// Adding Peer to peer list
|
||||
m_listModel->insertRow(row);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP), ip);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP), ip, Qt::ToolTipRole);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PORT), peer.ip.port());
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PORT), peer.address().port);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::IP_HIDDEN), ip);
|
||||
if (m_displayFlags) {
|
||||
const QIcon ico = GeoIPManager::CountryISOCodeToIcon(peer.country);
|
||||
const QIcon ico = GeoIPManager::CountryISOCodeToIcon(peer.country());
|
||||
if (!ico.isNull()) {
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), ico, Qt::DecorationRole);
|
||||
const QString country_name = GeoIPManager::CountryISOCodeToName(peer.country);
|
||||
const QString country_name = GeoIPManager::CountryISOCodeToName(peer.country());
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), country_name, Qt::ToolTipRole);
|
||||
} else {
|
||||
m_missingFlags.insert(ip);
|
||||
}
|
||||
}
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CONNECTION), getConnectionString(peer));
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CONNECTION), peer.connectionType());
|
||||
QString flags, tooltip;
|
||||
getFlags(peer, flags, tooltip);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), flags);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), tooltip, Qt::ToolTipRole);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CLIENT), misc::toQStringU(peer.client));
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PROGRESS), peer.progress);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWN_SPEED), peer.payload_down_speed);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::UP_SPEED), peer.payload_up_speed);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_DOWN), (qulonglong)peer.total_download);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_UP), (qulonglong)peer.total_upload);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::RELEVANCE), getPeerRelevance(status, peer));
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CLIENT), peer.client());
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PROGRESS), peer.progress());
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWN_SPEED), peer.payloadDownSpeed());
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::UP_SPEED), peer.payloadUpSpeed());
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_DOWN), peer.totalDownload());
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_UP), peer.totalUpload());
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::RELEVANCE), getPeerRelevance(torrent->pieces(), peer.pieces()));
|
||||
return m_listModel->item(row, PeerListDelegate::IP);
|
||||
}
|
||||
|
||||
void PeerListWidget::updatePeer(const QString& ip, const libtorrent::torrent_status &status, const peer_info& peer) {
|
||||
void PeerListWidget::updatePeer(const QString &ip, BitTorrent::TorrentHandle *const torrent, const BitTorrent::PeerInfo &peer) {
|
||||
QStandardItem *item = m_peerItems.value(ip);
|
||||
int row = item->row();
|
||||
if (m_displayFlags) {
|
||||
const QIcon ico = GeoIPManager::CountryISOCodeToIcon(peer.country);
|
||||
const QIcon ico = GeoIPManager::CountryISOCodeToIcon(peer.country());
|
||||
if (!ico.isNull()) {
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), ico, Qt::DecorationRole);
|
||||
const QString country_name = GeoIPManager::CountryISOCodeToName(peer.country);
|
||||
const QString country_name = GeoIPManager::CountryISOCodeToName(peer.country());
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::COUNTRY), country_name, Qt::ToolTipRole);
|
||||
m_missingFlags.remove(ip);
|
||||
}
|
||||
}
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CONNECTION), getConnectionString(peer));
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CONNECTION), peer.connectionType());
|
||||
QString flags, tooltip;
|
||||
getFlags(peer, flags, tooltip);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PORT), peer.ip.port());
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PORT), peer.address().port);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), flags);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), tooltip, Qt::ToolTipRole);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CLIENT), misc::toQStringU(peer.client));
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PROGRESS), peer.progress);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWN_SPEED), peer.payload_down_speed);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::UP_SPEED), peer.payload_up_speed);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_DOWN), (qulonglong)peer.total_download);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_UP), (qulonglong)peer.total_upload);
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::RELEVANCE), getPeerRelevance(status, peer));
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::CLIENT), peer.client());
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::PROGRESS), peer.progress());
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWN_SPEED), peer.payloadDownSpeed());
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::UP_SPEED), peer.payloadUpSpeed());
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_DOWN), peer.totalDownload());
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::TOT_UP), peer.totalUpload());
|
||||
m_listModel->setData(m_listModel->index(row, PeerListDelegate::RELEVANCE), getPeerRelevance(torrent->pieces(), peer.pieces()));
|
||||
}
|
||||
|
||||
void PeerListWidget::handleResolved(const QString &ip, const QString &hostname) {
|
||||
@@ -453,34 +357,11 @@ void PeerListWidget::handleSortColumnChanged(int col)
|
||||
}
|
||||
}
|
||||
|
||||
QString PeerListWidget::getConnectionString(const peer_info& peer)
|
||||
void PeerListWidget::getFlags(const BitTorrent::PeerInfo &peer, QString& flags, QString& tooltip)
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
if (peer.connection_type & peer_info::bittorrent_utp) {
|
||||
#else
|
||||
if (peer.flags & peer_info::utp_socket) {
|
||||
#endif
|
||||
return QString::fromUtf8("μTP");
|
||||
}
|
||||
|
||||
QString connection;
|
||||
switch(peer.connection_type) {
|
||||
case peer_info::http_seed:
|
||||
case peer_info::web_seed:
|
||||
connection = "Web";
|
||||
break;
|
||||
default:
|
||||
connection = "BT";
|
||||
break;
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
void PeerListWidget::getFlags(const peer_info& peer, QString& flags, QString& tooltip)
|
||||
{
|
||||
if (peer.flags & peer_info::interesting) {
|
||||
if (peer.isInteresting()) {
|
||||
//d = Your client wants to download, but peer doesn't want to send (interested and choked)
|
||||
if (peer.flags & peer_info::remote_choked) {
|
||||
if (peer.isRemoteChocked()) {
|
||||
flags += "d ";
|
||||
tooltip += tr("interested(local) and choked(peer)");
|
||||
tooltip += ", ";
|
||||
@@ -493,9 +374,9 @@ void PeerListWidget::getFlags(const peer_info& peer, QString& flags, QString& to
|
||||
}
|
||||
}
|
||||
|
||||
if (peer.flags & peer_info::remote_interested) {
|
||||
if (peer.isRemoteInterested()) {
|
||||
//u = Peer wants your client to upload, but your client doesn't want to (interested and choked)
|
||||
if (peer.flags & peer_info::choked) {
|
||||
if (peer.isChocked()) {
|
||||
flags += "u ";
|
||||
tooltip += tr("interested(peer) and choked(local)");
|
||||
tooltip += ", ";
|
||||
@@ -509,81 +390,78 @@ void PeerListWidget::getFlags(const peer_info& peer, QString& flags, QString& to
|
||||
}
|
||||
|
||||
//O = Optimistic unchoke
|
||||
if (peer.flags & peer_info::optimistic_unchoke) {
|
||||
if (peer.optimisticUnchoke()) {
|
||||
flags += "O ";
|
||||
tooltip += tr("optimistic unchoke");
|
||||
tooltip += ", ";
|
||||
}
|
||||
|
||||
//S = Peer is snubbed
|
||||
if (peer.flags & peer_info::snubbed) {
|
||||
if (peer.isSnubbed()) {
|
||||
flags += "S ";
|
||||
tooltip += tr("peer snubbed");
|
||||
tooltip += ", ";
|
||||
}
|
||||
|
||||
//I = Peer is an incoming connection
|
||||
if ((peer.flags & peer_info::local_connection) == 0 ) {
|
||||
if (!peer.isLocalConnection()) {
|
||||
flags += "I ";
|
||||
tooltip += tr("incoming connection");
|
||||
tooltip += ", ";
|
||||
}
|
||||
|
||||
//K = Peer is unchoking your client, but your client is not interested
|
||||
if (((peer.flags & peer_info::remote_choked) == 0) && ((peer.flags & peer_info::interesting) == 0)) {
|
||||
if (!peer.isRemoteChocked() && !peer.isInteresting()) {
|
||||
flags += "K ";
|
||||
tooltip += tr("not interested(local) and unchoked(peer)");
|
||||
tooltip += ", ";
|
||||
}
|
||||
|
||||
//? = Your client unchoked the peer but the peer is not interested
|
||||
if (((peer.flags & peer_info::choked) == 0) && ((peer.flags & peer_info::remote_interested) == 0)) {
|
||||
if (!peer.isChocked() && !peer.isRemoteInterested()) {
|
||||
flags += "? ";
|
||||
tooltip += tr("not interested(peer) and unchoked(local)");
|
||||
tooltip += ", ";
|
||||
}
|
||||
|
||||
//X = Peer was included in peerlists obtained through Peer Exchange (PEX)
|
||||
if (peer.source & peer_info::pex) {
|
||||
if (peer.fromPeX()) {
|
||||
flags += "X ";
|
||||
tooltip += tr("peer from PEX");
|
||||
tooltip += ", ";
|
||||
}
|
||||
|
||||
//H = Peer was obtained through DHT
|
||||
if (peer.source & peer_info::dht) {
|
||||
if (peer.fromDHT()) {
|
||||
flags += "H ";
|
||||
tooltip += tr("peer from DHT");
|
||||
tooltip += ", ";
|
||||
}
|
||||
|
||||
//E = Peer is using Protocol Encryption (all traffic)
|
||||
if (peer.flags & peer_info::rc4_encrypted) {
|
||||
if (peer.isRC4Encrypted()) {
|
||||
flags += "E ";
|
||||
tooltip += tr("encrypted traffic");
|
||||
tooltip += ", ";
|
||||
}
|
||||
|
||||
//e = Peer is using Protocol Encryption (handshake)
|
||||
if (peer.flags & peer_info::plaintext_encrypted) {
|
||||
if (peer.isPlaintextEncrypted()) {
|
||||
flags += "e ";
|
||||
tooltip += tr("encrypted handshake");
|
||||
tooltip += ", ";
|
||||
}
|
||||
|
||||
//P = Peer is using uTorrent uTP
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
if (peer.connection_type & peer_info::bittorrent_utp) {
|
||||
#else
|
||||
if (peer.flags & peer_info::utp_socket) {
|
||||
#endif
|
||||
|
||||
if (peer.useUTPSocket()) {
|
||||
flags += "P ";
|
||||
tooltip += QString::fromUtf8("μTP");
|
||||
tooltip += ", ";
|
||||
}
|
||||
|
||||
//L = Peer is local
|
||||
if (peer.source & peer_info::lsd) {
|
||||
if (peer.fromLSD()) {
|
||||
flags += "L";
|
||||
tooltip += tr("peer from LSD");
|
||||
}
|
||||
@@ -594,17 +472,15 @@ void PeerListWidget::getFlags(const peer_info& peer, QString& flags, QString& to
|
||||
tooltip.chop(1);
|
||||
}
|
||||
|
||||
double PeerListWidget::getPeerRelevance(const torrent_status& status, const libtorrent::peer_info &peer)
|
||||
qreal PeerListWidget::getPeerRelevance(const QBitArray &allPieces, const QBitArray &peerPieces)
|
||||
{
|
||||
int localMissing = 0;
|
||||
int remoteHaves = 0;
|
||||
libtorrent::bitfield local = status.pieces;
|
||||
libtorrent::bitfield remote = peer.pieces;
|
||||
|
||||
for (int i=0; i<local.size(); ++i) {
|
||||
if (!local[i]) {
|
||||
for (int i = 0; i < allPieces.size(); ++i) {
|
||||
if (!allPieces[i]) {
|
||||
++localMissing;
|
||||
if (remote[i])
|
||||
if (peerPieces[i])
|
||||
++remoteHaves;
|
||||
}
|
||||
}
|
||||
@@ -612,5 +488,5 @@ double PeerListWidget::getPeerRelevance(const torrent_status& status, const libt
|
||||
if (localMissing == 0)
|
||||
return 0.0;
|
||||
|
||||
return (double)remoteHaves/localMissing;
|
||||
return static_cast<qreal>(remoteHaves) / localMissing;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include <QHash>
|
||||
#include <QPointer>
|
||||
#include <QSet>
|
||||
#include <libtorrent/version.hpp>
|
||||
|
||||
namespace Net
|
||||
{
|
||||
@@ -45,7 +44,6 @@ namespace Net
|
||||
class PeerListDelegate;
|
||||
class PeerListSortModel;
|
||||
class PropertiesWidget;
|
||||
class QTorrentHandle;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QSortFilterProxyModel;
|
||||
@@ -53,18 +51,14 @@ class QStandardItem;
|
||||
class QStandardItemModel;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace libtorrent
|
||||
namespace BitTorrent
|
||||
{
|
||||
struct peer_info;
|
||||
struct torrent_status;
|
||||
}
|
||||
|
||||
#include <boost/version.hpp>
|
||||
#if BOOST_VERSION < 103500
|
||||
#include <libtorrent/asio/ip/tcp.hpp>
|
||||
#else
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#endif
|
||||
class TorrentHandle;
|
||||
class PeerInfo;
|
||||
struct PeerAddress;
|
||||
|
||||
}
|
||||
|
||||
class PeerListWidget : public QTreeView {
|
||||
Q_OBJECT
|
||||
@@ -74,9 +68,9 @@ public:
|
||||
~PeerListWidget();
|
||||
|
||||
public slots:
|
||||
void loadPeers(const QTorrentHandle &h, bool force_hostname_resolution = false);
|
||||
QStandardItem* addPeer(const QString& ip, const libtorrent::torrent_status &status, const libtorrent::peer_info& peer);
|
||||
void updatePeer(const QString& ip, const libtorrent::torrent_status &status, const libtorrent::peer_info& peer);
|
||||
void loadPeers(BitTorrent::TorrentHandle *const torrent, bool force_hostname_resolution = false);
|
||||
QStandardItem *addPeer(const QString &ip, BitTorrent::TorrentHandle *const torrent, const BitTorrent::PeerInfo &peer);
|
||||
void updatePeer(const QString &ip, BitTorrent::TorrentHandle *const torrent, const BitTorrent::PeerInfo &peer);
|
||||
void handleResolved(const QString &ip, const QString &hostname);
|
||||
void updatePeerHostNameResolutionState();
|
||||
void updatePeerCountryResolutionState();
|
||||
@@ -86,26 +80,19 @@ protected slots:
|
||||
void loadSettings();
|
||||
void saveSettings() const;
|
||||
void showPeerListMenu(const QPoint&);
|
||||
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
void limitUpRateSelectedPeers(const QStringList& peer_ips);
|
||||
void limitDlRateSelectedPeers(const QStringList& peer_ips);
|
||||
#endif
|
||||
|
||||
void banSelectedPeers(const QStringList& peer_ips);
|
||||
void handleSortColumnChanged(int col);
|
||||
|
||||
private:
|
||||
static QString getConnectionString(const libtorrent::peer_info &peer);
|
||||
static void getFlags(const libtorrent::peer_info& peer, QString& flags, QString& tooltip);
|
||||
double getPeerRelevance(const libtorrent::torrent_status &status, const libtorrent::peer_info &peer);
|
||||
static void getFlags(const BitTorrent::PeerInfo &peer, QString &flags, QString &tooltip);
|
||||
qreal getPeerRelevance(const QBitArray &allPieces, const QBitArray &peerPieces);
|
||||
|
||||
private:
|
||||
QStandardItemModel *m_listModel;
|
||||
PeerListDelegate *m_listDelegate;
|
||||
PeerListSortModel *m_proxyModel;
|
||||
QHash<QString, QStandardItem*> m_peerItems;
|
||||
QHash<QString, boost::asio::ip::tcp::endpoint> m_peerEndpoints;
|
||||
QHash<QString, BitTorrent::PeerAddress> m_peerAddresses;
|
||||
QSet<QString> m_missingFlags;
|
||||
QPointer<Net::ReverseResolution> m_resolver;
|
||||
PropertiesWidget *m_properties;
|
||||
|
||||
@@ -28,28 +28,25 @@
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include "pieceavailabilitybar.h"
|
||||
|
||||
//#include <QDebug>
|
||||
|
||||
PieceAvailabilityBar::PieceAvailabilityBar(QWidget *parent) :
|
||||
QWidget(parent)
|
||||
{
|
||||
setFixedHeight(BAR_HEIGHT);
|
||||
|
||||
bg_color = 0xffffff;
|
||||
border_color = palette().color(QPalette::Dark).rgb();
|
||||
piece_color = 0x0000ff;
|
||||
m_bgColor = 0xffffff;
|
||||
m_borderColor = palette().color(QPalette::Dark).rgb();
|
||||
m_pieceColor = 0x0000ff;
|
||||
|
||||
updatePieceColors();
|
||||
}
|
||||
|
||||
std::vector<float> PieceAvailabilityBar::intToFloatVector(const std::vector<int> &vecin, int reqSize)
|
||||
QVector<float> PieceAvailabilityBar::intToFloatVector(const QVector<int> &vecin, int reqSize)
|
||||
{
|
||||
std::vector<float> result(reqSize, 0.0);
|
||||
|
||||
if (vecin.empty())
|
||||
return result;
|
||||
QVector<float> result(reqSize, 0.0);
|
||||
if (vecin.isEmpty()) return result;
|
||||
|
||||
const float ratio = vecin.size() / (float)reqSize;
|
||||
|
||||
@@ -162,27 +159,27 @@ void PieceAvailabilityBar::updateImage()
|
||||
// qDebug() << "updateImageAv";
|
||||
QImage image2(width() - 2, 1, QImage::Format_RGB888);
|
||||
|
||||
if (pieces.empty()) {
|
||||
if (m_pieces.empty()) {
|
||||
image2.fill(0xffffff);
|
||||
image = image2;
|
||||
m_image = image2;
|
||||
update();
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<float> scaled_pieces = intToFloatVector(pieces, image2.width());
|
||||
QVector<float> scaled_pieces = intToFloatVector(m_pieces, image2.width());
|
||||
|
||||
// filling image
|
||||
for (unsigned int x = 0; x < scaled_pieces.size(); ++x)
|
||||
for (int x = 0; x < scaled_pieces.size(); ++x)
|
||||
{
|
||||
float pieces2_val = scaled_pieces.at(x);
|
||||
image2.setPixel(x, 0, piece_colors[pieces2_val * 255]);
|
||||
image2.setPixel(x, 0, m_pieceColors[pieces2_val * 255]);
|
||||
}
|
||||
image = image2;
|
||||
m_image = image2;
|
||||
}
|
||||
|
||||
void PieceAvailabilityBar::setAvailability(const std::vector<int>& avail)
|
||||
void PieceAvailabilityBar::setAvailability(const QVector<int> &avail)
|
||||
{
|
||||
pieces = std::vector<int>(avail);
|
||||
m_pieces = avail;
|
||||
|
||||
updateImage();
|
||||
update();
|
||||
@@ -190,16 +187,16 @@ void PieceAvailabilityBar::setAvailability(const std::vector<int>& avail)
|
||||
|
||||
void PieceAvailabilityBar::updatePieceColors()
|
||||
{
|
||||
piece_colors = std::vector<int>(256);
|
||||
m_pieceColors = QVector<int>(256);
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
float ratio = (i / 255.0);
|
||||
piece_colors[i] = mixTwoColors(bg_color, piece_color, ratio);
|
||||
m_pieceColors[i] = mixTwoColors(m_bgColor, m_pieceColor, ratio);
|
||||
}
|
||||
}
|
||||
|
||||
void PieceAvailabilityBar::clear()
|
||||
{
|
||||
image = QImage();
|
||||
m_image = QImage();
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -207,29 +204,29 @@ void PieceAvailabilityBar::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter painter(this);
|
||||
QRect imageRect(1, 1, width() - 2, height() - 2);
|
||||
if (image.isNull())
|
||||
if (m_image.isNull())
|
||||
{
|
||||
painter.setBrush(Qt::white);
|
||||
painter.drawRect(imageRect);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (image.width() != imageRect.width())
|
||||
if (m_image.width() != imageRect.width())
|
||||
updateImage();
|
||||
painter.drawImage(imageRect, image);
|
||||
painter.drawImage(imageRect, m_image);
|
||||
}
|
||||
QPainterPath border;
|
||||
border.addRect(0, 0, width() - 1, height() - 1);
|
||||
|
||||
painter.setPen(border_color);
|
||||
painter.setPen(m_borderColor);
|
||||
painter.drawPath(border);
|
||||
}
|
||||
|
||||
void PieceAvailabilityBar::setColors(int background, int border, int available)
|
||||
{
|
||||
bg_color = background;
|
||||
border_color = border;
|
||||
piece_color = available;
|
||||
m_bgColor = background;
|
||||
m_borderColor = border;
|
||||
m_pieceColor = available;
|
||||
|
||||
updatePieceColors();
|
||||
updateImage();
|
||||
|
||||
@@ -34,8 +34,6 @@
|
||||
#include <QWidget>
|
||||
#include <QPainter>
|
||||
#include <QImage>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
#define BAR_HEIGHT 18
|
||||
|
||||
@@ -44,25 +42,25 @@ class PieceAvailabilityBar: public QWidget {
|
||||
Q_DISABLE_COPY(PieceAvailabilityBar)
|
||||
|
||||
private:
|
||||
QImage image;
|
||||
QImage m_image;
|
||||
|
||||
// I used values, bacause it should be possible to change colors in runtime
|
||||
|
||||
// background color
|
||||
int bg_color;
|
||||
int m_bgColor;
|
||||
// border color
|
||||
int border_color;
|
||||
int m_borderColor;
|
||||
// complete piece color
|
||||
int piece_color;
|
||||
int m_pieceColor;
|
||||
// buffered 256 levels gradient from bg_color to piece_color
|
||||
std::vector<int> piece_colors;
|
||||
QVector<int> m_pieceColors;
|
||||
|
||||
// last used int vector, uses to better resize redraw
|
||||
// TODO: make a diff pieces to new pieces and update only changed pixels, speedup when update > 20x faster
|
||||
std::vector<int> pieces;
|
||||
QVector<int> m_pieces;
|
||||
|
||||
// scale int vector to float vector
|
||||
std::vector<float> intToFloatVector(const std::vector<int> &vecin, int reqSize);
|
||||
QVector<float> intToFloatVector(const QVector<int> &vecin, int reqSize);
|
||||
|
||||
// mix two colors by light model, ratio <0, 1>
|
||||
int mixTwoColors(int &rgb1, int &rgb2, float ratio);
|
||||
@@ -72,7 +70,7 @@ private:
|
||||
public:
|
||||
PieceAvailabilityBar(QWidget *parent);
|
||||
|
||||
void setAvailability(const std::vector<int>& avail);
|
||||
void setAvailability(const QVector<int> &avail);
|
||||
void updatePieceColors();
|
||||
void clear();
|
||||
|
||||
|
||||
@@ -40,11 +40,11 @@
|
||||
#include <QMenu>
|
||||
#include <QFileDialog>
|
||||
#include <QDesktopServices>
|
||||
#include <libtorrent/version.hpp>
|
||||
#include <QBitArray>
|
||||
|
||||
#include "propertieswidget.h"
|
||||
#include "transferlistwidget.h"
|
||||
#include "core/torrentpersistentdata.h"
|
||||
#include "qbtsession.h"
|
||||
#include "core/bittorrent/session.h"
|
||||
#include "proplistdelegate.h"
|
||||
#include "torrentcontentfiltermodel.h"
|
||||
#include "torrentcontentmodel.h"
|
||||
@@ -55,20 +55,18 @@
|
||||
#include "pieceavailabilitybar.h"
|
||||
#include "core/preferences.h"
|
||||
#include "proptabbar.h"
|
||||
#include "iconprovider.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "lineedit.h"
|
||||
#include "core/fs_utils.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
|
||||
using namespace libtorrent;
|
||||
|
||||
PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow* main_window, TransferListWidget *transferList):
|
||||
QWidget(parent), transferList(transferList), main_window(main_window) {
|
||||
QWidget(parent), transferList(transferList), main_window(main_window), m_torrent(0) {
|
||||
setupUi(this);
|
||||
|
||||
// Icons
|
||||
trackerUpButton->setIcon(IconProvider::instance()->getIcon("go-up"));
|
||||
trackerDownButton->setIcon(IconProvider::instance()->getIcon("go-down"));
|
||||
trackerUpButton->setIcon(GuiIconProvider::instance()->getIcon("go-up"));
|
||||
trackerDownButton->setIcon(GuiIconProvider::instance()->getIcon("go-down"));
|
||||
|
||||
state = VISIBLE;
|
||||
|
||||
@@ -92,11 +90,11 @@ PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow* main_window, Tra
|
||||
connect(filesList, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(openDoubleClickedFile(const QModelIndex &)));
|
||||
connect(PropListModel, SIGNAL(filteredFilesChanged()), this, SLOT(filteredFilesChanged()));
|
||||
connect(listWebSeeds, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayWebSeedListMenu(const QPoint&)));
|
||||
connect(transferList, SIGNAL(currentTorrentChanged(QTorrentHandle)), this, SLOT(loadTorrentInfos(QTorrentHandle)));
|
||||
connect(transferList, SIGNAL(currentTorrentChanged(BitTorrent::TorrentHandle *const)), this, SLOT(loadTorrentInfos(BitTorrent::TorrentHandle *const)));
|
||||
connect(PropDelegate, SIGNAL(filteredFilesChanged()), this, SLOT(filteredFilesChanged()));
|
||||
connect(stackedProperties, SIGNAL(currentChanged(int)), this, SLOT(loadDynamicData()));
|
||||
connect(QBtSession::instance(), SIGNAL(savePathChanged(QTorrentHandle)), this, SLOT(updateSavePath(QTorrentHandle)));
|
||||
connect(QBtSession::instance(), SIGNAL(metadataReceived(QTorrentHandle)), this, SLOT(updateTorrentInfos(QTorrentHandle)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(torrentSavePathChanged(BitTorrent::TorrentHandle *const)), this, SLOT(updateSavePath(BitTorrent::TorrentHandle *const)));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(torrentMetadataLoaded(BitTorrent::TorrentHandle *const)), this, SLOT(updateTorrentInfos(BitTorrent::TorrentHandle *const)));
|
||||
connect(filesList->header(), SIGNAL(sectionMoved(int, int, int)), this, SLOT(saveSettings()));
|
||||
connect(filesList->header(), SIGNAL(sectionResized(int, int, int)), this, SLOT(saveSettings()));
|
||||
connect(filesList->header(), SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), this, SLOT(saveSettings()));
|
||||
@@ -111,9 +109,6 @@ PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow* main_window, Tra
|
||||
trackerList = new TrackerList(this);
|
||||
connect(trackerUpButton, SIGNAL(clicked()), trackerList, SLOT(moveSelectionUp()));
|
||||
connect(trackerDownButton, SIGNAL(clicked()), trackerList, SLOT(moveSelectionDown()));
|
||||
connect(trackerList, SIGNAL(trackersAdded(const QStringList &, const QString &)), this, SIGNAL(trackersAdded(const QStringList &, const QString &)));
|
||||
connect(trackerList, SIGNAL(trackersRemoved(const QStringList &, const QString &)), this, SIGNAL(trackersRemoved(const QStringList &, const QString &)));
|
||||
connect(trackerList, SIGNAL(trackerlessChange(bool, const QString &)), this, SIGNAL(trackerlessChange(bool, const QString &)));
|
||||
horizontalLayout_trackers->insertWidget(0, trackerList);
|
||||
connect(trackerList->header(), SIGNAL(sectionMoved(int, int, int)), trackerList, SLOT(saveSettings()));
|
||||
connect(trackerList->header(), SIGNAL(sectionResized(int, int, int)), trackerList, SLOT(saveSettings()));
|
||||
@@ -230,61 +225,56 @@ void PropertiesWidget::clear() {
|
||||
showPiecesDownloaded(false);
|
||||
}
|
||||
|
||||
QTorrentHandle PropertiesWidget::getCurrentTorrent() const {
|
||||
return h;
|
||||
BitTorrent::TorrentHandle *PropertiesWidget::getCurrentTorrent() const
|
||||
{
|
||||
return m_torrent;
|
||||
}
|
||||
|
||||
void PropertiesWidget::updateSavePath(const QTorrentHandle& _h) {
|
||||
if (h.is_valid() && h == _h) {
|
||||
save_path->setText(fsutils::toNativePath(h.save_path_parsed()));
|
||||
void PropertiesWidget::updateSavePath(BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
if (m_torrent == torrent) {
|
||||
save_path->setText(m_torrent->savePathParsed());
|
||||
}
|
||||
}
|
||||
|
||||
void PropertiesWidget::loadTrackers(const QTorrentHandle &handle)
|
||||
void PropertiesWidget::loadTrackers(BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
if (handle == h)
|
||||
if (torrent == m_torrent)
|
||||
trackerList->loadTrackers();
|
||||
}
|
||||
|
||||
void PropertiesWidget::updateTorrentInfos(const QTorrentHandle& _h) {
|
||||
if (h.is_valid() && h == _h) {
|
||||
loadTorrentInfos(h);
|
||||
}
|
||||
void PropertiesWidget::updateTorrentInfos(BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
if (m_torrent == torrent)
|
||||
loadTorrentInfos(m_torrent);
|
||||
}
|
||||
|
||||
void PropertiesWidget::loadTorrentInfos(const QTorrentHandle& _h)
|
||||
void PropertiesWidget::loadTorrentInfos(BitTorrent::TorrentHandle *const torrent)
|
||||
{
|
||||
clear();
|
||||
h = _h;
|
||||
if (!h.is_valid())
|
||||
return;
|
||||
m_torrent = torrent;
|
||||
if (!m_torrent) return;
|
||||
|
||||
try {
|
||||
// Save path
|
||||
updateSavePath(h);
|
||||
updateSavePath(m_torrent);
|
||||
// Hash
|
||||
hash_lbl->setText(h.hash());
|
||||
hash_lbl->setText(m_torrent->hash());
|
||||
PropListModel->model()->clear();
|
||||
if (h.has_metadata()) {
|
||||
if (m_torrent->hasMetadata()) {
|
||||
// Creation date
|
||||
lbl_creationDate->setText(h.creation_date());
|
||||
lbl_creationDate->setText(m_torrent->creationDate().toString());
|
||||
// Piece size
|
||||
pieceSize_lbl->setText(misc::friendlyUnit(h.piece_length()));
|
||||
pieceSize_lbl->setText(misc::friendlyUnit(m_torrent->pieceLength()));
|
||||
// Comment
|
||||
comment_text->setHtml(misc::parseHtmlLinks(h.comment()));
|
||||
comment_text->setHtml(misc::parseHtmlLinks(m_torrent->comment()));
|
||||
// URL seeds
|
||||
loadUrlSeeds();
|
||||
// List files in torrent
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
PropListModel->model()->setupModelData(h.get_torrent_info());
|
||||
#else
|
||||
PropListModel->model()->setupModelData(*h.torrent_file());
|
||||
#endif
|
||||
PropListModel->model()->setupModelData(m_torrent->info());
|
||||
filesList->setExpanded(PropListModel->index(0, 0), true);
|
||||
// Load file priorities
|
||||
PropListModel->model()->updateFilesPriorities(h.file_priorities());
|
||||
PropListModel->model()->updateFilesPriorities(m_torrent->filePriorities());
|
||||
}
|
||||
} catch(const invalid_handle& e) { }
|
||||
// Load dynamic data
|
||||
loadDynamicData();
|
||||
}
|
||||
@@ -338,55 +328,44 @@ void PropertiesWidget::reloadPreferences() {
|
||||
|
||||
void PropertiesWidget::loadDynamicData() {
|
||||
// Refresh only if the torrent handle is valid and if visible
|
||||
if (!h.is_valid() || main_window->getCurrentTabWidget() != transferList || state != VISIBLE) return;
|
||||
try {
|
||||
if (!m_torrent || (main_window->getCurrentTabWidget() != transferList) || (state != VISIBLE)) return;
|
||||
|
||||
// Transfer infos
|
||||
if (stackedProperties->currentIndex() == PropTabBar::MAIN_TAB) {
|
||||
libtorrent::torrent_status status = h.status(torrent_handle::query_accurate_download_counters
|
||||
| torrent_handle::query_distributed_copies
|
||||
| torrent_handle::query_pieces);
|
||||
|
||||
wasted->setText(misc::friendlyUnit(status.total_failed_bytes+status.total_redundant_bytes));
|
||||
upTotal->setText(misc::friendlyUnit(status.all_time_upload) + " ("+misc::friendlyUnit(status.total_payload_upload)+" "+tr("this session")+")");
|
||||
dlTotal->setText(misc::friendlyUnit(status.all_time_download) + " ("+misc::friendlyUnit(status.total_payload_download)+" "+tr("this session")+")");
|
||||
lbl_uplimit->setText(h.upload_limit() <= 0 ? QString::fromUtf8("∞") : misc::friendlyUnit(h.upload_limit())+tr("/s", "/second (i.e. per second)"));
|
||||
lbl_dllimit->setText(h.download_limit() <= 0 ? QString::fromUtf8("∞") : misc::friendlyUnit(h.download_limit())+tr("/s", "/second (i.e. per second)"));
|
||||
QString elapsed_txt = misc::userFriendlyDuration(status.active_time);
|
||||
if (h.is_seed(status)) {
|
||||
elapsed_txt += " ("+tr("Seeded for %1", "e.g. Seeded for 3m10s").arg(misc::userFriendlyDuration(status.seeding_time))+")";
|
||||
wasted->setText(misc::friendlyUnit(m_torrent->wastedSize()));
|
||||
upTotal->setText(misc::friendlyUnit(m_torrent->totalUpload()) + " ("+misc::friendlyUnit(m_torrent->totalPayloadUpload())+" "+tr("this session")+")");
|
||||
dlTotal->setText(misc::friendlyUnit(m_torrent->totalDownload()) + " ("+misc::friendlyUnit(m_torrent->totalPayloadDownload())+" "+tr("this session")+")");
|
||||
lbl_uplimit->setText(m_torrent->uploadLimit() <= 0 ? QString::fromUtf8("∞") : misc::friendlyUnit(m_torrent->uploadLimit())+tr("/s", "/second (i.e. per second)"));
|
||||
lbl_dllimit->setText(m_torrent->downloadLimit() <= 0 ? QString::fromUtf8("∞") : misc::friendlyUnit(m_torrent->downloadLimit())+tr("/s", "/second (i.e. per second)"));
|
||||
QString elapsed_txt = misc::userFriendlyDuration(m_torrent->activeTime());
|
||||
if (m_torrent->isSeed()) {
|
||||
elapsed_txt += " ("+tr("Seeded for %1", "e.g. Seeded for 3m10s").arg(misc::userFriendlyDuration(m_torrent->seedingTime()))+")";
|
||||
}
|
||||
lbl_elapsed->setText(elapsed_txt);
|
||||
if (status.connections_limit > 0)
|
||||
lbl_connections->setText(QString::number(status.num_connections)+" ("+tr("%1 max", "e.g. 10 max").arg(QString::number(status.connections_limit))+")");
|
||||
if (m_torrent->connectionsLimit() > 0)
|
||||
lbl_connections->setText(QString::number(m_torrent->connectionsCount())+" ("+tr("%1 max", "e.g. 10 max").arg(QString::number(m_torrent->connectionsLimit()))+")");
|
||||
else
|
||||
lbl_connections->setText(QString::number(status.num_connections));
|
||||
lbl_connections->setText(QString::number(m_torrent->connectionsLimit()));
|
||||
// Update next announce time
|
||||
reannounce_lbl->setText(misc::userFriendlyDuration(status.next_announce.total_seconds()));
|
||||
reannounce_lbl->setText(misc::userFriendlyDuration(m_torrent->nextAnnounce()));
|
||||
// Update ratio info
|
||||
const qreal ratio = QBtSession::instance()->getRealRatio(status);
|
||||
shareRatio->setText(ratio > QBtSession::MAX_RATIO ? QString::fromUtf8("∞") : misc::accurateDoubleToString(ratio, 2));
|
||||
if (!h.is_seed(status) && status.has_metadata) {
|
||||
const qreal ratio = m_torrent->realRatio();
|
||||
shareRatio->setText(ratio > BitTorrent::TorrentHandle::MAX_RATIO ? QString::fromUtf8("∞") : misc::accurateDoubleToString(ratio, 2));
|
||||
if (!m_torrent->isSeed() && m_torrent->hasMetadata()) {
|
||||
showPiecesDownloaded(true);
|
||||
// Downloaded pieces
|
||||
#if LIBTORRENT_VERSION_NUM < 10000
|
||||
bitfield bf(h.get_torrent_info().num_pieces(), 0);
|
||||
#else
|
||||
bitfield bf(h.torrent_file()->num_pieces(), 0);
|
||||
#endif
|
||||
h.downloading_pieces(bf);
|
||||
downloaded_pieces->setProgress(status.pieces, bf);
|
||||
downloaded_pieces->setProgress(m_torrent->pieces(), m_torrent->downloadingPieces());
|
||||
// Pieces availability
|
||||
if (!h.is_paused(status) && !h.is_queued(status) && !h.is_checking(status)) {
|
||||
if (!m_torrent->isPaused() && !m_torrent->isQueued() && !m_torrent->isChecking()) {
|
||||
showPiecesAvailability(true);
|
||||
std::vector<int> avail;
|
||||
h.piece_availability(avail);
|
||||
pieces_availability->setAvailability(avail);
|
||||
avail_average_lbl->setText(misc::accurateDoubleToString(status.distributed_copies, 3));
|
||||
pieces_availability->setAvailability(m_torrent->pieceAvailability());
|
||||
avail_average_lbl->setText(misc::accurateDoubleToString(m_torrent->distributedCopies(), 3));
|
||||
} else {
|
||||
showPiecesAvailability(false);
|
||||
}
|
||||
// Progress
|
||||
qreal progress = h.progress(status)*100.;
|
||||
qreal progress = m_torrent->progress() * 100.;
|
||||
progress_lbl->setText(misc::accurateDoubleToString(progress, 1)+"%");
|
||||
} else {
|
||||
showPiecesAvailability(false);
|
||||
@@ -401,20 +380,15 @@ void PropertiesWidget::loadDynamicData() {
|
||||
}
|
||||
if (stackedProperties->currentIndex() == PropTabBar::PEERS_TAB) {
|
||||
// Load peers
|
||||
peersList->loadPeers(h);
|
||||
peersList->loadPeers(m_torrent);
|
||||
return;
|
||||
}
|
||||
if (stackedProperties->currentIndex() == PropTabBar::FILES_TAB) {
|
||||
libtorrent::torrent_status status = h.status(torrent_handle::query_accurate_download_counters
|
||||
| torrent_handle::query_distributed_copies
|
||||
| torrent_handle::query_pieces);
|
||||
// Files progress
|
||||
if (h.is_valid() && status.has_metadata) {
|
||||
if (m_torrent->hasMetadata()) {
|
||||
qDebug("Updating priorities in files tab");
|
||||
filesList->setUpdatesEnabled(false);
|
||||
std::vector<size_type> fp;
|
||||
h.file_progress(fp);
|
||||
PropListModel->model()->updateFilesProgress(fp);
|
||||
PropListModel->model()->updateFilesProgress(m_torrent->filesProgress());
|
||||
// XXX: We don't update file priorities regularly for performance
|
||||
// reasons. This means that priorities will not be updated if
|
||||
// set from the Web UI.
|
||||
@@ -422,25 +396,22 @@ void PropertiesWidget::loadDynamicData() {
|
||||
filesList->setUpdatesEnabled(true);
|
||||
}
|
||||
}
|
||||
} catch(const invalid_handle& e) {
|
||||
qWarning() << "Caught exception in PropertiesWidget::loadDynamicData(): " << misc::toQStringU(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void PropertiesWidget::loadUrlSeeds() {
|
||||
listWebSeeds->clear();
|
||||
qDebug("Loading URL seeds");
|
||||
const QStringList hc_seeds = h.url_seeds();
|
||||
const QList<QUrl> hc_seeds = m_torrent->urlSeeds();
|
||||
// Add url seeds
|
||||
foreach (const QString &hc_seed, hc_seeds) {
|
||||
qDebug("Loading URL seed: %s", qPrintable(hc_seed));
|
||||
new QListWidgetItem(hc_seed, listWebSeeds);
|
||||
foreach (const QUrl &hc_seed, hc_seeds) {
|
||||
qDebug("Loading URL seed: %s", qPrintable(hc_seed.toString()));
|
||||
new QListWidgetItem(hc_seed.toString(), listWebSeeds);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertiesWidget::openDoubleClickedFile(const QModelIndex &index) {
|
||||
if (!index.isValid()) return;
|
||||
if (!h.is_valid() || !h.has_metadata()) return;
|
||||
if (!m_torrent || !m_torrent->hasMetadata()) return;
|
||||
if (PropListModel->itemType(index) == TorrentContentModelItem::FileType)
|
||||
openFile(index);
|
||||
else
|
||||
@@ -449,12 +420,12 @@ void PropertiesWidget::openDoubleClickedFile(const QModelIndex &index) {
|
||||
|
||||
void PropertiesWidget::openFile(const QModelIndex &index) {
|
||||
int i = PropListModel->getFileIndex(index);
|
||||
const QDir saveDir(h.save_path());
|
||||
const QString filename = h.filepath_at(i);
|
||||
const QDir saveDir(m_torrent->actualSavePath());
|
||||
const QString filename = m_torrent->filePath(i);
|
||||
const QString file_path = fsutils::expandPath(saveDir.absoluteFilePath(filename));
|
||||
qDebug("Trying to open file at %s", qPrintable(file_path));
|
||||
// Flush data
|
||||
h.flush_cache();
|
||||
m_torrent->flushCache();
|
||||
if (QFile::exists(file_path)) {
|
||||
if (file_path.startsWith("//"))
|
||||
QDesktopServices::openUrl(fsutils::toNativePath("file:" + file_path));
|
||||
@@ -484,24 +455,24 @@ void PropertiesWidget::openFolder(const QModelIndex &index, bool containing_fold
|
||||
if (containing_folder)
|
||||
path_items.removeLast();
|
||||
#endif
|
||||
const QDir saveDir(h.save_path());
|
||||
const QDir saveDir(m_torrent->actualSavePath());
|
||||
const QString relative_path = path_items.join("/");
|
||||
absolute_path = fsutils::expandPath(saveDir.absoluteFilePath(relative_path));
|
||||
}
|
||||
else {
|
||||
int i = PropListModel->getFileIndex(index);
|
||||
const QDir saveDir(h.save_path());
|
||||
const QString relative_path = h.filepath_at(i);
|
||||
absolute_path = fsutils::expandPath(saveDir.absoluteFilePath(relative_path));
|
||||
int i = PropListModel->getFileIndex(index);
|
||||
const QDir saveDir(m_torrent->actualSavePath());
|
||||
const QString relative_path = m_torrent->filePath(i);
|
||||
absolute_path = fsutils::expandPath(saveDir.absoluteFilePath(relative_path));
|
||||
|
||||
#if !(defined(Q_OS_WIN) || (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)))
|
||||
if (containing_folder)
|
||||
absolute_path = fsutils::folderName(absolute_path);
|
||||
if (containing_folder)
|
||||
absolute_path = fsutils::folderName(absolute_path);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Flush data
|
||||
h.flush_cache();
|
||||
m_torrent->flushCache();
|
||||
if (!QFile::exists(absolute_path))
|
||||
return;
|
||||
qDebug("Trying to open folder at %s", qPrintable(absolute_path));
|
||||
@@ -544,8 +515,8 @@ void PropertiesWidget::openFolder(const QModelIndex &index, bool containing_fold
|
||||
}
|
||||
|
||||
void PropertiesWidget::displayFilesListMenu(const QPoint&) {
|
||||
if (!h.is_valid())
|
||||
return;
|
||||
if (!m_torrent) return;
|
||||
|
||||
QModelIndexList selectedRows = filesList->selectionModel()->selectedRows(0);
|
||||
if (selectedRows.empty())
|
||||
return;
|
||||
@@ -554,13 +525,13 @@ void PropertiesWidget::displayFilesListMenu(const QPoint&) {
|
||||
QAction *actOpenContainingFolder = 0;
|
||||
QAction *actRename = 0;
|
||||
if (selectedRows.size() == 1) {
|
||||
actOpen = myFilesLlistMenu.addAction(IconProvider::instance()->getIcon("folder-documents"), tr("Open"));
|
||||
actOpenContainingFolder = myFilesLlistMenu.addAction(IconProvider::instance()->getIcon("inode-directory"), tr("Open Containing Folder"));
|
||||
actRename = myFilesLlistMenu.addAction(IconProvider::instance()->getIcon("edit-rename"), tr("Rename..."));
|
||||
actOpen = myFilesLlistMenu.addAction(GuiIconProvider::instance()->getIcon("folder-documents"), tr("Open"));
|
||||
actOpenContainingFolder = myFilesLlistMenu.addAction(GuiIconProvider::instance()->getIcon("inode-directory"), tr("Open Containing Folder"));
|
||||
actRename = myFilesLlistMenu.addAction(GuiIconProvider::instance()->getIcon("edit-rename"), tr("Rename..."));
|
||||
myFilesLlistMenu.addSeparator();
|
||||
}
|
||||
QMenu subMenu;
|
||||
if (!h.status(0x0).is_seeding) {
|
||||
if (!m_torrent->isSeed()) {
|
||||
subMenu.setTitle(tr("Priority"));
|
||||
subMenu.addAction(actionNot_downloaded);
|
||||
subMenu.addAction(actionNormal);
|
||||
@@ -603,20 +574,20 @@ void PropertiesWidget::displayFilesListMenu(const QPoint&) {
|
||||
}
|
||||
|
||||
void PropertiesWidget::displayWebSeedListMenu(const QPoint&) {
|
||||
if (!h.is_valid())
|
||||
return;
|
||||
if (!m_torrent) return;
|
||||
|
||||
QMenu seedMenu;
|
||||
QModelIndexList rows = listWebSeeds->selectionModel()->selectedRows();
|
||||
QAction *actAdd = seedMenu.addAction(IconProvider::instance()->getIcon("list-add"), tr("New Web seed"));
|
||||
QAction *actAdd = seedMenu.addAction(GuiIconProvider::instance()->getIcon("list-add"), tr("New Web seed"));
|
||||
QAction *actDel = 0;
|
||||
QAction *actCpy = 0;
|
||||
QAction *actEdit = 0;
|
||||
|
||||
if (rows.size()) {
|
||||
actDel = seedMenu.addAction(IconProvider::instance()->getIcon("list-remove"), tr("Remove Web seed"));
|
||||
actDel = seedMenu.addAction(GuiIconProvider::instance()->getIcon("list-remove"), tr("Remove Web seed"));
|
||||
seedMenu.addSeparator();
|
||||
actCpy = seedMenu.addAction(IconProvider::instance()->getIcon("edit-copy"), tr("Copy Web seed URL"));
|
||||
actEdit = seedMenu.addAction(IconProvider::instance()->getIcon("edit-rename"), tr("Edit Web seed URL"));
|
||||
actCpy = seedMenu.addAction(GuiIconProvider::instance()->getIcon("edit-copy"), tr("Copy Web seed URL"));
|
||||
actEdit = seedMenu.addAction(GuiIconProvider::instance()->getIcon("edit-rename"), tr("Edit Web seed URL"));
|
||||
}
|
||||
|
||||
const QAction *act = seedMenu.exec(QCursor::pos());
|
||||
@@ -654,8 +625,8 @@ void PropertiesWidget::renameSelectedFile() {
|
||||
if (PropListModel->itemType(index) == TorrentContentModelItem::FileType) {
|
||||
// File renaming
|
||||
const int file_index = PropListModel->getFileIndex(index);
|
||||
if (!h.is_valid() || !h.has_metadata()) return;
|
||||
QString old_name = h.filepath_at(file_index);
|
||||
if (!m_torrent || !m_torrent->hasMetadata()) return;
|
||||
QString old_name = m_torrent->filePath(file_index);
|
||||
if (old_name.endsWith(".!qB") && !new_name_last.endsWith(".!qB")) {
|
||||
new_name_last += ".!qB";
|
||||
}
|
||||
@@ -669,12 +640,12 @@ void PropertiesWidget::renameSelectedFile() {
|
||||
}
|
||||
new_name = fsutils::expandPath(new_name);
|
||||
// Check if that name is already used
|
||||
for (int i=0; i<h.num_files(); ++i) {
|
||||
for (int i = 0; i < m_torrent->filesCount(); ++i) {
|
||||
if (i == file_index) continue;
|
||||
#if defined(Q_OS_UNIX) || defined(Q_WS_QWS)
|
||||
if (h.filepath_at(i).compare(new_name, Qt::CaseSensitive) == 0) {
|
||||
if (m_torrent->filePath(i).compare(new_name, Qt::CaseSensitive) == 0) {
|
||||
#else
|
||||
if (h.filepath_at(i).compare(new_name, Qt::CaseInsensitive) == 0) {
|
||||
if (m_torrent->filePath(i).compare(new_name, Qt::CaseInsensitive) == 0) {
|
||||
#endif
|
||||
// Display error message
|
||||
QMessageBox::warning(this, tr("The file could not be renamed"),
|
||||
@@ -683,11 +654,11 @@ void PropertiesWidget::renameSelectedFile() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const bool force_recheck = QFile::exists(h.save_path()+"/"+new_name);
|
||||
const bool force_recheck = QFile::exists(m_torrent->actualSavePath() + "/" + new_name);
|
||||
qDebug("Renaming %s to %s", qPrintable(old_name), qPrintable(new_name));
|
||||
h.rename_file(file_index, new_name);
|
||||
m_torrent->renameFile(file_index, new_name);
|
||||
// Force recheck
|
||||
if (force_recheck) h.force_recheck();
|
||||
if (force_recheck) m_torrent->forceRecheck();
|
||||
// Rename if torrent files model too
|
||||
if (new_name_last.endsWith(".!qB"))
|
||||
new_name_last.chop(4);
|
||||
@@ -707,9 +678,9 @@ void PropertiesWidget::renameSelectedFile() {
|
||||
QString new_path = path_items.join("/");
|
||||
if (!new_path.endsWith("/")) new_path += "/";
|
||||
// Check for overwriting
|
||||
const int num_files = h.num_files();
|
||||
const int num_files = m_torrent->filesCount();
|
||||
for (int i=0; i<num_files; ++i) {
|
||||
const QString current_name = h.filepath_at(i);
|
||||
const QString current_name = m_torrent->filePath(i);
|
||||
#if defined(Q_OS_UNIX) || defined(Q_WS_QWS)
|
||||
if (current_name.startsWith(new_path, Qt::CaseSensitive)) {
|
||||
#else
|
||||
@@ -724,23 +695,23 @@ void PropertiesWidget::renameSelectedFile() {
|
||||
bool force_recheck = false;
|
||||
// Replace path in all files
|
||||
for (int i=0; i<num_files; ++i) {
|
||||
const QString current_name = h.filepath_at(i);
|
||||
const QString current_name = m_torrent->filePath(i);
|
||||
if (current_name.startsWith(old_path)) {
|
||||
QString new_name = current_name;
|
||||
new_name.replace(0, old_path.length(), new_path);
|
||||
if (!force_recheck && QDir(h.save_path()).exists(new_name))
|
||||
if (!force_recheck && QDir(m_torrent->actualSavePath()).exists(new_name))
|
||||
force_recheck = true;
|
||||
new_name = fsutils::expandPath(new_name);
|
||||
qDebug("Rename %s to %s", qPrintable(current_name), qPrintable(new_name));
|
||||
h.rename_file(i, new_name);
|
||||
m_torrent->renameFile(i, new_name);
|
||||
}
|
||||
}
|
||||
// Force recheck
|
||||
if (force_recheck) h.force_recheck();
|
||||
if (force_recheck) m_torrent->forceRecheck();
|
||||
// Rename folder in torrent files model too
|
||||
PropListModel->setData(index, new_name_last);
|
||||
// Remove old folder
|
||||
const QDir old_folder(h.save_path()+"/"+old_path);
|
||||
const QDir old_folder(m_torrent->actualSavePath() + "/" + old_path);
|
||||
int timeout = 10;
|
||||
while(!QDir().rmpath(old_folder.absolutePath()) && timeout > 0) {
|
||||
// XXX: We should not sleep here (freezes the UI for 1 second)
|
||||
@@ -765,28 +736,23 @@ void PropertiesWidget::askWebSeed() {
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
if (h.is_valid())
|
||||
h.add_url_seed(url_seed);
|
||||
if (m_torrent)
|
||||
m_torrent->addUrlSeeds(QList<QUrl>() << url_seed);
|
||||
// Refresh the seeds list
|
||||
loadUrlSeeds();
|
||||
}
|
||||
|
||||
void PropertiesWidget::deleteSelectedUrlSeeds() {
|
||||
const QList<QListWidgetItem *> selectedItems = listWebSeeds->selectedItems();
|
||||
if (selectedItems.isEmpty())
|
||||
return;
|
||||
bool change = false;
|
||||
foreach (const QListWidgetItem *item, selectedItems) {
|
||||
QString url_seed = item->text();
|
||||
try {
|
||||
h.remove_url_seed(url_seed);
|
||||
change = true;
|
||||
} catch (invalid_handle&) {}
|
||||
}
|
||||
if (change) {
|
||||
// Refresh list
|
||||
loadUrlSeeds();
|
||||
}
|
||||
if (selectedItems.isEmpty()) return;
|
||||
|
||||
QList<QUrl> urlSeeds;
|
||||
foreach (const QListWidgetItem *item, selectedItems)
|
||||
urlSeeds << item->text();
|
||||
|
||||
m_torrent->removeUrlSeeds(urlSeeds);
|
||||
// Refresh list
|
||||
loadUrlSeeds();
|
||||
}
|
||||
|
||||
void PropertiesWidget::copySelectedWebSeedsToClipboard() const {
|
||||
@@ -822,31 +788,28 @@ void PropertiesWidget::editWebSeed() {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
h.remove_url_seed(old_seed);
|
||||
h.add_url_seed(new_seed);
|
||||
loadUrlSeeds();
|
||||
} catch (invalid_handle&) {}
|
||||
m_torrent->removeUrlSeeds(QList<QUrl>() << old_seed);
|
||||
m_torrent->addUrlSeeds(QList<QUrl>() << new_seed);
|
||||
loadUrlSeeds();
|
||||
}
|
||||
|
||||
bool PropertiesWidget::applyPriorities() {
|
||||
qDebug("Saving files priorities");
|
||||
const std::vector<int> priorities = PropListModel->model()->getFilesPriorities();
|
||||
const QVector<int> priorities = PropListModel->model()->getFilePriorities();
|
||||
// Save first/last piece first option state
|
||||
bool first_last_piece_first = h.first_last_piece_first();
|
||||
bool first_last_piece_first = m_torrent->hasFirstLastPiecePriority();
|
||||
// Prioritize the files
|
||||
qDebug("prioritize files: %d", priorities[0]);
|
||||
h.prioritize_files(priorities);
|
||||
m_torrent->prioritizeFiles(priorities);
|
||||
// Restore first/last piece first option if necessary
|
||||
if (first_last_piece_first)
|
||||
h.prioritize_first_last_piece(true);
|
||||
m_torrent->setFirstLastPiecePriority(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PropertiesWidget::filteredFilesChanged() {
|
||||
if (h.is_valid()) {
|
||||
if (m_torrent)
|
||||
applyPriorities();
|
||||
}
|
||||
}
|
||||
|
||||
void PropertiesWidget::filterText(const QString& filter) {
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include <QShortcut>
|
||||
#include <QWidget>
|
||||
#include "ui_propertieswidget.h"
|
||||
#include "qtorrenthandle.h"
|
||||
#include "core/bittorrent/torrenthandle.h"
|
||||
|
||||
|
||||
class TransferListWidget;
|
||||
@@ -64,23 +64,18 @@ public:
|
||||
public:
|
||||
PropertiesWidget(QWidget *parent, MainWindow* main_window, TransferListWidget *transferList);
|
||||
~PropertiesWidget();
|
||||
QTorrentHandle getCurrentTorrent() const;
|
||||
BitTorrent::TorrentHandle *getCurrentTorrent() const;
|
||||
TrackerList* getTrackerList() const { return trackerList; }
|
||||
PeerListWidget* getPeerList() const { return peersList; }
|
||||
QTreeView* getFilesList() const { return filesList; }
|
||||
|
||||
signals:
|
||||
void trackersAdded(const QStringList &trackers, const QString &hash);
|
||||
void trackersRemoved(const QStringList &trackers, const QString &hash);
|
||||
void trackerlessChange(bool trackerless, const QString &hash);
|
||||
|
||||
protected:
|
||||
QPushButton* getButtonFromIndex(int index);
|
||||
bool applyPriorities();
|
||||
|
||||
protected slots:
|
||||
void loadTorrentInfos(const QTorrentHandle &h);
|
||||
void updateTorrentInfos(const QTorrentHandle &h);
|
||||
void loadTorrentInfos(BitTorrent::TorrentHandle *const torrent);
|
||||
void updateTorrentInfos(BitTorrent::TorrentHandle *const torrent);
|
||||
void loadUrlSeeds();
|
||||
void askWebSeed();
|
||||
void deleteSelectedUrlSeeds();
|
||||
@@ -101,8 +96,8 @@ public slots:
|
||||
void saveSettings();
|
||||
void reloadPreferences();
|
||||
void openDoubleClickedFile(const QModelIndex &);
|
||||
void updateSavePath(const QTorrentHandle& h);
|
||||
void loadTrackers(const QTorrentHandle &handle);
|
||||
void updateSavePath(BitTorrent::TorrentHandle *const torrent);
|
||||
void loadTrackers(BitTorrent::TorrentHandle *const torrent);
|
||||
|
||||
private:
|
||||
void openFile(const QModelIndex &index);
|
||||
@@ -111,7 +106,7 @@ private:
|
||||
private:
|
||||
TransferListWidget *transferList;
|
||||
MainWindow *main_window;
|
||||
QTorrentHandle h;
|
||||
BitTorrent::TorrentHandle *m_torrent;
|
||||
QTimer *refreshTimer;
|
||||
SlideState state;
|
||||
TorrentContentFilterModel *PropListModel;
|
||||
|
||||
@@ -154,8 +154,8 @@ public:
|
||||
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex &index) const {
|
||||
if (index.column() != PRIORITY) return 0;
|
||||
if (properties) {
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
if (!h.is_valid() || !h.has_metadata() || h.status(0x0).is_seeding)
|
||||
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
|
||||
if (!torrent || !torrent->hasMetadata() || torrent->isSeed())
|
||||
return 0;
|
||||
}
|
||||
if (index.data().toInt() <= 0) {
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include <QKeySequence>
|
||||
|
||||
#include "proptabbar.h"
|
||||
#include "iconprovider.h"
|
||||
#include "guiiconprovider.h"
|
||||
|
||||
PropTabBar::PropTabBar(QWidget *parent) :
|
||||
QHBoxLayout(parent), m_currentIndex(-1)
|
||||
@@ -42,24 +42,24 @@ PropTabBar::PropTabBar(QWidget *parent) :
|
||||
setSpacing(2);
|
||||
m_btnGroup = new QButtonGroup(this);
|
||||
// General tab
|
||||
QPushButton *main_infos_button = new QPushButton(IconProvider::instance()->getIcon("document-properties"), tr("General"), parent);
|
||||
QPushButton *main_infos_button = new QPushButton(GuiIconProvider::instance()->getIcon("document-properties"), tr("General"), parent);
|
||||
main_infos_button->setShortcut(QKeySequence(QString::fromUtf8("Alt+P")));
|
||||
addWidget(main_infos_button);
|
||||
m_btnGroup->addButton(main_infos_button, MAIN_TAB);
|
||||
// Trackers tab
|
||||
QPushButton *trackers_button = new QPushButton(IconProvider::instance()->getIcon("network-server"), tr("Trackers"), parent);
|
||||
QPushButton *trackers_button = new QPushButton(GuiIconProvider::instance()->getIcon("network-server"), tr("Trackers"), parent);
|
||||
addWidget(trackers_button);
|
||||
m_btnGroup->addButton(trackers_button, TRACKERS_TAB);
|
||||
// Peers tab
|
||||
QPushButton *peers_button = new QPushButton(IconProvider::instance()->getIcon("edit-find-user"), tr("Peers"), parent);
|
||||
QPushButton *peers_button = new QPushButton(GuiIconProvider::instance()->getIcon("edit-find-user"), tr("Peers"), parent);
|
||||
addWidget(peers_button);
|
||||
m_btnGroup->addButton(peers_button, PEERS_TAB);
|
||||
// URL seeds tab
|
||||
QPushButton *urlseeds_button = new QPushButton(IconProvider::instance()->getIcon("network-server"), tr("HTTP Sources"), parent);
|
||||
QPushButton *urlseeds_button = new QPushButton(GuiIconProvider::instance()->getIcon("network-server"), tr("HTTP Sources"), parent);
|
||||
addWidget(urlseeds_button);
|
||||
m_btnGroup->addButton(urlseeds_button, URLSEEDS_TAB);
|
||||
// Files tab
|
||||
QPushButton *files_button = new QPushButton(IconProvider::instance()->getIcon("inode-directory"), tr("Content"), parent);
|
||||
QPushButton *files_button = new QPushButton(GuiIconProvider::instance()->getIcon("inode-directory"), tr("Content"), parent);
|
||||
addWidget(files_button);
|
||||
m_btnGroup->addButton(files_button, FILES_TAB);
|
||||
// Spacer
|
||||
|
||||
@@ -36,19 +36,18 @@
|
||||
#include <QColor>
|
||||
#include <QDebug>
|
||||
#include <QUrl>
|
||||
#include <libtorrent/version.hpp>
|
||||
#include <libtorrent/peer_info.hpp>
|
||||
#include "trackerlist.h"
|
||||
#include "propertieswidget.h"
|
||||
#include "trackersadditiondlg.h"
|
||||
#include "iconprovider.h"
|
||||
#include "qbtsession.h"
|
||||
#include "guiiconprovider.h"
|
||||
#include "core/bittorrent/session.h"
|
||||
#include "core/bittorrent/torrenthandle.h"
|
||||
#include "core/bittorrent/peerinfo.h"
|
||||
#include "core/bittorrent/trackerentry.h"
|
||||
#include "core/preferences.h"
|
||||
#include "core/misc.h"
|
||||
#include "autoexpandabledialog.h"
|
||||
|
||||
using namespace libtorrent;
|
||||
|
||||
TrackerList::TrackerList(PropertiesWidget *properties): QTreeWidget(), properties(properties) {
|
||||
// Graphical settings
|
||||
setRootIsDecorated(false);
|
||||
@@ -108,8 +107,8 @@ void TrackerList::setRowColor(int row, QColor color) {
|
||||
}
|
||||
|
||||
void TrackerList::moveSelectionUp() {
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
if (!h.is_valid()) {
|
||||
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
|
||||
if (!torrent) {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
@@ -131,23 +130,23 @@ void TrackerList::moveSelectionUp() {
|
||||
}
|
||||
setSelectionModel(selection);
|
||||
// Update torrent trackers
|
||||
std::vector<announce_entry> trackers;
|
||||
for (int i=NB_STICKY_ITEM; i<topLevelItemCount(); ++i) {
|
||||
QList<BitTorrent::TrackerEntry> trackers;
|
||||
for (int i = NB_STICKY_ITEM; i < topLevelItemCount(); ++i) {
|
||||
QString tracker_url = topLevelItem(i)->data(COL_URL, Qt::DisplayRole).toString();
|
||||
announce_entry e(tracker_url.toStdString());
|
||||
e.tier = i-NB_STICKY_ITEM;
|
||||
trackers.push_back(e);
|
||||
BitTorrent::TrackerEntry e(tracker_url);
|
||||
e.setTier(i - NB_STICKY_ITEM);
|
||||
trackers.append(e);
|
||||
}
|
||||
h.replace_trackers(trackers);
|
||||
|
||||
torrent->replaceTrackers(trackers);
|
||||
// Reannounce
|
||||
if (!h.is_paused())
|
||||
h.force_reannounce();
|
||||
loadTrackers();
|
||||
if (!torrent->isPaused())
|
||||
torrent->forceReannounce();
|
||||
}
|
||||
|
||||
void TrackerList::moveSelectionDown() {
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
if (!h.is_valid()) {
|
||||
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
|
||||
if (!torrent) {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
@@ -169,18 +168,18 @@ void TrackerList::moveSelectionDown() {
|
||||
}
|
||||
setSelectionModel(selection);
|
||||
// Update torrent trackers
|
||||
std::vector<announce_entry> trackers;
|
||||
for (int i=NB_STICKY_ITEM; i<topLevelItemCount(); ++i) {
|
||||
QList<BitTorrent::TrackerEntry> trackers;
|
||||
for (int i = NB_STICKY_ITEM; i < topLevelItemCount(); ++i) {
|
||||
QString tracker_url = topLevelItem(i)->data(COL_URL, Qt::DisplayRole).toString();
|
||||
announce_entry e(tracker_url.toStdString());
|
||||
e.tier = i-NB_STICKY_ITEM;
|
||||
trackers.push_back(e);
|
||||
BitTorrent::TrackerEntry e(tracker_url);
|
||||
e.setTier(i - NB_STICKY_ITEM);
|
||||
trackers.append(e);
|
||||
}
|
||||
h.replace_trackers(trackers);
|
||||
|
||||
torrent->replaceTrackers(trackers);
|
||||
// Reannounce
|
||||
if (!h.is_paused())
|
||||
h.force_reannounce();
|
||||
loadTrackers();
|
||||
if (!torrent->isPaused())
|
||||
torrent->forceReannounce();
|
||||
}
|
||||
|
||||
void TrackerList::clear() {
|
||||
@@ -197,29 +196,29 @@ void TrackerList::clear() {
|
||||
lsd_item->setText(COL_MSG, "");
|
||||
}
|
||||
|
||||
void TrackerList::loadStickyItems(const QTorrentHandle &h) {
|
||||
void TrackerList::loadStickyItems(BitTorrent::TorrentHandle *const torrent) {
|
||||
QString working = tr("Working");
|
||||
QString disabled = tr("Disabled");
|
||||
|
||||
// load DHT information
|
||||
if (QBtSession::instance()->isDHTEnabled() && !h.priv())
|
||||
if (BitTorrent::Session::instance()->isDHTEnabled() && !torrent->isPrivate())
|
||||
dht_item->setText(COL_STATUS, working);
|
||||
else
|
||||
dht_item->setText(COL_STATUS, disabled);
|
||||
|
||||
// Load PeX Information
|
||||
if (QBtSession::instance()->isPexEnabled() && !h.priv())
|
||||
if (BitTorrent::Session::instance()->isPexEnabled() && !torrent->isPrivate())
|
||||
pex_item->setText(COL_STATUS, working);
|
||||
else
|
||||
pex_item->setText(COL_STATUS, disabled);
|
||||
|
||||
// Load LSD Information
|
||||
if (QBtSession::instance()->isLSDEnabled() && !h.priv())
|
||||
if (BitTorrent::Session::instance()->isLSDEnabled() && !torrent->isPrivate())
|
||||
lsd_item->setText(COL_STATUS, working);
|
||||
else
|
||||
lsd_item->setText(COL_STATUS, disabled);
|
||||
|
||||
if (h.priv()) {
|
||||
if (torrent->isPrivate()) {
|
||||
QString privateMsg = tr("This torrent is private");
|
||||
dht_item->setText(COL_MSG, privateMsg);
|
||||
pex_item->setText(COL_MSG, privateMsg);
|
||||
@@ -229,16 +228,12 @@ void TrackerList::loadStickyItems(const QTorrentHandle &h) {
|
||||
// XXX: libtorrent should provide this info...
|
||||
// Count peers from DHT, LSD, PeX
|
||||
uint nb_dht = 0, nb_lsd = 0, nb_pex = 0;
|
||||
std::vector<peer_info> peers;
|
||||
h.get_peer_info(peers);
|
||||
std::vector<peer_info>::iterator it = peers.begin();
|
||||
std::vector<peer_info>::iterator end = peers.end();
|
||||
for ( ; it != end; ++it) {
|
||||
if (it->source & peer_info::dht)
|
||||
foreach (const BitTorrent::PeerInfo &peer, torrent->peers()) {
|
||||
if (peer.fromDHT())
|
||||
++nb_dht;
|
||||
if (it->source & peer_info::lsd)
|
||||
if (peer.fromLSD())
|
||||
++nb_lsd;
|
||||
if (it->source & peer_info::pex)
|
||||
if (peer.fromPeX())
|
||||
++nb_pex;
|
||||
}
|
||||
dht_item->setText(COL_PEERS, QString::number(nb_dht));
|
||||
@@ -248,47 +243,47 @@ void TrackerList::loadStickyItems(const QTorrentHandle &h) {
|
||||
|
||||
void TrackerList::loadTrackers() {
|
||||
// Load trackers from torrent handle
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
if (!h.is_valid()) return;
|
||||
loadStickyItems(h);
|
||||
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
|
||||
if (!torrent) return;
|
||||
|
||||
loadStickyItems(torrent);
|
||||
// Load actual trackers information
|
||||
QHash<QString, TrackerInfos> trackers_data = QBtSession::instance()->getTrackersInfo(h.hash());
|
||||
QHash<QString, BitTorrent::TrackerInfo> trackers_data = torrent->trackerInfos();
|
||||
QStringList old_trackers_urls = tracker_items.keys();
|
||||
const std::vector<announce_entry> trackers = h.trackers();
|
||||
std::vector<announce_entry>::const_iterator it = trackers.begin();
|
||||
std::vector<announce_entry>::const_iterator end = trackers.end();
|
||||
for ( ; it != end; ++it) {
|
||||
QString tracker_url = misc::toQString(it->url);
|
||||
QTreeWidgetItem *item = tracker_items.value(tracker_url, 0);
|
||||
foreach (const BitTorrent::TrackerEntry &entry, torrent->trackers()) {
|
||||
QString trackerUrl = entry.url();
|
||||
QTreeWidgetItem *item = tracker_items.value(trackerUrl, 0);
|
||||
if (!item) {
|
||||
item = new QTreeWidgetItem();
|
||||
item->setText(COL_URL, tracker_url);
|
||||
item->setText(COL_URL, trackerUrl);
|
||||
addTopLevelItem(item);
|
||||
tracker_items[tracker_url] = item;
|
||||
tracker_items[trackerUrl] = item;
|
||||
} else {
|
||||
old_trackers_urls.removeOne(tracker_url);
|
||||
old_trackers_urls.removeOne(trackerUrl);
|
||||
}
|
||||
item->setText(COL_TIER, QString::number(it->tier));
|
||||
TrackerInfos data = trackers_data.value(tracker_url, TrackerInfos(tracker_url));
|
||||
QString error_message = data.last_message.trimmed();
|
||||
if (it->verified) {
|
||||
item->setText(COL_STATUS, tr("Working"));
|
||||
item->setText(COL_MSG, "");
|
||||
} else {
|
||||
if (it->updating && it->fails == 0) {
|
||||
item->setText(COL_TIER, QString::number(entry.tier()));
|
||||
BitTorrent::TrackerInfo data = trackers_data.value(trackerUrl);
|
||||
QString error_message = data.lastMessage.trimmed();
|
||||
switch (entry.status()) {
|
||||
case BitTorrent::TrackerEntry::Working:
|
||||
item->setText(COL_STATUS, tr("Working"));
|
||||
item->setText(COL_MSG, "");
|
||||
break;
|
||||
case BitTorrent::TrackerEntry::Updating:
|
||||
item->setText(COL_STATUS, tr("Updating..."));
|
||||
item->setText(COL_MSG, "");
|
||||
} else {
|
||||
if (it->fails > 0) {
|
||||
item->setText(COL_STATUS, tr("Not working"));
|
||||
item->setText(COL_MSG, error_message);
|
||||
} else {
|
||||
item->setText(COL_STATUS, tr("Not contacted yet"));
|
||||
item->setText(COL_MSG, "");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BitTorrent::TrackerEntry::NotWorking:
|
||||
item->setText(COL_STATUS, tr("Not working"));
|
||||
item->setText(COL_MSG, error_message);
|
||||
break;
|
||||
case BitTorrent::TrackerEntry::NotContacted:
|
||||
item->setText(COL_STATUS, tr("Not contacted yet"));
|
||||
item->setText(COL_MSG, "");
|
||||
break;
|
||||
}
|
||||
item->setText(COL_PEERS, QString::number(trackers_data.value(tracker_url, TrackerInfos(tracker_url)).num_peers));
|
||||
|
||||
item->setText(COL_PEERS, QString::number(trackers_data.value(trackerUrl).numPeers));
|
||||
}
|
||||
// Remove old trackers
|
||||
foreach (const QString &tracker, old_trackers_urls) {
|
||||
@@ -298,12 +293,13 @@ void TrackerList::loadTrackers() {
|
||||
|
||||
// Ask the user for new trackers and add them to the torrent
|
||||
void TrackerList::askForTrackers() {
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
if (!h.is_valid()) return;
|
||||
QString hash = h.hash();
|
||||
QStringList trackers = TrackersAdditionDlg::askForTrackers(h);
|
||||
QBtSession::instance()->addTrackersAndUrlSeeds(hash, trackers, QStringList());
|
||||
loadTrackers();
|
||||
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
|
||||
if (!torrent) return;
|
||||
|
||||
QList<BitTorrent::TrackerEntry> trackers;
|
||||
foreach (const QString &tracker, TrackersAdditionDlg::askForTrackers(torrent))
|
||||
trackers << tracker;
|
||||
torrent->addTrackers(trackers);
|
||||
}
|
||||
|
||||
void TrackerList::copyTrackerUrl() {
|
||||
@@ -320,14 +316,15 @@ void TrackerList::copyTrackerUrl() {
|
||||
|
||||
|
||||
void TrackerList::deleteSelectedTrackers() {
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
if (!h.is_valid()) {
|
||||
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
|
||||
if (!torrent) {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
QString hash = h.hash();
|
||||
|
||||
QList<QTreeWidgetItem *> selected_items = getSelectedTrackerItems();
|
||||
if (selected_items.isEmpty()) return;
|
||||
|
||||
QStringList urls_to_remove;
|
||||
foreach (QTreeWidgetItem *item, selected_items) {
|
||||
QString tracker_url = item->data(COL_URL, Qt::DisplayRole).toString();
|
||||
@@ -335,32 +332,26 @@ void TrackerList::deleteSelectedTrackers() {
|
||||
tracker_items.remove(tracker_url);
|
||||
delete item;
|
||||
}
|
||||
// Iterate of trackers and remove selected ones
|
||||
std::vector<announce_entry> remaining_trackers;
|
||||
std::vector<announce_entry> trackers = h.trackers();
|
||||
|
||||
std::vector<announce_entry>::iterator it = trackers.begin();
|
||||
std::vector<announce_entry>::iterator itend = trackers.end();
|
||||
for ( ; it != itend; ++it) {
|
||||
if (!urls_to_remove.contains(misc::toQString((*it).url))) {
|
||||
remaining_trackers.push_back(*it);
|
||||
// Iterate of trackers and remove selected ones
|
||||
QList<BitTorrent::TrackerEntry> remaining_trackers;
|
||||
QList<BitTorrent::TrackerEntry> trackers = torrent->trackers();
|
||||
foreach (const BitTorrent::TrackerEntry &entry, trackers) {
|
||||
if (!urls_to_remove.contains(entry.url())) {
|
||||
remaining_trackers.push_back(entry);
|
||||
}
|
||||
}
|
||||
h.replace_trackers(remaining_trackers);
|
||||
if (!urls_to_remove.empty())
|
||||
emit trackersRemoved(urls_to_remove, hash);
|
||||
if (remaining_trackers.empty())
|
||||
emit trackerlessChange(true, hash);
|
||||
if (!h.is_paused())
|
||||
h.force_reannounce();
|
||||
// Reload Trackers
|
||||
loadTrackers();
|
||||
|
||||
torrent->replaceTrackers(remaining_trackers);
|
||||
if (!torrent->isPaused())
|
||||
torrent->forceReannounce();
|
||||
}
|
||||
|
||||
void TrackerList::editSelectedTracker() {
|
||||
try {
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
QString hash = h.hash();
|
||||
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
|
||||
if (!torrent) return;
|
||||
|
||||
QString hash = torrent->hash();
|
||||
|
||||
QList<QTreeWidgetItem *> selected_items = getSelectedTrackerItems();
|
||||
if (selected_items.isEmpty())
|
||||
@@ -381,91 +372,78 @@ void TrackerList::editSelectedTracker() {
|
||||
if (new_tracker_url == tracker_url)
|
||||
return;
|
||||
|
||||
std::vector<announce_entry> trackers = h.trackers();
|
||||
std::vector<announce_entry>::iterator it = trackers.begin();
|
||||
std::vector<announce_entry>::iterator itend = trackers.end();
|
||||
QList<BitTorrent::TrackerEntry> trackers = torrent->trackers();
|
||||
bool match = false;
|
||||
|
||||
for ( ; it != itend; ++it) {
|
||||
if (new_tracker_url == QUrl(misc::toQString(it->url))) {
|
||||
for (int i = 0; i < trackers.size(); ++i) {
|
||||
BitTorrent::TrackerEntry &entry = trackers[i];
|
||||
if (new_tracker_url == QUrl(entry.url())) {
|
||||
QMessageBox::warning(this, tr("Tracker editing failed"), tr("The tracker URL already exists."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (tracker_url == QUrl(misc::toQStringU(it->url)) && !match) {
|
||||
announce_entry new_entry(new_tracker_url.toString().toUtf8().constData());
|
||||
new_entry.tier = it->tier;
|
||||
if (tracker_url == QUrl(entry.url()) && !match) {
|
||||
BitTorrent::TrackerEntry new_entry(new_tracker_url.toString());
|
||||
new_entry.setTier(entry.tier());
|
||||
match = true;
|
||||
*it = new_entry;
|
||||
emit trackersRemoved(QStringList(tracker_url.toString()), hash);
|
||||
emit trackersAdded(QStringList(new_tracker_url.toString()), hash);
|
||||
entry = new_entry;
|
||||
}
|
||||
}
|
||||
|
||||
h.replace_trackers(trackers);
|
||||
if (!h.is_paused()) {
|
||||
h.force_reannounce();
|
||||
h.force_dht_announce();
|
||||
torrent->replaceTrackers(trackers);
|
||||
if (!torrent->isPaused()) {
|
||||
torrent->forceReannounce();
|
||||
torrent->forceDHTAnnounce();
|
||||
}
|
||||
} catch(invalid_handle&) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadTrackers();
|
||||
}
|
||||
|
||||
#if LIBTORRENT_VERSION_NUM >= 10000
|
||||
void TrackerList::reannounceSelected() {
|
||||
try {
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
|
||||
if (!torrent) return;
|
||||
|
||||
QList<QTreeWidgetItem *> selected_items = getSelectedTrackerItems();
|
||||
if (selected_items.isEmpty())
|
||||
return;
|
||||
if (selected_items.isEmpty()) return;
|
||||
|
||||
std::vector<announce_entry> trackers = h.trackers();
|
||||
for (size_t i = 0; i < trackers.size(); ++i) {
|
||||
QList<BitTorrent::TrackerEntry> trackers = torrent->trackers();
|
||||
for (int i = 0; i < trackers.size(); ++i) {
|
||||
foreach (QTreeWidgetItem* w, selected_items) {
|
||||
if (w->text(COL_URL) == misc::toQString(trackers[i].url)) {
|
||||
h.force_reannounce(0, i);
|
||||
if (w->text(COL_URL) == trackers[i].url()) {
|
||||
torrent->forceReannounce(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(invalid_handle&) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadTrackers();
|
||||
loadTrackers();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void TrackerList::showTrackerListMenu(QPoint) {
|
||||
QTorrentHandle h = properties->getCurrentTorrent();
|
||||
if (!h.is_valid()) return;
|
||||
BitTorrent::TorrentHandle *const torrent = properties->getCurrentTorrent();
|
||||
if (!torrent) return;
|
||||
//QList<QTreeWidgetItem*> selected_items = getSelectedTrackerItems();
|
||||
QMenu menu;
|
||||
// Add actions
|
||||
QAction *addAct = menu.addAction(IconProvider::instance()->getIcon("list-add"), tr("Add a new tracker..."));
|
||||
QAction *addAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-add"), tr("Add a new tracker..."));
|
||||
QAction *copyAct = 0;
|
||||
QAction *delAct = 0;
|
||||
QAction *editAct = 0;
|
||||
if (!getSelectedTrackerItems().isEmpty()) {
|
||||
delAct = menu.addAction(IconProvider::instance()->getIcon("list-remove"), tr("Remove tracker"));
|
||||
copyAct = menu.addAction(IconProvider::instance()->getIcon("edit-copy"), tr("Copy tracker url"));
|
||||
editAct = menu.addAction(IconProvider::instance()->getIcon("edit-rename"),tr("Edit selected tracker URL"));
|
||||
delAct = menu.addAction(GuiIconProvider::instance()->getIcon("list-remove"), tr("Remove tracker"));
|
||||
copyAct = menu.addAction(GuiIconProvider::instance()->getIcon("edit-copy"), tr("Copy tracker url"));
|
||||
editAct = menu.addAction(GuiIconProvider::instance()->getIcon("edit-rename"),tr("Edit selected tracker URL"));
|
||||
}
|
||||
#if LIBTORRENT_VERSION_NUM >= 10000
|
||||
QAction *reannounceSelAct = NULL;
|
||||
#endif
|
||||
QAction *reannounceAct = NULL;
|
||||
if (!h.is_paused()) {
|
||||
if (!torrent->isPaused()) {
|
||||
#if LIBTORRENT_VERSION_NUM >= 10000
|
||||
reannounceSelAct = menu.addAction(IconProvider::instance()->getIcon("view-refresh"), tr("Force reannounce to selected trackers"));
|
||||
reannounceSelAct = menu.addAction(GuiIconProvider::instance()->getIcon("view-refresh"), tr("Force reannounce to selected trackers"));
|
||||
#endif
|
||||
menu.addSeparator();
|
||||
reannounceAct = menu.addAction(IconProvider::instance()->getIcon("view-refresh"), tr("Force reannounce to all trackers"));
|
||||
reannounceAct = menu.addAction(GuiIconProvider::instance()->getIcon("view-refresh"), tr("Force reannounce to all trackers"));
|
||||
}
|
||||
QAction *act = menu.exec(QCursor::pos());
|
||||
if (act == 0) return;
|
||||
@@ -488,7 +466,7 @@ void TrackerList::showTrackerListMenu(QPoint) {
|
||||
}
|
||||
#endif
|
||||
if (act == reannounceAct) {
|
||||
properties->getCurrentTorrent().force_reannounce();
|
||||
properties->getCurrentTorrent()->forceReannounce();
|
||||
return;
|
||||
}
|
||||
if (act == editAct) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user