diff --git a/doc/rtorrent.1.xml b/doc/rtorrent.1.xml
index 51a4388c..20447673 100644
--- a/doc/rtorrent.1.xml
+++ b/doc/rtorrent.1.xml
@@ -241,6 +241,20 @@
+
+ k
+
+Disconnect peer.
+
+
+
+
+ *
+
+Choke/Snubb peer.
+
+
+
diff --git a/rak/address_info.h b/rak/address_info.h
new file mode 100644
index 00000000..26d22681
--- /dev/null
+++ b/rak/address_info.h
@@ -0,0 +1,98 @@
+// rak - Rakshasa's toolbox
+// Copyright (C) 2005-2006, Jari Sundell
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// In addition, as a special exception, the copyright holders give
+// permission to link the code of portions of this program with the
+// OpenSSL library under certain conditions as described in each
+// individual source file, and distribute linked combinations
+// including the two.
+//
+// You must obey the GNU General Public License in all respects for
+// all of the code used other than OpenSSL. If you modify file(s)
+// with this exception, you may extend this exception to your version
+// of the file(s), but you are not obligated to do so. If you do not
+// wish to do so, delete this exception statement from your version.
+// If you delete this exception statement from all source files in the
+// program, then also delete it here.
+//
+// Contact: Jari Sundell
+//
+// Skomakerveien 33
+// 3185 Skoppum, NORWAY
+
+// Wrapper for addrinfo with focus on zero-copy conversion to and from
+// the c-type and wrapper.
+//
+// Do use the wrapper on a pre-existing struct addrinfo, cast the
+// pointer rather than the base type.
+
+#ifndef RAK_ADDRESS_INFO_H
+#define RAK_ADDRESS_INFO_H
+
+#include
+#include
+
+namespace rak {
+
+class address_info {
+public:
+ void clear() { std::memset(this, 0, sizeof(address_info)); }
+
+ int flags() const { return m_addrinfo.ai_flags; }
+ void set_flags(int f) { m_addrinfo.ai_flags = f; }
+
+ int family() const { return m_addrinfo.ai_family; }
+ void set_family(int f) { m_addrinfo.ai_family = f; }
+
+ int socket_type() const { return m_addrinfo.ai_socktype; }
+ void set_socket_type(int t) { m_addrinfo.ai_socktype = t; }
+
+ int protocol() const { return m_addrinfo.ai_protocol; }
+ void set_protocol(int p) { m_addrinfo.ai_protocol = p; }
+
+ size_t length() const { return m_addrinfo.ai_addrlen; }
+
+ socket_address* address() { return reinterpret_cast(m_addrinfo.ai_addr); }
+
+ addrinfo* c_addrinfo() { return &m_addrinfo; }
+ const addrinfo* c_addrinfo() const { return &m_addrinfo; }
+
+ address_info* next() { return reinterpret_cast(m_addrinfo.ai_next); }
+
+ static int get_address_info(const char* node, int domain, int type, address_info** ai);
+
+ static void free_address_info(address_info* ai) { ::freeaddrinfo(ai->c_addrinfo()); }
+
+ static const char* strerror(int err) { return gai_strerror(err); }
+
+private:
+ addrinfo m_addrinfo;
+};
+
+inline int
+address_info::get_address_info(const char* node, int pfamily, int stype, address_info** ai) {
+ address_info hints;
+ hints.clear();
+ hints.set_family(pfamily);
+ hints.set_socket_type(stype);
+
+ return ::getaddrinfo(node, NULL, hints.c_addrinfo(), reinterpret_cast(ai));
+}
+
+}
+
+#endif
diff --git a/rak/functional_fun.h b/rak/functional_fun.h
index 32928ac3..c8ba1c5e 100644
--- a/rak/functional_fun.h
+++ b/rak/functional_fun.h
@@ -34,7 +34,7 @@
// Skomakerveien 33
// 3185 Skoppum, NORWAY
-// This file contains functors that wrap function points and member
+// This file contains functors that wrap function pointers and member
// function pointers.
//
// 'fn' functors are polymorphic and derives from 'rak::function' and
diff --git a/rak/ranges.h b/rak/ranges.h
index b954b6c7..a2440ceb 100644
--- a/rak/ranges.h
+++ b/rak/ranges.h
@@ -1,4 +1,4 @@
-// libTorrent - BitTorrent library
+// rak - Rakshasa's toolbox
// Copyright (C) 2005-2006, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
diff --git a/rak/socket_address.h b/rak/socket_address.h
new file mode 100644
index 00000000..c567ba17
--- /dev/null
+++ b/rak/socket_address.h
@@ -0,0 +1,335 @@
+// rak - Rakshasa's toolbox
+// Copyright (C) 2005-2006, Jari Sundell
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// In addition, as a special exception, the copyright holders give
+// permission to link the code of portions of this program with the
+// OpenSSL library under certain conditions as described in each
+// individual source file, and distribute linked combinations
+// including the two.
+//
+// You must obey the GNU General Public License in all respects for
+// all of the code used other than OpenSSL. If you modify file(s)
+// with this exception, you may extend this exception to your version
+// of the file(s), but you are not obligated to do so. If you do not
+// wish to do so, delete this exception statement from your version.
+// If you delete this exception statement from all source files in the
+// program, then also delete it here.
+//
+// Contact: Jari Sundell
+//
+// Skomakerveien 33
+// 3185 Skoppum, NORWAY
+
+// Wrappers for the various sockaddr types with focus on zero-copy
+// casting between the original type and the wrapper class.
+//
+// The default ctor does not initialize any data.
+//
+// _n suffixes indicate that the argument or return value is in
+// network byte order, _h that they are in hardware byte order.
+
+// Add define for inet6 scope id?
+
+#ifndef RAK_SOCKET_ADDRESS_H
+#define RAK_SOCKET_ADDRESS_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace rak {
+
+class socket_address_inet;
+class socket_address_inet6;
+
+class socket_address {
+public:
+ static const sa_family_t af_local = AF_LOCAL;
+ static const sa_family_t af_unix = AF_UNIX;
+ static const sa_family_t af_file = AF_FILE;
+ static const sa_family_t af_inet = AF_INET;
+ static const sa_family_t af_inet6 = AF_INET6;
+ static const sa_family_t af_unspec = AF_UNSPEC;
+
+ bool is_valid() const;
+ bool is_bindable() const;
+ bool is_address_any() const;
+
+ // Should we need to set AF_UNSPEC?
+ void clear() { std::memset(this, 0, sizeof(socket_address)); set_family(); }
+
+ sa_family_t family() const { return m_sa.m_sockaddr.sa_family; }
+ void set_family() { m_sa.m_sockaddr.sa_family = af_unspec; }
+
+ uint16_t port() const;
+ void set_port(uint16_t p);
+
+ std::string address_str() const;
+ bool address_c_str(char* buf, socklen_t size) const;
+
+ // Attemts to set it as an inet, then an inet6 address. It will
+ // never set anything but net addresses, no local/unix.
+ bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); }
+ bool set_address_c_str(const char* a);
+
+ socket_address_inet* sa_inet() { return reinterpret_cast(this); }
+ socket_address_inet6* sa_inet6() { return reinterpret_cast(this); }
+
+ const socket_address_inet* sa_inet() const { return reinterpret_cast(this); }
+ const socket_address_inet6* sa_inet6() const { return reinterpret_cast(this); }
+
+ sockaddr* c_sockaddr() { return &m_sa.m_sockaddr; }
+ sockaddr_in* c_sockaddr_inet() { return &m_sa.m_sockaddrInet; }
+ sockaddr_in6* c_sockaddr_inet6() { return &m_sa.m_sockaddrInet6; }
+
+ const sockaddr* c_sockaddr() const { return &m_sa.m_sockaddr; }
+ const sockaddr_in* c_sockaddr_inet() const { return &m_sa.m_sockaddrInet; }
+ const sockaddr_in6* c_sockaddr_inet6() const { return &m_sa.m_sockaddrInet6; }
+
+ // Copy a socket address which has the length 'length. Zero out any
+ // extranous bytes and ensure it does not go beyond the size of this
+ // struct.
+ void copy(const socket_address& src, size_t length);
+
+ // The different families will be sorted according to the
+ // sa_family_t's numeric value.
+ bool operator == (const socket_address& rhs) const;
+ bool operator < (const socket_address& rhs) const;
+
+private:
+ union sa_union {
+ sockaddr m_sockaddr;
+ sockaddr_in m_sockaddrInet;
+ sockaddr_in6 m_sockaddrInet6;
+ };
+
+ sa_union m_sa;
+};
+
+// Remeber to set the AF_INET.
+
+class socket_address_inet {
+public:
+ bool is_any() const { return is_port_any() && is_address_any(); }
+ bool is_valid() const { return !is_port_any() && !is_address_any(); }
+ bool is_port_any() const { return port() == 0; }
+ bool is_address_any() const { return m_sockaddr.sin_addr.s_addr == htonl(INADDR_ANY); }
+
+ void clear() { std::memset(this, 0, sizeof(socket_address_inet)); set_family(); }
+
+ uint16_t port() const { return ntohs(m_sockaddr.sin_port); }
+ uint16_t port_n() const { return m_sockaddr.sin_port; }
+ void set_port(uint16_t p) { m_sockaddr.sin_port = htons(p); }
+ void set_port_n(uint16_t p) { m_sockaddr.sin_port = p; }
+
+ // Should address() return the uint32_t?
+ in_addr address() const { return m_sockaddr.sin_addr; }
+ uint32_t address_h() const { return ntohl(m_sockaddr.sin_addr.s_addr); }
+ uint32_t address_n() const { return m_sockaddr.sin_addr.s_addr; }
+ std::string address_str() const;
+ bool address_c_str(char* buf, socklen_t size) const;
+
+ void set_address(in_addr a) { m_sockaddr.sin_addr = a; }
+ void set_address_h(uint32_t a) { m_sockaddr.sin_addr.s_addr = htonl(a); }
+ void set_address_n(uint32_t a) { m_sockaddr.sin_addr.s_addr = a; }
+ bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); }
+ bool set_address_c_str(const char* a);
+
+ void set_address_any() { set_port(0); set_address_h(INADDR_ANY); }
+
+ sa_family_t family() const { return m_sockaddr.sin_family; }
+ void set_family() { m_sockaddr.sin_family = AF_INET; }
+
+ sockaddr* c_sockaddr() { return reinterpret_cast(&m_sockaddr); }
+ sockaddr_in* c_sockaddr_inet() { return &m_sockaddr; }
+
+ const sockaddr* c_sockaddr() const { return reinterpret_cast(&m_sockaddr); }
+ const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddr; }
+
+ bool operator == (const socket_address_inet& rhs) const;
+ bool operator < (const socket_address_inet& rhs) const;
+
+private:
+ struct sockaddr_in m_sockaddr;
+};
+
+inline bool
+socket_address::is_valid() const {
+ switch (family()) {
+ case af_inet:
+ return sa_inet()->is_valid();
+// case af_inet6:
+// return sa_inet6().is_valid();
+ default:
+ return false;
+ }
+}
+
+inline bool
+socket_address::is_bindable() const {
+ switch (family()) {
+ case af_inet:
+ return !sa_inet()->is_address_any();
+ default:
+ return false;
+ }
+}
+
+inline bool
+socket_address::is_address_any() const {
+ switch (family()) {
+ case af_inet:
+ return sa_inet()->is_address_any();
+ default:
+ return true;
+ }
+}
+
+inline uint16_t
+socket_address::port() const {
+ switch (family()) {
+ case af_inet:
+ return sa_inet()->port();
+ default:
+ return 0;
+ }
+}
+
+inline void
+socket_address::set_port(uint16_t p) {
+ switch (family()) {
+ case af_inet:
+ return sa_inet()->set_port(p);
+ default:
+ break;
+ }
+}
+
+inline std::string
+socket_address::address_str() const {
+ switch (family()) {
+ case af_inet:
+ return sa_inet()->address_str();
+ default:
+ return std::string();
+ }
+}
+
+inline bool
+socket_address::address_c_str(char* buf, socklen_t size) const {
+ switch (family()) {
+ case af_inet:
+ return sa_inet()->address_c_str(buf, size);
+ default:
+ return false;
+ }
+}
+
+inline bool
+socket_address::set_address_c_str(const char* a) {
+ if (sa_inet()->set_address_c_str(a)) {
+ sa_inet()->set_family();
+ return true;
+
+ } else {
+ return false;
+ }
+}
+
+inline void
+socket_address::copy(const socket_address& src, size_t length) {
+ length = std::min(length, sizeof(socket_address));
+
+ // Does this get properly optimized?
+ std::memset(this, 0, sizeof(socket_address));
+ std::memcpy(this, &src, length);
+}
+
+// Should we be able to compare af_unspec?
+
+inline bool
+socket_address::operator == (const socket_address& rhs) const {
+ if (family() != rhs.family())
+ return false;
+
+ switch (family()) {
+ case af_inet:
+ return *sa_inet() == *rhs.sa_inet();
+// case af_inet6:
+// return *sa_inet6() == *rhs.sa_inet6();
+ default:
+ throw std::logic_error("socket_address::operator == (rhs) invalid type comparison.");
+ }
+}
+
+inline bool
+socket_address::operator < (const socket_address& rhs) const {
+ if (family() != rhs.family())
+ return family() < rhs.family();
+
+ switch (family()) {
+ case af_inet:
+ return *sa_inet() < *rhs.sa_inet();
+// case af_inet6:
+// return *sa_inet6() < *rhs.sa_inet6();
+ default:
+ throw std::logic_error("socket_address::operator < (rhs) invalid type comparison.");
+ }
+}
+
+inline std::string
+socket_address_inet::address_str() const {
+ char buf[INET_ADDRSTRLEN];
+
+ if (!address_c_str(buf, INET_ADDRSTRLEN))
+ return std::string();
+
+ return std::string(buf);
+}
+
+inline bool
+socket_address_inet::address_c_str(char* buf, socklen_t size) const {
+ return inet_ntop(family(), &m_sockaddr.sin_addr, buf, size);
+}
+
+inline bool
+socket_address_inet::set_address_c_str(const char* a) {
+ return inet_pton(AF_INET, a, &m_sockaddr.sin_addr);
+}
+
+inline bool
+socket_address_inet::operator == (const socket_address_inet& rhs) const {
+ return
+ m_sockaddr.sin_addr.s_addr == rhs.m_sockaddr.sin_addr.s_addr &&
+ m_sockaddr.sin_port == rhs.m_sockaddr.sin_port;
+}
+
+inline bool
+socket_address_inet::operator < (const socket_address_inet& rhs) const {
+ return
+ m_sockaddr.sin_addr.s_addr < rhs.m_sockaddr.sin_addr.s_addr ||
+ (m_sockaddr.sin_addr.s_addr == rhs.m_sockaddr.sin_addr.s_addr &&
+ m_sockaddr.sin_port < rhs.m_sockaddr.sin_port);
+}
+
+}
+
+#endif
diff --git a/rak/string_manip.h b/rak/string_manip.h
index 85c1f169..5ed3942f 100644
--- a/rak/string_manip.h
+++ b/rak/string_manip.h
@@ -130,6 +130,19 @@ split_iterator(__UNUSED const Sequence& seq) {
return split_iterator_t();
}
+// Could optimize this abit.
+inline char
+hexchar_to_value(char c) {
+ if (c >= '0' && c <= '9')
+ return c - '0';
+
+ else if (c >= 'A' && c <= 'F')
+ return 10 + c - 'A';
+
+ else
+ return 10 + c - 'a';
+}
+
template
inline char
value_to_hexchar(Value v) {
diff --git a/rak/unordered_vector.h b/rak/unordered_vector.h
index 36f71fdf..c47727dc 100644
--- a/rak/unordered_vector.h
+++ b/rak/unordered_vector.h
@@ -75,8 +75,12 @@ public:
using Base::push_back;
using Base::pop_back;
+ // Use the range erase function, the single element erase gets
+ // overloaded.
+ using Base::erase;
+
iterator insert(iterator position, const value_type& x);
- iterator erase(iterator position);
+ iterator erase(iterator position);
private:
};
diff --git a/src/display/client_info.cc b/src/display/client_info.cc
index 470090ff..b2e787e7 100644
--- a/src/display/client_info.cc
+++ b/src/display/client_info.cc
@@ -38,6 +38,7 @@
#include
#include
+#include
#include
#include "client_info.h"
@@ -85,17 +86,17 @@ ClientInfo::ClientInfo() {
insert(TYPE_AZUREUS, "SZ", "Shareaza");
insert(TYPE_AZUREUS, "RT", "Retriever");
- m_containers[TYPE_THREE_COMPACT].reserve(10);
+ m_containers[TYPE_COMPACT].reserve(10);
- insert(TYPE_THREE_COMPACT, "A", "ABC");
- insert(TYPE_THREE_COMPACT, "T", "BitTornado");
- insert(TYPE_THREE_COMPACT, "S", "Shadow's client");
- insert(TYPE_THREE_COMPACT, "U", "UPnP NAT Bit Torrent");
- insert(TYPE_THREE_COMPACT, "O", "Osprey Permaseed");
+ insert(TYPE_COMPACT, "A", "ABC");
+ insert(TYPE_COMPACT, "T", "BitTornado");
+ insert(TYPE_COMPACT, "S", "Shadow's client");
+ insert(TYPE_COMPACT, "U", "UPnP NAT Bit Torrent");
+ insert(TYPE_COMPACT, "O", "Osprey Permaseed");
- m_containers[TYPE_THREE_SPARSE].reserve(4);
+ m_containers[TYPE_MAINLINE].reserve(4);
- insert(TYPE_THREE_SPARSE, "M", "Mainline");
+ insert(TYPE_MAINLINE, "M", "Mainline");
}
void
@@ -108,21 +109,20 @@ ClientInfo::insert(Type t, const char* key, const char* name) {
if (keySize != std::strlen(key))
throw torrent::input_error("Client info key size not what was expected.");
- // Check if it is already present.
+ // Check if it is already present, not entirely optimal when
+ // initializing but this only get run once.
+ iterator itr = std::find_if(m_containers[t].begin(), m_containers[t].end(), client_info_equal(key, sizeof_key(t)));
+
+ if (itr == m_containers[t].end())
+ itr = m_containers[t].insert(m_containers[t].end(), value_type());
- value_type v;
-
- std::memcpy(v.first, key, keySize);
- v.second = name;
-
- m_containers[t].push_back(v);
+ std::memcpy(itr->first, key, keySize);
+ itr->second = name;
}
char*
ClientInfo::print(char* first, char* last, const char* id) {
- // Start with an UDP0 test.
-
if (id[0] == '-' && id[7] == '-' &&
std::isalpha(id[1]) && std::isalpha(id[2]) &&
std::isxdigit(id[3]) && std::isxdigit(id[4]) && std::isxdigit(id[5]) && std::isxdigit(id[6])) {
@@ -132,38 +132,52 @@ ClientInfo::print(char* first, char* last, const char* id) {
client_info_equal(id + 1, sizeof_key(TYPE_AZUREUS)));
if (itr != m_containers[TYPE_AZUREUS].end())
- first = print_buffer(first, last, "%s %c.%c.%c.%c", itr->second, id[3], id[4], id[5], id[6]);
+ first = print_buffer(first, last, "%s %hhu.%hhu.%hhu.%hhu", itr->second,
+ rak::hexchar_to_value(id[3]), rak::hexchar_to_value(id[4]),
+ rak::hexchar_to_value(id[5]), rak::hexchar_to_value(id[6]));
else
- first = print_buffer(first, last, "unknown %c%c %c.%c.%c.%c", id[1], id[2], id[3], id[4], id[5], id[6]);
+ first = print_buffer(first, last, "unknown %c%c %hhu.%hhu.%hhu.%hhu", id[1], id[2],
+ rak::hexchar_to_value(id[3]), rak::hexchar_to_value(id[4]),
+ rak::hexchar_to_value(id[5]), rak::hexchar_to_value(id[6]));
} else if (std::isalpha(id[0]) && id[4] == '-' &&
std::isxdigit(id[1]) && std::isxdigit(id[2]) && std::isxdigit(id[3])) {
// TYPE_THREE_COMPACT.
- iterator itr = std::find_if(m_containers[TYPE_THREE_COMPACT].begin(), m_containers[TYPE_THREE_COMPACT].end(),
- client_info_equal(id, sizeof_key(TYPE_THREE_COMPACT)));
+ iterator itr = std::find_if(m_containers[TYPE_COMPACT].begin(), m_containers[TYPE_COMPACT].end(),
+ client_info_equal(id, sizeof_key(TYPE_COMPACT)));
- if (itr != m_containers[TYPE_THREE_COMPACT].end())
- first = print_buffer(first, last, "%s %c.%c.%c", itr->second, id[1], id[2], id[3]);
+ if (itr != m_containers[TYPE_COMPACT].end())
+ first = print_buffer(first, last, "%s %hhu.%hhu.%hhu", itr->second,
+ rak::hexchar_to_value(id[1]), rak::hexchar_to_value(id[2]), rak::hexchar_to_value(id[3]));
else
- first = print_buffer(first, last, "unknown %c %c.%c.%c", id[0], id[1], id[2], id[3]);
+ first = print_buffer(first, last, "unknown %c %hhu.%hhu.%hhu", id[0],
+ rak::hexchar_to_value(id[1]), rak::hexchar_to_value(id[2]), rak::hexchar_to_value(id[3]));
} else if (std::isalpha(id[0]) && id[2] == '-' && id[4] == '-' && id[6] == '-' &&
std::isxdigit(id[1]) && std::isxdigit(id[3]) && std::isxdigit(id[5])) {
// TYPE_THREE_SPARSE.
- iterator itr = std::find_if(m_containers[TYPE_THREE_SPARSE].begin(), m_containers[TYPE_THREE_SPARSE].end(),
- client_info_equal(id, sizeof_key(TYPE_THREE_SPARSE)));
+ iterator itr = std::find_if(m_containers[TYPE_MAINLINE].begin(), m_containers[TYPE_MAINLINE].end(),
+ client_info_equal(id, sizeof_key(TYPE_MAINLINE)));
- if (itr != m_containers[TYPE_THREE_SPARSE].end())
- first = print_buffer(first, last, "%s %c.%c.%c", itr->second, id[1], id[3], id[5]);
+ if (itr != m_containers[TYPE_MAINLINE].end())
+ first = print_buffer(first, last, "%s %hhu.%hhu.%hhu", itr->second,
+ rak::hexchar_to_value(id[1]), rak::hexchar_to_value(id[3]), rak::hexchar_to_value(id[5]));
else
- first = print_buffer(first, last, "unknown %c %c.%c.%c", id[0], id[1], id[3], id[5]);
+ first = print_buffer(first, last, "unknown %c %hhu.%hhu.%hhu", id[0],
+ rak::hexchar_to_value(id[1]), rak::hexchar_to_value(id[3]), rak::hexchar_to_value(id[5]));
+ // And then the incompatible idiots that make life difficult for us
+ // others. (There's '3' schemes to choose from already...)
+
+ // Well... fuck this... I don't feel like adding the rest of the
+ // checks as they wouldn't be possible to remove/modify.
+
} else {
first = print_buffer(first, last, "unknown");
}
diff --git a/src/display/client_info.h b/src/display/client_info.h
index 362eec44..7ff1efb0 100644
--- a/src/display/client_info.h
+++ b/src/display/client_info.h
@@ -54,8 +54,8 @@ public:
typedef enum {
TYPE_AZUREUS,
- TYPE_THREE_COMPACT,
- TYPE_THREE_SPARSE,
+ TYPE_COMPACT,
+ TYPE_MAINLINE,
TYPE_MAXSIZE
} Type;
@@ -67,10 +67,10 @@ public:
size_type sizeof_key(Type t) {
switch (t) {
- case TYPE_AZUREUS: return 2;
- case TYPE_THREE_COMPACT: return 1;
- case TYPE_THREE_SPARSE: return 1;
- case TYPE_MAXSIZE: return 0;
+ case TYPE_AZUREUS: return 2;
+ case TYPE_COMPACT: return 1;
+ case TYPE_MAINLINE: return 1;
+ case TYPE_MAXSIZE: return 0;
}
}
diff --git a/src/option_parser.cc b/src/option_parser.cc
index 93ac2a1a..eb54f735 100644
--- a/src/option_parser.cc
+++ b/src/option_parser.cc
@@ -37,6 +37,7 @@
#include "config.h"
#include
+#include
#include
#include
#include
diff --git a/src/ui/download.cc b/src/ui/download.cc
index 0b0370d4..32628431 100644
--- a/src/ui/download.cc
+++ b/src/ui/download.cc
@@ -171,6 +171,16 @@ Download::receive_prev() {
mark_dirty();
}
+void
+Download::receive_disconnect_peer() {
+ if (m_focus == m_peers.end())
+ return;
+
+ m_download->get_download().disconnect_peer(*m_focus);
+
+ mark_dirty();
+}
+
void
Download::receive_peer_connected(torrent::Peer p) {
m_peers.push_back(p);
@@ -250,6 +260,8 @@ Download::bind_keys() {
(*m_bindings)['+'] = sigc::mem_fun(*this, &Download::receive_next_priority);
(*m_bindings)['-'] = sigc::mem_fun(*this, &Download::receive_prev_priority);
+ (*m_bindings)['k'] = sigc::mem_fun(*this, &Download::receive_disconnect_peer);
+
(*m_bindings)['t'] = sigc::bind(sigc::mem_fun(m_download->get_download(), &torrent::Download::tracker_manual_request), false);
(*m_bindings)['T'] = sigc::bind(sigc::mem_fun(m_download->get_download(), &torrent::Download::tracker_manual_request), true);
diff --git a/src/ui/download.h b/src/ui/download.h
index fdbbd1b7..6fd1b18f 100644
--- a/src/ui/download.h
+++ b/src/ui/download.h
@@ -98,6 +98,8 @@ private:
void receive_next();
void receive_prev();
+ void receive_disconnect_peer();
+
void receive_peer_connected(torrent::Peer p);
void receive_peer_disconnected(torrent::Peer p);