Redesign main core classes.

This commit is contained in:
Vladimir Golovnev (Glassez) 2015-04-19 18:17:47 +03:00
parent 60c0939e05
commit d16d1fdb3a
152 changed files with 11366 additions and 8967 deletions

View file

@ -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 &params)
{
return sendMessage(params.join(QLatin1String(PARAMS_SEPARATOR)));
@ -114,45 +211,32 @@ void Application::processParams(const QStringList &params)
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);
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 &params)
{
// 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
}

View file

@ -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 &params);
void sendNotificationEmail(BitTorrent::TorrentHandle *const torrent);
};
#endif // APPLICATION_H

View file

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

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

View 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

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

View 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

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

View 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

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

View 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

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

View 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

View 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");
}

View file

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

View 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

View 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();
}

View 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

View 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();
}
}

View 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

View 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

File diff suppressed because it is too large Load diff

View 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 &params = AddTorrentParams());
bool addTorrent(const TorrentInfo &torrentInfo, const AddTorrentParams &params = 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

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

View 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

View 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()));
}
}

View 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

File diff suppressed because it is too large Load diff

View 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

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

View 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

View file

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

View 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

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

View 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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -35,6 +35,7 @@
QT_BEGIN_NAMESPACE
class QNetworkAccessManager;
class QNetworkReply;
class QUrl;
QT_END_NAMESPACE
namespace Net

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

View 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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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
View 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
View 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

View file

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

View file

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

View file

@ -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))
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 &current_name = m_filesPath.at(i);
for (int i = 0; i < m_torrentInfo.filesCount(); ++i) {
const QString &current_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 &current_name = m_filesPath.at(i);
for (int i = 0; i < m_torrentInfo.filesCount(); ++i) {
const QString &current_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)
if (info.hash() != m_hash) return;
disconnect(this, SLOT(updateMetadata(BitTorrent::TorrentInfo)));
if (!info.isValid()) {
MessageBoxRaised::critical(0, tr("I/O Error"), ("Invalid metadata."));
setMetadataProgressIndicator(false, tr("Invalid metadata"));
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_torrentInfo = info;
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"));
return;
}
}
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();
}

View file

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

View file

@ -9,7 +9,7 @@
#include <QLineEdit>
#include <QComboBox>
#include <QNetworkInterface>
#include <libtorrent/version.hpp>
#include "core/preferences.h"
enum AdvSettingsCols {PROPERTY, VALUE};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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);
AddNewTorrentDialog::show(file, this);
else
QBtSession::instance()->addMagnetUri(file);
}
else {
// Local file
if (useTorrentAdditionDialog)
AddNewTorrentDialog::showTorrent(file, QString(), this);
else
QBtSession::instance()->addTorrent(file);
}
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(),
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);
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
QBtSession::instance()->addTorrent(pathsList.at(i));
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'/>&nbsp;" + 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'/>&nbsp;" + 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'/>&nbsp;" + 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'/>&nbsp;" + 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);
AddNewTorrentDialog::show(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);
}
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

View file

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

View file

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

View file

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

View 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

View file

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

View file

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

View file

@ -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 {
class PeerAdditionDlg: public QDialog, private Ui::addPeerDialog
{
Q_OBJECT
public:
PeerAdditionDlg(QWidget *parent=0): QDialog(parent) {
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();
}
return QString();
~PeerAdditionDlg()
{
}
unsigned short getPort() const {
QHostAddress getAddress() const
{
return QHostAddress(lineIP->text());
}
ushort getPort() const
{
return spinPort->value();
}
static libtorrent::asio::ip::tcp::endpoint askForPeerEndpoint() {
libtorrent::asio::ip::tcp::endpoint ep;
static BitTorrent::PeerAddress askForPeerAddress()
{
BitTorrent::PeerAddress addr;
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;
}
addr.ip = dlg.getAddress();
if (addr.ip.isNull())
qDebug("Unable to parse the provided IP.");
else
qDebug("Provided IP is correct");
ep = libtorrent::asio::ip::tcp::endpoint(addr, dlg.getPort());
addr.port = dlg.getPort();
}
return ep;
return addr;
}
protected slots:
void validateInput() {
if (getIP().isEmpty()) {
QMessageBox::warning(this, tr("Invalid IP"),
tr("The IP you provided is invalid."),
QMessageBox::Ok);
} else {
if (getAddress().isNull())
QMessageBox::warning(this, tr("Invalid IP"), tr("The IP you provided is invalid."), QMessageBox::Ok);
else
accept();
}
}
};
#endif // PEERADDITION_H

View file

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

View file

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

View file

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

View file

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

View file

@ -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,14 +455,14 @@ 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);
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)))
@ -501,7 +472,7 @@ void PropertiesWidget::openFolder(const QModelIndex &index, bool containing_fold
}
// 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) {
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);
m_torrent->removeUrlSeeds(QList<QUrl>() << old_seed);
m_torrent->addUrlSeeds(QList<QUrl>() << new_seed);
loadUrlSeeds();
} catch (invalid_handle&) {}
}
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) {

View file

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

View file

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

View file

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

View file

@ -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_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, "");
} else {
if (it->updating && it->fails == 0) {
break;
case BitTorrent::TrackerEntry::Updating:
item->setText(COL_STATUS, tr("Updating..."));
item->setText(COL_MSG, "");
} else {
if (it->fails > 0) {
break;
case BitTorrent::TrackerEntry::NotWorking:
item->setText(COL_STATUS, tr("Not working"));
item->setText(COL_MSG, error_message);
} else {
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,60 +372,47 @@ 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();
}
@ -442,30 +420,30 @@ void TrackerList::reannounceSelected() {
#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