Browse Source

Fix indentation size in qtlibtorrent/* files.

adaptive-webui-19844
Vladimir Golovnev (Glassez) 10 years ago
parent
commit
0e4ef42ddf
  1. 114
      src/core/qtlibtorrent/alertdispatcher.cpp
  2. 38
      src/core/qtlibtorrent/alertdispatcher.h
  3. 106
      src/core/qtlibtorrent/bandwidthscheduler.h
  4. 602
      src/core/qtlibtorrent/filterparserthread.cpp
  5. 36
      src/core/qtlibtorrent/filterparserthread.h
  6. 4822
      src/core/qtlibtorrent/qbtsession.cpp
  7. 488
      src/core/qtlibtorrent/qbtsession.h
  8. 8
      src/core/qtlibtorrent/qtorrenthandle.cpp
  9. 116
      src/core/qtlibtorrent/shutdownconfirm.cpp
  10. 26
      src/core/qtlibtorrent/shutdownconfirm.h
  11. 872
      src/core/qtlibtorrent/torrentmodel.cpp
  12. 112
      src/core/qtlibtorrent/torrentmodel.h
  13. 154
      src/core/qtlibtorrent/torrentspeedmonitor.cpp
  14. 18
      src/core/qtlibtorrent/torrentspeedmonitor.h
  15. 126
      src/core/qtlibtorrent/torrentstatistics.cpp
  16. 38
      src/core/qtlibtorrent/torrentstatistics.h
  17. 34
      src/core/qtlibtorrent/trackerinfos.h

114
src/core/qtlibtorrent/alertdispatcher.cpp

@ -37,99 +37,99 @@
const size_t DEFAULT_ALERTS_CAPACITY = 32; const size_t DEFAULT_ALERTS_CAPACITY = 32;
struct QAlertDispatcher::Tag { struct QAlertDispatcher::Tag {
Tag(QAlertDispatcher* dispatcher); Tag(QAlertDispatcher* dispatcher);
QAlertDispatcher* dispatcher; QAlertDispatcher* dispatcher;
QMutex alerts_mutex; QMutex alerts_mutex;
}; };
QAlertDispatcher::Tag::Tag(QAlertDispatcher* dispatcher) QAlertDispatcher::Tag::Tag(QAlertDispatcher* dispatcher)
: dispatcher(dispatcher) : dispatcher(dispatcher)
{} {}
QAlertDispatcher::QAlertDispatcher(libtorrent::session *session, QObject* parent) QAlertDispatcher::QAlertDispatcher(libtorrent::session *session, QObject* parent)
: QObject(parent) : QObject(parent)
, m_session(session) , m_session(session)
, current_tag(new Tag(this)) , current_tag(new Tag(this))
, event_posted(false) , event_posted(false)
{ {
alerts.reserve(DEFAULT_ALERTS_CAPACITY); alerts.reserve(DEFAULT_ALERTS_CAPACITY);
m_session->set_alert_dispatch(boost::bind(&QAlertDispatcher::dispatch, current_tag, _1)); m_session->set_alert_dispatch(boost::bind(&QAlertDispatcher::dispatch, current_tag, _1));
} }
QAlertDispatcher::~QAlertDispatcher() { QAlertDispatcher::~QAlertDispatcher() {
// When QAlertDispatcher is destoyed, libtorrent still can call // When QAlertDispatcher is destoyed, libtorrent still can call
// QAlertDispatcher::dispatch a few times after destruction. This is // QAlertDispatcher::dispatch a few times after destruction. This is
// handled by passing a "tag". A tag is a object that references QAlertDispatch. // handled by passing a "tag". A tag is a object that references QAlertDispatch.
// Tag could be invalidated. So on destruction QAlertDispatcher invalidates a tag // Tag could be invalidated. So on destruction QAlertDispatcher invalidates a tag
// and then unsubscribes from alerts. When QAlertDispatcher::dispatch is called // and then unsubscribes from alerts. When QAlertDispatcher::dispatch is called
// with invalid tag it simply discard an alert. // with invalid tag it simply discard an alert.
{ {
QMutexLocker lock(&current_tag->alerts_mutex); QMutexLocker lock(&current_tag->alerts_mutex);
current_tag->dispatcher = 0; current_tag->dispatcher = 0;
current_tag.clear(); current_tag.clear();
} }
typedef boost::function<void (std::auto_ptr<libtorrent::alert>)> dispatch_function_t; typedef boost::function<void (std::auto_ptr<libtorrent::alert>)> dispatch_function_t;
m_session->set_alert_dispatch(dispatch_function_t()); m_session->set_alert_dispatch(dispatch_function_t());
} }
void QAlertDispatcher::getPendingAlertsNoWait(std::vector<libtorrent::alert*>& out) { void QAlertDispatcher::getPendingAlertsNoWait(std::vector<libtorrent::alert*>& out) {
Q_ASSERT(out.empty()); Q_ASSERT(out.empty());
out.reserve(DEFAULT_ALERTS_CAPACITY); out.reserve(DEFAULT_ALERTS_CAPACITY);
QMutexLocker lock(&current_tag->alerts_mutex); QMutexLocker lock(&current_tag->alerts_mutex);
alerts.swap(out); alerts.swap(out);
event_posted = false; event_posted = false;
} }
void QAlertDispatcher::getPendingAlerts(std::vector<libtorrent::alert*>& out, unsigned long time) { void QAlertDispatcher::getPendingAlerts(std::vector<libtorrent::alert*>& out, unsigned long time) {
Q_ASSERT(out.empty()); Q_ASSERT(out.empty());
out.reserve(DEFAULT_ALERTS_CAPACITY); out.reserve(DEFAULT_ALERTS_CAPACITY);
QMutexLocker lock(&current_tag->alerts_mutex); QMutexLocker lock(&current_tag->alerts_mutex);
while (alerts.empty()) while (alerts.empty())
alerts_condvar.wait(&current_tag->alerts_mutex, time); alerts_condvar.wait(&current_tag->alerts_mutex, time);
alerts.swap(out); alerts.swap(out);
event_posted = false; event_posted = false;
} }
void QAlertDispatcher::dispatch(QSharedPointer<Tag> tag, void QAlertDispatcher::dispatch(QSharedPointer<Tag> tag,
std::auto_ptr<libtorrent::alert> alert_ptr) { std::auto_ptr<libtorrent::alert> alert_ptr) {
QMutexLocker lock(&(tag->alerts_mutex)); QMutexLocker lock(&(tag->alerts_mutex));
QAlertDispatcher* that = tag->dispatcher; QAlertDispatcher* that = tag->dispatcher;
if (!that) if (!that)
return; return;
bool was_empty = that->alerts.empty(); bool was_empty = that->alerts.empty();
that->alerts.push_back(alert_ptr.get()); that->alerts.push_back(alert_ptr.get());
alert_ptr.release(); alert_ptr.release();
if (was_empty) if (was_empty)
that->alerts_condvar.wakeAll(); that->alerts_condvar.wakeAll();
that->enqueueToMainThread(); that->enqueueToMainThread();
Q_ASSERT(that->current_tag == tag); Q_ASSERT(that->current_tag == tag);
} }
void QAlertDispatcher::enqueueToMainThread() { void QAlertDispatcher::enqueueToMainThread() {
if (!event_posted) { if (!event_posted) {
event_posted = true; event_posted = true;
QMetaObject::invokeMethod(this, "deliverSignal", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "deliverSignal", Qt::QueuedConnection);
} }
} }
void QAlertDispatcher::deliverSignal() { void QAlertDispatcher::deliverSignal() {
emit alertsReceived(); emit alertsReceived();
QMutexLocker lock(&current_tag->alerts_mutex); QMutexLocker lock(&current_tag->alerts_mutex);
event_posted = false; event_posted = false;
if (!alerts.empty()) if (!alerts.empty())
enqueueToMainThread(); enqueueToMainThread();
} }

38
src/core/qtlibtorrent/alertdispatcher.h

@ -41,40 +41,40 @@
#include <memory> #include <memory>
namespace libtorrent { namespace libtorrent {
class session; class session;
class alert; class alert;
} }
class QAlertDispatcher : public QObject { class QAlertDispatcher : public QObject {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(QAlertDispatcher) Q_DISABLE_COPY(QAlertDispatcher)
struct Tag; struct Tag;
public: public:
QAlertDispatcher(libtorrent::session *session, QObject* parent); QAlertDispatcher(libtorrent::session *session, QObject* parent);
~QAlertDispatcher(); ~QAlertDispatcher();
void getPendingAlertsNoWait(std::vector<libtorrent::alert*>&); void getPendingAlertsNoWait(std::vector<libtorrent::alert*>&);
void getPendingAlerts(std::vector<libtorrent::alert*>&, unsigned long time = ULONG_MAX); void getPendingAlerts(std::vector<libtorrent::alert*>&, unsigned long time = ULONG_MAX);
signals: signals:
void alertsReceived(); void alertsReceived();
private: private:
static void dispatch(QSharedPointer<Tag>, static void dispatch(QSharedPointer<Tag>,
std::auto_ptr<libtorrent::alert>); std::auto_ptr<libtorrent::alert>);
void enqueueToMainThread(); void enqueueToMainThread();
private slots: private slots:
void deliverSignal(); void deliverSignal();
private: private:
libtorrent::session *m_session; libtorrent::session *m_session;
QWaitCondition alerts_condvar; QWaitCondition alerts_condvar;
std::vector<libtorrent::alert*> alerts; std::vector<libtorrent::alert*> alerts;
QSharedPointer<Tag> current_tag; QSharedPointer<Tag> current_tag;
bool event_posted; bool event_posted;
}; };
#endif // ALERTDISPATCHER_H #endif // ALERTDISPATCHER_H

106
src/core/qtlibtorrent/bandwidthscheduler.h

@ -9,71 +9,71 @@
class BandwidthScheduler: public QTimer { class BandwidthScheduler: public QTimer {
Q_OBJECT Q_OBJECT
public: public:
BandwidthScheduler(QObject *parent): QTimer(parent) { BandwidthScheduler(QObject *parent): QTimer(parent) {
Q_ASSERT(Preferences::instance()->isSchedulerEnabled()); Q_ASSERT(Preferences::instance()->isSchedulerEnabled());
// Signal shot, we call start() again manually // Signal shot, we call start() again manually
setSingleShot(true); setSingleShot(true);
// Connect Signals/Slots // Connect Signals/Slots
connect(this, SIGNAL(timeout()), this, SLOT(start())); connect(this, SIGNAL(timeout()), this, SLOT(start()));
} }
public slots: public slots:
void start() { void start() {
const Preferences* const pref = Preferences::instance(); const Preferences* const pref = Preferences::instance();
Q_ASSERT(pref->isSchedulerEnabled()); Q_ASSERT(pref->isSchedulerEnabled());
bool alt_bw_enabled = pref->isAltBandwidthEnabled(); bool alt_bw_enabled = pref->isAltBandwidthEnabled();
QTime start = pref->getSchedulerStartTime(); QTime start = pref->getSchedulerStartTime();
QTime end = pref->getSchedulerEndTime(); QTime end = pref->getSchedulerEndTime();
QTime now = QTime::currentTime(); QTime now = QTime::currentTime();
int sched_days = pref->getSchedulerDays(); int sched_days = pref->getSchedulerDays();
int day = QDateTime::currentDateTime().toLocalTime().date().dayOfWeek(); int day = QDateTime::currentDateTime().toLocalTime().date().dayOfWeek();
bool new_mode = false; bool new_mode = false;
bool reverse = false; bool reverse = false;
if (start > end) { if (start > end) {
QTime temp = start; QTime temp = start;
start = end; start = end;
end = temp; end = temp;
reverse = true; reverse = true;
} }
if (start <= now && end >= now) { if (start <= now && end >= now) {
switch(sched_days) { switch(sched_days) {
case EVERY_DAY: case EVERY_DAY:
new_mode = true; new_mode = true;
break; break;
case WEEK_ENDS: case WEEK_ENDS:
if (day == 6 || day == 7) if (day == 6 || day == 7)
new_mode = true; new_mode = true;
break; break;
case WEEK_DAYS: case WEEK_DAYS:
if (day != 6 && day != 7) if (day != 6 && day != 7)
new_mode = true; new_mode = true;
break; break;
default: default:
if (day == sched_days - 2) if (day == sched_days - 2)
new_mode = true; new_mode = true;
break; break;
} }
} }
if (reverse) if (reverse)
new_mode = !new_mode; new_mode = !new_mode;
if (new_mode != alt_bw_enabled) if (new_mode != alt_bw_enabled)
emit switchToAlternativeMode(new_mode); emit switchToAlternativeMode(new_mode);
// Timeout regularly to accomodate for external system clock changes // Timeout regularly to accomodate for external system clock changes
// eg from the user or from a timesync utility // eg from the user or from a timesync utility
QTimer::start(1500); QTimer::start(1500);
} }
signals: signals:
void switchToAlternativeMode(bool alternative); void switchToAlternativeMode(bool alternative);
}; };
#endif // BANDWIDTHSCHEDULER_H #endif // BANDWIDTHSCHEDULER_H

602
src/core/qtlibtorrent/filterparserthread.cpp

@ -41,290 +41,290 @@ FilterParserThread::FilterParserThread(QObject* parent, libtorrent::session *s)
} }
FilterParserThread::~FilterParserThread() { FilterParserThread::~FilterParserThread() {
abort = true; abort = true;
wait(); wait();
} }
// Parser for eMule ip filter in DAT format // Parser for eMule ip filter in DAT format
int FilterParserThread::parseDATFilterFile(QString filePath, libtorrent::ip_filter& filter) { int FilterParserThread::parseDATFilterFile(QString filePath, libtorrent::ip_filter& filter) {
int ruleCount = 0; int ruleCount = 0;
QFile file(filePath); QFile file(filePath);
if (file.exists()) { if (file.exists()) {
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl; std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl;
return ruleCount; return ruleCount;
} }
unsigned int nbLine = 0; unsigned int nbLine = 0;
while (!file.atEnd() && !abort) { while (!file.atEnd() && !abort) {
++nbLine; ++nbLine;
QByteArray line = file.readLine(); QByteArray line = file.readLine();
// Ignoring empty lines // Ignoring empty lines
line = line.trimmed(); line = line.trimmed();
if (line.isEmpty()) continue; if (line.isEmpty()) continue;
// Ignoring commented lines // Ignoring commented lines
if (line.startsWith('#') || line.startsWith("//")) continue; if (line.startsWith('#') || line.startsWith("//")) continue;
// Line should be splitted by commas // Line should be splitted by commas
QList<QByteArray> partsList = line.split(','); QList<QByteArray> partsList = line.split(',');
const uint nbElem = partsList.size(); const uint nbElem = partsList.size();
// IP Range should be splitted by a dash // IP Range should be splitted by a dash
QList<QByteArray> IPs = partsList.first().split('-'); QList<QByteArray> IPs = partsList.first().split('-');
if (IPs.size() != 2) { if (IPs.size() != 2) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine); qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("Line was %s", line.constData()); qDebug("Line was %s", line.constData());
continue; continue;
} }
boost::system::error_code ec; boost::system::error_code ec;
const QString strStartIP = cleanupIPAddress(IPs.at(0)); const QString strStartIP = cleanupIPAddress(IPs.at(0));
if (strStartIP.isEmpty()) { if (strStartIP.isEmpty()) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine); qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("Start IP of the range is malformated: %s", qPrintable(strStartIP)); qDebug("Start IP of the range is malformated: %s", qPrintable(strStartIP));
continue; continue;
} }
libtorrent::address startAddr = libtorrent::address::from_string(qPrintable(strStartIP), ec); libtorrent::address startAddr = libtorrent::address::from_string(qPrintable(strStartIP), ec);
if (ec) { if (ec) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine); qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("Start IP of the range is malformated: %s", qPrintable(strStartIP)); qDebug("Start IP of the range is malformated: %s", qPrintable(strStartIP));
continue; continue;
} }
const QString strEndIP = cleanupIPAddress(IPs.at(1)); const QString strEndIP = cleanupIPAddress(IPs.at(1));
if (strEndIP.isEmpty()) { if (strEndIP.isEmpty()) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine); qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("End IP of the range is malformated: %s", qPrintable(strEndIP)); qDebug("End IP of the range is malformated: %s", qPrintable(strEndIP));
continue; continue;
} }
libtorrent::address endAddr = libtorrent::address::from_string(qPrintable(strEndIP), ec); libtorrent::address endAddr = libtorrent::address::from_string(qPrintable(strEndIP), ec);
if (ec) { if (ec) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine); qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("End IP of the range is malformated: %s", qPrintable(strEndIP)); qDebug("End IP of the range is malformated: %s", qPrintable(strEndIP));
continue; continue;
} }
if (startAddr.is_v4() != endAddr.is_v4()) { if (startAddr.is_v4() != endAddr.is_v4()) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine); qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
qDebug("One IP is IPv4 and the other is IPv6!"); qDebug("One IP is IPv4 and the other is IPv6!");
continue; continue;
} }
// Check if there is an access value (apparently not mandatory) // Check if there is an access value (apparently not mandatory)
int nbAccess = 0; int nbAccess = 0;
if (nbElem > 1) { if (nbElem > 1) {
// There is possibly one // There is possibly one
nbAccess = partsList.at(1).trimmed().toInt(); nbAccess = partsList.at(1).trimmed().toInt();
} }
if (nbAccess > 127) { if (nbAccess > 127) {
// Ignoring this rule because access value is too high // Ignoring this rule because access value is too high
continue; continue;
} }
// Now Add to the filter // Now Add to the filter
try { try {
filter.add_rule(startAddr, endAddr, libtorrent::ip_filter::blocked); filter.add_rule(startAddr, endAddr, libtorrent::ip_filter::blocked);
++ruleCount; ++ruleCount;
}catch(exception) { }catch(exception) {
qDebug("Bad line in filter file, avoided crash..."); qDebug("Bad line in filter file, avoided crash...");
} }
}
file.close();
} }
file.close(); return ruleCount;
}
return ruleCount;
} }
// Parser for PeerGuardian ip filter in p2p format // Parser for PeerGuardian ip filter in p2p format
int FilterParserThread::parseP2PFilterFile(QString filePath, libtorrent::ip_filter& filter) { int FilterParserThread::parseP2PFilterFile(QString filePath, libtorrent::ip_filter& filter) {
int ruleCount = 0; int ruleCount = 0;
QFile file(filePath); QFile file(filePath);
if (file.exists()) { if (file.exists()) {
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl; std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl;
return ruleCount; return ruleCount;
} }
unsigned int nbLine = 0; unsigned int nbLine = 0;
while (!file.atEnd() && !abort) { while (!file.atEnd() && !abort) {
++nbLine; ++nbLine;
QByteArray line = file.readLine().trimmed(); QByteArray line = file.readLine().trimmed();
if (line.isEmpty()) continue; if (line.isEmpty()) continue;
// Ignoring commented lines // Ignoring commented lines
if (line.startsWith('#') || line.startsWith("//")) continue; if (line.startsWith('#') || line.startsWith("//")) continue;
// Line is splitted by : // Line is splitted by :
QList<QByteArray> partsList = line.split(':'); QList<QByteArray> partsList = line.split(':');
if (partsList.size() < 2) { if (partsList.size() < 2) {
qDebug("p2p file: line %d is malformed.", nbLine); qDebug("p2p file: line %d is malformed.", nbLine);
continue; continue;
} }
// Get IP range // Get IP range
QList<QByteArray> IPs = partsList.last().split('-'); QList<QByteArray> IPs = partsList.last().split('-');
if (IPs.size() != 2) { if (IPs.size() != 2) {
qDebug("p2p file: line %d is malformed.", nbLine); qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("line was: %s", line.constData()); qDebug("line was: %s", line.constData());
continue; continue;
} }
boost::system::error_code ec; boost::system::error_code ec;
QString strStartIP = cleanupIPAddress(IPs.at(0)); QString strStartIP = cleanupIPAddress(IPs.at(0));
if (strStartIP.isEmpty()) { if (strStartIP.isEmpty()) {
qDebug("p2p file: line %d is malformed.", nbLine); qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("Start IP is invalid: %s", qPrintable(strStartIP)); qDebug("Start IP is invalid: %s", qPrintable(strStartIP));
continue; continue;
} }
libtorrent::address startAddr = libtorrent::address::from_string(qPrintable(strStartIP), ec); libtorrent::address startAddr = libtorrent::address::from_string(qPrintable(strStartIP), ec);
if (ec) { if (ec) {
qDebug("p2p file: line %d is malformed.", nbLine); qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("Start IP is invalid: %s", qPrintable(strStartIP)); qDebug("Start IP is invalid: %s", qPrintable(strStartIP));
continue; continue;
} }
QString strEndIP = cleanupIPAddress(IPs.at(1)); QString strEndIP = cleanupIPAddress(IPs.at(1));
if (strEndIP.isEmpty()) { if (strEndIP.isEmpty()) {
qDebug("p2p file: line %d is malformed.", nbLine); qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("End IP is invalid: %s", qPrintable(strStartIP)); qDebug("End IP is invalid: %s", qPrintable(strStartIP));
continue; continue;
} }
libtorrent::address endAddr = libtorrent::address::from_string(qPrintable(strEndIP), ec); libtorrent::address endAddr = libtorrent::address::from_string(qPrintable(strEndIP), ec);
if (ec) { if (ec) {
qDebug("p2p file: line %d is malformed.", nbLine); qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("End IP is invalid: %s", qPrintable(strStartIP)); qDebug("End IP is invalid: %s", qPrintable(strStartIP));
continue; continue;
} }
if (startAddr.is_v4() != endAddr.is_v4()) { if (startAddr.is_v4() != endAddr.is_v4()) {
qDebug("p2p file: line %d is malformed.", nbLine); qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("Line was: %s", line.constData()); qDebug("Line was: %s", line.constData());
continue; continue;
} }
try { try {
filter.add_rule(startAddr, endAddr, libtorrent::ip_filter::blocked); filter.add_rule(startAddr, endAddr, libtorrent::ip_filter::blocked);
++ruleCount; ++ruleCount;
} catch(std::exception&) { } catch(std::exception&) {
qDebug("p2p file: line %d is malformed.", nbLine); qDebug("p2p file: line %d is malformed.", nbLine);
qDebug("Line was: %s", line.constData()); qDebug("Line was: %s", line.constData());
continue; continue;
} }
}
file.close();
} }
file.close(); return ruleCount;
}
return ruleCount;
} }
int FilterParserThread::getlineInStream(QDataStream& stream, string& name, char delim) { int FilterParserThread::getlineInStream(QDataStream& stream, string& name, char delim) {
char c; char c;
int total_read = 0; int total_read = 0;
int read; int read;
do { do {
read = stream.readRawData(&c, 1); read = stream.readRawData(&c, 1);
total_read += read; total_read += read;
if (read > 0) { if (read > 0) {
if (c != delim) { if (c != delim) {
name += c; name += c;
} else { } else {
// Delim found // Delim found
return total_read; return total_read;
} }
} }
} while(read > 0); } while(read > 0);
return total_read; return total_read;
} }
// Parser for PeerGuardian ip filter in p2p format // Parser for PeerGuardian ip filter in p2p format
int FilterParserThread::parseP2BFilterFile(QString filePath, libtorrent::ip_filter& filter) { int FilterParserThread::parseP2BFilterFile(QString filePath, libtorrent::ip_filter& filter) {
int ruleCount = 0; int ruleCount = 0;
QFile file(filePath); QFile file(filePath);
if (file.exists()) { if (file.exists()) {
if (!file.open(QIODevice::ReadOnly)) { if (!file.open(QIODevice::ReadOnly)) {
std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl; std::cerr << "I/O Error: Could not open ip filer file in read mode." << std::endl;
return ruleCount; return ruleCount;
} }
QDataStream stream(&file); QDataStream stream(&file);
// Read header // Read header
char buf[7]; char buf[7];
unsigned char version; 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 ( if (
!stream.readRawData((char*)&start, sizeof(start)) || !stream.readRawData(buf, sizeof(buf)) ||
!stream.readRawData((char*)&end, sizeof(end)) 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; std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
return ruleCount; return ruleCount;
} }
// Network byte order to Host byte order
// asio address_v4 contructor expects it if (version==1 || version==2) {
// that way qDebug ("p2b version 1 or 2");
libtorrent::address_v4 first(ntohl(start)); unsigned int start, end;
libtorrent::address_v4 last(ntohl(end));
// Apply to bittorrent session string name;
try { while(getlineInStream(stream, name, '\0') && !abort) {
filter.add_rule(first, last, libtorrent::ip_filter::blocked); if (
++ruleCount; !stream.readRawData((char*)&start, sizeof(start)) ||
} catch(std::exception&) {} !stream.readRawData((char*)&end, sizeof(end))
} ) {
} std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
else if (version==3) { return ruleCount;
qDebug ("p2b version 3"); }
unsigned int namecount; // Network byte order to Host byte order
if (!stream.readRawData((char*)&namecount, sizeof(namecount))) { // asio address_v4 contructor expects it
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl; // that way
return ruleCount; libtorrent::address_v4 first(ntohl(start));
} libtorrent::address_v4 last(ntohl(end));
namecount=ntohl(namecount); // Apply to bittorrent session
// Reading names although, we don't really care about them try {
for (unsigned int i=0; i<namecount; i++) { filter.add_rule(first, last, libtorrent::ip_filter::blocked);
string name; ++ruleCount;
if (!getlineInStream(stream, name, '\0')) { } catch(std::exception&) {}
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl; }
return ruleCount;
} }
if (abort) return ruleCount; else if (version==3) {
} qDebug ("p2b version 3");
// Reading the ranges unsigned int namecount;
unsigned int rangecount; if (!stream.readRawData((char*)&namecount, sizeof(namecount))) {
if (!stream.readRawData((char*)&rangecount, sizeof(rangecount))) { std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl; return ruleCount;
return ruleCount; }
} namecount=ntohl(namecount);
rangecount=ntohl(rangecount); // 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; unsigned int name, start, end;
for (unsigned int i=0; i<rangecount; i++) { for (unsigned int i=0; i<rangecount; i++) {
if ( if (
!stream.readRawData((char*)&name, sizeof(name)) || !stream.readRawData((char*)&name, sizeof(name)) ||
!stream.readRawData((char*)&start, sizeof(start)) || !stream.readRawData((char*)&start, sizeof(start)) ||
!stream.readRawData((char*)&end, sizeof(end)) !stream.readRawData((char*)&end, sizeof(end))
) { ) {
std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl; std::cerr << "Parsing Error: The filter file is not a valid PeerGuardian P2B file." << std::endl;
return ruleCount; 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;
} }
// Network byte order to Host byte order file.close();
// 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;
}
return ruleCount;
} }
// Process ip filter file // Process ip filter file
@ -333,62 +333,62 @@ int FilterParserThread::parseP2BFilterFile(QString filePath, libtorrent::ip_filt
// * PeerGuardian Text (P2P): http://wiki.phoenixlabs.org/wiki/P2P_Format // * PeerGuardian Text (P2P): http://wiki.phoenixlabs.org/wiki/P2P_Format
// * PeerGuardian Binary (P2B): http://wiki.phoenixlabs.org/wiki/P2B_Format // * PeerGuardian Binary (P2B): http://wiki.phoenixlabs.org/wiki/P2B_Format
void FilterParserThread::processFilterFile(QString _filePath) { void FilterParserThread::processFilterFile(QString _filePath) {
if (isRunning()) { if (isRunning()) {
// Already parsing a filter, abort first // Already parsing a filter, abort first
abort = true; abort = true;
wait(); wait();
} }
abort = false; abort = false;
filePath = _filePath; filePath = _filePath;
// Run it // Run it
start(); start();
} }
void FilterParserThread::processFilterList(libtorrent::session *s, const QStringList& IPs) { void FilterParserThread::processFilterList(libtorrent::session *s, const QStringList& IPs) {
// First, import current filter // First, import current filter
libtorrent::ip_filter filter = s->get_ip_filter(); libtorrent::ip_filter filter = s->get_ip_filter();
foreach (const QString &ip, IPs) { foreach (const QString &ip, IPs) {
qDebug("Manual ban of peer %s", ip.toLocal8Bit().constData()); qDebug("Manual ban of peer %s", ip.toLocal8Bit().constData());
boost::system::error_code ec; boost::system::error_code ec;
libtorrent::address addr = libtorrent::address::from_string(ip.toLocal8Bit().constData(), ec); libtorrent::address addr = libtorrent::address::from_string(ip.toLocal8Bit().constData(), ec);
Q_ASSERT(!ec); Q_ASSERT(!ec);
if (!ec) if (!ec)
filter.add_rule(addr, addr, libtorrent::ip_filter::blocked); filter.add_rule(addr, addr, libtorrent::ip_filter::blocked);
} }
s->set_ip_filter(filter); s->set_ip_filter(filter);
} }
QString FilterParserThread::cleanupIPAddress(QString _ip) { QString FilterParserThread::cleanupIPAddress(QString _ip) {
QHostAddress ip(_ip.trimmed()); QHostAddress ip(_ip.trimmed());
if (ip.isNull()) { if (ip.isNull()) {
return QString(); return QString();
} }
return ip.toString(); return ip.toString();
} }
void FilterParserThread::run() { void FilterParserThread::run() {
qDebug("Processing filter file"); qDebug("Processing filter file");
libtorrent::ip_filter filter = s->get_ip_filter(); libtorrent::ip_filter filter = s->get_ip_filter();
int ruleCount = 0; int ruleCount = 0;
if (filePath.endsWith(".p2p", Qt::CaseInsensitive)) { if (filePath.endsWith(".p2p", Qt::CaseInsensitive)) {
// PeerGuardian p2p file // PeerGuardian p2p file
ruleCount = parseP2PFilterFile(filePath, filter); ruleCount = parseP2PFilterFile(filePath, filter);
} else {
if (filePath.endsWith(".p2b", Qt::CaseInsensitive)) {
// PeerGuardian p2b file
ruleCount = parseP2BFilterFile(filePath, filter);
} else { } else {
// Default: eMule DAT format if (filePath.endsWith(".p2b", Qt::CaseInsensitive)) {
ruleCount = parseDATFilterFile(filePath, filter); // PeerGuardian p2b file
ruleCount = parseP2BFilterFile(filePath, filter);
} else {
// Default: eMule DAT format
ruleCount = parseDATFilterFile(filePath, filter);
}
} }
} if (abort)
if (abort) return;
return; try {
try { s->set_ip_filter(filter);
s->set_ip_filter(filter); emit IPFilterParsed(ruleCount);
emit IPFilterParsed(ruleCount); } catch(std::exception&) {
} catch(std::exception&) { emit IPFilterError();
emit IPFilterError(); }
} qDebug("IP Filter thread: finished parsing, filter applied");
qDebug("IP Filter thread: finished parsing, filter applied");
} }

36
src/core/qtlibtorrent/filterparserthread.h

@ -36,8 +36,8 @@
#include <QStringList> #include <QStringList>
namespace libtorrent { namespace libtorrent {
class session; class session;
struct ip_filter; struct ip_filter;
} }
using namespace std; using namespace std;
@ -52,31 +52,31 @@ using namespace std;
// End of P2B stuff // End of P2B stuff
class FilterParserThread : public QThread { class FilterParserThread : public QThread {
Q_OBJECT Q_OBJECT
public: public:
FilterParserThread(QObject* parent, libtorrent::session *s); FilterParserThread(QObject* parent, libtorrent::session *s);
~FilterParserThread(); ~FilterParserThread();
int parseDATFilterFile(QString filePath, libtorrent::ip_filter& filter); int parseDATFilterFile(QString filePath, libtorrent::ip_filter& filter);
int parseP2PFilterFile(QString filePath, libtorrent::ip_filter& filter); int parseP2PFilterFile(QString filePath, libtorrent::ip_filter& filter);
int getlineInStream(QDataStream& stream, string& name, char delim); int getlineInStream(QDataStream& stream, string& name, char delim);
int parseP2BFilterFile(QString filePath, libtorrent::ip_filter& filter); int parseP2BFilterFile(QString filePath, libtorrent::ip_filter& filter);
void processFilterFile(QString _filePath); void processFilterFile(QString _filePath);
static void processFilterList(libtorrent::session *s, const QStringList& IPs); static void processFilterList(libtorrent::session *s, const QStringList& IPs);
signals: signals:
void IPFilterParsed(int ruleCount); void IPFilterParsed(int ruleCount);
void IPFilterError(); void IPFilterError();
protected: protected:
QString cleanupIPAddress(QString _ip); QString cleanupIPAddress(QString _ip);
void run(); void run();
private: private:
libtorrent::session *s; libtorrent::session *s;
bool abort; bool abort;
QString filePath; QString filePath;
}; };
#endif #endif

4822
src/core/qtlibtorrent/qbtsession.cpp

File diff suppressed because it is too large Load Diff

488
src/core/qtlibtorrent/qbtsession.h

@ -49,42 +49,42 @@
#endif #endif
namespace libtorrent { namespace libtorrent {
struct add_torrent_params; struct add_torrent_params;
struct pe_settings; struct pe_settings;
struct proxy_settings; struct proxy_settings;
class session; class session;
struct session_status; struct session_status;
class alert; class alert;
struct torrent_finished_alert; struct torrent_finished_alert;
struct save_resume_data_alert; struct save_resume_data_alert;
struct file_renamed_alert; struct file_renamed_alert;
struct torrent_deleted_alert; struct torrent_deleted_alert;
struct storage_moved_alert; struct storage_moved_alert;
struct storage_moved_failed_alert; struct storage_moved_failed_alert;
struct metadata_received_alert; struct metadata_received_alert;
struct file_error_alert; struct file_error_alert;
struct file_completed_alert; struct file_completed_alert;
struct torrent_paused_alert; struct torrent_paused_alert;
struct tracker_error_alert; struct tracker_error_alert;
struct tracker_reply_alert; struct tracker_reply_alert;
struct tracker_warning_alert; struct tracker_warning_alert;
struct portmap_error_alert; struct portmap_error_alert;
struct portmap_alert; struct portmap_alert;
struct peer_blocked_alert; struct peer_blocked_alert;
struct peer_ban_alert; struct peer_ban_alert;
struct fastresume_rejected_alert; struct fastresume_rejected_alert;
struct url_seed_alert; struct url_seed_alert;
struct listen_succeeded_alert; struct listen_succeeded_alert;
struct listen_failed_alert; struct listen_failed_alert;
struct torrent_checked_alert; struct torrent_checked_alert;
struct external_ip_alert; struct external_ip_alert;
struct state_update_alert; struct state_update_alert;
struct stats_alert; struct stats_alert;
#if LIBTORRENT_VERSION_NUM < 10000 #if LIBTORRENT_VERSION_NUM < 10000
class upnp; class upnp;
class natpmp; class natpmp;
#endif #endif
} }
@ -97,250 +97,250 @@ class TorrentStatistics;
class QAlertDispatcher; class QAlertDispatcher;
enum TorrentExportFolder { enum TorrentExportFolder {
RegularTorrentExportFolder, RegularTorrentExportFolder,
FinishedTorrentExportFolder FinishedTorrentExportFolder
}; };
class QTracker; class QTracker;
class QBtSession : public QObject { class QBtSession : public QObject {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(QBtSession) Q_DISABLE_COPY(QBtSession)
public: public:
static const qreal MAX_RATIO; static const qreal MAX_RATIO;
private: private:
explicit QBtSession(); explicit QBtSession();
static QBtSession* m_instance; static QBtSession* m_instance;
public: public:
static QBtSession* instance(); static QBtSession* instance();
static void drop(); static void drop();
~QBtSession(); ~QBtSession();
QTorrentHandle getTorrentHandle(const QString &hash) const; QTorrentHandle getTorrentHandle(const QString &hash) const;
std::vector<libtorrent::torrent_handle> getTorrents() const; std::vector<libtorrent::torrent_handle> getTorrents() const;
bool isFilePreviewPossible(const QString& hash) const; bool isFilePreviewPossible(const QString& hash) const;
qreal getPayloadDownloadRate() const; qreal getPayloadDownloadRate() const;
qreal getPayloadUploadRate() const; qreal getPayloadUploadRate() const;
libtorrent::session_status getSessionStatus() const; libtorrent::session_status getSessionStatus() const;
int getListenPort() const; int getListenPort() const;
qreal getRealRatio(const libtorrent::torrent_status &status) const; qreal getRealRatio(const libtorrent::torrent_status &status) const;
QHash<QString, TrackerInfos> getTrackersInfo(const QString &hash) const; QHash<QString, TrackerInfos> getTrackersInfo(const QString &hash) const;
bool hasActiveTorrents() const; bool hasActiveTorrents() const;
bool hasDownloadingTorrents() const; bool hasDownloadingTorrents() const;
//int getMaximumActiveDownloads() const; //int getMaximumActiveDownloads() const;
//int getMaximumActiveTorrents() const; //int getMaximumActiveTorrents() const;
inline libtorrent::session* getSession() const { return s; } inline libtorrent::session* getSession() const { return s; }
inline bool useTemporaryFolder() const { return !defaultTempPath.isEmpty(); } inline bool useTemporaryFolder() const { return !defaultTempPath.isEmpty(); }
inline QString getDefaultSavePath() const { return defaultSavePath; } inline QString getDefaultSavePath() const { return defaultSavePath; }
inline ScanFoldersModel* getScanFoldersModel() const { return m_scanFolders; } inline ScanFoldersModel* getScanFoldersModel() const { return m_scanFolders; }
inline bool isDHTEnabled() const { return DHTEnabled; } inline bool isDHTEnabled() const { return DHTEnabled; }
inline bool isLSDEnabled() const { return LSDEnabled; } inline bool isLSDEnabled() const { return LSDEnabled; }
inline bool isPexEnabled() const { return PeXEnabled; } inline bool isPexEnabled() const { return PeXEnabled; }
inline bool isQueueingEnabled() const { return queueingEnabled; } inline bool isQueueingEnabled() const { return queueingEnabled; }
quint64 getAlltimeDL() const; quint64 getAlltimeDL() const;
quint64 getAlltimeUL() const; quint64 getAlltimeUL() const;
void postTorrentUpdate(); void postTorrentUpdate();
public slots: public slots:
QTorrentHandle addTorrent(QString path, bool fromScanDir = false, QString from_url = QString(), bool resumed = false, bool imported = false); 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()); QTorrentHandle addMagnetUri(QString magnet_uri, bool resumed=false, bool fromScanDir=false, const QString &filePath=QString());
void loadSessionState(); void loadSessionState();
void saveSessionState(); void saveSessionState();
void downloadFromUrl(const QString &url, const QList<QNetworkCookie>& cookies = QList<QNetworkCookie>()); void downloadFromUrl(const QString &url, const QList<QNetworkCookie>& cookies = QList<QNetworkCookie>());
void deleteTorrent(const QString &hash, bool delete_local_files = false); void deleteTorrent(const QString &hash, bool delete_local_files = false);
void startUpTorrents(); void startUpTorrents();
void recheckTorrent(const QString &hash); void recheckTorrent(const QString &hash);
void useAlternativeSpeedsLimit(bool alternative); void useAlternativeSpeedsLimit(bool alternative);
qlonglong getETA(const QString& hash, const libtorrent::torrent_status &status) const; qlonglong getETA(const QString& hash, const libtorrent::torrent_status &status) const;
/* Needed by Web UI */ /* Needed by Web UI */
void pauseAllTorrents(); void pauseAllTorrents();
void pauseTorrent(const QString &hash); void pauseTorrent(const QString &hash);
void resumeTorrent(const QString &hash); void resumeTorrent(const QString &hash);
void resumeAllTorrents(); void resumeAllTorrents();
/* End Web UI */ /* End Web UI */
void preAllocateAllFiles(bool b); void preAllocateAllFiles(bool b);
void saveFastResumeData(); void saveFastResumeData();
void enableIPFilter(const QString &filter_path, bool force=false); void enableIPFilter(const QString &filter_path, bool force=false);
void disableIPFilter(); void disableIPFilter();
void setQueueingEnabled(bool enable); void setQueueingEnabled(bool enable);
void handleDownloadFailure(QString url, QString reason); void handleDownloadFailure(QString url, QString reason);
void handleMagnetRedirect(const QString &url_new, const QString &url_old); void handleMagnetRedirect(const QString &url_new, const QString &url_old);
#ifndef DISABLE_GUI #ifndef DISABLE_GUI
void downloadUrlAndSkipDialog(QString url, QString save_path=QString(), QString label=QString(), void downloadUrlAndSkipDialog(QString url, QString save_path=QString(), QString label=QString(),
const QList<QNetworkCookie>& cookies = QList<QNetworkCookie>(), const QList<QNetworkCookie>& cookies = QList<QNetworkCookie>(),
const RssDownloadRule::AddPausedState &aps = RssDownloadRule::USE_GLOBAL); const RssDownloadRule::AddPausedState &aps = RssDownloadRule::USE_GLOBAL);
#else #else
void downloadUrlAndSkipDialog(QString url, QString save_path=QString(), QString label=QString(), void downloadUrlAndSkipDialog(QString url, QString save_path=QString(), QString label=QString(),
const QList<QNetworkCookie>& cookies = QList<QNetworkCookie>()); const QList<QNetworkCookie>& cookies = QList<QNetworkCookie>());
#endif #endif
// Session configuration - Setters // Session configuration - Setters
void setListeningPort(int port); void setListeningPort(int port);
void setMaxConnectionsPerTorrent(int max); void setMaxConnectionsPerTorrent(int max);
void setMaxUploadsPerTorrent(int max); void setMaxUploadsPerTorrent(int max);
void setDownloadRateLimit(long rate); void setDownloadRateLimit(long rate);
void setUploadRateLimit(long rate); void setUploadRateLimit(long rate);
void setGlobalMaxRatio(qreal ratio); void setGlobalMaxRatio(qreal ratio);
qreal getGlobalMaxRatio() const { return global_ratio_limit; } qreal getGlobalMaxRatio() const { return global_ratio_limit; }
void setMaxRatioPerTorrent(const QString &hash, qreal ratio); void setMaxRatioPerTorrent(const QString &hash, qreal ratio);
qreal getMaxRatioPerTorrent(const QString &hash, bool *usesGlobalRatio) const; qreal getMaxRatioPerTorrent(const QString &hash, bool *usesGlobalRatio) const;
void removeRatioPerTorrent(const QString &hash); void removeRatioPerTorrent(const QString &hash);
void setDefaultSavePath(const QString &savepath); void setDefaultSavePath(const QString &savepath);
void setDefaultTempPath(const QString &temppath); void setDefaultTempPath(const QString &temppath);
void setAppendLabelToSavePath(bool append); void setAppendLabelToSavePath(bool append);
void appendLabelToTorrentSavePath(const QTorrentHandle &h); void appendLabelToTorrentSavePath(const QTorrentHandle &h);
void changeLabelInTorrentSavePath(const QTorrentHandle &h, QString old_label, QString new_label); void changeLabelInTorrentSavePath(const QTorrentHandle &h, QString old_label, QString new_label);
void appendqBextensionToTorrent(const QTorrentHandle &h, bool append); void appendqBextensionToTorrent(const QTorrentHandle &h, bool append);
void setAppendqBExtension(bool append); void setAppendqBExtension(bool append);
void setDownloadLimit(QString hash, long val); void setDownloadLimit(QString hash, long val);
void setUploadLimit(QString hash, long val); void setUploadLimit(QString hash, long val);
void enableUPnP(bool b); void enableUPnP(bool b);
void enableLSD(bool b); void enableLSD(bool b);
void enableDHT(bool b); void enableDHT(bool b);
void processDownloadedFile(QString, QString); void processDownloadedFile(QString, QString);
#ifndef DISABLE_GUI #ifndef DISABLE_GUI
void addMagnetSkipAddDlg(const QString& uri, const QString& save_path = QString(), const QString& label = QString(), 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()); const RssDownloadRule::AddPausedState &aps = RssDownloadRule::USE_GLOBAL, const QString &uri_old = QString());
#else #else
void addMagnetSkipAddDlg(const QString& uri, const QString& save_path = QString(), const QString& label = QString(), const QString &uri_old = QString()); void addMagnetSkipAddDlg(const QString& uri, const QString& save_path = QString(), const QString& label = QString(), const QString &uri_old = QString());
#endif #endif
void addMagnetInteractive(const QString& uri); void addMagnetInteractive(const QString& uri);
void downloadFromURLList(const QStringList& urls); void downloadFromURLList(const QStringList& urls);
void banIP(QString ip); void banIP(QString ip);
void recursiveTorrentDownload(const QTorrentHandle &h); void recursiveTorrentDownload(const QTorrentHandle &h);
void unhideMagnet(const QString &hash); void unhideMagnet(const QString &hash);
private: private:
void applyEncryptionSettings(libtorrent::pe_settings se); void applyEncryptionSettings(libtorrent::pe_settings se);
void setProxySettings(libtorrent::proxy_settings proxySettings); void setProxySettings(libtorrent::proxy_settings proxySettings);
void setSessionSettings(const libtorrent::session_settings &sessionSettings); void setSessionSettings(const libtorrent::session_settings &sessionSettings);
QString getSavePath(const QString &hash, bool fromScanDir = false, QString filePath = QString::null, bool imported = false); QString getSavePath(const QString &hash, bool fromScanDir = false, QString filePath = QString::null, bool imported = false);
bool loadFastResumeData(const QString &hash, std::vector<char> &buf); bool loadFastResumeData(const QString &hash, std::vector<char> &buf);
void loadTorrentSettings(QTorrentHandle &h); void loadTorrentSettings(QTorrentHandle &h);
void loadTorrentTempData(QTorrentHandle &h, QString savePath, bool magnet); void loadTorrentTempData(QTorrentHandle &h, QString savePath, bool magnet);
void initializeAddTorrentParams(const QString &hash, libtorrent::add_torrent_params &p); void initializeAddTorrentParams(const QString &hash, libtorrent::add_torrent_params &p);
void updateRatioTimer(); void updateRatioTimer();
void recoverPersistentData(const QString &hash, const std::vector<char> &buf); void recoverPersistentData(const QString &hash, const std::vector<char> &buf);
void backupPersistentData(const QString &hash, boost::shared_ptr<libtorrent::entry> data); void backupPersistentData(const QString &hash, boost::shared_ptr<libtorrent::entry> data);
void handleAlert(libtorrent::alert* a); void handleAlert(libtorrent::alert* a);
void handleTorrentFinishedAlert(libtorrent::torrent_finished_alert* p); void handleTorrentFinishedAlert(libtorrent::torrent_finished_alert* p);
void handleSaveResumeDataAlert(libtorrent::save_resume_data_alert* p); void handleSaveResumeDataAlert(libtorrent::save_resume_data_alert* p);
void handleFileRenamedAlert(libtorrent::file_renamed_alert* p); void handleFileRenamedAlert(libtorrent::file_renamed_alert* p);
void handleTorrentDeletedAlert(libtorrent::torrent_deleted_alert* p); void handleTorrentDeletedAlert(libtorrent::torrent_deleted_alert* p);
void handleStorageMovedAlert(libtorrent::storage_moved_alert* p); void handleStorageMovedAlert(libtorrent::storage_moved_alert* p);
void handleStorageMovedFailedAlert(libtorrent::storage_moved_failed_alert* p); void handleStorageMovedFailedAlert(libtorrent::storage_moved_failed_alert* p);
void handleMetadataReceivedAlert(libtorrent::metadata_received_alert* p); void handleMetadataReceivedAlert(libtorrent::metadata_received_alert* p);
void handleFileErrorAlert(libtorrent::file_error_alert* p); void handleFileErrorAlert(libtorrent::file_error_alert* p);
void handleFileCompletedAlert(libtorrent::file_completed_alert* p); void handleFileCompletedAlert(libtorrent::file_completed_alert* p);
void handleTorrentPausedAlert(libtorrent::torrent_paused_alert* p); void handleTorrentPausedAlert(libtorrent::torrent_paused_alert* p);
void handleTrackerErrorAlert(libtorrent::tracker_error_alert* p); void handleTrackerErrorAlert(libtorrent::tracker_error_alert* p);
void handleTrackerReplyAlert(libtorrent::tracker_reply_alert* p); void handleTrackerReplyAlert(libtorrent::tracker_reply_alert* p);
void handleTrackerWarningAlert(libtorrent::tracker_warning_alert* p); void handleTrackerWarningAlert(libtorrent::tracker_warning_alert* p);
void handlePortmapWarningAlert(libtorrent::portmap_error_alert* p); void handlePortmapWarningAlert(libtorrent::portmap_error_alert* p);
void handlePortmapAlert(libtorrent::portmap_alert* p); void handlePortmapAlert(libtorrent::portmap_alert* p);
void handlePeerBlockedAlert(libtorrent::peer_blocked_alert* p); void handlePeerBlockedAlert(libtorrent::peer_blocked_alert* p);
void handlePeerBanAlert(libtorrent::peer_ban_alert* p); void handlePeerBanAlert(libtorrent::peer_ban_alert* p);
void handleFastResumeRejectedAlert(libtorrent::fastresume_rejected_alert* p); void handleFastResumeRejectedAlert(libtorrent::fastresume_rejected_alert* p);
void handleUrlSeedAlert(libtorrent::url_seed_alert* p); void handleUrlSeedAlert(libtorrent::url_seed_alert* p);
void handleListenSucceededAlert(libtorrent::listen_succeeded_alert *p); void handleListenSucceededAlert(libtorrent::listen_succeeded_alert *p);
void handleListenFailedAlert(libtorrent::listen_failed_alert *p); void handleListenFailedAlert(libtorrent::listen_failed_alert *p);
void handleTorrentCheckedAlert(libtorrent::torrent_checked_alert* p); void handleTorrentCheckedAlert(libtorrent::torrent_checked_alert* p);
void handleExternalIPAlert(libtorrent::external_ip_alert *p); void handleExternalIPAlert(libtorrent::external_ip_alert *p);
void handleStateUpdateAlert(libtorrent::state_update_alert *p); void handleStateUpdateAlert(libtorrent::state_update_alert *p);
void handleStatsAlert(libtorrent::stats_alert *p); void handleStatsAlert(libtorrent::stats_alert *p);
private slots: private slots:
void addTorrentsFromScanFolder(QStringList&); void addTorrentsFromScanFolder(QStringList&);
void readAlerts(); void readAlerts();
void processBigRatios(); void processBigRatios();
void exportTorrentFiles(QString path); void exportTorrentFiles(QString path);
void saveTempFastResumeData(); void saveTempFastResumeData();
void sendNotificationEmail(const QTorrentHandle &h); void sendNotificationEmail(const QTorrentHandle &h);
void autoRunExternalProgram(const QTorrentHandle &h); void autoRunExternalProgram(const QTorrentHandle &h);
void mergeTorrents(QTorrentHandle& h_ex, boost::intrusive_ptr<libtorrent::torrent_info> t); void mergeTorrents(QTorrentHandle& h_ex, boost::intrusive_ptr<libtorrent::torrent_info> t);
void mergeTorrents(QTorrentHandle& h_ex, const QString& magnet_uri); void mergeTorrents(QTorrentHandle& h_ex, const QString& magnet_uri);
void exportTorrentFile(const QTorrentHandle &h, TorrentExportFolder folder = RegularTorrentExportFolder); void exportTorrentFile(const QTorrentHandle &h, TorrentExportFolder folder = RegularTorrentExportFolder);
void handleIPFilterParsed(int ruleCount); void handleIPFilterParsed(int ruleCount);
void handleIPFilterError(); void handleIPFilterError();
void configureSession(); void configureSession();
signals: signals:
void addedTorrent(const QTorrentHandle& h); void addedTorrent(const QTorrentHandle& h);
void torrentAboutToBeRemoved(const QTorrentHandle &h); void torrentAboutToBeRemoved(const QTorrentHandle &h);
void pausedTorrent(const QTorrentHandle& h); void pausedTorrent(const QTorrentHandle& h);
void resumedTorrent(const QTorrentHandle& h); void resumedTorrent(const QTorrentHandle& h);
void finishedTorrent(const QTorrentHandle& h); void finishedTorrent(const QTorrentHandle& h);
void fullDiskError(const QTorrentHandle& h, QString msg); void fullDiskError(const QTorrentHandle& h, QString msg);
void trackerError(const QString &hash, QString time, QString msg); void trackerError(const QString &hash, QString time, QString msg);
void trackerAuthenticationRequired(const QTorrentHandle& h); void trackerAuthenticationRequired(const QTorrentHandle& h);
void newDownloadedTorrent(QString path, QString url); void newDownloadedTorrent(QString path, QString url);
void newDownloadedTorrentFromRss(QString url); void newDownloadedTorrentFromRss(QString url);
void newMagnetLink(const QString& link); void newMagnetLink(const QString& link);
void updateFileSize(const QString &hash); void updateFileSize(const QString &hash);
void downloadFromUrlFailure(QString url, QString reason); void downloadFromUrlFailure(QString url, QString reason);
void torrentFinishedChecking(const QTorrentHandle& h); void torrentFinishedChecking(const QTorrentHandle& h);
void metadataReceived(const QTorrentHandle &h); void metadataReceived(const QTorrentHandle &h);
void savePathChanged(const QTorrentHandle &h); void savePathChanged(const QTorrentHandle &h);
void alternativeSpeedsModeChanged(bool alternative); void alternativeSpeedsModeChanged(bool alternative);
void recursiveTorrentDownloadPossible(const QTorrentHandle &h); void recursiveTorrentDownloadPossible(const QTorrentHandle &h);
void ipFilterParsed(bool error, int ruleCount); void ipFilterParsed(bool error, int ruleCount);
void metadataReceivedHidden(const QTorrentHandle &h); void metadataReceivedHidden(const QTorrentHandle &h);
void stateUpdate(const std::vector<libtorrent::torrent_status> &statuses); void stateUpdate(const std::vector<libtorrent::torrent_status> &statuses);
void statsReceived(const libtorrent::stats_alert&); void statsReceived(const libtorrent::stats_alert&);
private: private:
// Bittorrent // Bittorrent
libtorrent::session *s; libtorrent::session *s;
QPointer<BandwidthScheduler> bd_scheduler; QPointer<BandwidthScheduler> bd_scheduler;
QMap<QUrl, QPair<QString, QString> > savepathLabel_fromurl; // Use QMap for compatibility with Qt < 4.7: qHash(QUrl) QMap<QUrl, QPair<QString, QString> > savepathLabel_fromurl; // Use QMap for compatibility with Qt < 4.7: qHash(QUrl)
#ifndef DISABLE_GUI #ifndef DISABLE_GUI
QMap<QUrl, RssDownloadRule::AddPausedState> addpaused_fromurl; QMap<QUrl, RssDownloadRule::AddPausedState> addpaused_fromurl;
#endif #endif
QHash<QString, QHash<QString, TrackerInfos> > trackersInfos; QHash<QString, QHash<QString, TrackerInfos> > trackersInfos;
QHash<QString, QString> savePathsToRemove; QHash<QString, QString> savePathsToRemove;
QStringList torrentsToPausedAfterChecking; QStringList torrentsToPausedAfterChecking;
QTimer resumeDataTimer; QTimer resumeDataTimer;
// Ratio // Ratio
QPointer<QTimer> BigRatioTimer; QPointer<QTimer> BigRatioTimer;
// HTTP // HTTP
DownloadThread* downloader; DownloadThread* downloader;
// File System // File System
ScanFoldersModel *m_scanFolders; ScanFoldersModel *m_scanFolders;
// Settings // Settings
bool preAllocateAll; bool preAllocateAll;
qreal global_ratio_limit; qreal global_ratio_limit;
int high_ratio_action; int high_ratio_action;
bool LSDEnabled; bool LSDEnabled;
bool DHTEnabled; bool DHTEnabled;
bool PeXEnabled; bool PeXEnabled;
bool queueingEnabled; bool queueingEnabled;
bool appendLabelToSavePath; bool appendLabelToSavePath;
bool m_torrentExportEnabled; bool m_torrentExportEnabled;
bool m_finishedTorrentExportEnabled; bool m_finishedTorrentExportEnabled;
bool appendqBExtension; bool appendqBExtension;
QString defaultSavePath; QString defaultSavePath;
QString defaultTempPath; QString defaultTempPath;
// IP filtering // IP filtering
QPointer<FilterParserThread> filterParser; QPointer<FilterParserThread> filterParser;
QString filterPath; QString filterPath;
QList<QUrl> url_skippingDlg; QList<QUrl> url_skippingDlg;
// GeoIP // GeoIP
#ifndef DISABLE_GUI #ifndef DISABLE_GUI
bool geoipDBLoaded; bool geoipDBLoaded;
bool resolve_countries; bool resolve_countries;
#endif #endif
// Tracker // Tracker
QPointer<QTracker> m_tracker; QPointer<QTracker> m_tracker;
TorrentSpeedMonitor *m_speedMonitor; TorrentSpeedMonitor *m_speedMonitor;
shutDownAction m_shutdownAct; shutDownAction m_shutdownAct;
// Port forwarding // Port forwarding
#if LIBTORRENT_VERSION_NUM < 10000 #if LIBTORRENT_VERSION_NUM < 10000
libtorrent::upnp *m_upnp; libtorrent::upnp *m_upnp;
libtorrent::natpmp *m_natpmp; libtorrent::natpmp *m_natpmp;
#endif #endif
QAlertDispatcher* m_alertDispatcher; QAlertDispatcher* m_alertDispatcher;
TorrentStatistics* m_torrentStatistics; TorrentStatistics* m_torrentStatistics;
}; };
#endif #endif

8
src/core/qtlibtorrent/qtorrenthandle.cpp

@ -182,7 +182,7 @@ bool QTorrentHandle::first_last_piece_first() const
QPair<int, int> extremities = get_file_extremity_pieces(*t, index); QPair<int, int> extremities = get_file_extremity_pieces(*t, index);
return (torrent_handle::piece_priority(extremities.first) == 7) return (torrent_handle::piece_priority(extremities.first) == 7)
&& (torrent_handle::piece_priority(extremities.second) == 7); && (torrent_handle::piece_priority(extremities.second) == 7);
} }
QString QTorrentHandle::save_path() const QString QTorrentHandle::save_path() const
@ -512,7 +512,7 @@ void QTorrentHandle::pause() const
torrent_handle::auto_managed(false); torrent_handle::auto_managed(false);
torrent_handle::pause(); torrent_handle::pause();
if (!TorrentPersistentData::instance()->getHasMissingFiles(this->hash())) if (!TorrentPersistentData::instance()->getHasMissingFiles(this->hash()))
torrent_handle::save_resume_data(); torrent_handle::save_resume_data();
} }
void QTorrentHandle::resume() const void QTorrentHandle::resume() const
@ -770,13 +770,13 @@ bool QTorrentHandle::is_queued(const libtorrent::torrent_status &status)
bool QTorrentHandle::is_seed(const libtorrent::torrent_status &status) bool QTorrentHandle::is_seed(const libtorrent::torrent_status &status)
{ {
return status.state == torrent_status::finished return status.state == torrent_status::finished
|| status.state == torrent_status::seeding; || status.state == torrent_status::seeding;
} }
bool QTorrentHandle::is_checking(const libtorrent::torrent_status &status) bool QTorrentHandle::is_checking(const libtorrent::torrent_status &status)
{ {
return status.state == torrent_status::checking_files return status.state == torrent_status::checking_files
|| status.state == torrent_status::checking_resume_data; || status.state == torrent_status::checking_resume_data;
} }
bool QTorrentHandle::has_error(const libtorrent::torrent_status &status) bool QTorrentHandle::has_error(const libtorrent::torrent_status &status)

116
src/core/qtlibtorrent/shutdownconfirm.cpp

@ -35,80 +35,80 @@
#include <QPushButton> #include <QPushButton>
ShutdownConfirmDlg::ShutdownConfirmDlg(const shutDownAction &action): exit_now(NULL), timeout(15), action0(action) { ShutdownConfirmDlg::ShutdownConfirmDlg(const shutDownAction &action): exit_now(NULL), timeout(15), action0(action) {
// Title and button // Title and button
if (action0 == NO_SHUTDOWN) { if (action0 == NO_SHUTDOWN) {
setWindowTitle(tr("Exit confirmation")); setWindowTitle(tr("Exit confirmation"));
exit_now = addButton(tr("Exit now"), QMessageBox::AcceptRole); exit_now = addButton(tr("Exit now"), QMessageBox::AcceptRole);
} }
else { else {
setWindowTitle(tr("Shutdown confirmation")); setWindowTitle(tr("Shutdown confirmation"));
exit_now = addButton(tr("Shutdown now"), QMessageBox::AcceptRole); exit_now = addButton(tr("Shutdown now"), QMessageBox::AcceptRole);
} }
// Cancel Button // Cancel Button
addButton(QMessageBox::Cancel); addButton(QMessageBox::Cancel);
// Text // Text
updateText(); updateText();
// Icon // Icon
setIcon(QMessageBox::Warning); setIcon(QMessageBox::Warning);
// Always on top // Always on top
setWindowFlags(windowFlags()|Qt::WindowStaysOnTopHint); setWindowFlags(windowFlags()|Qt::WindowStaysOnTopHint);
// Set 'Cancel' as default button. // Set 'Cancel' as default button.
setDefaultButton(QMessageBox::Cancel); setDefaultButton(QMessageBox::Cancel);
timer.setInterval(1000); // 1sec timer.setInterval(1000); // 1sec
connect(&timer, SIGNAL(timeout()), this, SLOT(updateSeconds())); connect(&timer, SIGNAL(timeout()), this, SLOT(updateSeconds()));
show(); show();
// Move to center // Move to center
move(misc::screenCenter(this)); move(misc::screenCenter(this));
} }
void ShutdownConfirmDlg::showEvent(QShowEvent *event) { void ShutdownConfirmDlg::showEvent(QShowEvent *event) {
QMessageBox::showEvent(event); QMessageBox::showEvent(event);
timer.start(); timer.start();
} }
bool ShutdownConfirmDlg::askForConfirmation(const shutDownAction &action) { bool ShutdownConfirmDlg::askForConfirmation(const shutDownAction &action) {
ShutdownConfirmDlg dlg(action); ShutdownConfirmDlg dlg(action);
dlg.exec(); dlg.exec();
return dlg.shutdown(); return dlg.shutdown();
} }
void ShutdownConfirmDlg::updateSeconds() { void ShutdownConfirmDlg::updateSeconds() {
--timeout; --timeout;
updateText(); updateText();
if (timeout == 0) { if (timeout == 0) {
timer.stop(); timer.stop();
accept(); accept();
} }
} }
bool ShutdownConfirmDlg::shutdown() const { bool ShutdownConfirmDlg::shutdown() const {
// This is necessary because result() in the case of QMessageBox // This is necessary because result() in the case of QMessageBox
// returns a type of StandardButton, but since we use a custom button // returns a type of StandardButton, but since we use a custom button
// it will return 0 instead, even though we set the 'accept' role on it. // it will return 0 instead, even though we set the 'accept' role on it.
if (result() != QDialog::Accepted) if (result() != QDialog::Accepted)
return (clickedButton() == exit_now); return (clickedButton() == exit_now);
else else
return true; return true;
} }
void ShutdownConfirmDlg::updateText() { void ShutdownConfirmDlg::updateText() {
QString text; QString text;
switch (action0) { switch (action0) {
case NO_SHUTDOWN: case NO_SHUTDOWN:
text = tr("qBittorrent will now exit unless you cancel within the next %1 seconds.").arg(QString::number(timeout)); text = tr("qBittorrent will now exit unless you cancel within the next %1 seconds.").arg(QString::number(timeout));
break; break;
case SHUTDOWN_COMPUTER: case SHUTDOWN_COMPUTER:
text = tr("The computer will now be switched off unless you cancel within the next %1 seconds.").arg(QString::number(timeout)); text = tr("The computer will now be switched off unless you cancel within the next %1 seconds.").arg(QString::number(timeout));
break; break;
case SUSPEND_COMPUTER: case SUSPEND_COMPUTER:
text = tr("The computer will now go to sleep mode unless you cancel within the next %1 seconds.").arg(QString::number(timeout)); text = tr("The computer will now go to sleep mode unless you cancel within the next %1 seconds.").arg(QString::number(timeout));
break; break;
case HIBERNATE_COMPUTER: case HIBERNATE_COMPUTER:
text = tr("The computer will now go to hibernation mode unless you cancel within the next %1 seconds.").arg(QString::number(timeout)); text = tr("The computer will now go to hibernation mode unless you cancel within the next %1 seconds.").arg(QString::number(timeout));
break; break;
} }
setText(text); setText(text);
} }

26
src/core/qtlibtorrent/shutdownconfirm.h

@ -36,29 +36,29 @@
#include "misc.h" #include "misc.h"
class ShutdownConfirmDlg : public QMessageBox { class ShutdownConfirmDlg : public QMessageBox {
Q_OBJECT Q_OBJECT
public: public:
ShutdownConfirmDlg(const shutDownAction &action); ShutdownConfirmDlg(const shutDownAction &action);
bool shutdown() const; bool shutdown() const;
static bool askForConfirmation(const shutDownAction &action); static bool askForConfirmation(const shutDownAction &action);
protected: protected:
void showEvent(QShowEvent *event); void showEvent(QShowEvent *event);
private slots: private slots:
void updateSeconds(); void updateSeconds();
private: private:
// Methods // Methods
void updateText(); void updateText();
// Vars // Vars
QAbstractButton *exit_now; QAbstractButton *exit_now;
QTimer timer; QTimer timer;
int timeout; int timeout;
shutDownAction action0; shutDownAction action0;
}; };
#endif // SHUTDOWNCONFIRM_H #endif // SHUTDOWNCONFIRM_H

872
src/core/qtlibtorrent/torrentmodel.cpp

File diff suppressed because it is too large Load Diff

112
src/core/qtlibtorrent/torrentmodel.h

@ -40,89 +40,89 @@
#include "qtorrenthandle.h" #include "qtorrenthandle.h"
struct TorrentStatusReport { struct TorrentStatusReport {
TorrentStatusReport(): nb_downloading(0), nb_seeding(0), nb_active(0), nb_inactive(0), nb_paused(0) {} TorrentStatusReport(): nb_downloading(0), nb_seeding(0), nb_active(0), nb_inactive(0), nb_paused(0) {}
uint nb_downloading; uint nb_seeding; uint nb_active; uint nb_inactive; uint nb_paused; uint nb_downloading; uint nb_seeding; uint nb_active; uint nb_inactive; uint nb_paused;
}; };
class TorrentModelItem : public QObject { class TorrentModelItem : public QObject {
Q_OBJECT Q_OBJECT
public: public:
enum State {STATE_DOWNLOADING, STATE_DOWNLOADING_META, STATE_ALLOCATING, STATE_STALLED_DL, STATE_SEEDING, STATE_STALLED_UP, STATE_QUEUED_DL, STATE_QUEUED_UP, STATE_CHECKING_UP, STATE_CHECKING_DL, STATE_QUEUED_CHECK, STATE_QUEUED_FASTCHECK, STATE_PAUSED_DL, STATE_PAUSED_UP, STATE_PAUSED_MISSING, STATE_INVALID}; enum State {STATE_DOWNLOADING, STATE_DOWNLOADING_META, STATE_ALLOCATING, STATE_STALLED_DL, STATE_SEEDING, STATE_STALLED_UP, STATE_QUEUED_DL, STATE_QUEUED_UP, STATE_CHECKING_UP, STATE_CHECKING_DL, STATE_QUEUED_CHECK, STATE_QUEUED_FASTCHECK, STATE_PAUSED_DL, STATE_PAUSED_UP, STATE_PAUSED_MISSING, STATE_INVALID};
enum Column {TR_NAME, TR_PRIORITY, TR_SIZE, TR_TOTAL_SIZE, TR_PROGRESS, TR_STATUS, TR_SEEDS, TR_PEERS, TR_DLSPEED, TR_UPSPEED, TR_ETA, TR_RATIO, TR_LABEL, TR_ADD_DATE, TR_SEED_DATE, TR_TRACKER, TR_DLLIMIT, TR_UPLIMIT, TR_AMOUNT_DOWNLOADED, TR_AMOUNT_UPLOADED, TR_AMOUNT_LEFT, TR_TIME_ELAPSED, TR_SAVE_PATH, TR_COMPLETED, TR_RATIO_LIMIT, TR_SEEN_COMPLETE_DATE, TR_LAST_ACTIVITY, NB_COLUMNS}; enum Column {TR_NAME, TR_PRIORITY, TR_SIZE, TR_TOTAL_SIZE, TR_PROGRESS, TR_STATUS, TR_SEEDS, TR_PEERS, TR_DLSPEED, TR_UPSPEED, TR_ETA, TR_RATIO, TR_LABEL, TR_ADD_DATE, TR_SEED_DATE, TR_TRACKER, TR_DLLIMIT, TR_UPLIMIT, TR_AMOUNT_DOWNLOADED, TR_AMOUNT_UPLOADED, TR_AMOUNT_LEFT, TR_TIME_ELAPSED, TR_SAVE_PATH, TR_COMPLETED, TR_RATIO_LIMIT, TR_SEEN_COMPLETE_DATE, TR_LAST_ACTIVITY, NB_COLUMNS};
public: public:
TorrentModelItem(const QTorrentHandle& h); TorrentModelItem(const QTorrentHandle& h);
void refreshStatus(libtorrent::torrent_status const& status); void refreshStatus(libtorrent::torrent_status const& status);
inline int columnCount() const { return NB_COLUMNS; } inline int columnCount() const { return NB_COLUMNS; }
QVariant data(int column, int role = Qt::DisplayRole) const; QVariant data(int column, int role = Qt::DisplayRole) const;
bool setData(int column, const QVariant &value, int role = Qt::DisplayRole); bool setData(int column, const QVariant &value, int role = Qt::DisplayRole);
inline QString const& hash() const { return m_hash; } inline QString const& hash() const { return m_hash; }
State state() const; State state() const;
signals: signals:
void labelChanged(QString previous, QString current); void labelChanged(QString previous, QString current);
private: private:
static QIcon getIconByState(State state); static QIcon getIconByState(State state);
static QColor getColorByState(State state); static QColor getColorByState(State state);
private: private:
QTorrentHandle m_torrent; QTorrentHandle m_torrent;
libtorrent::torrent_status m_lastStatus; libtorrent::torrent_status m_lastStatus;
QDateTime m_addedTime; QDateTime m_addedTime;
QString m_label; QString m_label;
QString m_name; QString m_name;
QString m_hash; // Cached for safety reasons QString m_hash; // Cached for safety reasons
}; };
class TorrentModel : public QAbstractListModel class TorrentModel : public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(TorrentModel) Q_DISABLE_COPY(TorrentModel)
public: public:
explicit TorrentModel(QObject *parent = 0); explicit TorrentModel(QObject *parent = 0);
~TorrentModel(); ~TorrentModel();
inline int rowCount(const QModelIndex& index = QModelIndex()) const { Q_UNUSED(index); return m_torrents.size(); } inline int rowCount(const QModelIndex& index = QModelIndex()) const { Q_UNUSED(index); return m_torrents.size(); }
int columnCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return TorrentModelItem::NB_COLUMNS; } int columnCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return TorrentModelItem::NB_COLUMNS; }
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole); bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole);
QVariant headerData(int section, Qt::Orientation orientation, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const;
int torrentRow(const QString &hash) const; int torrentRow(const QString &hash) const;
QString torrentHash(int row) const; QString torrentHash(int row) const;
void setRefreshInterval(int refreshInterval); void setRefreshInterval(int refreshInterval);
TorrentStatusReport getTorrentStatusReport() const; TorrentStatusReport getTorrentStatusReport() const;
Qt::ItemFlags flags(const QModelIndex &index) const; Qt::ItemFlags flags(const QModelIndex &index) const;
void populate(); void populate();
bool inhibitSystem(); bool inhibitSystem();
signals: signals:
void torrentAdded(TorrentModelItem *torrentItem); void torrentAdded(TorrentModelItem *torrentItem);
void torrentAboutToBeRemoved(TorrentModelItem *torrentItem); void torrentAboutToBeRemoved(TorrentModelItem *torrentItem);
void torrentChangedLabel(TorrentModelItem *torrentItem, QString previous, QString current); void torrentChangedLabel(TorrentModelItem *torrentItem, QString previous, QString current);
void modelRefreshed(); void modelRefreshed();
private slots: private slots:
void addTorrent(const QTorrentHandle& h); void addTorrent(const QTorrentHandle& h);
void handleTorrentUpdate(const QTorrentHandle &h); void handleTorrentUpdate(const QTorrentHandle &h);
void handleFinishedTorrent(const QTorrentHandle& h); void handleFinishedTorrent(const QTorrentHandle& h);
void notifyTorrentChanged(int row); void notifyTorrentChanged(int row);
void forceModelRefresh(); void forceModelRefresh();
void handleTorrentLabelChange(QString previous, QString current); void handleTorrentLabelChange(QString previous, QString current);
void handleTorrentAboutToBeRemoved(const QTorrentHandle & h); void handleTorrentAboutToBeRemoved(const QTorrentHandle & h);
void stateUpdated(const std::vector<libtorrent::torrent_status> &statuses); void stateUpdated(const std::vector<libtorrent::torrent_status> &statuses);
private: private:
void beginInsertTorrent(int row); void beginInsertTorrent(int row);
void endInsertTorrent(); void endInsertTorrent();
void beginRemoveTorrent(int row); void beginRemoveTorrent(int row);
void endRemoveTorrent(); void endRemoveTorrent();
private: private:
QList<TorrentModelItem*> m_torrents; QList<TorrentModelItem*> m_torrents;
int m_refreshInterval; int m_refreshInterval;
QTimer m_refreshTimer; QTimer m_refreshTimer;
}; };
#endif // TORRENTMODEL_H #endif // TORRENTMODEL_H

154
src/core/qtlibtorrent/torrentspeedmonitor.cpp

@ -38,88 +38,88 @@ using namespace libtorrent;
namespace { namespace {
template<class T> struct Sample { template<class T> struct Sample {
Sample() Sample()
: download() : download()
, upload() , upload()
{} {}
Sample(T download, T upload) Sample(T download, T upload)
: download(download) : download(download)
, upload(upload) , upload(upload)
{} {}
template <typename U> template <typename U>
explicit Sample(Sample<U> other) explicit Sample(Sample<U> other)
: download(static_cast<U>(other.download)) : download(static_cast<U>(other.download))
, upload(static_cast<U>(other.upload)) , upload(static_cast<U>(other.upload))
{} {}
T download; T download;
T upload; T upload;
}; };
template <typename T> template <typename T>
Sample<T>& operator+=(Sample<T>& lhs, Sample<T> const& rhs) { Sample<T>& operator+=(Sample<T>& lhs, Sample<T> const& rhs) {
lhs.download += rhs.download; lhs.download += rhs.download;
lhs.upload += rhs.upload; lhs.upload += rhs.upload;
return lhs; return lhs;
} }
template <typename T> template <typename T>
Sample<T>& operator-=(Sample<T>& lhs, Sample<T> const& rhs) { Sample<T>& operator-=(Sample<T>& lhs, Sample<T> const& rhs) {
lhs.download -= rhs.download; lhs.download -= rhs.download;
lhs.upload -= rhs.upload; lhs.upload -= rhs.upload;
return lhs; return lhs;
} }
template <typename T> template <typename T>
Sample<T> operator+(Sample<T> const& lhs, Sample<T> const& rhs) { Sample<T> operator+(Sample<T> const& lhs, Sample<T> const& rhs) {
return Sample<T>(lhs.download + rhs.download, lhs.upload + rhs.upload); return Sample<T>(lhs.download + rhs.download, lhs.upload + rhs.upload);
} }
template <typename T> template <typename T>
Sample<T> operator-(Sample<T> const& lhs, Sample<T> const& rhs) { Sample<T> operator-(Sample<T> const& lhs, Sample<T> const& rhs) {
return Sample<T>(lhs.download - rhs.download, lhs.upload - rhs.upload); return Sample<T>(lhs.download - rhs.download, lhs.upload - rhs.upload);
} }
template <typename T> template <typename T>
Sample<T> operator*(Sample<T> const& lhs, T rhs) { Sample<T> operator*(Sample<T> const& lhs, T rhs) {
return Sample<T>(lhs.download * rhs, lhs.upload * rhs); return Sample<T>(lhs.download * rhs, lhs.upload * rhs);
} }
template <typename T> template <typename T>
Sample<T> operator*(T lhs,Sample<T> const& rhs) { Sample<T> operator*(T lhs,Sample<T> const& rhs) {
return Sample<T>(lhs * rhs.download, lhs * rhs.upload); return Sample<T>(lhs * rhs.download, lhs * rhs.upload);
} }
template <typename T> template <typename T>
Sample<T> operator/(Sample<T> const& lhs, T rhs) { Sample<T> operator/(Sample<T> const& lhs, T rhs) {
return Sample<T>(lhs.download / rhs, lhs.upload / rhs); return Sample<T>(lhs.download / rhs, lhs.upload / rhs);
} }
} }
class SpeedSample { class SpeedSample {
public: public:
SpeedSample() {} SpeedSample() {}
void addSample(Sample<int> const& item); void addSample(Sample<int> const& item);
Sample<qreal> average() const; Sample<qreal> average() const;
private: private:
static const int max_samples = 30; static const int max_samples = 30;
private: private:
QList<Sample<int> > m_speedSamples; QList<Sample<int> > m_speedSamples;
Sample<long long> m_sum; Sample<long long> m_sum;
}; };
TorrentSpeedMonitor::TorrentSpeedMonitor(QBtSession* session) TorrentSpeedMonitor::TorrentSpeedMonitor(QBtSession* session)
: m_session(session) : m_session(session)
{ {
connect(m_session, SIGNAL(torrentAboutToBeRemoved(QTorrentHandle)), SLOT(removeSamples(QTorrentHandle))); connect(m_session, SIGNAL(torrentAboutToBeRemoved(QTorrentHandle)), SLOT(removeSamples(QTorrentHandle)));
connect(m_session, SIGNAL(pausedTorrent(QTorrentHandle)), SLOT(removeSamples(QTorrentHandle))); connect(m_session, SIGNAL(pausedTorrent(QTorrentHandle)), SLOT(removeSamples(QTorrentHandle)));
connect(m_session, SIGNAL(statsReceived(libtorrent::stats_alert)), SLOT(statsReceived(libtorrent::stats_alert))); connect(m_session, SIGNAL(statsReceived(libtorrent::stats_alert)), SLOT(statsReceived(libtorrent::stats_alert)));
} }
TorrentSpeedMonitor::~TorrentSpeedMonitor() TorrentSpeedMonitor::~TorrentSpeedMonitor()
@ -127,69 +127,69 @@ TorrentSpeedMonitor::~TorrentSpeedMonitor()
void SpeedSample::addSample(Sample<int> const& item) void SpeedSample::addSample(Sample<int> const& item)
{ {
m_speedSamples.push_back(item); m_speedSamples.push_back(item);
m_sum += Sample<long long>(item); m_sum += Sample<long long>(item);
if (m_speedSamples.size() > max_samples) { if (m_speedSamples.size() > max_samples) {
m_sum -= Sample<long long>(m_speedSamples.front()); m_sum -= Sample<long long>(m_speedSamples.front());
m_speedSamples.pop_front(); m_speedSamples.pop_front();
} }
} }
Sample<qreal> SpeedSample::average() const Sample<qreal> SpeedSample::average() const
{ {
if (m_speedSamples.empty()) if (m_speedSamples.empty())
return Sample<qreal>(); return Sample<qreal>();
return Sample<qreal>(m_sum) * (qreal(1.) / m_speedSamples.size()); return Sample<qreal>(m_sum) * (qreal(1.) / m_speedSamples.size());
} }
void TorrentSpeedMonitor::removeSamples(const QTorrentHandle& h) { void TorrentSpeedMonitor::removeSamples(const QTorrentHandle& h) {
try { try {
m_samples.remove(h.hash()); m_samples.remove(h.hash());
} catch(invalid_handle&) {} } catch(invalid_handle&) {}
} }
qlonglong TorrentSpeedMonitor::getETA(const QString &hash, const libtorrent::torrent_status &status) const qlonglong TorrentSpeedMonitor::getETA(const QString &hash, const libtorrent::torrent_status &status) const
{ {
if (QTorrentHandle::is_paused(status)) if (QTorrentHandle::is_paused(status))
return MAX_ETA; return MAX_ETA;
QHash<QString, SpeedSample>::const_iterator i = m_samples.find(hash); QHash<QString, SpeedSample>::const_iterator i = m_samples.find(hash);
if (i == m_samples.end()) if (i == m_samples.end())
return MAX_ETA; return MAX_ETA;
const Sample<qreal> speed_average = i->average(); const Sample<qreal> speed_average = i->average();
if (QTorrentHandle::is_seed(status)) { if (QTorrentHandle::is_seed(status)) {
if (!speed_average.upload) if (!speed_average.upload)
return MAX_ETA; return MAX_ETA;
bool _unused; bool _unused;
qreal max_ratio = m_session->getMaxRatioPerTorrent(hash, &_unused); qreal max_ratio = m_session->getMaxRatioPerTorrent(hash, &_unused);
if (max_ratio < 0) if (max_ratio < 0)
return MAX_ETA; return MAX_ETA;
libtorrent::size_type realDL = status.all_time_download; libtorrent::size_type realDL = status.all_time_download;
if (realDL <= 0) if (realDL <= 0)
realDL = status.total_wanted; realDL = status.total_wanted;
return (realDL * max_ratio - status.all_time_upload) / speed_average.upload; return (realDL * max_ratio - status.all_time_upload) / speed_average.upload;
} }
if (!speed_average.download) if (!speed_average.download)
return MAX_ETA; return MAX_ETA;
return (status.total_wanted - status.total_wanted_done) / speed_average.download; return (status.total_wanted - status.total_wanted_done) / speed_average.download;
} }
void TorrentSpeedMonitor::statsReceived(const stats_alert &stats) void TorrentSpeedMonitor::statsReceived(const stats_alert &stats)
{ {
Q_ASSERT(stats.interval >= 1000); Q_ASSERT(stats.interval >= 1000);
Sample<int> transferred(stats.transferred[stats_alert::download_payload], Sample<int> transferred(stats.transferred[stats_alert::download_payload],
stats.transferred[stats_alert::upload_payload]); stats.transferred[stats_alert::upload_payload]);
Sample<int> normalized = Sample<int>(Sample<long long>(transferred) * 1000LL / static_cast<long long>(stats.interval)); Sample<int> normalized = Sample<int>(Sample<long long>(transferred) * 1000LL / static_cast<long long>(stats.interval));
m_samples[misc::toQString(stats.handle.info_hash())].addSample(normalized); m_samples[misc::toQString(stats.handle.info_hash())].addSample(normalized);
} }

18
src/core/qtlibtorrent/torrentspeedmonitor.h

@ -42,21 +42,21 @@ class SpeedSample;
class TorrentSpeedMonitor : public QObject class TorrentSpeedMonitor : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(TorrentSpeedMonitor) Q_DISABLE_COPY(TorrentSpeedMonitor)
public: public:
explicit TorrentSpeedMonitor(QBtSession* session); explicit TorrentSpeedMonitor(QBtSession* session);
~TorrentSpeedMonitor(); ~TorrentSpeedMonitor();
qlonglong getETA(const QString &hash, const libtorrent::torrent_status &status) const; qlonglong getETA(const QString &hash, const libtorrent::torrent_status &status) const;
private slots: private slots:
void statsReceived(const libtorrent::stats_alert& stats); void statsReceived(const libtorrent::stats_alert& stats);
void removeSamples(const QTorrentHandle& h); void removeSamples(const QTorrentHandle& h);
private: private:
QHash<QString, SpeedSample> m_samples; QHash<QString, SpeedSample> m_samples;
QBtSession *m_session; QBtSession *m_session;
}; };
#endif // TORRENTSPEEDMONITOR_H #endif // TORRENTSPEEDMONITOR_H

126
src/core/qtlibtorrent/torrentstatistics.cpp

@ -9,92 +9,92 @@
#include "preferences.h" #include "preferences.h"
TorrentStatistics::TorrentStatistics(QBtSession* session, QObject* parent) TorrentStatistics::TorrentStatistics(QBtSession* session, QObject* parent)
: QObject(parent) : QObject(parent)
, m_session(session) , m_session(session)
, m_sessionUL(0) , m_sessionUL(0)
, m_sessionDL(0) , m_sessionDL(0)
, m_lastWrite(0) , m_lastWrite(0)
, m_dirty(false) , m_dirty(false)
{ {
loadStats(); loadStats();
connect(&m_timer, SIGNAL(timeout()), this, SLOT(gatherStats())); connect(&m_timer, SIGNAL(timeout()), this, SLOT(gatherStats()));
m_timer.start(60 * 1000); m_timer.start(60 * 1000);
} }
TorrentStatistics::~TorrentStatistics() { TorrentStatistics::~TorrentStatistics() {
if (m_dirty) if (m_dirty)
m_lastWrite = 0; m_lastWrite = 0;
saveStats(); saveStats();
} }
quint64 TorrentStatistics::getAlltimeDL() const { quint64 TorrentStatistics::getAlltimeDL() const {
return m_alltimeDL + m_sessionDL; return m_alltimeDL + m_sessionDL;
} }
quint64 TorrentStatistics::getAlltimeUL() const { quint64 TorrentStatistics::getAlltimeUL() const {
return m_alltimeUL + m_sessionUL; return m_alltimeUL + m_sessionUL;
} }
void TorrentStatistics::gatherStats() { void TorrentStatistics::gatherStats() {
libtorrent::session_status ss = m_session->getSessionStatus(); libtorrent::session_status ss = m_session->getSessionStatus();
if (ss.total_download > m_sessionDL) { if (ss.total_download > m_sessionDL) {
m_sessionDL = ss.total_download; m_sessionDL = ss.total_download;
m_dirty = true; m_dirty = true;
} }
if (ss.total_upload > m_sessionUL) { if (ss.total_upload > m_sessionUL) {
m_sessionUL = ss.total_upload; m_sessionUL = ss.total_upload;
m_dirty = true; m_dirty = true;
} }
saveStats(); saveStats();
} }
void TorrentStatistics::saveStats() const { void TorrentStatistics::saveStats() const {
if (!(m_dirty && (QDateTime::currentMSecsSinceEpoch() - m_lastWrite >= 15*60*1000) )) if (!(m_dirty && (QDateTime::currentMSecsSinceEpoch() - m_lastWrite >= 15*60*1000) ))
return; return;
QIniSettings s("qBittorrent", "qBittorrent-data"); QIniSettings s("qBittorrent", "qBittorrent-data");
QVariantHash v; QVariantHash v;
v.insert("AlltimeDL", m_alltimeDL + m_sessionDL); v.insert("AlltimeDL", m_alltimeDL + m_sessionDL);
v.insert("AlltimeUL", m_alltimeUL + m_sessionUL); v.insert("AlltimeUL", m_alltimeUL + m_sessionUL);
s.setValue("Stats/AllStats", v); s.setValue("Stats/AllStats", v);
m_dirty = false; m_dirty = false;
m_lastWrite = QDateTime::currentMSecsSinceEpoch(); m_lastWrite = QDateTime::currentMSecsSinceEpoch();
} }
void TorrentStatistics::loadStats() { void TorrentStatistics::loadStats() {
// Temp code. Versions v3.1.4 and v3.1.5 saved the data in the qbittorrent.ini file. // 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 // 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. // from the old file. This code should be removed after some time has passed.
// e.g. When we reach v3.3.0 // e.g. When we reach v3.3.0
// Don't forget to remove: // Don't forget to remove:
// 1. Preferences::getStats() // 1. Preferences::getStats()
// 2. Preferences::removeStats() // 2. Preferences::removeStats()
// 3. #include "preferences.h" // 3. #include "preferences.h"
Preferences* const pref = Preferences::instance(); Preferences* const pref = Preferences::instance();
QIniSettings s("qBittorrent", "qBittorrent-data"); QIniSettings s("qBittorrent", "qBittorrent-data");
QVariantHash v = pref->getStats(); QVariantHash v = pref->getStats();
// Let's test if the qbittorrent.ini holds the key // Let's test if the qbittorrent.ini holds the key
if (!v.isEmpty()) { if (!v.isEmpty()) {
m_dirty = true; m_dirty = true;
// If the user has used qbt > 3.1.5 and then reinstalled/used // 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 // qbt < 3.1.6, there will be stats in qbittorrent-data.ini too
// so we need to merge those 2. // so we need to merge those 2.
if (s.contains("Stats/AllStats")) { if (s.contains("Stats/AllStats")) {
QVariantHash tmp = s.value("Stats/AllStats").toHash(); QVariantHash tmp = s.value("Stats/AllStats").toHash();
v["AlltimeDL"] = v["AlltimeDL"].toULongLong() + tmp["AlltimeDL"].toULongLong(); v["AlltimeDL"] = v["AlltimeDL"].toULongLong() + tmp["AlltimeDL"].toULongLong();
v["AlltimeUL"] = v["AlltimeUL"].toULongLong() + tmp["AlltimeUL"].toULongLong(); v["AlltimeUL"] = v["AlltimeUL"].toULongLong() + tmp["AlltimeUL"].toULongLong();
}
} }
} else
else v = s.value("Stats/AllStats").toHash();
v = s.value("Stats/AllStats").toHash();
m_alltimeDL = v["AlltimeDL"].toULongLong(); m_alltimeDL = v["AlltimeDL"].toULongLong();
m_alltimeUL = v["AlltimeUL"].toULongLong(); m_alltimeUL = v["AlltimeUL"].toULongLong();
if (m_dirty) { if (m_dirty) {
saveStats(); saveStats();
pref->removeStats(); pref->removeStats();
} }
} }

38
src/core/qtlibtorrent/torrentstatistics.h

@ -8,34 +8,34 @@ class QBtSession;
class TorrentStatistics : QObject class TorrentStatistics : QObject
{ {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(TorrentStatistics) Q_DISABLE_COPY(TorrentStatistics)
public: public:
TorrentStatistics(QBtSession* session, QObject* parent = 0); TorrentStatistics(QBtSession* session, QObject* parent = 0);
~TorrentStatistics(); ~TorrentStatistics();
quint64 getAlltimeDL() const; quint64 getAlltimeDL() const;
quint64 getAlltimeUL() const; quint64 getAlltimeUL() const;
private slots: private slots:
void gatherStats(); void gatherStats();
private: private:
void saveStats() const; void saveStats() const;
void loadStats(); void loadStats();
private: private:
QBtSession* m_session; QBtSession* m_session;
// Will overflow at 15.9 EiB // Will overflow at 15.9 EiB
quint64 m_alltimeUL; quint64 m_alltimeUL;
quint64 m_alltimeDL; quint64 m_alltimeDL;
qint64 m_sessionUL; qint64 m_sessionUL;
qint64 m_sessionDL; qint64 m_sessionDL;
mutable qint64 m_lastWrite; mutable qint64 m_lastWrite;
mutable bool m_dirty; mutable bool m_dirty;
QTimer m_timer; QTimer m_timer;
}; };
#endif // TORRENTSTATISTICS_H #endif // TORRENTSTATISTICS_H

34
src/core/qtlibtorrent/trackerinfos.h

@ -35,25 +35,25 @@
class TrackerInfos { class TrackerInfos {
public: public:
QString name_or_url; QString name_or_url;
QString last_message; QString last_message;
unsigned long num_peers; unsigned long num_peers;
//TrackerInfos() {} //TrackerInfos() {}
TrackerInfos(const TrackerInfos &b) TrackerInfos(const TrackerInfos &b)
: name_or_url(b.name_or_url) : name_or_url(b.name_or_url)
, last_message(b.last_message) , last_message(b.last_message)
, num_peers(b.num_peers) , num_peers(b.num_peers)
{ {
Q_ASSERT(!name_or_url.isEmpty()); Q_ASSERT(!name_or_url.isEmpty());
} }
TrackerInfos(QString name_or_url) TrackerInfos(QString name_or_url)
: name_or_url(name_or_url) : name_or_url(name_or_url)
, last_message("") , last_message("")
, num_peers(0) , num_peers(0)
{ {
} }
}; };
#endif // TRACKERINFOS_H #endif // TRACKERINFOS_H

Loading…
Cancel
Save