diff --git a/Changelog b/Changelog
index 77a9a97ee..1153b3ebd 100644
--- a/Changelog
+++ b/Changelog
@@ -24,6 +24,7 @@
- FEATURE: Torrents can be rechecked from Web UI (Stephanos Antaris)
- FEATURE: New peers can manually be added to the torrents
- FEATURE: Support per-peer rate limiting
+ - FEATURE: Support peer manual ban
- COSMETIC: Merged download / upload lists
- COSMETIC: Torrents can be filtered based on their status
- COSMETIC: Torrent properties are now displayed in main window
diff --git a/src/Icons/oxygen/add_peer.png b/src/Icons/oxygen/add_peer.png
deleted file mode 100644
index a28a8a2e9..000000000
Binary files a/src/Icons/oxygen/add_peer.png and /dev/null differ
diff --git a/src/Icons/oxygen/user-group-delete.png b/src/Icons/oxygen/user-group-delete.png
new file mode 100644
index 000000000..13d300c2d
Binary files /dev/null and b/src/Icons/oxygen/user-group-delete.png differ
diff --git a/src/Icons/oxygen/user-group-new.png b/src/Icons/oxygen/user-group-new.png
new file mode 100644
index 000000000..c39092037
Binary files /dev/null and b/src/Icons/oxygen/user-group-new.png differ
diff --git a/src/bittorrent.cpp b/src/bittorrent.cpp
index df74ecca7..5ebc6e86f 100644
--- a/src/bittorrent.cpp
+++ b/src/bittorrent.cpp
@@ -363,6 +363,7 @@ void bittorrent::configureSession() {
// * Maximum ratio
setDeleteRatio(Preferences::getDeleteRatio());
// Ip Filter
+ FilterParserThread::processFilterList(s, Preferences::bannedIPs());
if(Preferences::isFilteringEnabled()) {
enableIPFilter(Preferences::getFilter());
}else{
@@ -516,6 +517,11 @@ bool bittorrent::hasActiveTorrents() const {
return false;
}
+void bittorrent::banIP(QString ip) {
+ FilterParserThread::processFilterList(s, QStringList(ip));
+ Preferences::banIP(ip);
+}
+
// Delete a torrent from the session, given its hash
// permanent = true means that the torrent will be removed from the hard-drive too
void bittorrent::deleteTorrent(QString hash, bool permanent) {
diff --git a/src/bittorrent.h b/src/bittorrent.h
index a2722e9f7..ea4954881 100644
--- a/src/bittorrent.h
+++ b/src/bittorrent.h
@@ -169,6 +169,7 @@ class bittorrent : public QObject {
void addMagnetSkipAddDlg(QString uri);
void downloadFromURLList(const QStringList& urls);
void configureSession();
+ void banIP(QString ip);
protected slots:
void addTorrentsFromScanFolder(QStringList&);
diff --git a/src/filterParserThread.h b/src/filterParserThread.h
index de1907fe8..9080834ab 100644
--- a/src/filterParserThread.h
+++ b/src/filterParserThread.h
@@ -389,6 +389,8 @@ class FilterParserThread : public QThread {
// * PeerGuardian Text (P2P): http://wiki.phoenixlabs.org/wiki/P2P_Format
// * PeerGuardian Binary (P2B): http://wiki.phoenixlabs.org/wiki/P2B_Format
void processFilterFile(QString _filePath){
+ // First, import current filter
+ filter = s->get_ip_filter();
if(isRunning()) {
// Already parsing a filter, abort first
abort = true;
@@ -400,6 +402,17 @@ class FilterParserThread : public QThread {
start();
}
+ static void processFilterList(session *s, QStringList IPs) {
+ // First, import current filter
+ ip_filter filter = s->get_ip_filter();
+ foreach(const QString &ip, IPs) {
+ qDebug("Manual ban of peer %s", ip.toLocal8Bit().data());
+ address_v4 addr = address_v4::from_string(ip.toLocal8Bit().data());
+ filter.add_rule(addr, addr, ip_filter::blocked);
+ }
+ s->set_ip_filter(filter);
+ }
+
};
#endif
diff --git a/src/icons.qrc b/src/icons.qrc
index 7214c0166..239136387 100644
--- a/src/icons.qrc
+++ b/src/icons.qrc
@@ -105,6 +105,8 @@
Icons/oxygen/edit-paste.png
Icons/oxygen/run-build.png
Icons/oxygen/proxy.png
+ Icons/oxygen/user-group-delete.png
+ Icons/oxygen/user-group-new.png
Icons/oxygen/log.png
Icons/oxygen/unavailable.png
Icons/oxygen/button_ok.png
@@ -142,6 +144,5 @@
Icons/oxygen/unsubscribe.png
Icons/oxygen/draw-rectangle.png
Icons/oxygen/subscribe16.png
- Icons/oxygen/add_peer.png
\ No newline at end of file
diff --git a/src/peerlistdelegate.h b/src/peerlistdelegate.h
index 9652b8fcd..7408a6de4 100644
--- a/src/peerlistdelegate.h
+++ b/src/peerlistdelegate.h
@@ -34,7 +34,7 @@
#include
#include "misc.h"
-enum PeerListColumns {IP, CLIENT, PROGRESS, DOWN_SPEED, UP_SPEED, TOT_DOWN, TOT_UP};
+enum PeerListColumns {IP, CLIENT, PROGRESS, DOWN_SPEED, UP_SPEED, TOT_DOWN, TOT_UP, IP_HIDDEN};
class PeerListDelegate: public QItemDelegate {
Q_OBJECT
diff --git a/src/peerlistwidget.cpp b/src/peerlistwidget.cpp
index b7729c8ef..74e62e83e 100644
--- a/src/peerlistwidget.cpp
+++ b/src/peerlistwidget.cpp
@@ -48,8 +48,9 @@ PeerListWidget::PeerListWidget(PropertiesWidget *parent): properties(parent), di
setRootIsDecorated(false);
setItemsExpandable(false);
setAllColumnsShowFocus(true);
+ setSelectionMode(QAbstractItemView::ExtendedSelection);
// List Model
- listModel = new QStandardItemModel(0, 7);
+ listModel = new QStandardItemModel(0, 8);
listModel->setHeaderData(IP, Qt::Horizontal, tr("IP"));
listModel->setHeaderData(CLIENT, Qt::Horizontal, tr("Client", "i.e.: Client application"));
listModel->setHeaderData(PROGRESS, Qt::Horizontal, tr("Progress", "i.e: % downloaded"));
@@ -62,6 +63,7 @@ PeerListWidget::PeerListWidget(PropertiesWidget *parent): properties(parent), di
proxyModel->setDynamicSortFilter(true);
proxyModel->setSourceModel(listModel);
setModel(proxyModel);
+ hideColumn(IP_HIDDEN);
// Context menu
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showPeerListMenu(QPoint)));
@@ -112,26 +114,33 @@ void PeerListWidget::updatePeerCountryResolutionState() {
void PeerListWidget::showPeerListMenu(QPoint) {
QMenu menu;
+ bool empty_menu = true;
QTorrentHandle h = properties->getCurrentTorrent();
if(!h.is_valid()) return;
QModelIndexList selectedIndexes = selectionModel()->selectedRows();
QStringList selectedPeerIPs;
foreach(const QModelIndex &index, selectedIndexes) {
- QString IP = proxyModel->data(index).toString();
+ int row = proxyModel->mapToSource(index).row();
+ QString IP = listModel->data(listModel->index(row, IP_HIDDEN)).toString();
selectedPeerIPs << IP;
}
// Add Peer Action
QAction *addPeerAct = 0;
if(!h.is_queued() && !h.is_checking()) {
- addPeerAct = menu.addAction(QIcon(":/Icons/oxygen/add_peer.png"), tr("Add a new peer"));
+ addPeerAct = menu.addAction(QIcon(":/Icons/oxygen/user-group-new.png"), tr("Add a new peer"));
+ empty_menu = false;
}
// Per Peer Speed limiting actions
QAction *upLimitAct = 0;
QAction *dlLimitAct = 0;
+ QAction *banAct = 0;
if(!selectedPeerIPs.isEmpty()) {
upLimitAct = menu.addAction(QIcon(":/Icons/skin/seeding.png"), tr("Limit upload rate"));
dlLimitAct = menu.addAction(QIcon(":/Icons/skin/downloading.png"), tr("Limit download rate"));
+ banAct = menu.addAction(QIcon(":/Icons/oxygen/user-group-delete.png"), tr("Ban peer permanently"));
+ empty_menu = false;
}
+ if(empty_menu) return;
QAction *act = menu.exec(QCursor::pos());
if(act == addPeerAct) {
boost::asio::ip::tcp::endpoint ep = PeerAdditionDlg::askForPeerEndpoint();
@@ -155,6 +164,25 @@ void PeerListWidget::showPeerListMenu(QPoint) {
limitDlRateSelectedPeers(selectedPeerIPs);
return;
}
+ if(act == banAct) {
+ banSelectedPeers(selectedPeerIPs);
+ return;
+ }
+}
+
+void PeerListWidget::banSelectedPeers(QStringList peer_ips) {
+ // Confirm first
+ int ret = QMessageBox::question(this, tr("Are you sure? -- qBittorrent"), tr("Are you sure you want to ban permanently the selected peers?"),
+ tr("&Yes"), tr("&No"),
+ QString(), 0, 1);
+ if(ret) return;
+ foreach(const QString &ip, peer_ips) {
+ qDebug("Banning peer %s...", ip.toLocal8Bit().data());
+ properties->getBTSession()->addConsoleMessage(tr("Manually banning peer %1...").arg(ip));
+ properties->getBTSession()->banIP(ip);
+ }
+ // Refresh list
+ loadPeers(properties->getCurrentTorrent());
}
void PeerListWidget::limitUpRateSelectedPeers(QStringList peer_ips) {
@@ -270,6 +298,7 @@ QStandardItem* PeerListWidget::addPeer(QString ip, peer_info peer) {
// Adding Peer to peer list
listModel->insertRow(row);
listModel->setData(listModel->index(row, IP), ip);
+ listModel->setData(listModel->index(row, IP_HIDDEN), ip);
// Resolve peer host name is asked
if(resolver)
resolver->resolve(peer.ip);
diff --git a/src/peerlistwidget.h b/src/peerlistwidget.h
index 35b9a0049..ee15cd7bb 100644
--- a/src/peerlistwidget.h
+++ b/src/peerlistwidget.h
@@ -78,6 +78,7 @@ protected slots:
void showPeerListMenu(QPoint);
void limitUpRateSelectedPeers(QStringList peer_ips);
void limitDlRateSelectedPeers(QStringList peer_ips);
+ void banSelectedPeers(QStringList peer_ips);
};
#endif // PEERLISTWIDGET_H
diff --git a/src/preferences.h b/src/preferences.h
index 6bf7df93c..cf02933e2 100644
--- a/src/preferences.h
+++ b/src/preferences.h
@@ -367,6 +367,20 @@ public:
return settings.value(QString::fromUtf8("Preferences/IPFilter/File"), QString()).toString();
}
+ static void banIP(QString ip) {
+ QSettings settings("qBittorrent", "qBittorrent");
+ QStringList banned_ips = settings.value(QString::fromUtf8("Preferences/IPFilter/BannedIPs"), QStringList()).toStringList();
+ if(!banned_ips.contains(ip)) {
+ banned_ips << ip;
+ settings.setValue("Preferences/IPFilter/BannedIPs", banned_ips);
+ }
+ }
+
+ static QStringList bannedIPs() {
+ QSettings settings("qBittorrent", "qBittorrent");
+ return settings.value(QString::fromUtf8("Preferences/IPFilter/BannedIPs"), QStringList()).toStringList();
+ }
+
// RSS
static bool isRSSEnabled() {
QSettings settings("qBittorrent", "qBittorrent");
@@ -423,6 +437,7 @@ public:
QSettings settings("qBittorrent", "qBittorrent");
return settings.value("Preferences/WebUI/Password", "").toString();
}
+
};
#endif // PREFERENCES_H
diff --git a/src/propertieswidget.cpp b/src/propertieswidget.cpp
index a05a59fe3..ff1413f7b 100644
--- a/src/propertieswidget.cpp
+++ b/src/propertieswidget.cpp
@@ -186,6 +186,10 @@ const QTorrentHandle& PropertiesWidget::getCurrentTorrent() const {
return h;
}
+bittorrent* PropertiesWidget::getBTSession() const {
+ return BTSession;
+}
+
void PropertiesWidget::loadTorrentInfos(QTorrentHandle &_h) {
h = _h;
if(!h.is_valid()) {
diff --git a/src/propertieswidget.h b/src/propertieswidget.h
index cefce5e4b..896174705 100644
--- a/src/propertieswidget.h
+++ b/src/propertieswidget.h
@@ -113,6 +113,7 @@ public:
PropertiesWidget(QWidget *parent, TransferListWidget *transferList, bittorrent* BTSession);
~PropertiesWidget();
const QTorrentHandle& getCurrentTorrent() const;
+ bittorrent* getBTSession() const;
};
#endif // PROPERTIESWIDGET_H