summaryrefslogtreecommitdiffstats
path: root/rtorrent-extended
diff options
context:
space:
mode:
Diffstat (limited to 'rtorrent-extended')
-rw-r--r--rtorrent-extended/PKGBUILD122
-rw-r--r--rtorrent-extended/bad_peer_handling.patch219
-rw-r--r--rtorrent-extended/canvas_color.patch282
-rw-r--r--rtorrent-extended/dht_pex_static_map.patch12
-rw-r--r--rtorrent-extended/ip_filter_no_boost_fast.patch1083
-rw-r--r--rtorrent-extended/ipv6.patch572
-rw-r--r--rtorrent-extended/karabaja_mod.patch438
-rw-r--r--rtorrent-extended/magnet_uri.patch228
-rw-r--r--rtorrent-extended/rtorrent-extended.install9
-rw-r--r--rtorrent-extended/trackerinfo.patch21
-rw-r--r--rtorrent-extended/vi_kb_akston.patch176
-rw-r--r--rtorrent-extended/vi_kb_tjwoosta.patch175
12 files changed, 0 insertions, 3337 deletions
diff --git a/rtorrent-extended/PKGBUILD b/rtorrent-extended/PKGBUILD
deleted file mode 100644
index 52ebeb4..0000000
--- a/rtorrent-extended/PKGBUILD
+++ /dev/null
@@ -1,122 +0,0 @@
-# Maintainer: Lucky <aur.archlinux.org [at] lucky.take0ver [dot] net>
-# Contributor: Ashren <edgar [at] archlinux [dot] us>
-# Contributor: Daenyth <Daenyth [at] gmail [dot] com>
-# Contributor: Jeff Mickey <jeff@archlinux.org>
-# Contributor: sh__
-
-pkgname=rtorrent-extended
-_pkgname=rtorrent
-pkgver=0.8.6
-pkgrel=4
-pkgdesc="Ncurses BitTorrent client based on libTorrent with magnet link, IPv6, ipfilter, bad peers, color and trackerinfo patch."
-arch=('i686' 'x86_64')
-url="http://libtorrent.rakshasa.no"
-license=('GPL')
-depends=('libtorrent-extended=0.12.6-3' 'curl>=7.14.3' 'xmlrpc-c>=1858')
-conflicts=('rtorrent')
-provides=('rtorrent')
-install=${pkgname}.install
-source=(http://libtorrent.rakshasa.no/downloads/${_pkgname}-${pkgver}.tar.gz
- # support for magnet links
- # http://libtorrent.rakshasa.no/ticket/955 (deleted)
- # http://libtorrent.rakshasa.no/ticket/2100
- dht_pex_static_map.patch
- magnet_uri.patch
- # support for IPv6
- # http://libtorrent.rakshasa.no/ticket/1111
- ipv6.patch
- # support for ipfilter.dat
- # http://libtorrent.rakshasa.no/ticket/239
- ip_filter_no_boost_fast.patch
- # support for bad peers (kick/ban)
- # http://ovh.ttdpatch.net/~jdrexler/rt/experimental/bad_peer_handling.diff
- # https://calomel.org/rtorrent_mods.html
- bad_peer_handling.patch
- # support for colors
- # http://libtorrent.rakshasa.no/ticket/1382
- canvas_color.patch
- # karabaja mod patchset (color, interface)
- # http://aur.archlinux.org/packages.php?ID=36604
- karabaja_mod.patch
- # more infos at tracker list
- trackerinfo.patch
- # http://aur.archlinux.org/packages.php?ID=33756
- vi_kb_akston.patch
- # http://aur.archlinux.org/packages.php?ID=35642
- vi_kb_tjwoosta.patch)
-md5sums=('b804c45c01c40312926bcea6b55bb084'
- '795c2818d4d869f90f1b7734f94347fc'
- '8dcd2c76ee2ed48e86707a2b94b34c34'
- 'cd9f4ce9202f6e03699b962f372a09e0'
- '142f39586cd916608a7d569473bce1b0'
- 'e698da498f306435fb8f89824c47e0e8'
- '8721dea9d4da9a4f11051de7a2490e40'
- 'fdcee74cc8dc4abb1a5b627ae00b8345'
- '1fc3b40153450f34f8f4c4e1a161b6b8'
- '752590f272e48a2828a7e64746778df8'
- 'c5620714083fff8d609924c6bdb37fa0')
-
-build() {
- cd "${srcdir}/${_pkgname}-${pkgver}"
-
- echo -e "\e[1;32m===> \e[0m Do you want magentlink patch? [Y/n]"
- echo -e "\e[1;31m===> \e[0m !!! needed by ipv6 patch !!!"
- read _answer_ml
- if [[ ! ${_answer_ml} = [n,N] ]]; then
- patch -p1 < ${srcdir}/dht_pex_static_map.patch
- patch -p1 < ${srcdir}/magnet_uri.patch
- fi
- echo -e "\e[1;32m===> \e[0m Do you want ipv6 patch? [y/N]"
- echo -e "\e[1;33m===> \e[0m !!! scgi/xmlrpc-c won't work with this patch !!!"
- read _answer_ipv6
- if [[ ${_answer_ipv6} = [y,Y] ]]; then
- patch -p1 < ${srcdir}/ipv6.patch
- _option_ipv6="--enable-ipv6"
- fi
- echo -e "\e[1;32m===> \e[0m Do you want ipfilter patch? [Y/n]"
- read _answer_ipf
- if [[ ! ${_answer_ipf} = [n,N] ]]; then
- patch -p1 < ${srcdir}/ip_filter_no_boost_fast.patch
- fi
- echo -e "\e[1;32m===> \e[0m Do you want bad peer handling patch? [Y/n]"
- read _answer_bph
- if [[ ! ${_answer_bph} = [n,N] ]]; then
- patch -p1 < ${srcdir}/bad_peer_handling.patch
- fi
- echo -e "\e[1;32m===> \e[0m Do you want color/mod patch? [1/2/n]"
- echo -e "\e[1;33m===> \e[0m 1) karabaja mod (default)"
- echo -e "\e[1;33m===> \e[0m 2) canvas color"
- read _answer_cc
- if [[ ! ${_answer_cc} = [n,N] ]]; then
- if [[ ! ${_answer_cc} = [2] ]]; then
- patch -p1 < ${srcdir}/karabaja_mod.patch
- else
- patch -p1 < ${srcdir}/canvas_color.patch
- fi
- fi
- echo -e "\e[1;32m===> \e[0m Do you want tracker info patch? [Y/n]"
- read _answer_ti
- if [[ ! ${_answer_ti} = [n,N] ]]; then
- patch -p1 < ${srcdir}/trackerinfo.patch
- fi
- echo -e "\e[1;32m===> \e[0m Do you want keybindings patch? [1/2/n]"
- echo -e "\e[1;33m===> \e[0m 1) vi_kb_tjwoosta (default)"
- echo -e "\e[1;33m===> \e[0m 2) vi_kb_akston"
- read _answer_kb
- if [[ ! ${_answer_kb} = [n,N] ]]; then
- if [[ ! ${_answer_kb} = [2] ]]; then
- patch -p1 < ${srcdir}/vi_kb_tjwoosta.patch
- else
- patch -p1 < ${srcdir}/vi_kb_akston.patch
- fi
- fi
-
- sed -i 's/rTorrent \" VERSION/rTorrent-eXtended " VERSION/' src/ui/download_list.cc
-
- ./autogen.sh
- CXXFLAGS="${CXXFLAGS} -fno-strict-aliasing" \
- ./configure --prefix=/usr --enable-posix-fallocate --disable-debug ${_option_ipv6} --with-xmlrpc-c || return 1
- make || return 1
- make DESTDIR="${pkgdir}" install
-}
-# vim:set ts=2 sw=2 et:
diff --git a/rtorrent-extended/bad_peer_handling.patch b/rtorrent-extended/bad_peer_handling.patch
deleted file mode 100644
index 293cfad..0000000
--- a/rtorrent-extended/bad_peer_handling.patch
+++ /dev/null
@@ -1,219 +0,0 @@
-diff --git a/src/command_download.cc b/src/command_download.cc
-index 6043662..9afd9b0 100644
---- a/src/command_download.cc
-+++ b/src/command_download.cc
-@@ -51,12 +51,14 @@
- #include <torrent/data/file.h>
- #include <torrent/data/file_list.h>
- #include <torrent/peer/connection_list.h>
-+#include <torrent/peer/peer_info.h>
- #include <torrent/peer/peer_list.h>
-
- #include "core/download.h"
- #include "core/download_store.h"
- #include "core/manager.h"
- #include "rpc/command_variable.h"
-+#include "rpc/parse.h"
-
- #include "globals.h"
- #include "control.h"
-@@ -170,6 +172,120 @@ apply_d_delete_tied(core::Download* download) {
- rpc::call_command("d.set_tied_to_file", std::string(), rpc::make_target(download));
- }
-
-+torrent::Object
-+apply_d_snub_leechers(core::Download* download, const torrent::Object& rawArgs) {
-+ if (!download->is_open() || download->is_done() || rpc::call_command_value("d.get_ignore_commands", rpc::make_target(download)) != 0)
-+ return torrent::Object();
-+
-+ const torrent::Object::list_type& args = rawArgs.as_list();
-+
-+ if (args.size() < 3)
-+ throw torrent::input_error("Too few arguments.");
-+
-+ torrent::Object::list_type::const_iterator argItr = args.begin();
-+ uint64_t snub_ratio = rpc::convert_to_value(*argItr++);
-+ uint64_t unsnub_ratio = rpc::convert_to_value(*argItr++);
-+ uint64_t min_transfer = rpc::convert_to_value(*argItr++);
-+
-+ for (torrent::ConnectionList::iterator itr = download->download()->connection_list()->begin(); itr != download->download()->connection_list()->end(); ++itr) {
-+#if LIBTORRENT_FRIENDS
-+ if (((*itr)->bitfield() && (*itr)->bitfield()->is_all_set()) || (*itr)->peer_info()->is_friend())
-+#else
-+ if (((*itr)->bitfield() && (*itr)->bitfield()->is_all_set()))
-+#endif
-+ continue;
-+
-+ uint64_t up = (*itr)->up_rate()->total();
-+ uint64_t down = (*itr)->down_rate()->total();
-+
-+ if ((*itr)->is_snubbed()) {
-+ if (down * unsnub_ratio >= std::max<uint64_t>(up, min_transfer))
-+ (*itr)->set_snubbed(false);
-+
-+ } else if (up > min_transfer && down * snub_ratio < up) {
-+ (*itr)->set_snubbed(true);
-+ }
-+ }
-+
-+ return torrent::Object();
-+}
-+
-+torrent::Object
-+apply_d_ban_slow_peers(core::Download* download, const torrent::Object& rawArgs) {
-+ if (!download->is_open() || download->is_done() || rpc::call_command_value("d.get_ignore_commands", rpc::make_target(download)) != 0)
-+ return torrent::Object();
-+
-+ const torrent::Object::list_type& args = rawArgs.as_list();
-+
-+ if (args.size() < 4)
-+ throw torrent::input_error("Too few arguments.");
-+
-+ torrent::ConnectionList* clist = download->download()->connection_list();
-+ int extraPeers = clist->size() - clist->min_size();
-+ if (extraPeers <= 0)
-+ return torrent::Object();
-+
-+ torrent::Object::list_type::const_iterator argItrStart = args.begin();
-+ int extraSeeds = download->download()->peers_complete() - rpc::convert_to_value(*argItrStart++);
-+ uint32_t minRate = rpc::convert_to_value(*argItrStart++);
-+
-+ for (torrent::ConnectionList::iterator itr = clist->begin(); extraPeers > 0 && itr != clist->end(); ++itr) {
-+#if LIBTORRENT_FRIENDS
-+ if ((*itr)->peer_info()->is_friend())
-+ continue;
-+#endif
-+
-+ bool isSeed = (*itr)->bitfield() && (*itr)->bitfield()->is_all_set();
-+ if (isSeed && extraSeeds <= 0)
-+ continue;
-+
-+ int64_t down = (*itr)->down_rate()->total();
-+ uint32_t rate = (*itr)->down_rate()->rate();
-+
-+ for (torrent::Object::list_type::const_iterator argItr = argItrStart; argItr != args.end(); ++argItr) {
-+ if (rate >= minRate || down >= rpc::convert_to_value(*argItr++))
-+ break;
-+
-+ if (cachedTime.seconds() - (*itr)->peer_info()->last_connection() < rpc::convert_to_value(*argItr) * 60)
-+ continue;
-+
-+ (*itr)->set_banned();
-+
-+ extraSeeds -= isSeed;
-+ extraPeers--;
-+ break;
-+ }
-+ }
-+
-+ // Need to go by indices because erasing may invalidate iterators.
-+ for (size_t pId = 0; pId < clist->size(); )
-+ if ((*(clist->begin() + pId))->is_banned())
-+ download->connection_list()->erase(*(clist->begin() + pId), 0);
-+ else
-+ pId++;
-+
-+ return torrent::Object();
-+}
-+
-+void
-+apply_d_unban_peers(core::Download* download) {
-+ torrent::PeerList* list = download->download()->peer_list();
-+
-+ for (torrent::PeerList::const_iterator itr = list->begin(); itr != list->end(); ++itr)
-+ if (itr->second->is_banned())
-+ itr->second->set_unbanned();
-+}
-+
-+void
-+apply_d_unsnub_peers(core::Download* download) {
-+ if (!download->is_open())
-+ return;
-+
-+ for (torrent::ConnectionList::iterator itr = download->download()->connection_list()->begin(); itr != download->download()->connection_list()->end(); ++itr)
-+ if ((*itr)->is_snubbed())
-+ (*itr)->set_snubbed(false);
-+}
-+
- void
- apply_d_connection_type(core::Download* download, const std::string& name) {
- torrent::Download::ConnectionType connType;
-@@ -580,6 +696,11 @@ initialize_command_download() {
- ADD_CD_LIST("delete_link", rak::bind_ptr_fn(&apply_d_change_link, 1));
- ADD_CD_V_VOID("delete_tied", &apply_d_delete_tied);
-
-+ ADD_CD_LIST("ban_slow_peers", rak::ptr_fn(&apply_d_ban_slow_peers));
-+ ADD_CD_LIST("snub_leechers", rak::ptr_fn(&apply_d_snub_leechers));
-+ ADD_CD_V_VOID("unban_peers", &apply_d_unban_peers);
-+ ADD_CD_V_VOID("unsnub_peers", &apply_d_unsnub_peers);
-+
- CMD_FUNC_SINGLE("d.start", "d.set_hashing_failed=0 ;view.set_visible=started");
- CMD_FUNC_SINGLE("d.stop", "view.set_visible=stopped");
- CMD_FUNC_SINGLE("d.try_start", "branch=\"or={d.get_hashing_failed=,d.get_ignore_commands=}\",{},{view.set_visible=started}");
-diff --git a/src/command_events.cc b/src/command_events.cc
-index b25dfbc..a0250d9 100644
---- a/src/command_events.cc
-+++ b/src/command_events.cc
-@@ -42,6 +42,8 @@
- #include <rak/path.h>
- #include <rak/string_manip.h>
- #include <sigc++/adaptors/bind.h>
-+#include <torrent/peer/connection_list.h>
-+#include <torrent/peer/peer_info.h>
- #include <torrent/rate.h>
- #include <torrent/hash_string.h>
-
-@@ -276,6 +278,31 @@ apply_close_low_diskspace(int64_t arg) {
- control->core()->push_log("Closed torrents due to low diskspace.");
- }
-
-+// Should call the d.* commands via RPC, but there doesn't seem to be a way to
-+// pass variable-sized argument lists, so call the functions directly for now.
-+torrent::Object apply_d_snub_leechers(core::Download*, const torrent::Object&);
-+torrent::Object apply_d_ban_slow_peers(core::Download*, const torrent::Object&);
-+
-+torrent::Object
-+apply_snub_leechers(const torrent::Object& rawArgs) {
-+ for (core::Manager::DListItr ditr = control->core()->download_list()->begin(); ditr != control->core()->download_list()->end(); ditr++) {
-+ if ((*ditr)->is_open() && !(*ditr)->is_done() && rpc::call_command_value("d.get_ignore_commands", rpc::make_target(*ditr)) == 0)
-+ apply_d_snub_leechers(*ditr, rawArgs);
-+ }
-+
-+ return torrent::Object();
-+}
-+
-+torrent::Object
-+apply_ban_slow_peers(const torrent::Object& rawArgs) {
-+ for (core::Manager::DListItr ditr = control->core()->download_list()->begin(); ditr != control->core()->download_list()->end(); ditr++) {
-+ if ((*ditr)->is_open() && !(*ditr)->is_done() && rpc::call_command_value("d.get_ignore_commands", rpc::make_target(*ditr)) == 0)
-+ apply_d_ban_slow_peers(*ditr, rawArgs);
-+ }
-+
-+ return torrent::Object();
-+}
-+
- torrent::Object
- apply_download_list(const torrent::Object& rawArgs) {
- const torrent::Object::list_type& args = rawArgs.as_list();
-@@ -369,6 +396,8 @@ initialize_command_events() {
- ADD_COMMAND_LIST("on_finished", rak::bind_ptr_fn(&apply_on_state_change, "event.download.finished"));
-
- ADD_COMMAND_STRING("on_ratio", rak::ptr_fn(&apply_on_ratio));
-+ ADD_COMMAND_LIST("snub_leechers", rak::ptr_fn(&apply_snub_leechers));
-+ ADD_COMMAND_LIST("ban_slow_peers", rak::ptr_fn(&apply_ban_slow_peers));
-
- ADD_COMMAND_VOID("start_tied", &apply_start_tied);
- ADD_COMMAND_VOID("stop_untied", &apply_stop_untied);
-diff --git a/src/command_helpers.h b/src/command_helpers.h
-index a807b5f..cda29d8 100644
---- a/src/command_helpers.h
-+++ b/src/command_helpers.h
-@@ -54,7 +54,7 @@ namespace rpc {
- #define COMMAND_DOWNLOAD_SLOTS_SIZE 150
- #define COMMAND_FILE_SLOTS_SIZE 30
- #define COMMAND_FILE_ITR_SLOTS_SIZE 10
--#define COMMAND_PEER_SLOTS_SIZE 20
-+#define COMMAND_PEER_SLOTS_SIZE 30
- #define COMMAND_TRACKER_SLOTS_SIZE 15
- #define COMMAND_ANY_SLOTS_SIZE 50
-
diff --git a/rtorrent-extended/canvas_color.patch b/rtorrent-extended/canvas_color.patch
deleted file mode 100644
index 88423b1..0000000
--- a/rtorrent-extended/canvas_color.patch
+++ /dev/null
@@ -1,282 +0,0 @@
-diff --git a/src/command_network.cc b/src/command_network.cc
-index 2494988..7b105ca 100644
---- a/src/command_network.cc
-+++ b/src/command_network.cc
-@@ -560,4 +560,8 @@ initialize_command_network() {
- // Not really network stuff:
- ADD_VARIABLE_BOOL ("handshake_log", false);
- ADD_VARIABLE_STRING("log.tracker", "");
-+ ADD_COMMAND_VALUE_TRI("done_fg_color", rak::make_mem_fun(control->ui(), &ui::Root::set_done_fg_color), rak::make_mem_fun(control->ui(), &ui::Root::get_done_fg_color));
-+ ADD_COMMAND_VALUE_TRI("done_bg_color", rak::make_mem_fun(control->ui(), &ui::Root::set_done_bg_color), rak::make_mem_fun(control->ui(), &ui::Root::get_done_bg_color));
-+ ADD_COMMAND_VALUE_TRI("active_fg_color", rak::make_mem_fun(control->ui(), &ui::Root::set_active_fg_color), rak::make_mem_fun(control->ui(), &ui::Root::get_active_fg_color));
-+ ADD_COMMAND_VALUE_TRI("active_bg_color", rak::make_mem_fun(control->ui(), &ui::Root::set_active_bg_color), rak::make_mem_fun(control->ui(), &ui::Root::get_active_bg_color));
- }
-diff --git a/src/display/canvas.cc b/src/display/canvas.cc
-index 4e621df..0c97eea 100644
---- a/src/display/canvas.cc
-+++ b/src/display/canvas.cc
-@@ -92,6 +92,10 @@ Canvas::initialize() {
- m_isInitialized = true;
-
- initscr();
-+ start_color();
-+ use_default_colors();
-+ init_pair(2, -1, -1);
-+ init_pair(1, -1, -1);
- raw();
- noecho();
- nodelay(stdscr, TRUE);
-diff --git a/src/display/window_download_list.cc b/src/display/window_download_list.cc
-index 71efec0..06e7cd4 100644
---- a/src/display/window_download_list.cc
-+++ b/src/display/window_download_list.cc
-@@ -37,6 +37,7 @@
- #include "config.h"
-
- #include <rak/algorithm.h>
-+#include <torrent/rate.h>
-
- #include "core/download.h"
- #include "core/view.h"
-@@ -96,12 +97,30 @@ WindowDownloadList::redraw() {
- char* position;
- char* last = buffer + m_canvas->width() - 2 + 1;
-
-+ if( pos >= m_canvas->height() ) break;
- position = print_download_title(buffer, last, *range.first);
-- m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer);
-+ m_canvas->print(0, pos, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer);
-+ if( (*range.first)->is_done() ) {
-+ if( (*range.first)->download()->up_rate()->rate() != 0 ) {
-+ m_canvas->set_attr(0, pos, m_canvas->width()-1, A_BOLD, 2);
-+ } else {
-+ m_canvas->set_attr(0, pos, m_canvas->width()-1, A_NORMAL, 2);
-+ }
-+ } else if( (*range.first)->download()->is_active() ) {
-+ if( (*range.first)->download()->down_rate()->rate() != 0 ) {
-+ m_canvas->set_attr(0, pos, m_canvas->width()-1, A_BOLD, 1);
-+ } else {
-+ m_canvas->set_attr(0, pos, m_canvas->width()-1, A_NORMAL, 1);
-+ }
-+ }
-+ pos++;
-
-+ if( pos >= m_canvas->height() ) break;
-+
- position = print_download_info(buffer, last, *range.first);
- m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer);
-
-+ if( pos >= m_canvas->height() ) break;
- position = print_download_status(buffer, last, *range.first);
- m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer);
-
-@@ -109,4 +128,40 @@ WindowDownloadList::redraw() {
- }
- }
-
-+void
-+WindowDownloadList::set_done_fg_color(int64_t color) {
-+ short fg, bg;
-+ pair_content(2, &fg, &bg);
-+ if( color < 0 ) color = -1;
-+ color = color % 8;
-+ init_pair(2, (short)color, bg);
-+}
-+
-+void
-+WindowDownloadList::set_done_bg_color(int64_t color) {
-+ short fg, bg;
-+ pair_content(2, &fg, &bg);
-+ if( color < 0 ) color = -1;
-+ color = color % 8;
-+ init_pair(2, fg, (short)color);
-+}
-+
-+void
-+WindowDownloadList::set_active_fg_color(int64_t color) {
-+ short fg, bg;
-+ pair_content(1, &fg, &bg);
-+ if( color < 0 ) color = -1;
-+ color = color % 8;
-+ init_pair(1, (short)color, bg);
-+}
-+
-+void
-+WindowDownloadList::set_active_bg_color(int64_t color) {
-+ short fg, bg;
-+ pair_content(1, &fg, &bg);
-+ if( color < 0 ) color = -1;
-+ color = color % 8;
-+ init_pair(1, fg, (short)color);
-+}
-+
- }
-diff --git a/src/display/window_download_list.h b/src/display/window_download_list.h
-index 4ce5ea1..313e87b 100644
---- a/src/display/window_download_list.h
-+++ b/src/display/window_download_list.h
-@@ -59,6 +59,10 @@ public:
- virtual void redraw();
-
- void set_view(core::View* l);
-+ void set_done_fg_color(int64_t color);
-+ void set_done_bg_color(int64_t color);
-+ void set_active_fg_color(int64_t color);
-+ void set_active_bg_color(int64_t color);
-
- private:
- core::View* m_view;
-diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc
-index b7d6983..e72bff6 100644
---- a/src/ui/download_list.cc
-+++ b/src/ui/download_list.cc
-@@ -137,6 +137,11 @@ DownloadList::unfocus_download(core::Download* d) {
- current_view()->next_focus();
- }
-
-+display::WindowDownloadList*
-+DownloadList::current_window_list() {
-+ return dynamic_cast<ElementDownloadList*>(m_uiArray[DISPLAY_DOWNLOAD_LIST])->window();
-+}
-+
- void
- DownloadList::activate_display(Display displayType) {
- if (!is_active())
-diff --git a/src/ui/download_list.h b/src/ui/download_list.h
-index dda1b34..11137fa 100644
---- a/src/ui/download_list.h
-+++ b/src/ui/download_list.h
-@@ -101,6 +101,7 @@ public:
- void activate_display(Display d);
-
- core::View* current_view();
-+ display::WindowDownloadList* current_window_list();
- void set_current_view(const std::string& name);
-
- void slot_open_uri(SlotOpenUri s) { m_slotOpenUri = s; }
-diff --git a/src/ui/element_download_list.h b/src/ui/element_download_list.h
-index ed5de30..7c0fb9d 100644
---- a/src/ui/element_download_list.h
-+++ b/src/ui/element_download_list.h
-@@ -60,6 +60,7 @@ public:
- void disable();
-
- core::View* view() { return m_view; }
-+ WDownloadList* window() { return m_window; }
- void set_view(core::View* l);
-
- void receive_command(const char* cmd);
-diff --git a/src/ui/root.cc b/src/ui/root.cc
-index b01f4ed..d344718 100644
---- a/src/ui/root.cc
-+++ b/src/ui/root.cc
-@@ -44,6 +44,7 @@
-
- #include "core/manager.h"
- #include "display/frame.h"
-+#include "display/window_download_list.h"
- #include "display/window_http_queue.h"
- #include "display/window_title.h"
- #include "display/window_input.h"
-@@ -65,7 +66,11 @@ Root::Root() :
- m_windowTitle(NULL),
- m_windowHttpQueue(NULL),
- m_windowInput(NULL),
-- m_windowStatusbar(NULL) {
-+ m_windowStatusbar(NULL),
-+ done_fg_color(-1),
-+ done_bg_color(-1),
-+ active_fg_color(-1),
-+ active_bg_color(-1) {
- }
-
- void
-@@ -97,6 +102,10 @@ Root::init(Control* c) {
- setup_keys();
-
- m_downloadList->activate(rootFrame->frame(1));
-+ m_downloadList->current_window_list()->set_done_fg_color(done_fg_color);
-+ m_downloadList->current_window_list()->set_done_bg_color(done_bg_color);
-+ m_downloadList->current_window_list()->set_active_fg_color(active_fg_color);
-+ m_downloadList->current_window_list()->set_active_bg_color(active_bg_color);
- }
-
- void
-@@ -219,6 +228,46 @@ Root::set_up_throttle(unsigned int throttle) {
- torrent::set_max_unchoked(maxUnchoked);
- }
-
-+int
-+Root::get_done_fg_color() {
-+ return done_fg_color;
-+}
-+
-+void
-+Root::set_done_fg_color(int64_t color) {
-+ done_fg_color = color;
-+}
-+
-+int
-+Root::get_done_bg_color() {
-+ return done_bg_color;
-+}
-+
-+void
-+Root::set_done_bg_color(int64_t color) {
-+ done_bg_color = color;
-+}
-+
-+int
-+Root::get_active_fg_color() {
-+ return active_fg_color;
-+}
-+
-+void
-+Root::set_active_fg_color(int64_t color) {
-+ active_fg_color = color;
-+}
-+
-+int
-+Root::get_active_bg_color() {
-+ return active_bg_color;
-+}
-+
-+void
-+Root::set_active_bg_color(int64_t color) {
-+ active_bg_color = color;
-+}
-+
- void
- Root::adjust_down_throttle(int throttle) {
- set_down_throttle(std::max<int>(torrent::down_throttle_global()->max_rate() / 1024 + throttle, 0));
-diff --git a/src/ui/root.h b/src/ui/root.h
-index e9a7907..4eef1df 100644
---- a/src/ui/root.h
-+++ b/src/ui/root.h
-@@ -83,6 +83,15 @@ public:
- void set_down_throttle_i64(int64_t throttle) { set_down_throttle(throttle >> 10); }
- void set_up_throttle_i64(int64_t throttle) { set_up_throttle(throttle >> 10); }
-
-+ int get_done_fg_color();
-+ void set_done_fg_color(int64_t color);
-+ int get_done_bg_color();
-+ void set_done_bg_color(int64_t color);
-+ int get_active_fg_color();
-+ void set_active_fg_color(int64_t color);
-+ int get_active_bg_color();
-+ void set_active_bg_color(int64_t color);
-+
- void adjust_down_throttle(int throttle);
- void adjust_up_throttle(int throttle);
-
-@@ -105,6 +114,10 @@ private:
- WStatusbar* m_windowStatusbar;
-
- input::Bindings m_bindings;
-+ int64_t done_fg_color;
-+ int64_t done_bg_color;
-+ int64_t active_fg_color;
-+ int64_t active_bg_color;
- };
-
- }
diff --git a/rtorrent-extended/dht_pex_static_map.patch b/rtorrent-extended/dht_pex_static_map.patch
deleted file mode 100644
index e302b4c..0000000
--- a/rtorrent-extended/dht_pex_static_map.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff --git a/src/core/view.cc b/src/core/view.cc
-index 8e2d997..f3b4f0d 100644
---- a/src/core/view.cc
-+++ b/src/core/view.cc
-@@ -90,6 +90,7 @@ struct view_downloads_filter : std::unary_function<Download*, bool> {
- case torrent::Object::TYPE_STRING: return !result.as_string().empty();
- case torrent::Object::TYPE_LIST: return !result.as_list().empty();
- case torrent::Object::TYPE_MAP: return !result.as_map().empty();
-+ case torrent::Object::TYPE_SSTRING:return !result.as_sstring().empty();
- }
-
- // The default filter action is to return true, to not filter
diff --git a/rtorrent-extended/ip_filter_no_boost_fast.patch b/rtorrent-extended/ip_filter_no_boost_fast.patch
deleted file mode 100644
index d13fb69..0000000
--- a/rtorrent-extended/ip_filter_no_boost_fast.patch
+++ /dev/null
@@ -1,1083 +0,0 @@
-diff --git a/src/command_network.cc b/src/command_network.cc
-index 34f75ab..2494988 100644
---- a/src/command_network.cc
-+++ b/src/command_network.cc
-@@ -36,6 +36,11 @@
-
- #include "config.h"
-
-+#include <string>
-+#include <sstream>
-+#include <list>
-+#include <unistd.h>
-+
- #include <functional>
- #include <cstdio>
- #include <rak/address_info.h>
-@@ -62,6 +67,10 @@
- #include "control.h"
- #include "command_helpers.h"
-
-+#include "utils/pattern.h"
-+#include "core/ip_filter.h"
-+
-+
- torrent::Object
- apply_throttle(bool up, const torrent::Object& rawArgs) {
- const torrent::Object::list_type& args = rawArgs.as_list();
-@@ -209,6 +218,59 @@ apply_encryption(const torrent::Object& rawArgs) {
- }
-
- torrent::Object
-+apply_ip_filter(const torrent::Object& rawArgs) {
-+ const torrent::Object::list_type& args = rawArgs.as_list();
-+
-+ std::list<std::string> files;
-+
-+ for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
-+ std::string file( itr->as_string() );
-+ utils::trim( file );
-+ if( access(file.c_str(),F_OK | R_OK) )
-+ throw torrent::input_error("IpFilter file '" + file + "' does not exist or not readable. Filter could not be loaded");
-+ files.push_back( file );
-+ }
-+
-+ std::stringstream logMsg;
-+ if( files.empty() ) {
-+ logMsg << "IpFilter is empty";
-+ control->core()->push_log( logMsg.str().c_str() );
-+ }
-+ else {
-+ core::IpFilter* f = new core::IpFilter();
-+ logMsg << "IpFilter is initialized with files: ";
-+ int entries = 0;
-+ clock_t time_start = clock();
-+ for( std::list<std::string>::iterator itr = files.begin(); itr != files.end(); itr++) {
-+ std::cout << "Loading IP filters from '" << *itr << "'...";
-+ std::cout.flush();
-+ if( itr != files.begin() )
-+ logMsg << ", ";
-+ logMsg << *itr;
-+ int merges = f->add_from_file( *itr );
-+ if( merges < 0 ) {
-+ std::cout << "error" << std::endl;
-+ std::cout.flush();
-+ throw torrent::input_error("IpFilter could not load file '" + *itr + "'");
-+ }
-+ std::cout << "done. Loaded " << (f->size()-entries) << " ranges. " << merges << " ranges were merged." << std::endl;
-+ std::cout.flush();
-+ entries = f->size();
-+ }
-+ control->core()->push_log( logMsg.str().c_str() );
-+ std::stringstream logMsg2("IpFilter loaded with ");
-+ logMsg2 << f->size() << " ranges total. " << f->get_merges() << " ranges were merged.";
-+ control->core()->push_log( logMsg2.str().c_str() );
-+ std::cout << logMsg2.str() << std::endl;
-+ std::cout << "IP_Filters loaded in " << (double)(clock()-time_start)/CLOCKS_PER_SEC << " seconds" << std::endl;
-+ std::cout.flush();
-+ control->core()->set_ip_filter( f );
-+ }
-+
-+ return torrent::Object();
-+}
-+
-+torrent::Object
- apply_tos(const torrent::Object& rawArg) {
- rpc::Command::value_type value;
- torrent::ConnectionManager* cm = torrent::connection_manager();
-@@ -492,6 +554,9 @@ initialize_command_network() {
-
- ADD_VARIABLE_BOOL("peer_exchange", true);
-
-+ ADD_COMMAND_VOID("reload_ip_filter", rak::make_mem_fun(control->core(), &core::Manager::reload_ip_filter));
-+ ADD_COMMAND_LIST("ip_filter", rak::ptr_fn(&apply_ip_filter));
-+
- // Not really network stuff:
- ADD_VARIABLE_BOOL ("handshake_log", false);
- ADD_VARIABLE_STRING("log.tracker", "");
-diff --git a/src/core/Makefile.am b/src/core/Makefile.am
-index fe07cbf..fb26380 100644
---- a/src/core/Makefile.am
-+++ b/src/core/Makefile.am
-@@ -36,6 +36,15 @@ libsub_core_a_SOURCES = \
- view.cc \
- view.h \
- view_manager.cc \
-- view_manager.h
-+ view_manager.h \
-+ ip_address.cc \
-+ ip_address.h \
-+ ip_filter.cc \
-+ ip_filter.h \
-+ ip_range.cc \
-+ ip_range.h \
-+ printable.h \
-+ regex_namespace.h \
-+ ip_filter_statics.cc
-
- INCLUDES = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir)
-diff --git a/src/core/Makefile.in b/src/core/Makefile.in
-index 24b7eb4..32b0f6b 100644
---- a/src/core/Makefile.in
-+++ b/src/core/Makefile.in
-@@ -63,7 +63,11 @@ am_libsub_core_a_OBJECTS = curl_get.$(OBJEXT) curl_socket.$(OBJEXT) \
- manager.$(OBJEXT) poll_manager.$(OBJEXT) \
- poll_manager_epoll.$(OBJEXT) poll_manager_kqueue.$(OBJEXT) \
- poll_manager_select.$(OBJEXT) view.$(OBJEXT) \
-- view_manager.$(OBJEXT)
-+ view_manager.$(OBJEXT) \
-+ ip_address.$(OBJEXT) \
-+ ip_filter.$(OBJEXT) \
-+ ip_range.$(OBJEXT) \
-+ ip_filter_statics.$(OBJEXT)
- libsub_core_a_OBJECTS = $(am_libsub_core_a_OBJECTS)
- DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
- depcomp = $(SHELL) $(top_srcdir)/depcomp
-@@ -252,7 +256,16 @@ libsub_core_a_SOURCES = \
- view.cc \
- view.h \
- view_manager.cc \
-- view_manager.h
-+ view_manager.h \
-+ ip_address.cc \
-+ ip_address.h \
-+ ip_filter.cc \
-+ ip_filter.h \
-+ ip_range.cc \
-+ ip_range.h \
-+ printable.h \
-+ regex_namespace.h \
-+ ip_filter_statics.cc
-
- INCLUDES = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir)
- all: all-am
-@@ -320,6 +333,9 @@ distclean-compile:
- @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/poll_manager_select.Po@am__quote@
- @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/view.Po@am__quote@
- @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/view_manager.Po@am__quote@
-+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ip_address.Po@am__quote@
-+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ip_range.Po@am__quote@
-+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ip_filter_statics.Po@am__quote@
-
- .cc.o:
- @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
-diff --git a/src/core/ip_address.cc b/src/core/ip_address.cc
-new file mode 100644
-index 0000000..a9a9251
---- /dev/null
-+++ b/src/core/ip_address.cc
-@@ -0,0 +1,25 @@
-+#include <cstdlib>
-+#include <string>
-+#include <arpa/inet.h>
-+
-+#include "ip_address.h"
-+#include "utils/pattern.h"
-+
-+namespace core {
-+
-+std::pair<bool,uint32_t> IpAddress::to_int( const std::string& address ) {
-+ uint32_t a;
-+ int r = inet_pton( AF_INET, address.c_str(), &a);
-+ if( r )
-+ a = ntohl( a );
-+ return std::pair<bool,uint32_t>( (r!=0), a );
-+}
-+
-+std::string IpAddress::to_string() const {
-+ char buf[128] = "";
-+ uint32_t a = htonl( m_address );
-+ inet_ntop( AF_INET, &a, buf, sizeof(buf) );
-+ return std::string( buf );
-+}
-+
-+}
-diff --git a/src/core/ip_address.h b/src/core/ip_address.h
-new file mode 100644
-index 0000000..a9ad142
---- /dev/null
-+++ b/src/core/ip_address.h
-@@ -0,0 +1,65 @@
-+#ifndef IPADDRESS_H
-+#define IPADDRESS_H
-+
-+#include <inttypes.h>
-+#include <string>
-+
-+#include "printable.h"
-+#include "utils/pattern.h"
-+#include "regex_namespace.h"
-+
-+namespace core {
-+
-+class IpAddress : public Printable {
-+ friend class IpRange;
-+
-+ private: // constants
-+ static const std::string PATTERN_IP_EXPRESSION;
-+ static const std::string PATTERN_IP_BYTES_EXPRESSION;
-+ static const regex::Pattern PATTERN_IP_BYTES;
-+
-+ static const int GRP_IP_FIRST_BYTE;
-+ static const int GRP_IP_BYTES_COUNT;
-+
-+ private: // fields
-+ uint32_t m_address;
-+
-+ private: // static methods
-+
-+ private: // dynamic methods
-+ IpAddress() : m_address(0) {}
-+
-+ void copy( const IpAddress& addr ) { m_address = addr.m_address;}
-+
-+ public: // static methods
-+ static std::pair<bool,uint32_t> to_int( const std::string& strAddress );
-+ static IpAddress* parse( const std::string& strAddress ) {
-+ std::pair<bool,uint32_t> result = to_int( strAddress );
-+ return ( !result.first ) ? NULL : new IpAddress( result.second );
-+ }
-+
-+ public: // dynamic methods
-+ IpAddress( uint32_t address ) : m_address(address) {}
-+ IpAddress( const IpAddress& addr ) { copy( addr ); }
-+ IpAddress& operator= ( const IpAddress& addr ) { copy( addr ); return *this; }
-+
-+ operator uint32_t() const { return m_address; }
-+
-+ bool operator>= ( const IpAddress& ip ) const { return (m_address >= ip.m_address); }
-+ bool operator<= ( const IpAddress& ip ) const { return (m_address <= ip.m_address); }
-+ bool operator< ( const IpAddress& ip ) const { return (m_address < ip.m_address); }
-+ bool operator> ( const IpAddress& ip ) const { return (m_address > ip.m_address); }
-+ bool operator== ( const IpAddress& ip ) const { return (m_address == ip.m_address); }
-+ bool operator!= ( const IpAddress& ip ) const { return (m_address != ip.m_address); }
-+
-+ bool operator>= ( uint32_t ip ) const { return (m_address >= ip); }
-+ bool operator<= ( uint32_t ip ) const { return (m_address <= ip); }
-+ bool operator< ( uint32_t ip ) const { return (m_address < ip); }
-+ bool operator> ( uint32_t ip ) const { return (m_address > ip); }
-+ bool operator== ( uint32_t ip ) const { return (m_address == ip); }
-+ bool operator!= ( uint32_t ip ) const { return (m_address != ip); }
-+
-+ std::string to_string() const;
-+ };
-+}
-+#endif
-diff --git a/src/core/ip_filter.cc b/src/core/ip_filter.cc
-new file mode 100644
-index 0000000..8f46a42
---- /dev/null
-+++ b/src/core/ip_filter.cc
-@@ -0,0 +1,165 @@
-+#include <sstream>
-+#include <string>
-+#include <map>
-+#include <list>
-+#include <fstream>
-+#include <stdio.h>
-+#include <stdlib.h>
-+
-+#include "ip_filter.h"
-+
-+namespace core {
-+
-+int IpFilter::merge_and_insert( range_map* rs, IpRange* r ) {
-+ if( !r || !r->get_from() )
-+ return 0;
-+
-+ std::pair<const IpAddress,IpRange::ptr> p( *r->get_from(), IpRange::ptr(r) );
-+ std::pair<range_itr,bool> duo = rs->insert( p );
-+
-+ range_itr idx = duo.first;
-+ bool wasInserted = duo.second;
-+ IpRange* curr = NULL;
-+ int mergeCount = 0;
-+
-+ if( !wasInserted ) { // exactly the same start address already exists
-+ curr = idx->second;
-+ if( *curr->get_to() < *r->get_to() )
-+ curr->set_to( r->get_to() );
-+ delete r;
-+ r = curr;
-+ mergeCount++;
-+ }
-+ else {
-+ if( idx != rs->begin() ) {
-+ --idx;
-+ curr = idx->second; // previous
-+ if( *r->get_from() <= *curr->get_to() )
-+ r = curr;
-+ else
-+ ++idx;
-+ }
-+ }
-+
-+ if( idx != rs->end() )
-+ ++idx;
-+
-+ while( idx != rs->end() ) {
-+ curr = idx->second;
-+ if( *r->get_to() < *curr->get_from() )
-+ break;
-+
-+ std::string d = r->get_description();
-+ d += " / " + curr->get_description();
-+ r->set_description( d );
-+ if( *r->get_to() < *curr->get_to() )
-+ r->set_to( curr->get_to() );
-+ rs->erase( idx++ );
-+ delete curr;
-+ mergeCount++;
-+ }
-+ return mergeCount;
-+}
-+
-+int IpFilter::add_from_file( const std::string& fileName, range_map* rs, str_list* files ) {
-+ FILE *f = fopen(fileName.c_str(),"r");
-+ int mergeCount = 0;
-+ if (f==0) return -1;
-+ char *line = (char *)malloc(64);
-+ size_t sz=64;
-+ int charsread = 0;
-+ int linesread=0;
-+ while( (charsread=getline(&line,&sz,f)) >=0 ) {
-+ if( (line[0] == '#' ) || ( charsread <= 1 ) )
-+ continue;
-+
-+ IpRange* ir = IpRange::parse( line, charsread );
-+ if( !ir || !ir->get_from() || !ir->get_to() )
-+ continue;
-+
-+ mergeCount += merge_and_insert( rs, ir );
-+ }
-+ free(line);
-+ files->push_back( std::string(fileName) );
-+ fclose(f);
-+ m_merges += mergeCount;
-+ return mergeCount;
-+}
-+
-+int IpFilter::add_from_file( const std::string& fileName ) {
-+ if( !m_ranges )
-+ m_ranges = new range_map();
-+ if( !m_loadedFiles )
-+ m_loadedFiles = new std::list<std::string>();
-+
-+ return add_from_file( fileName, m_ranges, m_loadedFiles );
-+}
-+
-+int IpFilter::reload() {
-+ if( !m_loadedFiles || m_loadedFiles->empty() )
-+ return 0;
-+
-+ range_map* rs = new range_map();
-+ str_list* files = new str_list();
-+ int mergeCount = 0;
-+ for( str_list::const_iterator it = m_loadedFiles->begin(), end = m_loadedFiles->end(); it != end; it++ )
-+ mergeCount += add_from_file( *it, rs, files );
-+
-+ range_map* rsOld = m_ranges;
-+ m_ranges = rs;
-+ if( rsOld ) {
-+ clear( rsOld );
-+ delete rsOld;
-+ }
-+
-+ str_list* filesOld = m_loadedFiles;
-+ m_loadedFiles = files;
-+ if( filesOld ) {
-+ clear( filesOld );
-+ delete filesOld;
-+ }
-+
-+ m_merges = mergeCount;
-+ return mergeCount;
-+}
-+
-+IpRange* IpFilter::find_range( uint32_t ip ) const {
-+ if( (ip >= 0) && m_ranges && !m_ranges->empty() ) {
-+ range_itr idx = m_ranges->upper_bound( ip );
-+ if( idx != m_ranges->begin() )
-+ --idx;
-+ IpRange* curr = idx->second;
-+ if( curr->includes( ip ) )
-+ return curr;
-+ }
-+ return NULL;
-+}
-+
-+std::string IpFilter::to_string() const {
-+ std::stringstream result;
-+ if( !m_ranges )
-+ result << "NULL" << std::endl;
-+ else {
-+ for( range_map::const_iterator it = m_ranges->begin() ; it != m_ranges->end(); it++ ) {
-+ const IpAddress a = it->first;
-+ IpRange* ir = it->second;
-+ result << a << ": " << *ir << std::endl;
-+ }
-+ }
-+ return result.str();
-+}
-+
-+void IpFilter::clear( range_map* map ) {
-+ if( map ) {
-+ for( range_itr i = map->begin(), j = map->end(); i != j; i++ )
-+ delete i->second;
-+ map->clear();
-+ }
-+}
-+
-+void IpFilter::clear( str_list* list ) {
-+ if( list )
-+ list->clear();
-+}
-+
-+}
-diff --git a/src/core/ip_filter.h b/src/core/ip_filter.h
-new file mode 100644
-index 0000000..07f2004
---- /dev/null
-+++ b/src/core/ip_filter.h
-@@ -0,0 +1,85 @@
-+#ifndef IPFILTER_H
-+#define IPFILTER_H
-+
-+#include <string>
-+#include <map>
-+#include <list>
-+
-+#include "printable.h"
-+#include "ip_address.h"
-+#include "ip_range.h"
-+
-+namespace core {
-+
-+typedef std::map<const IpAddress,IpRange::ptr> range_map;
-+typedef range_map::iterator range_itr;
-+typedef std::list<std::string> str_list;
-+
-+class IpFilter : public Printable {
-+ private: // fields
-+ int m_merges;
-+ range_map* m_ranges;
-+ str_list* m_loadedFiles;
-+
-+ private: // static methods
-+ static void clear( range_map* map );
-+ static void clear( str_list* list );
-+
-+ private: // dynamic methods
-+ void init_members(void) { // to avoid long constructor lines for every ctor
-+ m_ranges = NULL;
-+ m_loadedFiles = NULL;
-+ m_merges = 0;
-+ }
-+ int merge_and_insert( range_map* rs, IpRange* r );
-+ int add_from_file( const std::string& fileName, range_map* rs, str_list* files );
-+
-+ public: // static methods
-+
-+ public: // dynamic methods
-+ IpFilter() { init_members(); }
-+ ~IpFilter() {
-+ clear();
-+ if( m_ranges ) delete m_ranges;
-+ if( m_loadedFiles ) delete m_loadedFiles;
-+ m_ranges = NULL;
-+ m_loadedFiles = NULL;
-+ }
-+ IpFilter( std::string* files, int size ) {
-+ init_members();
-+ for( int i = 0; i < size; i++, files++ )
-+ add_from_file( *files );
-+ }
-+ IpFilter( str_list& files ) {
-+ init_members();
-+ for( str_list::const_iterator i = files.begin(), last = files.end(); i != last; i++ )
-+ add_from_file( *i );
-+ }
-+ IpFilter( IpFilter& f ) {
-+ init_members();
-+ m_ranges = new range_map( *f.m_ranges );
-+ m_loadedFiles = new str_list( *f.m_loadedFiles );
-+ }
-+
-+ int reload();
-+ int add_from_file( const std::string& fileName );
-+ int add_from_file( char* fileName ) { std::string s( fileName ); return add_from_file(s); }
-+ void clear() { clear( m_ranges ); clear( m_loadedFiles ); }
-+
-+ IpRange* find_range( uint32_t ip ) const;
-+
-+ bool is_filtered( uint32_t ip ) const { return (find_range( ip ) != NULL); }
-+ bool is_filtered( std::string ip ) const {
-+ static std::pair<bool,uint32_t> ipInt = IpAddress::to_int( ip );
-+ return (!ipInt.first ? false : is_filtered( ipInt.second ));
-+ }
-+
-+ std::string to_string() const;
-+
-+ int size(void) { return ( m_ranges ? m_ranges->size() : 0 ); }
-+ int get_merges(void) { return m_merges; }
-+ void set_files( str_list& files) { m_loadedFiles = new str_list( files ); }
-+};
-+
-+}
-+#endif
-diff --git a/src/core/ip_filter_statics.cc b/src/core/ip_filter_statics.cc
-new file mode 100644
-index 0000000..042377d
---- /dev/null
-+++ b/src/core/ip_filter_statics.cc
-@@ -0,0 +1,21 @@
-+#include "ip_address.h"
-+#include "ip_range.h"
-+#include "utils/pattern.h"
-+
-+namespace core {
-+
-+const std::string IpAddress::PATTERN_IP_EXPRESSION = "(([0-9]{1,3}\\.){3}[0-9]{1,3})";
-+const std::string IpAddress::PATTERN_IP_BYTES_EXPRESSION = "([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})";
-+const regex::Pattern IpAddress::PATTERN_IP_BYTES = PATTERN_IP_BYTES_EXPRESSION;
-+
-+const int IpAddress::GRP_IP_FIRST_BYTE = 1;
-+const int IpAddress::GRP_IP_BYTES_COUNT = 4;
-+
-+const std::string IpRange::PATTERN_RANGE_EXPRESSION = "[[:space:]]*(.*)[[:space:]]*:[[:space:]]*" + IpAddress::PATTERN_IP_EXPRESSION + "[[:space:]]*-[[:space:]]*" + IpAddress::PATTERN_IP_EXPRESSION + "[[:space:]]*";
-+const regex::Pattern IpRange::PATTERN_RANGE = PATTERN_RANGE_EXPRESSION;
-+
-+const int IpRange::GRP_DESCRIPTION = 1;
-+const int IpRange::GRP_FIRST_IP = 2;
-+const int IpRange::GRP_SECOND_IP = 4;
-+
-+}
-diff --git a/src/core/ip_range.cc b/src/core/ip_range.cc
-new file mode 100644
-index 0000000..3923e53
---- /dev/null
-+++ b/src/core/ip_range.cc
-@@ -0,0 +1,112 @@
-+#include <sstream>
-+#include <string>
-+
-+#include "ip_range.h"
-+#include "utils/pattern.h"
-+#include "regex_namespace.h"
-+
-+namespace core {
-+
-+IpRange* IpRange::parse( const std::string& s ) {
-+ regex::Match m = PATTERN_RANGE.match( s );
-+
-+ if( !m.matches() ) {
-+ std::cout << "!! range format is invalid: '" << s << "'" << std::endl;
-+ return NULL;
-+ }
-+
-+ std::string description = m.group( GRP_DESCRIPTION );
-+ std::string ip1 = m.group( GRP_FIRST_IP );
-+ std::string ip2 = m.group( GRP_SECOND_IP );
-+ IpAddress* from = IpAddress::parse( ip1 );
-+ IpAddress* to = IpAddress::parse( ip2 );
-+
-+ if( !from ) {
-+ std::cout << "!! from is invalid: description='" << description << ", ip1=" << ip1 << ", ip2=" << ip2 << std::endl;
-+ return NULL;
-+ }
-+ if( !to ) {
-+ std::cout << "!! to is invalid: description='" << description << ", ip1=" << ip1 << ", ip2=" << ip2 << std::endl;
-+ return NULL;
-+ }
-+
-+// if( !from || !to || (*to < *from) )
-+// return NULL;
-+
-+ IpRange* r = new IpRange();
-+
-+ r->m_description = description;
-+ r->m_from = from;
-+ r->m_to = to;
-+
-+ if( to && from && (*to < *from) ) {
-+ std::cout << "!! to < from: " << r->to_string() << std::endl;
-+ delete r;
-+ return NULL;
-+ }
-+
-+ return r;
-+}
-+
-+//fast version
-+IpRange* IpRange::parse( const char *s, const int size ){
-+ static char description[256];
-+ static char ip1[24], ip2[24];
-+ int pos=0, post=0, enddesc=size-1;
-+ while (enddesc>0 && s[enddesc]!=':') enddesc--; //find last ':' in the line
-+ while((pos<enddesc) && (unsigned char)s[pos]<=' ') pos++; // strip from start
-+ while ((pos<enddesc)){
-+ if (post<255) description[post++]=s[pos];
-+ pos++;
-+ }
-+ description[post]=0;
-+ if (s[pos]==':') pos++;
-+ post=0;
-+ while ((pos<size) && s[pos]!='-'){
-+ if (post<23) ip1[post++]=s[pos];
-+ pos++;
-+ }
-+ ip1[post]=0;
-+ if (s[pos]=='-'){
-+ pos++;
-+ post=0;
-+ while ((pos<size) && s[pos]>' '){
-+ if (post<23) ip2[post++]=s[pos];
-+ pos++;
-+ }
-+ ip2[post]=0;
-+ } else ip2[0]=0;
-+
-+ IpAddress* from = IpAddress::parse(ip1);
-+ IpAddress* to = IpAddress::parse(ip2);
-+
-+ if( !from ) {
-+ std::cout << "!! from is invalid: description='" << description << ", ip1=" << ip1 << ", ip2=" << ip2 << std::endl;
-+ return NULL;
-+ }
-+ if( !to ) {
-+ std::cout << "!! to is invalid: description='" << description << ", ip1=" << ip1 << ", ip2=" << ip2 << std::endl;
-+ return NULL;
-+ }
-+
-+ IpRange* r = new IpRange();
-+ r->m_description = description;
-+ r->m_from = from;
-+ r->m_to = to;
-+
-+ if( (*to < *from) ) {
-+ std::cout << "!! to < from: " << r->to_string() << std::endl;
-+ delete r;
-+ return NULL;
-+ }
-+
-+ return r;
-+}
-+
-+std::string IpRange::to_string() const {
-+ std::stringstream result;
-+ result << m_description << ": [" << m_from->to_string() << " - " << m_to->to_string() << ']';
-+ return result.str();
-+}
-+
-+}
-diff --git a/src/core/ip_range.h b/src/core/ip_range.h
-new file mode 100644
-index 0000000..1fb2322
---- /dev/null
-+++ b/src/core/ip_range.h
-@@ -0,0 +1,67 @@
-+#ifndef IPRANGE_H
-+#define IPRANGE_H
-+
-+#include <string>
-+
-+#include "printable.h"
-+#include "ip_address.h"
-+#include "utils/pattern.h"
-+#include "regex_namespace.h"
-+
-+namespace core {
-+
-+class IpRange : public Printable {
-+ public: // constants
-+ static const std::string PATTERN_RANGE_EXPRESSION;
-+ static const regex::Pattern PATTERN_RANGE;
-+
-+ static const int GRP_DESCRIPTION;
-+ static const int GRP_FIRST_IP;
-+ static const int GRP_SECOND_IP;
-+
-+ private: // fields
-+ std::string m_description;
-+ const IpAddress* m_from;
-+ const IpAddress* m_to;
-+
-+ private: // dynamic methods
-+ IpRange() : m_description(), m_from(NULL), m_to(NULL) {}
-+
-+ public: // static methods
-+ typedef IpRange* ptr;
-+ static IpRange* parse( const std::string& s );
-+ static IpRange* parse( const char *s, const int size );
-+
-+ public: // dynamic methods
-+ IpRange( IpRange& rng ) { copy(rng); }
-+ IpRange& operator= ( IpRange& rng ) { copy(rng); return *this; }
-+
-+ void copy( IpRange& rng ) {
-+ m_description = rng.m_description;
-+ m_from = (!rng.m_from) ? NULL : new IpAddress( *rng.m_from );
-+ m_to = (!rng.m_to) ? NULL : new IpAddress( *rng.m_to );
-+ }
-+
-+ const std::string& get_description ( void ) const { return m_description; }
-+ const IpAddress* get_from ( void ) const { return m_from; }
-+ const IpAddress* get_to ( void ) const { return m_to; }
-+
-+ void set_description ( const std::string& description ) { m_description = description; }
-+ void set_from ( const IpAddress* from ) { if( m_from ) delete m_from; m_from = new IpAddress( *from ); }
-+ void set_to ( const IpAddress* to ) { if( m_to ) delete m_to; m_to = new IpAddress( *to ); }
-+
-+ bool includes( const IpAddress& ip ) const { return includes((uint32_t)ip); }
-+ bool includes( uint32_t ip ) const { return (*m_from <= ip) && (*m_to >= ip); }
-+
-+ ~IpRange() {
-+ delete m_from;
-+ m_from = NULL;
-+ delete m_to;
-+ m_to = NULL;
-+ }
-+
-+ std::string to_string() const;
-+};
-+
-+}
-+#endif
-diff --git a/src/core/manager.cc b/src/core/manager.cc
-index 2a422c8..9c1d004 100644
---- a/src/core/manager.cc
-+++ b/src/core/manager.cc
-@@ -153,6 +153,24 @@ Manager::handshake_log(const sockaddr* sa, int msg, int err, const torrent::Hash
- }
- }
-
-+uint32_t
-+Manager::filter_ip(const sockaddr* sa) {
-+ IpRange* r = NULL;
-+ // if something's wrong with filter or address it's gonna be allowed
-+ if( m_ipFilter && sa ) {
-+ const rak::socket_address* socketAddress = rak::socket_address::cast_from(sa);
-+ if( socketAddress->is_valid() && (socketAddress->family() == rak::socket_address::af_inet) )
-+ r = m_ipFilter->find_range( socketAddress->sa_inet()->address_h() );
-+ if( r )
-+ m_logComplete.push_front("Address '" + socketAddress->address_str() + "' is rejected by IP filter range '" + r->to_string());
-+ else
-+ if( rpc::call_command_value("get_handshake_log") )
-+ m_logComplete.push_front("IP Filter allowed connection with '" + socketAddress->address_str() + "'");
-+ }
-+ return (r==NULL);
-+}
-+
-+
- void
- Manager::push_log(const char* msg) {
- m_logImportant.push_front(msg);
-@@ -160,7 +178,8 @@ Manager::push_log(const char* msg) {
- }
-
- Manager::Manager() :
-- m_hashingView(NULL)
-+ m_hashingView(NULL),
-+ m_ipFilter(NULL)
- // m_pollManager(NULL) {
- {
- m_downloadStore = new DownloadStore();
-@@ -181,6 +200,8 @@ Manager::~Manager() {
- delete m_downloadStore;
- delete m_httpQueue;
- delete m_fileStatusCache;
-+
-+ set_ip_filter( NULL );
- }
-
- void
-@@ -226,6 +247,7 @@ Manager::initialize_second() {
- CurlStack::global_init();
-
- torrent::connection_manager()->set_signal_handshake_log(sigc::mem_fun(this, &Manager::handshake_log));
-+ torrent::connection_manager()->set_filter(sigc::mem_fun(this, &Manager::filter_ip));
- }
-
- void
-@@ -585,4 +607,13 @@ Manager::receive_hashing_changed() {
- }
- }
-
-+void Manager::reload_ip_filter(void) {
-+ if( m_ipFilter ) {
-+ push_log("Reloading IP filter");
-+ m_ipFilter->reload();
-+ std::stringstream logMsg("IpFilter reloaded with ");
-+ logMsg << m_ipFilter->size() << " ranges total. " << m_ipFilter->get_merges() << " ranges were merged.";
-+ push_log( logMsg.str().c_str() );
-+}
-+}
- }
-diff --git a/src/core/manager.h b/src/core/manager.h
-index 16902af..ac01981 100644
---- a/src/core/manager.h
-+++ b/src/core/manager.h
-@@ -47,6 +47,8 @@
- #include "range_map.h"
- #include "log.h"
-
-+#include "ip_filter.h"
-+
- namespace torrent {
- class Bencode;
- }
-@@ -118,6 +120,15 @@ public:
-
- void handshake_log(const sockaddr* sa, int msg, int err, const torrent::HashString* hash);
-
-+ uint32_t filter_ip(const sockaddr* sa);
-+
-+ void set_ip_filter( IpFilter* ipFilter ) {
-+ IpFilter* old = m_ipFilter;
-+ m_ipFilter = ipFilter;
-+ if( old ) delete old;
-+ }
-+ void reload_ip_filter(void);
-+
- static const int create_start = 0x1;
- static const int create_tied = 0x2;
- static const int create_quiet = 0x4;
-@@ -154,6 +165,8 @@ private:
-
- Log m_logImportant;
- Log m_logComplete;
-+
-+ IpFilter* m_ipFilter;
- };
-
- // Meh, cleanup.
-diff --git a/src/core/printable.h b/src/core/printable.h
-new file mode 100644
-index 0000000..8520af4
---- /dev/null
-+++ b/src/core/printable.h
-@@ -0,0 +1,16 @@
-+#ifndef PRINTABLE_H
-+#define PRINTABLE_H
-+
-+#include <iostream>
-+
-+class Printable {
-+ public:
-+ virtual std::string to_string() const = 0;
-+};
-+
-+template<typename _CharT,class _Traits> inline std::basic_ostream<_CharT,_Traits>&
-+ operator<<( std::basic_ostream<_CharT,_Traits>& out, const Printable& val) {
-+ return out << val.to_string();
-+}
-+
-+#endif
-diff --git a/src/core/regex_namespace.h b/src/core/regex_namespace.h
-new file mode 100644
-index 0000000..6e10b3c
---- /dev/null
-+++ b/src/core/regex_namespace.h
-@@ -0,0 +1,6 @@
-+#ifndef REGEXNAMESPACE_H
-+#define REGEXNAMESPACE_H
-+
-+namespace regex = utils;
-+
-+#endif
-diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am
-index 55ea9ff..cdad48a 100644
---- a/src/utils/Makefile.am
-+++ b/src/utils/Makefile.am
-@@ -9,6 +9,8 @@ libsub_utils_a_SOURCES = \
- lockfile.cc \
- lockfile.h \
- socket_fd.cc \
-- socket_fd.h
-+ socket_fd.h \
-+ pattern.cc \
-+ pattern.h
-
- INCLUDES = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir)
-diff --git a/src/utils/Makefile.in b/src/utils/Makefile.in
-index a684a9c..5424965 100644
---- a/src/utils/Makefile.in
-+++ b/src/utils/Makefile.in
-@@ -58,7 +58,7 @@ libsub_utils_a_AR = $(AR) $(ARFLAGS)
- libsub_utils_a_LIBADD =
- am_libsub_utils_a_OBJECTS = directory.$(OBJEXT) \
- file_status_cache.$(OBJEXT) lockfile.$(OBJEXT) \
-- socket_fd.$(OBJEXT)
-+ socket_fd.$(OBJEXT) pattern.$(OBJEXT)
- libsub_utils_a_OBJECTS = $(am_libsub_utils_a_OBJECTS)
- DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
- depcomp = $(SHELL) $(top_srcdir)/depcomp
-@@ -220,7 +220,9 @@ libsub_utils_a_SOURCES = \
- lockfile.cc \
- lockfile.h \
- socket_fd.cc \
-- socket_fd.h
-+ socket_fd.h \
-+ pattern.cc \
-+ pattern.h
-
- INCLUDES = -I$(srcdir) -I$(srcdir)/.. -I$(top_srcdir)
- all: all-am
-@@ -275,6 +277,7 @@ distclean-compile:
- @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_status_cache.Po@am__quote@
- @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lockfile.Po@am__quote@
- @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket_fd.Po@am__quote@
-+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pattern.@am__quote@
-
- .cc.o:
- @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
-diff --git a/src/utils/pattern.cc b/src/utils/pattern.cc
-new file mode 100644
-index 0000000..c44bb38
---- /dev/null
-+++ b/src/utils/pattern.cc
-@@ -0,0 +1,79 @@
-+#include <string>
-+#include <sys/types.h>
-+#include <ctype.h>
-+#include <regex.h>
-+
-+#include "pattern.h"
-+
-+namespace utils {
-+
-+int Pattern::countGroups( const std::string& str ) {
-+ int count1 = 0;
-+ int count2 = 0;
-+
-+ for( size_t index = -1; (index = str.find( '(', index+1 )) != std::string::npos; )
-+ count1++;
-+ for( size_t index = -1; (index = str.find( ')', index+1 )) != std::string::npos; )
-+ count2++;
-+
-+ return (count1 < count2) ? count1 : count2;
-+}
-+
-+Pattern::Pattern( const std::string& pattern, Flags flags ) : lastResult(-1),
-+ preg(NULL) {
-+ int regFlags = REG_EXTENDED | REG_ICASE | REG_NEWLINE;
-+ if( !(flags & CASE_SENSITIVE) )
-+ regFlags ^= REG_ICASE;
-+ if( (flags & DOT_MATCH_NEWLINE) )
-+ regFlags ^= REG_NEWLINE;
-+
-+ preg = new regex_t;
-+ numGroups = countGroups( pattern ) + 1;
-+
-+ lastResult = regcomp( preg, pattern.c_str(), regFlags );
-+}
-+
-+Pattern::~Pattern() {
-+ regfree( preg );
-+ delete( preg );
-+}
-+
-+std::string Pattern::getLastError() const {
-+ char errBuf[1024];
-+ regerror( lastResult, preg, errBuf, sizeof(errBuf) );
-+ return std::string(errBuf);
-+}
-+
-+Match Pattern::match( const std::string& expression ) const {
-+
-+ regmatch_t* pmatch = new regmatch_t[numGroups];
-+ int res = regexec( preg, expression.c_str(), numGroups, pmatch, 0 );
-+ return Match( expression, numGroups, pmatch, res, getLastError() );
-+}
-+
-+Match::Match( const std::string& expr, int ngroups, regmatch_t* groups, int result, const std::string& message ) :
-+ expression( expr ),
-+ nmatch( ngroups ),
-+ pmatch( groups ),
-+ matchResult( result ),
-+ matchMessage( message ) {
-+}
-+
-+std::string Match::group( int i ) {
-+ if( (i >= nmatch) || (pmatch[i].rm_so < 0) )
-+ return "";
-+
-+ return expression.substr( pmatch[i].rm_so, pmatch[i].rm_eo - pmatch[i].rm_so );
-+}
-+
-+std::string& trim( std::string& str ) {
-+ std::string::iterator it;
-+ for( it = str.begin(); (it < str.end()) && ( isspace(*it) || (*it == 0) ) ; it++ );
-+ str.erase( str.begin(), it );
-+ for( it = str.end()-1; (it >= str.begin()) && ( isspace(*it) || (*it == 0) ) ; it-- );
-+ str.erase( ++it, str.end() );
-+ return str;
-+}
-+
-+}
-+
-diff --git a/src/utils/pattern.h b/src/utils/pattern.h
-new file mode 100644
-index 0000000..99e95a4
---- /dev/null
-+++ b/src/utils/pattern.h
-@@ -0,0 +1,59 @@
-+#ifndef PATTERN_H
-+#define PATTERN_H
-+
-+#include <string>
-+#include <sys/types.h>
-+#include <ctype.h>
-+#include <regex.h>
-+
-+namespace utils {
-+
-+class Match {
-+ public:
-+ Match( const std::string& expr, int ngroups, regmatch_t* pmatch, int matchResult, const std::string& matchMessage );
-+ ~Match() { delete[] pmatch; }
-+ std::string group( int i );
-+ bool found() { return (matchResult == 0); }
-+ bool matches() { return found(); }
-+ std::string& getMatchMessage() { return matchMessage; }
-+
-+ private:
-+ std::string expression;
-+ int nmatch;
-+ regmatch_t* pmatch;
-+ int matchResult;
-+ std::string matchMessage;
-+};
-+
-+class Pattern {
-+ public:
-+ enum Flags {
-+ DEFAULT = 0, // REG_EXTENDED | REG_ICASE | REG_NEWLINE
-+ CASE_SENSITIVE,
-+ DOT_MATCH_NEWLINE
-+ };
-+
-+ public:
-+ Pattern( const std::string& pattern, Flags f = Pattern::DEFAULT );
-+ ~Pattern();
-+ bool isSuccess() { return (lastResult == 0); }
-+ std::string getLastError() const;
-+ Match match( const std::string& expression ) const;
-+
-+ private:
-+ int countGroups( const std::string& str );
-+
-+ private:
-+ regex_t* preg;
-+ int lastResult;
-+ int numGroups;
-+};
-+
-+
-+std::string& trim( std::string& str );
-+
-+}
-+
-+// end of ifdef PATTERN_H
-+#endif
-+
diff --git a/rtorrent-extended/ipv6.patch b/rtorrent-extended/ipv6.patch
deleted file mode 100644
index de72d94..0000000
--- a/rtorrent-extended/ipv6.patch
+++ /dev/null
@@ -1,572 +0,0 @@
-diff --git a/rak/socket_address.h b/rak/socket_address.h
-index 25fdb37..d38533e 100644
---- a/rak/socket_address.h
-+++ b/rak/socket_address.h
-@@ -145,7 +145,7 @@ private:
- };
- };
-
--// Remeber to set the AF_INET.
-+// Remember to set the AF_INET.
-
- class socket_address_inet {
- public:
-@@ -184,6 +184,10 @@ public:
-
- const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
- const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddr; }
-+
-+#ifdef RAK_USE_INET6
-+ socket_address_inet6 to_mapped_address() const;
-+#endif
-
- bool operator == (const socket_address_inet& rhs) const;
- bool operator < (const socket_address_inet& rhs) const;
-@@ -192,6 +196,52 @@ private:
- struct sockaddr_in m_sockaddr;
- };
-
-+#ifdef RAK_USE_INET6
-+// Remember to set the AF_INET6.
-+
-+class socket_address_inet6 {
-+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 std::memcmp(&m_sockaddr.sin6_addr, &in6addr_any, sizeof(in6_addr)) == 0; }
-+
-+ void clear() { std::memset(this, 0, sizeof(socket_address_inet6)); set_family(); }
-+
-+ uint16_t port() const { return ntohs(m_sockaddr.sin6_port); }
-+ uint16_t port_n() const { return m_sockaddr.sin6_port; }
-+ void set_port(uint16_t p) { m_sockaddr.sin6_port = htons(p); }
-+ void set_port_n(uint16_t p) { m_sockaddr.sin6_port = p; }
-+
-+ in6_addr address() const { return m_sockaddr.sin6_addr; }
-+ std::string address_str() const;
-+ bool address_c_str(char* buf, socklen_t size) const;
-+
-+ void set_address(in6_addr a) { m_sockaddr.sin6_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(in6addr_any); }
-+
-+ sa_family_t family() const { return m_sockaddr.sin6_family; }
-+ void set_family() { m_sockaddr.sin6_family = AF_INET6; }
-+
-+ sockaddr* c_sockaddr() { return reinterpret_cast<sockaddr*>(&m_sockaddr); }
-+ sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddr; }
-+
-+ const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
-+ const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddr; }
-+
-+ socket_address normalize_address() const;
-+
-+ bool operator == (const socket_address_inet6& rhs) const;
-+ bool operator < (const socket_address_inet6& rhs) const;
-+
-+private:
-+ struct sockaddr_in6 m_sockaddr;
-+};
-+#endif
-+
- // Unique key for the address, excluding port numbers etc.
- class socket_address_key {
- public:
-@@ -241,8 +291,10 @@ socket_address::is_valid() const {
- switch (family()) {
- case af_inet:
- return sa_inet()->is_valid();
--// case af_inet6:
--// return sa_inet6().is_valid();
-+#ifdef RAK_USE_INET6
-+ case af_inet6:
-+ return sa_inet6()->is_valid();
-+#endif
- default:
- return false;
- }
-@@ -253,6 +305,10 @@ socket_address::is_bindable() const {
- switch (family()) {
- case af_inet:
- return !sa_inet()->is_address_any();
-+#ifdef RAK_USE_INET6
-+ case af_inet6:
-+ return !sa_inet6()->is_address_any();
-+#endif
- default:
- return false;
- }
-@@ -263,6 +319,10 @@ socket_address::is_address_any() const {
- switch (family()) {
- case af_inet:
- return sa_inet()->is_address_any();
-+#ifdef RAK_USE_INET6
-+ case af_inet6:
-+ return sa_inet6()->is_address_any();
-+#endif
- default:
- return true;
- }
-@@ -273,6 +333,10 @@ socket_address::port() const {
- switch (family()) {
- case af_inet:
- return sa_inet()->port();
-+#ifdef RAK_USE_INET6
-+ case af_inet6:
-+ return sa_inet6()->port();
-+#endif
- default:
- return 0;
- }
-@@ -283,6 +347,10 @@ socket_address::set_port(uint16_t p) {
- switch (family()) {
- case af_inet:
- return sa_inet()->set_port(p);
-+#ifdef RAK_USE_INET6
-+ case af_inet6:
-+ return sa_inet6()->set_port(p);
-+#endif
- default:
- break;
- }
-@@ -293,6 +361,10 @@ socket_address::address_str() const {
- switch (family()) {
- case af_inet:
- return sa_inet()->address_str();
-+#ifdef RAK_USE_INET6
-+ case af_inet6:
-+ return sa_inet6()->address_str();
-+#endif
- default:
- return std::string();
- }
-@@ -303,6 +375,10 @@ socket_address::address_c_str(char* buf, socklen_t size) const {
- switch (family()) {
- case af_inet:
- return sa_inet()->address_c_str(buf, size);
-+#ifdef RAK_USE_INET6
-+ case af_inet6:
-+ return sa_inet6()->address_c_str(buf, size);
-+#endif
- default:
- return false;
- }
-@@ -314,6 +390,12 @@ socket_address::set_address_c_str(const char* a) {
- sa_inet()->set_family();
- return true;
-
-+#ifdef RAK_USE_INET6
-+ } else if (sa_inet6()->set_address_c_str(a)) {
-+ sa_inet6()->set_family();
-+ return true;
-+#endif
-+
- } else {
- return false;
- }
-@@ -325,6 +407,10 @@ socket_address::length() const {
- switch(family()) {
- case af_inet:
- return sizeof(sockaddr_in);
-+#ifdef RAK_USE_INET6
-+ case af_inet6:
-+ return sizeof(sockaddr_in6);
-+#endif
- default:
- return 0;
- }
-@@ -349,8 +435,10 @@ socket_address::operator == (const socket_address& rhs) const {
- switch (family()) {
- case af_inet:
- return *sa_inet() == *rhs.sa_inet();
--// case af_inet6:
--// return *sa_inet6() == *rhs.sa_inet6();
-+#ifdef RAK_USE_INET6
-+ case af_inet6:
-+ return *sa_inet6() == *rhs.sa_inet6();
-+#endif
- default:
- throw std::logic_error("socket_address::operator == (rhs) invalid type comparison.");
- }
-@@ -364,8 +452,10 @@ socket_address::operator < (const socket_address& rhs) const {
- switch (family()) {
- case af_inet:
- return *sa_inet() < *rhs.sa_inet();
--// case af_inet6:
--// return *sa_inet6() < *rhs.sa_inet6();
-+#ifdef RAK_USE_INET6
-+ case af_inet6:
-+ return *sa_inet6() < *rhs.sa_inet6();
-+#endif
- default:
- throw std::logic_error("socket_address::operator < (rhs) invalid type comparison.");
- }
-@@ -391,6 +481,23 @@ socket_address_inet::set_address_c_str(const char* a) {
- return inet_pton(AF_INET, a, &m_sockaddr.sin_addr);
- }
-
-+#ifdef RAK_USE_INET6
-+inline socket_address_inet6
-+socket_address_inet::to_mapped_address() const {
-+ uint32_t addr32[4];
-+ addr32[0] = 0;
-+ addr32[1] = 0;
-+ addr32[2] = htonl(0xffff);
-+ addr32[3] = m_sockaddr.sin_addr.s_addr;
-+
-+ socket_address_inet6 sa;
-+ sa.clear();
-+ sa.set_address(*reinterpret_cast<in6_addr *>(addr32));
-+ sa.set_port_n(m_sockaddr.sin_port);
-+ return sa;
-+}
-+#endif
-+
- inline bool
- socket_address_inet::operator == (const socket_address_inet& rhs) const {
- return
-@@ -406,6 +513,59 @@ socket_address_inet::operator < (const socket_address_inet& rhs) const {
- m_sockaddr.sin_port < rhs.m_sockaddr.sin_port);
- }
-
-+#ifdef RAK_USE_INET6
-+
-+inline std::string
-+socket_address_inet6::address_str() const {
-+ char buf[INET6_ADDRSTRLEN];
-+
-+ if (!address_c_str(buf, INET6_ADDRSTRLEN))
-+ return std::string();
-+
-+ return std::string(buf);
-+}
-+
-+inline bool
-+socket_address_inet6::address_c_str(char* buf, socklen_t size) const {
-+ return inet_ntop(family(), &m_sockaddr.sin6_addr, buf, size);
-+}
-+
-+inline bool
-+socket_address_inet6::set_address_c_str(const char* a) {
-+ return inet_pton(AF_INET6, a, &m_sockaddr.sin6_addr);
-+}
-+
-+inline socket_address
-+socket_address_inet6::normalize_address() const {
-+ const uint32_t *addr32 = reinterpret_cast<const uint32_t *>(m_sockaddr.sin6_addr.s6_addr);
-+ if (addr32[0] == 0 && addr32[1] == 0 && addr32[2] == htonl(0xffff)) {
-+ socket_address addr4;
-+ addr4.sa_inet()->set_family();
-+ addr4.sa_inet()->set_address_n(addr32[3]);
-+ addr4.sa_inet()->set_port_n(m_sockaddr.sin6_port);
-+ return addr4;
-+ }
-+ return *reinterpret_cast<const socket_address*>(this);
-+}
-+
-+inline bool
-+socket_address_inet6::operator == (const socket_address_inet6& rhs) const {
-+ return
-+ memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr)) == 0 &&
-+ m_sockaddr.sin6_port == rhs.m_sockaddr.sin6_port;
-+}
-+
-+inline bool
-+socket_address_inet6::operator < (const socket_address_inet6& rhs) const {
-+ int addr_comp = memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr));
-+ return
-+ addr_comp < 0 ||
-+ (addr_comp == 0 ||
-+ m_sockaddr.sin6_port < rhs.m_sockaddr.sin6_port);
-+}
-+
-+#endif
-+
- }
-
- #endif
-diff --git a/src/command_peer.cc b/src/command_peer.cc
-index 9708a8d..0aae8e0 100644
---- a/src/command_peer.cc
-+++ b/src/command_peer.cc
-@@ -68,7 +68,13 @@ retrieve_p_id_html(torrent::Peer* peer) {
-
- torrent::Object
- retrieve_p_address(torrent::Peer* peer) {
-- return rak::socket_address::cast_from(peer->peer_info()->socket_address())->address_str();
-+ const rak::socket_address *addr = rak::socket_address::cast_from(peer->peer_info()->socket_address());
-+#ifdef RAK_USE_INET6
-+ if (addr->family() == rak::socket_address::af_inet6)
-+ return "[" + addr->address_str() + "]";
-+ else
-+#endif
-+ return addr->address_str();
- }
-
- torrent::Object
-diff --git a/src/core/curl_get.cc b/src/core/curl_get.cc
-index f0767b7..4a904e1 100644
---- a/src/core/curl_get.cc
-+++ b/src/core/curl_get.cc
-@@ -88,8 +88,20 @@ CurlGet::start() {
- curl_easy_setopt(m_handle, CURLOPT_NOSIGNAL, (long)1);
- curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, (long)1);
- curl_easy_setopt(m_handle, CURLOPT_MAXREDIRS, (long)5);
-+
-+ // Even when IPv6-enabled, we don't want to use CURL_IPRESOLVE_WHATEVER,
-+ // since that will usually prefer connecting over IPv6 to the tracker.
-+ // Since it's usually a lot easier to find our global IPv6 address
-+ // (if we have one) than our global IPv4 address, we prefer connecting
-+ // over IPv4 if we can, so that the tracker will get our IPv4 address
-+ // that way. If the resolve fails, CurlStack will call retry_ipv6()
-+ // on us and we'll make a second attempt with CURL_IPRESOLVE_V6.
- curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
-+
- curl_easy_setopt(m_handle, CURLOPT_ENCODING, "");
-+#ifdef RAK_USE_INET6
-+ m_ipv6 = false;
-+#endif
-
- m_stack->add_get(this);
- }
-@@ -107,6 +119,17 @@ CurlGet::close() {
- m_handle = NULL;
- }
-
-+#ifdef RAK_USE_INET6
-+void
-+CurlGet::retry_ipv6() {
-+ CURL* nhandle = curl_easy_duphandle(m_handle);
-+ curl_easy_setopt(nhandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
-+ curl_easy_cleanup(m_handle);
-+ m_handle = nhandle;
-+ m_ipv6 = true;
-+}
-+#endif
-+
- void
- CurlGet::receive_timeout() {
- return m_stack->transfer_done(m_handle, "Timed out");
-diff --git a/src/core/curl_get.h b/src/core/curl_get.h
-index 1d3a0d5..2b7836b 100644
---- a/src/core/curl_get.h
-+++ b/src/core/curl_get.h
-@@ -56,6 +56,10 @@ public:
-
- void start();
- void close();
-+#ifdef RAK_USE_INET6
-+ bool is_using_ipv6() { return m_ipv6; }
-+ void retry_ipv6();
-+#endif
-
- bool is_busy() const { return m_handle; }
- bool is_active() const { return m_active; }
-@@ -74,6 +78,9 @@ private:
- void receive_timeout();
-
- bool m_active;
-+#ifdef RAK_USE_INET6
-+ bool m_ipv6;
-+#endif
-
- rak::priority_item m_taskTimeout;
-
-diff --git a/src/core/curl_stack.cc b/src/core/curl_stack.cc
-index 3adfab5..915b11a 100644
---- a/src/core/curl_stack.cc
-+++ b/src/core/curl_stack.cc
-@@ -111,6 +111,21 @@ CurlStack::receive_action(CurlSocket* socket, int events) {
- if (msg->msg != CURLMSG_DONE)
- throw torrent::internal_error("CurlStack::receive_action() msg->msg != CURLMSG_DONE.");
-
-+#ifdef RAK_USE_INET6
-+ if (msg->data.result == CURLE_COULDNT_RESOLVE_HOST) {
-+ iterator itr = std::find_if(begin(), end(), rak::equal(msg->easy_handle, std::mem_fun(&CurlGet::handle)));
-+
-+ if (itr == end())
-+ throw torrent::internal_error("Could not find CurlGet when calling CurlStack::receive_action.");
-+
-+ if (!(*itr)->is_using_ipv6()) {
-+ (*itr)->retry_ipv6();
-+ if (curl_multi_add_handle((CURLM*)m_handle, (*itr)->handle()) > 0)
-+ throw torrent::internal_error("Error calling curl_multi_add_handle.");
-+ continue;
-+ }
-+ } else
-+#endif
- transfer_done(msg->easy_handle, msg->data.result == CURLE_OK ? NULL : curl_easy_strerror(msg->data.result));
- }
-
-diff --git a/src/display/window_peer_list.cc b/src/display/window_peer_list.cc
-index 628b74b..63a22ef 100644
---- a/src/display/window_peer_list.cc
-+++ b/src/display/window_peer_list.cc
-@@ -68,7 +68,11 @@ WindowPeerList::redraw() {
- int x = 2;
- int y = 0;
-
-- m_canvas->print(x, y, "IP"); x += 16;
-+#ifdef RAK_USE_INET6
-+ m_canvas->print(x, y, "IP"); x += 25;
-+#else
-+ m_canvas->print(x, y, "IP"); x += 16;
-+#endif
- m_canvas->print(x, y, "UP"); x += 7;
- m_canvas->print(x, y, "DOWN"); x += 7;
- m_canvas->print(x, y, "PEER"); x += 7;
-@@ -99,10 +103,21 @@ WindowPeerList::redraw() {
-
- x = 0;
-
-+ std::string ip_address = rak::socket_address::cast_from(p->address())->address_str();
-+#ifdef RAK_USE_INET6
-+ if (ip_address.size() >= 24) {
-+ ip_address.replace(ip_address.begin() + 21, ip_address.end(), "...");
-+ }
-+#endif
-+
- m_canvas->print(x, y, "%c %s",
- range.first == *m_focus ? '*' : ' ',
-- rak::socket_address::cast_from(p->address())->address_str().c_str());
-+ ip_address.c_str());
-+#ifdef RAK_USE_INET6
-+ x += 27;
-+#else
- x += 18;
-+#endif
-
- m_canvas->print(x, y, "%.1f", (double)p->up_rate()->rate() / 1024); x += 7;
- m_canvas->print(x, y, "%.1f", (double)p->down_rate()->rate() / 1024); x += 7;
-diff --git a/src/utils/socket_fd.cc b/src/utils/socket_fd.cc
-index 414d4f7..2545304 100644
---- a/src/utils/socket_fd.cc
-+++ b/src/utils/socket_fd.cc
-@@ -71,6 +71,11 @@ SocketFd::set_priority(priority_type p) {
- check_valid();
- int opt = p;
-
-+#ifdef RAK_USE_INET6
-+ if (m_ipv6_socket)
-+ return setsockopt(m_fd, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) == 0;
-+ else
-+#endif
- return setsockopt(m_fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) == 0;
- }
-
-@@ -130,12 +135,36 @@ SocketFd::get_error() const {
-
- bool
- SocketFd::open_stream() {
-+#ifdef RAK_USE_INET6
-+ m_fd = socket(rak::socket_address::pf_inet6, SOCK_STREAM, IPPROTO_TCP);
-+ if (m_fd == -1) {
-+ m_ipv6_socket = false;
-+ return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1;
-+ }
-+ m_ipv6_socket = true;
-+
-+ int zero = 0;
-+ return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
-+#else
- return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1;
-+#endif
- }
-
- bool
- SocketFd::open_datagram() {
-+#ifdef RAK_USE_INET6
-+ m_fd = socket(rak::socket_address::pf_inet6, SOCK_DGRAM, 0);
-+ if (m_fd == -1) {
-+ m_ipv6_socket = false;
-+ return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1;
-+ }
-+ m_ipv6_socket = true;
-+
-+ int zero = 0;
-+ return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
-+#else
- return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1;
-+#endif
- }
-
- bool
-@@ -167,10 +196,34 @@ bool
- SocketFd::connect(const rak::socket_address& sa) {
- check_valid();
-
-+#ifdef RAK_USE_INET6
-+ if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
-+ rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
-+ return !::connect(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped)) || errno == EINPROGRESS;
-+ }
-+#endif
- return !::connect(m_fd, sa.c_sockaddr(), sa.length()) || errno == EINPROGRESS;
- }
-
- bool
-+SocketFd::getsockname(rak::socket_address *sa) {
-+ check_valid();
-+
-+ socklen_t len = sizeof(rak::socket_address);
-+ if (::getsockname(m_fd, sa->c_sockaddr(), &len)) {
-+ return false;
-+ }
-+
-+#ifdef RAK_USE_INET6
-+ if (m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) {
-+ *sa = sa->sa_inet6()->normalize_address();
-+ }
-+#endif
-+
-+ return true;
-+}
-+
-+bool
- SocketFd::listen(int size) {
- check_valid();
-
-@@ -182,7 +235,18 @@ SocketFd::accept(rak::socket_address* sa) {
- check_valid();
- socklen_t len = sizeof(rak::socket_address);
-
-+#ifdef RAK_USE_INET6
-+ if (sa == NULL) {
-+ return SocketFd(::accept(m_fd, NULL, &len));
-+ }
-+ int fd = ::accept(m_fd, sa->c_sockaddr(), &len);
-+ if (fd != -1 && m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) {
-+ *sa = sa->sa_inet6()->normalize_address();
-+ }
-+ return SocketFd(fd);
-+#else
- return SocketFd(::accept(m_fd, sa != NULL ? sa->c_sockaddr() : NULL, &len));
-+#endif
- }
-
- // unsigned int
-diff --git a/src/utils/socket_fd.h b/src/utils/socket_fd.h
-index 7898712..35d2eda 100644
---- a/src/utils/socket_fd.h
-+++ b/src/utils/socket_fd.h
-@@ -80,6 +80,7 @@ public:
- bool bind(const rak::socket_address& sa);
- bool bind(const rak::socket_address& sa, unsigned int length);
- bool connect(const rak::socket_address& sa);
-+ bool getsockname(rak::socket_address* sa);
-
- bool listen(int size);
- SocketFd accept(rak::socket_address* sa);
-@@ -91,6 +92,9 @@ private:
- inline void check_valid() const;
-
- int m_fd;
-+#ifdef RAK_USE_INET6
-+ bool m_ipv6_socket;
-+#endif
- };
-
- }
diff --git a/rtorrent-extended/karabaja_mod.patch b/rtorrent-extended/karabaja_mod.patch
deleted file mode 100644
index e309fff..0000000
--- a/rtorrent-extended/karabaja_mod.patch
+++ /dev/null
@@ -1,438 +0,0 @@
-diff --git a/src/display/canvas.cc b/src/display/canvas.cc
-index 4e621df..35244eb 100644
---- a/src/display/canvas.cc
-+++ b/src/display/canvas.cc
-@@ -92,6 +92,14 @@ Canvas::initialize() {
- m_isInitialized = true;
-
- initscr();
-+
-+ //colors
-+ start_color();
-+ use_default_colors();
-+ init_pair(1, COLOR_RED, -1);
-+ init_pair(2, COLOR_YELLOW, -1);
-+ init_pair(3, COLOR_GREEN, -1);
-+
- raw();
- noecho();
- nodelay(stdscr, TRUE);
-diff --git a/src/display/utils.cc b/src/display/utils.cc
-index d2f1af4..400b940 100644
---- a/src/display/utils.cc
-+++ b/src/display/utils.cc
-@@ -34,6 +34,9 @@
- // Skomakerveien 33
- // 3185 Skoppum, NORWAY
-
-+// interface modifications by karabaja4
-+// <karabaja4@archlinux.us>
-+
- #include "config.h"
-
- #include <cstring>
-@@ -52,6 +55,10 @@
- #include <torrent/data/file_list.h>
- #include <torrent/peer/client_info.h>
-
-+//peers
-+#include <torrent/peer/connection_list.h>
-+#include <torrent/peer/peer_list.h>
-+
- #include "core/download.h"
- #include "core/manager.h"
- #include "rpc/parse_commands.h"
-@@ -96,9 +103,9 @@ print_hhmmss_local(char* first, char* last, time_t t) {
- char*
- print_ddhhmm(char* first, char* last, time_t t) {
- if (t / (24 * 3600) < 100)
-- return print_buffer(first, last, "%2id %2i:%02i", (int)t / (24 * 3600), ((int)t / 3600) % 24, ((int)t / 60) % 60);
-+ return print_buffer(first, last, "%id:%ih:%im", (int)t / (24 * 3600), ((int)t / 3600) % 24, ((int)t / 60) % 60);
- else
-- return print_buffer(first, last, "--d --:--");
-+ return print_buffer(first, last, "--d:--h:--m");
- }
-
- char*
-@@ -127,91 +134,121 @@ print_address(char* first, char* last, const sockaddr* sa) {
-
- char*
- print_download_title(char* first, char* last, core::Download* d) {
-- return print_buffer(first, last, " %s", d->download()->name().c_str());
-+
-+ first = print_buffer(first, last, " %s", d->download()->name().c_str());
-+
-+ if (first > last)
-+ throw torrent::internal_error("print_download_status(...) wrote past end of the buffer.");
-+
-+ return first;
-+
- }
-
- char*
--print_download_info(char* first, char* last, core::Download* d) {
-- if (!d->download()->is_open())
-- first = print_buffer(first, last, "[CLOSED] ");
-- else if (!d->download()->is_active())
-- first = print_buffer(first, last, "[OPEN] ");
-- else
-- first = print_buffer(first, last, " ");
-+print_download_title_extra(char* first, char* last, core::Download* d) {
-+
-+ if (d->is_hash_checking()) {
-+ first = print_buffer(first, last, " | Checking hash [%2i%%]",
-+ (d->download()->chunks_hashed() * 100) / d->download()->file_list()->size_chunks());
-+ }
-+ else if (d->tracker_list()->has_active() && d->tracker_list()->focus() < d->tracker_list()->end()) {
-+
-+ torrent::TrackerList* tl = d->tracker_list();
-+ char status[128];
-+
-+ (*tl->focus())->get_status(status, sizeof(status));
-+ first = print_buffer(first, last, " | Tracker[%i:%i]: Connecting to %s %s",
-+ (*tl->focus())->group(), tl->focus_index(), (*tl->focus())->url().c_str(), status);
-+ }
-+ else if (!d->message().empty()) {
-+ first = print_buffer(first, last, " | %s", d->message().c_str());
-+ }
-+ else {
-+ *first = '\0';
-+ }
-+
-+ if (first > last)
-+ throw torrent::internal_error("print_download_status(...) wrote past end of the buffer.");
-+
-+ return first;
-+
-+}
-
-- if (d->is_done())
-- first = print_buffer(first, last, "done %10.1f MB", (double)d->download()->file_list()->size_bytes() / (double)(1 << 20));
-- else
-- first = print_buffer(first, last, "%6.1f / %6.1f MB",
-- (double)d->download()->bytes_done() / (double)(1 << 20),
-- (double)d->download()->file_list()->size_bytes() / (double)(1 << 20));
--
-- first = print_buffer(first, last, " Rate: %5.1f / %5.1f KB Uploaded: %7.1f MB",
-- (double)d->download()->up_rate()->rate() / (1 << 10),
-- (double)d->download()->down_rate()->rate() / (1 << 10),
-- (double)d->download()->up_rate()->total() / (1 << 20));
--
-- if (d->download()->is_active() && !d->is_done()) {
-- first = print_buffer(first, last, " ");
-- first = print_download_percentage_done(first, last, d);
--
-- first = print_buffer(first, last, " ");
-- first = print_download_time_left(first, last, d);
-- } else {
-- first = print_buffer(first, last, " ");
-- }
-+char*
-+print_download_info(char* first, char* last, core::Download* d) {
-+
-+ if (!d->download()->is_open()) {
-+ first = print_buffer(first, last, " CLOSED |");
-+ }
-+ else if (!d->download()->is_active()) {
-+ first = print_buffer(first, last, " PAUSED |");
-+ }
-+ else {
-+ first = print_buffer(first, last, " ACTIVE |");
-+ }
-+
-+ if (d->is_done()) {
-+ first = print_buffer(first, last, " finished %.1f MB [100%%] |", (double)d->download()->file_list()->size_bytes() / (double)(1 << 20));
-+ }
-+ else {
-+ first = print_buffer(first, last, " %.1f / %.1f MB [%i%%] |",
-+ (double)d->download()->bytes_done() / (double)(1 << 20),
-+ (double)d->download()->file_list()->size_bytes() / (double)(1 << 20),
-+ (int)(((double)d->download()->bytes_done() / (double)d->download()->file_list()->size_bytes()) * 100));
-+ }
-+
-+ //speed
-+ first = print_buffer(first, last, " Speed: %.1f / %.1f KB",
-+ (double)d->download()->down_rate()->rate() / (1 << 10),
-+ (double)d->download()->up_rate()->rate() / (1 << 10));
-+
-+ if (d->download()->is_active() && !d->is_done()) {
-+
-+ //peers
-+ first = print_buffer(first, last, " | Peers: %i(%i)",
-+ (int)d->download()->connection_list()->size(),
-+ (int)d->download()->peer_list()->available_list_size());
-+
-+ //eta
-+ first = print_buffer(first, last, " | ETA: ");
-+ first = print_download_time_left(first, last, d);
-+
-+ }
-+
-+ if (first > last)
-+ throw torrent::internal_error("print_download_info(...) wrote past end of the buffer.");
-+
-+ return first;
-+}
-
-- first = print_buffer(first, last, " [%c%c R: %4.2f",
-- rpc::call_command_string("d.get_tied_to_file", rpc::make_target(d)).empty() ? ' ' : 'T',
-- rpc::call_command_value("d.get_ignore_commands", rpc::make_target(d)) == 0 ? ' ' : 'I',
-- (double)rpc::call_command_value("d.get_ratio", rpc::make_target(d)) / 1000.0);
-+char*
-+print_download_info_extra(char* first, char* last, core::Download* d) {
-+
-+ first = print_buffer(first, last, "[%c%c R: %4.2f",
-+ rpc::call_command_string("d.get_tied_to_file", rpc::make_target(d)).empty() ? ' ' : 'T',
-+ rpc::call_command_value("d.get_ignore_commands", rpc::make_target(d)) == 0 ? ' ' : 'I',
-+ (double)rpc::call_command_value("d.get_ratio", rpc::make_target(d)) / 1000.0);
-
-- if (d->priority() != 2)
-- first = print_buffer(first, last, " %s", rpc::call_command_string("d.get_priority_str", rpc::make_target(d)).c_str());
-+ if (d->priority() != 2)
-+ first = print_buffer(first, last, " %s", rpc::call_command_string("d.get_priority_str", rpc::make_target(d)).c_str());
-
-- if (!d->bencode()->get_key("rtorrent").get_key_string("throttle_name").empty())
-- first = print_buffer(first, last , " %s", rpc::call_command_string("d.get_throttle_name", rpc::make_target(d)).c_str());
-+ if (!d->bencode()->get_key("rtorrent").get_key_string("throttle_name").empty())
-+ first = print_buffer(first, last , " %s", rpc::call_command_string("d.get_throttle_name", rpc::make_target(d)).c_str());
-
-- first = print_buffer(first, last , "]");
-+ first = print_buffer(first, last , "]");
-
-- if (first > last)
-- throw torrent::internal_error("print_download_info(...) wrote past end of the buffer.");
-+ if (first > last)
-+ throw torrent::internal_error("print_download_info(...) wrote past end of the buffer.");
-
-- return first;
-+ return first;
- }
-
- char*
- print_download_status(char* first, char* last, core::Download* d) {
-- if (d->is_active())
-- ;
-- else if (rpc::call_command_value("d.get_hashing", rpc::make_target(d)) != 0)
-- first = print_buffer(first, last, "Hashing: ");
-- else if (!d->is_active())
-- first = print_buffer(first, last, "Inactive: ");
--
-- if (d->is_hash_checking()) {
-- first = print_buffer(first, last, "Checking hash [%2i%%]",
-- (d->download()->chunks_hashed() * 100) / d->download()->file_list()->size_chunks());
--
-- } else if (d->tracker_list()->has_active() && d->tracker_list()->focus() < d->tracker_list()->end()) {
-- torrent::TrackerList* tl = d->tracker_list();
-- char status[128];
--
-- (*tl->focus())->get_status(status, sizeof(status));
-- first = print_buffer(first, last, "Tracker[%i:%i]: Connecting to %s %s",
-- (*tl->focus())->group(), tl->focus_index(), (*tl->focus())->url().c_str(), status);
--
-- } else if (!d->message().empty()) {
-- first = print_buffer(first, last, "%s", d->message().c_str());
--
-- } else {
-- *first = '\0';
-- }
--
-- if (first > last)
-- throw torrent::internal_error("print_download_status(...) wrote past end of the buffer.");
-
-+ *first = '\0';
- return first;
-+
- }
-
- char*
-@@ -219,7 +256,7 @@ print_download_time_left(char* first, char* last, core::Download* d) {
- uint32_t rate = d->download()->down_rate()->rate();
-
- if (rate < 512)
-- return print_buffer(first, last, "--d --:--");
-+ return print_buffer(first, last, "--d:--h:--m");
-
- time_t remaining = (d->download()->file_list()->size_bytes() - d->download()->bytes_done()) / (rate & ~(uint32_t)(512 - 1));
-
-@@ -230,9 +267,9 @@ char*
- print_download_percentage_done(char* first, char* last, core::Download* d) {
- if (!d->is_open() || d->is_done())
- //return print_buffer(first, last, "[--%%]");
-- return print_buffer(first, last, " ");
-+ return print_buffer(first, last, " ");
- else
-- return print_buffer(first, last, "[%2u%%]", (d->download()->file_list()->completed_chunks() * 100) / d->download()->file_list()->size_chunks());
-+ return print_buffer(first, last, "%u%%", (d->download()->file_list()->completed_chunks() * 100) / d->download()->file_list()->size_chunks());
- }
-
- char*
-@@ -255,19 +292,19 @@ print_client_version(char* first, char* last, const torrent::ClientInfo& clientI
-
- char*
- print_status_info(char* first, char* last) {
-- if (!torrent::up_throttle_global()->is_throttled())
-+ if (!torrent::down_throttle_global()->is_throttled())
- first = print_buffer(first, last, "[Throttle off");
- else
-- first = print_buffer(first, last, "[Throttle %3i", torrent::up_throttle_global()->max_rate() / 1024);
-+ first = print_buffer(first, last, "[Throttle %3i", torrent::down_throttle_global()->max_rate() / 1024);
-
-- if (!torrent::down_throttle_global()->is_throttled())
-+ if (!torrent::up_throttle_global()->is_throttled())
- first = print_buffer(first, last, "/off KB]");
- else
-- first = print_buffer(first, last, "/%3i KB]", torrent::down_throttle_global()->max_rate() / 1024);
-+ first = print_buffer(first, last, "/%3i KB]", torrent::up_throttle_global()->max_rate() / 1024);
-
- first = print_buffer(first, last, " [Rate %5.1f/%5.1f KB]",
-- (double)torrent::up_rate()->rate() / 1024.0,
-- (double)torrent::down_rate()->rate() / 1024.0);
-+ (double)torrent::down_rate()->rate() / 1024.0,
-+ (double)torrent::up_rate()->rate() / 1024.0);
-
- first = print_buffer(first, last, " [Port: %i]", (unsigned int)torrent::connection_manager()->listen_port());
-
-diff --git a/src/display/utils.h b/src/display/utils.h
-index 3d69021..c9145dd 100644
---- a/src/display/utils.h
-+++ b/src/display/utils.h
-@@ -66,7 +66,9 @@ char* print_ddhhmm(char* first, char* last, time_t t);
- char* print_ddmmyyyy(char* first, char* last, time_t t);
-
- char* print_download_title(char* first, char* last, core::Download* d);
-+char* print_download_title_extra(char* first, char* last, core::Download* d);
- char* print_download_info(char* first, char* last, core::Download* d);
-+char* print_download_info_extra(char* first, char* last, core::Download* d);
- char* print_download_status(char* first, char* last, core::Download* d);
- char* print_download_time_left(char* first, char* last, core::Download* d);
- char* print_download_percentage_done(char* first, char* last, core::Download* d);
-diff --git a/src/display/window_download_list.cc b/src/display/window_download_list.cc
-index 71efec0..353f6b5 100644
---- a/src/display/window_download_list.cc
-+++ b/src/display/window_download_list.cc
-@@ -34,6 +34,9 @@
- // Skomakerveien 33
- // 3185 Skoppum, NORWAY
-
-+// interface modifications by karabaja4
-+// <karabaja4@archlinux.us>
-+
- #include "config.h"
-
- #include <rak/algorithm.h>
-@@ -81,30 +84,90 @@ WindowDownloadList::redraw() {
- Range range = rak::advance_bidirectional(m_view->begin_visible(),
- m_view->focus() != m_view->end_visible() ? m_view->focus() : m_view->begin_visible(),
- m_view->end_visible(),
-- m_canvas->height() / 3);
-+ (m_canvas->height() - 1) / 3);
-
- // Make sure we properly fill out the last lines so it looks like
- // there are more torrents, yet don't hide it if we got the last one
- // in focus.
- if (range.second != m_view->end_visible())
-- ++range.second;
-+ ++range.second;
-
-- int pos = 1;
-+ int pos = 2;
-
- while (range.first != range.second) {
- char buffer[m_canvas->width() + 1];
- char* position;
- char* last = buffer + m_canvas->width() - 2 + 1;
--
-+ int title_length;
-+
-+ //1 = red
-+ //2 = yellow
-+ //3 = green
-+
-+ //do not print on last lines if cannot show whole torrent
-+ if (pos >= (m_canvas->height() - 1))
-+ break;
-+
-+ //print title
- position = print_download_title(buffer, last, *range.first);
-- m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer);
-+ title_length = strlen(buffer);
-+ m_canvas->print(0, pos, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer);
-+
-+ //title color
-+ if ((*range.first)->is_done()) {
-+ //finished
-+ m_canvas->set_attr(3, pos, (title_length - 1), A_NORMAL, 3);
-+ }
-+ else {
-+ //not finished
-+ m_canvas->set_attr(3, pos, (title_length - 1), A_NORMAL, 2);
-+ }
-+
-+ //print title extra
-+ position = print_download_title_extra(buffer, last, *range.first);
-+
-+ //do not let title extra get off screen
-+ buffer[m_canvas->width() - title_length - 2] = '\0';
-
-+ m_canvas->print((title_length + 2), pos++, "%s", buffer);
-+
-+ //print info
- position = print_download_info(buffer, last, *range.first);
-- m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer);
--
-- position = print_download_status(buffer, last, *range.first);
-- m_canvas->print(0, pos++, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer);
--
-+ m_canvas->print(0, pos, "%c %s", range.first == m_view->focus() ? '*' : ' ', buffer);
-+
-+ //info color
-+ if (!(*range.first)->download()->is_open()) {
-+ //closed
-+ m_canvas->set_attr(3, pos, 6, A_NORMAL, 1);
-+ }
-+ else if (!(*range.first)->download()->is_active()) {
-+ //paused
-+ m_canvas->set_attr(3, pos, 6, A_NORMAL, 2);
-+ }
-+ else {
-+ //active
-+ m_canvas->set_attr(3, pos, 6, A_NORMAL, 3);
-+ }
-+
-+ if ((*range.first)->is_done()) {
-+ //finished
-+ m_canvas->set_attr(12, pos, 8, A_NORMAL, 3);
-+ }
-+
-+ //do not print info extra if it collides with info
-+ if ((strlen(buffer) + 2) <= (m_canvas->width() - 16)) {
-+
-+ //print info extra
-+ position = print_download_info_extra(buffer, last, *range.first);
-+ m_canvas->print((m_canvas->width() - 16), pos++, "%s", buffer);
-+
-+ }
-+ else {
-+ pos++;
-+ }
-+
-+ //skip one line
-+ pos++;
- ++range.first;
- }
- }
-diff --git a/src/display/window_title.cc b/src/display/window_title.cc
-index 300f655..c0e7fe5 100644
---- a/src/display/window_title.cc
-+++ b/src/display/window_title.cc
-@@ -48,6 +48,10 @@ WindowTitle::redraw() {
-
- m_canvas->print(std::max(0, ((int)m_canvas->width() - (int)m_title.size()) / 2 - 4), 0,
- "*** %s ***", m_title.c_str());
-+
-+ //set color in title
-+ m_canvas->set_attr((((int)m_canvas->width() - (int)m_title.size()) / 2 - 4), 0, 3, A_NORMAL, 2);
-+ m_canvas->set_attr( ((((int)m_canvas->width() - (int)m_title.size()) / 2) + (int)m_title.size() + 1), 0, 3, A_NORMAL, 2);
- }
-
- }
diff --git a/rtorrent-extended/magnet_uri.patch b/rtorrent-extended/magnet_uri.patch
deleted file mode 100644
index 32d45f0..0000000
--- a/rtorrent-extended/magnet_uri.patch
+++ /dev/null
@@ -1,228 +0,0 @@
-diff --git a/src/core/download_factory.cc b/src/core/download_factory.cc
-index e2d8ee8..49ac3fa 100644
---- a/src/core/download_factory.cc
-+++ b/src/core/download_factory.cc
-@@ -69,6 +69,12 @@ is_network_uri(const std::string& uri) {
- std::strncmp(uri.c_str(), "ftp://", 6) == 0;
- }
-
-+bool
-+is_magnet_uri(const std::string& uri) {
-+ return
-+ std::strncmp(uri.c_str(), "magnet:?", 8) == 0;
-+}
-+
- DownloadFactory::DownloadFactory(Manager* m) :
- m_manager(m),
- m_stream(NULL),
-@@ -133,6 +139,13 @@ DownloadFactory::receive_load() {
-
- m_variables["tied_to_file"] = (int64_t)false;
-
-+ } else if (is_magnet_uri(m_uri)) {
-+ m_stream = new std::stringstream();
-+ *m_stream << "d10:magnet-uri" << m_uri.length() << ":" << m_uri << "e";
-+
-+ m_variables["tied_to_file"] = (int64_t)false;
-+ receive_loaded();
-+
- } else {
- std::fstream* stream = new std::fstream(rak::path_expand(m_uri).c_str(), std::ios::in | std::ios::binary);
- m_stream = stream;
-@@ -177,6 +190,16 @@ DownloadFactory::receive_success() {
-
- torrent::Object* root = download->bencode();
-
-+ if (download->download()->is_meta_download()) {
-+ torrent::Object& meta = root->insert_key("rtorrent_meta_download", torrent::Object::create_map());
-+ meta.insert_key("start", m_start);
-+ meta.insert_key("print_log", m_printLog);
-+
-+ torrent::Object::list_type& commands = meta.insert_key("commands", torrent::Object::create_list()).as_list();
-+ for (command_list_type::iterator itr = m_commands.begin(); itr != m_commands.end(); ++itr)
-+ commands.push_back(*itr);
-+ }
-+
- if (!m_session) {
- // We only allow session torrents to keep their
- // 'rtorrent/libtorrent' sections. The "fast_resume" section
-@@ -229,7 +252,7 @@ DownloadFactory::receive_success() {
- rpc::call_command("d.set_directory_base", rtorrent->get_key("directory"), rpc::make_target(download));
-
- if (!m_session && m_variables["tied_to_file"].as_value())
-- rpc::call_command("d.set_tied_to_file", m_uri, rpc::make_target(download));
-+ rpc::call_command("d.set_tied_to_file", m_uri.empty() ? m_variables["tied_file"] : m_uri, rpc::make_target(download));
-
- rpc::call_command("d.set_peer_exchange", rpc::call_command_value("get_peer_exchange"), rpc::make_target(download));
-
-diff --git a/src/core/download_factory.h b/src/core/download_factory.h
-index 045c9dc..3cc9622 100644
---- a/src/core/download_factory.h
-+++ b/src/core/download_factory.h
-@@ -112,6 +112,7 @@ private:
- };
-
- bool is_network_uri(const std::string& uri);
-+bool is_magnet_uri(const std::string& uri);
-
- }
-
-diff --git a/src/core/download_list.cc b/src/core/download_list.cc
-index 551f873..13df725 100644
---- a/src/core/download_list.cc
-+++ b/src/core/download_list.cc
-@@ -37,10 +37,12 @@
- #include "config.h"
-
- #include <algorithm>
-+#include <fstream>
- #include <iostream>
- #include <sigc++/adaptors/bind.h>
- #include <rak/functional.h>
- #include <rak/string_manip.h>
-+#include <torrent/data/file.h>
- #include <torrent/exceptions.h>
- #include <torrent/download.h>
- #include <torrent/hash_string.h>
-@@ -452,6 +454,9 @@ DownloadList::hash_done(Download* download) {
- int64_t hashing = rpc::call_command_value("d.get_hashing", rpc::make_target(download));
- rpc::call_command_set_value("d.set_hashing", Download::variable_hashing_stopped, rpc::make_target(download));
-
-+ if (download->is_done() && download->download()->is_meta_download())
-+ return process_meta_download(download);
-+
- switch (hashing) {
- case Download::variable_hashing_initial:
- case Download::variable_hashing_rehash:
-@@ -543,6 +548,9 @@ void
- DownloadList::confirm_finished(Download* download) {
- check_contains(download);
-
-+ if (download->download()->is_meta_download())
-+ return process_meta_download(download);
-+
- rpc::call_command("d.set_complete", (int64_t)1, rpc::make_target(download));
-
- rpc::call_command("d.set_connection_current", rpc::call_command_void("d.get_connection_seed", rpc::make_target(download)), rpc::make_target(download));
-@@ -576,4 +584,36 @@ DownloadList::confirm_finished(Download* download) {
- resume(download, torrent::Download::start_no_create | torrent::Download::start_skip_tracker | torrent::Download::start_keep_baseline);
- }
-
-+void
-+DownloadList::process_meta_download(Download* download) {
-+ rpc::call_command("d.stop", torrent::Object(), rpc::make_target(download));
-+ rpc::call_command("d.close", torrent::Object(), rpc::make_target(download));
-+
-+ std::string metafile = (*download->file_list()->begin())->frozen_path();
-+ std::fstream file(metafile.c_str(), std::ios::in | std::ios::binary);
-+ if (!file.is_open()) {
-+ control->core()->push_log("Could not read download metadata.");
-+ return;
-+ }
-+
-+ torrent::Object* bencode = new torrent::Object(torrent::Object::create_map());
-+ file >> bencode->insert_key("info", torrent::Object());
-+ if (file.fail()) {
-+ delete bencode;
-+ control->core()->push_log("Could not create download, the input is not a valid torrent.");
-+ return;
-+ }
-+ file.close();
-+
-+ // Steal the keys we still need. The old download has no use for them.
-+ bencode->insert_key("rtorrent_meta_download", torrent::Object()).swap(download->bencode()->get_key("rtorrent_meta_download"));
-+ if (download->bencode()->has_key("announce"))
-+ bencode->insert_key("announce", torrent::Object()).swap(download->bencode()->get_key("announce"));
-+ if (download->bencode()->has_key("announce-list"))
-+ bencode->insert_key("announce-list", torrent::Object()).swap(download->bencode()->get_key("announce-list"));
-+
-+ erase_ptr(download);
-+ control->core()->try_create_download_from_meta_download(bencode, metafile);
-+}
-+
- }
-diff --git a/src/core/download_list.h b/src/core/download_list.h
-index f7828ea..8ecffa0 100644
---- a/src/core/download_list.h
-+++ b/src/core/download_list.h
-@@ -161,6 +161,8 @@ private:
-
- void received_finished(Download* d);
- void confirm_finished(Download* d);
-+
-+ void process_meta_download(Download* d);
- };
-
- }
-diff --git a/src/core/manager.cc b/src/core/manager.cc
-index 62738ca..2a422c8 100644
---- a/src/core/manager.cc
-+++ b/src/core/manager.cc
-@@ -39,6 +39,7 @@
- #include <cstdio>
- #include <cstring>
- #include <fstream>
-+#include <sstream>
- #include <unistd.h>
- #include <sys/select.h>
- #include <rak/address_info.h>
-@@ -52,6 +53,7 @@
- #include <torrent/connection_manager.h>
- #include <torrent/error.h>
- #include <torrent/exceptions.h>
-+#include <torrent/object_stream.h>
- #include <torrent/resume.h>
- #include <torrent/tracker_list.h>
- #include <torrent/throttle.h>
-@@ -395,6 +397,7 @@ Manager::try_create_download(const std::string& uri, int flags, const command_li
- if ((flags & create_tied) &&
- !(flags & create_raw_data) &&
- !is_network_uri(uri) &&
-+ !is_magnet_uri(uri) &&
- !file_status_cache()->insert(uri, 0))
- return;
-
-@@ -416,6 +419,31 @@ Manager::try_create_download(const std::string& uri, int flags, const command_li
- f->commit();
- }
-
-+void
-+Manager::try_create_download_from_meta_download(torrent::Object* bencode, const std::string& metafile) {
-+ DownloadFactory* f = new DownloadFactory(this);
-+
-+ f->variables()["tied_to_file"] = (int64_t)true;
-+ f->variables()["tied_file"] = metafile;
-+
-+ torrent::Object& meta = bencode->get_key("rtorrent_meta_download");
-+ torrent::Object::list_type& commands = meta.get_key_list("commands");
-+ for (torrent::Object::list_type::const_iterator itr = commands.begin(); itr != commands.end(); ++itr)
-+ f->commands().insert(f->commands().end(), itr->as_string());
-+
-+ f->set_start(meta.get_key_value("start"));
-+ f->set_print_log(meta.get_key_value("print_log"));
-+ f->slot_finished(sigc::bind(sigc::ptr_fun(&rak::call_delete_func<core::DownloadFactory>), f));
-+
-+ // Bit of a waste to create the bencode repesentation here
-+ // only to have the DownloadFactory decode it.
-+ std::stringstream s;
-+ s.imbue(std::locale::classic());
-+ s << *bencode;
-+ f->load_raw_data(s.str());
-+ f->commit();
-+}
-+
- utils::Directory
- path_expand_transform(std::string path, const utils::directory_entry& entry) {
- return path + entry.d_name;
-diff --git a/src/core/manager.h b/src/core/manager.h
-index 3b23da3..16902af 100644
---- a/src/core/manager.h
-+++ b/src/core/manager.h
-@@ -128,6 +128,7 @@ public:
- // Temporary, find a better place for this.
- void try_create_download(const std::string& uri, int flags, const command_list_type& commands);
- void try_create_download_expand(const std::string& uri, int flags, command_list_type commands = command_list_type());
-+ void try_create_download_from_meta_download(torrent::Object* bencode, const std::string& metafile);
-
- private:
- typedef RangeMap<uint32_t, torrent::ThrottlePair> AddressThrottleMap;
diff --git a/rtorrent-extended/rtorrent-extended.install b/rtorrent-extended/rtorrent-extended.install
deleted file mode 100644
index 811a690..0000000
--- a/rtorrent-extended/rtorrent-extended.install
+++ /dev/null
@@ -1,9 +0,0 @@
-post_install() {
- echo ""
- echo "rTorrent-eXtended new options in .rtorrent.rc supported"
- echo "examples at http://lky.cc/rtorrent-extended/"
-}
-post_upgrade() {
- post_install
-}
-
diff --git a/rtorrent-extended/trackerinfo.patch b/rtorrent-extended/trackerinfo.patch
deleted file mode 100644
index 63998a5..0000000
--- a/rtorrent-extended/trackerinfo.patch
+++ /dev/null
@@ -1,21 +0,0 @@
-diff --git a/src/display/window_tracker_list.cc b/src/display/window_tracker_list.cc
-index 1903d67..2860f12 100644
---- a/src/display/window_tracker_list.cc
-+++ b/src/display/window_tracker_list.cc
-@@ -89,13 +89,14 @@ WindowTrackerList::redraw() {
- tracker->url().c_str());
-
- if (pos < m_canvas->height())
-- m_canvas->print(4, pos++, "Id: %s Focus: %s Enabled: %s Open: %s S/L: %u/%u",
-+ m_canvas->print(4, pos++, "Id: %s Focus: %s Enabled: %s Open: %s S/L/D: %u/%u/%u",
- rak::copy_escape_html(tracker->tracker_id()).c_str(),
- range.first == tl->focus_index() ? "yes" : " no",
- tracker->is_usable() ? "yes" : tracker->is_enabled() ? "off" : " no",
- tracker->is_busy() ? "yes" : " no",
- tracker->scrape_complete(),
-- tracker->scrape_incomplete());
-+ tracker->scrape_incomplete(),
-+ tracker->scrape_downloaded());
-
- // m_canvas->print(4, pos++, "Id: %s Focus: %s Enabled: %s Open: %s Timer: %u/%u",
- // rak::copy_escape_html(tracker->tracker_id()).c_str(),
diff --git a/rtorrent-extended/vi_kb_akston.patch b/rtorrent-extended/vi_kb_akston.patch
deleted file mode 100644
index 46ff7ea..0000000
--- a/rtorrent-extended/vi_kb_akston.patch
+++ /dev/null
@@ -1,176 +0,0 @@
-diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc
-index e72bff6..04b8625 100644
---- a/src/ui/download_list.cc
-+++ b/src/ui/download_list.cc
-@@ -346,13 +346,13 @@ DownloadList::setup_keys() {
- m_bindings['\x0F'] = sigc::bind(sigc::mem_fun(*this, &DownloadList::receive_view_input), INPUT_CHANGE_DIRECTORY);
- m_bindings['X' - '@'] = sigc::bind(sigc::mem_fun(*this, &DownloadList::receive_view_input), INPUT_COMMAND);
-
-- m_uiArray[DISPLAY_LOG]->bindings()[KEY_LEFT] =
-+ m_uiArray[DISPLAY_LOG]->bindings()['h'] =
- m_uiArray[DISPLAY_LOG]->bindings()['B' - '@'] =
- m_uiArray[DISPLAY_LOG]->bindings()[' '] = sigc::bind(sigc::mem_fun(*this, &DownloadList::activate_display), DISPLAY_DOWNLOAD_LIST);
-
-- m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()[KEY_RIGHT] =
-+ m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()['l'] =
- m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()['F' - '@'] = sigc::bind(sigc::mem_fun(*this, &DownloadList::activate_display), DISPLAY_DOWNLOAD);
-- m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()['l'] = sigc::bind(sigc::mem_fun(*this, &DownloadList::activate_display), DISPLAY_LOG);
-+ m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()['L'] = sigc::bind(sigc::mem_fun(*this, &DownloadList::activate_display), DISPLAY_LOG);
- }
-
- }
-diff --git a/src/ui/element_chunks_seen.cc b/src/ui/element_chunks_seen.cc
-index 8ee1dd9..d2636db 100644
---- a/src/ui/element_chunks_seen.cc
-+++ b/src/ui/element_chunks_seen.cc
-@@ -52,10 +52,10 @@ ElementChunksSeen::ElementChunksSeen(core::Download* d) :
- m_window(NULL),
- m_focus(0) {
-
-- m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-+ m_bindings['h'] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-
-- m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = sigc::mem_fun(*this, &ElementChunksSeen::receive_next);
-- m_bindings[KEY_UP] = m_bindings['P' - '@'] = sigc::mem_fun(*this, &ElementChunksSeen::receive_prev);
-+ m_bindings['j'] = m_bindings['N' - '@'] = sigc::mem_fun(*this, &ElementChunksSeen::receive_next);
-+ m_bindings['k'] = m_bindings['P' - '@'] = sigc::mem_fun(*this, &ElementChunksSeen::receive_prev);
- m_bindings[KEY_NPAGE] = sigc::mem_fun(*this, &ElementChunksSeen::receive_pagenext);
- m_bindings[KEY_PPAGE] = sigc::mem_fun(*this, &ElementChunksSeen::receive_pageprev);
- }
-diff --git a/src/ui/element_download_list.cc b/src/ui/element_download_list.cc
-index 1dc9ece..0c789f1 100644
---- a/src/ui/element_download_list.cc
-+++ b/src/ui/element_download_list.cc
-@@ -95,8 +95,8 @@ ElementDownloadList::ElementDownloadList() :
- m_bindings['8'] = sigc::bind(sigc::mem_fun(*this, &ElementDownloadList::receive_change_view), "seeding");
- m_bindings['9'] = sigc::bind(sigc::mem_fun(*this, &ElementDownloadList::receive_change_view), "active");
-
-- m_bindings[KEY_UP] = m_bindings['P' - '@'] = sigc::mem_fun(*this, &ElementDownloadList::receive_prev);
-- m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = sigc::mem_fun(*this, &ElementDownloadList::receive_next);
-+ m_bindings['k'] = m_bindings['P' - '@'] = sigc::mem_fun(*this, &ElementDownloadList::receive_prev);
-+ m_bindings['j'] = m_bindings['N' - '@'] = sigc::mem_fun(*this, &ElementDownloadList::receive_next);
- }
-
- void
-diff --git a/src/ui/element_file_list.cc b/src/ui/element_file_list.cc
-index 75ecec0..f23ef23 100644
---- a/src/ui/element_file_list.cc
-+++ b/src/ui/element_file_list.cc
-@@ -64,8 +64,8 @@ ElementFileList::ElementFileList(core::Download* d) :
- m_selected(iterator(d->download()->file_list()->begin())),
- m_collapsed(false) {
-
-- m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-- m_bindings[KEY_RIGHT] = m_bindings['F' - '@'] = sigc::mem_fun(*this, &ElementFileList::receive_select);
-+ m_bindings['h'] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-+ m_bindings['l'] = m_bindings['F' - '@'] = sigc::mem_fun(*this, &ElementFileList::receive_select);
-
- m_bindings[' '] = sigc::mem_fun(*this, &ElementFileList::receive_priority);
- m_bindings['*'] = sigc::mem_fun(*this, &ElementFileList::receive_change_all);
-@@ -73,8 +73,8 @@ ElementFileList::ElementFileList(core::Download* d) :
- m_bindings[KEY_NPAGE] = sigc::mem_fun(*this, &ElementFileList::receive_pagenext);
- m_bindings[KEY_PPAGE] = sigc::mem_fun(*this, &ElementFileList::receive_pageprev);
-
-- m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = sigc::mem_fun(*this, &ElementFileList::receive_next);
-- m_bindings[KEY_UP] = m_bindings['P' - '@'] = sigc::mem_fun(*this, &ElementFileList::receive_prev);
-+ m_bindings['j'] = m_bindings['N' - '@'] = sigc::mem_fun(*this, &ElementFileList::receive_next);
-+ m_bindings['k'] = m_bindings['P' - '@'] = sigc::mem_fun(*this, &ElementFileList::receive_prev);
- }
-
- inline ElementText*
-diff --git a/src/ui/element_menu.cc b/src/ui/element_menu.cc
-index 04130f3..41779eb 100644
---- a/src/ui/element_menu.cc
-+++ b/src/ui/element_menu.cc
-@@ -72,11 +72,11 @@ ElementMenu::ElementMenu() :
- m_entry(entry_invalid) {
-
- // Move bindings into a function that defines default bindings.
-- m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-- m_bindings[KEY_RIGHT] = m_bindings['F' - '@'] = sigc::mem_fun(this, &ElementMenu::entry_select);
-+ m_bindings['h'] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-+ m_bindings['l'] = m_bindings['F' - '@'] = sigc::mem_fun(this, &ElementMenu::entry_select);
-
-- m_bindings[KEY_UP] = m_bindings['P' - '@'] = sigc::mem_fun(this, &ElementMenu::entry_prev);
-- m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = sigc::mem_fun(this, &ElementMenu::entry_next);
-+ m_bindings['k'] = m_bindings['P' - '@'] = sigc::mem_fun(this, &ElementMenu::entry_prev);
-+ m_bindings['j'] = m_bindings['N' - '@'] = sigc::mem_fun(this, &ElementMenu::entry_next);
- }
-
- ElementMenu::~ElementMenu() {
-diff --git a/src/ui/element_peer_list.cc b/src/ui/element_peer_list.cc
-index be0e0b4..e38f3a2 100644
---- a/src/ui/element_peer_list.cc
-+++ b/src/ui/element_peer_list.cc
-@@ -73,14 +73,14 @@ ElementPeerList::ElementPeerList(core::Download* d) :
-
- m_elementInfo->slot_exit(sigc::bind(sigc::mem_fun(this, &ElementPeerList::activate_display), DISPLAY_LIST));
-
-- m_bindings['k'] = sigc::mem_fun(this, &ElementPeerList::receive_disconnect_peer);
-+ m_bindings['K'] = sigc::mem_fun(this, &ElementPeerList::receive_disconnect_peer);
- m_bindings['*'] = sigc::mem_fun(this, &ElementPeerList::receive_snub_peer);
- m_bindings['B'] = sigc::mem_fun(this, &ElementPeerList::receive_ban_peer);
-- m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-- m_bindings[KEY_RIGHT] = m_bindings['F' - '@'] = sigc::bind(sigc::mem_fun(this, &ElementPeerList::activate_display), DISPLAY_INFO);
-+ m_bindings['h'] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-+ m_bindings['l'] = m_bindings['F' - '@'] = sigc::bind(sigc::mem_fun(this, &ElementPeerList::activate_display), DISPLAY_INFO);
-
-- m_bindings[KEY_UP] = m_bindings['P' - '@'] = sigc::mem_fun(this, &ElementPeerList::receive_prev);
-- m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = sigc::mem_fun(this, &ElementPeerList::receive_next);
-+ m_bindings['k'] = m_bindings['P' - '@'] = sigc::mem_fun(this, &ElementPeerList::receive_prev);
-+ m_bindings['j'] = m_bindings['N' - '@'] = sigc::mem_fun(this, &ElementPeerList::receive_next);
- }
-
- ElementPeerList::~ElementPeerList() {
-diff --git a/src/ui/element_text.cc b/src/ui/element_text.cc
-index a7496f2..a564a81 100644
---- a/src/ui/element_text.cc
-+++ b/src/ui/element_text.cc
-@@ -54,7 +54,7 @@ ElementText::ElementText(rpc::target_type target) :
- m_columnWidth(0) {
-
- // Move bindings into a function that defines default bindings.
-- m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-+ m_bindings['h'] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-
- // m_bindings[KEY_UP] = sigc::mem_fun(this, &ElementText::entry_prev);
- // m_bindings[KEY_DOWN] = sigc::mem_fun(this, &ElementText::entry_next);
-diff --git a/src/ui/element_tracker_list.cc b/src/ui/element_tracker_list.cc
-index 7d81b89..8a51e80 100644
---- a/src/ui/element_tracker_list.cc
-+++ b/src/ui/element_tracker_list.cc
-@@ -54,13 +54,13 @@ ElementTrackerList::ElementTrackerList(core::Download* d) :
- m_window(NULL),
- m_focus(0) {
-
-- m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-+ m_bindings['h'] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-
- m_bindings[' '] = sigc::mem_fun(*this, &ElementTrackerList::receive_cycle_group);
- m_bindings['*'] = sigc::mem_fun(*this, &ElementTrackerList::receive_disable);
-
-- m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = sigc::mem_fun(*this, &ElementTrackerList::receive_next);
-- m_bindings[KEY_UP] = m_bindings['P' - '@'] = sigc::mem_fun(*this, &ElementTrackerList::receive_prev);
-+ m_bindings['j'] = m_bindings['N' - '@'] = sigc::mem_fun(*this, &ElementTrackerList::receive_next);
-+ m_bindings['k'] = m_bindings['P' - '@'] = sigc::mem_fun(*this, &ElementTrackerList::receive_prev);
- }
-
- void
-diff --git a/src/ui/element_transfer_list.cc b/src/ui/element_transfer_list.cc
-index 50eaec6..83ae26d 100644
---- a/src/ui/element_transfer_list.cc
-+++ b/src/ui/element_transfer_list.cc
-@@ -52,10 +52,10 @@ ElementTransferList::ElementTransferList(core::Download* d) :
- m_window(NULL),
- m_focus(0) {
-
-- m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-+ m_bindings['h'] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-
-- m_bindings[KEY_DOWN] = sigc::mem_fun(*this, &ElementTransferList::receive_next);
-- m_bindings[KEY_UP] = sigc::mem_fun(*this, &ElementTransferList::receive_prev);
-+ m_bindings['j'] = sigc::mem_fun(*this, &ElementTransferList::receive_next);
-+ m_bindings['k'] = sigc::mem_fun(*this, &ElementTransferList::receive_prev);
- m_bindings[KEY_NPAGE] = sigc::mem_fun(*this, &ElementTransferList::receive_pagenext);
- m_bindings[KEY_PPAGE] = sigc::mem_fun(*this, &ElementTransferList::receive_pageprev);
- }
diff --git a/rtorrent-extended/vi_kb_tjwoosta.patch b/rtorrent-extended/vi_kb_tjwoosta.patch
deleted file mode 100644
index b7ea5ac..0000000
--- a/rtorrent-extended/vi_kb_tjwoosta.patch
+++ /dev/null
@@ -1,175 +0,0 @@
-diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc
-index e72bff6..30b5987 100644
---- a/src/ui/download_list.cc
-+++ b/src/ui/download_list.cc
-@@ -350,9 +350,16 @@ DownloadList::setup_keys() {
- m_uiArray[DISPLAY_LOG]->bindings()['B' - '@'] =
- m_uiArray[DISPLAY_LOG]->bindings()[' '] = sigc::bind(sigc::mem_fun(*this, &DownloadList::activate_display), DISPLAY_DOWNLOAD_LIST);
-
-+ m_uiArray[DISPLAY_LOG]->bindings()['h'] =
-+ m_uiArray[DISPLAY_LOG]->bindings()['B' - '@'] =
-+ m_uiArray[DISPLAY_LOG]->bindings()[' '] = sigc::bind(sigc::mem_fun(*this, &DownloadList::activate_display), DISPLAY_DOWNLOAD_LIST);
-+
- m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()[KEY_RIGHT] =
- m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()['F' - '@'] = sigc::bind(sigc::mem_fun(*this, &DownloadList::activate_display), DISPLAY_DOWNLOAD);
-- m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()['l'] = sigc::bind(sigc::mem_fun(*this, &DownloadList::activate_display), DISPLAY_LOG);
-+
-+ m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()['l'] =
-+ m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()['F' - '@'] = sigc::bind(sigc::mem_fun(*this, &DownloadList::activate_display), DISPLAY_DOWNLOAD);
-+ m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()['L'] = sigc::bind(sigc::mem_fun(*this, &DownloadList::activate_display), DISPLAY_LOG);
- }
-
- }
-diff --git a/src/ui/element_chunks_seen.cc b/src/ui/element_chunks_seen.cc
-index 8ee1dd9..5336b05 100644
---- a/src/ui/element_chunks_seen.cc
-+++ b/src/ui/element_chunks_seen.cc
-@@ -54,8 +54,12 @@ ElementChunksSeen::ElementChunksSeen(core::Download* d) :
-
- m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-
-+ m_bindings['h'] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-+
- m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = sigc::mem_fun(*this, &ElementChunksSeen::receive_next);
-+ m_bindings['j'] = m_bindings['N' - '@'] = sigc::mem_fun(*this, &ElementChunksSeen::receive_next);
- m_bindings[KEY_UP] = m_bindings['P' - '@'] = sigc::mem_fun(*this, &ElementChunksSeen::receive_prev);
-+ m_bindings['k'] = m_bindings['P' - '@'] = sigc::mem_fun(*this, &ElementChunksSeen::receive_prev);
- m_bindings[KEY_NPAGE] = sigc::mem_fun(*this, &ElementChunksSeen::receive_pagenext);
- m_bindings[KEY_PPAGE] = sigc::mem_fun(*this, &ElementChunksSeen::receive_pageprev);
- }
-diff --git a/src/ui/element_download_list.cc b/src/ui/element_download_list.cc
-index 1dc9ece..f2763ca 100644
---- a/src/ui/element_download_list.cc
-+++ b/src/ui/element_download_list.cc
-@@ -96,7 +96,9 @@ ElementDownloadList::ElementDownloadList() :
- m_bindings['9'] = sigc::bind(sigc::mem_fun(*this, &ElementDownloadList::receive_change_view), "active");
-
- m_bindings[KEY_UP] = m_bindings['P' - '@'] = sigc::mem_fun(*this, &ElementDownloadList::receive_prev);
-+ m_bindings['k'] = m_bindings['P' - '@'] = sigc::mem_fun(*this, &ElementDownloadList::receive_prev);
- m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = sigc::mem_fun(*this, &ElementDownloadList::receive_next);
-+ m_bindings['j'] = m_bindings['N' - '@'] = sigc::mem_fun(*this, &ElementDownloadList::receive_next);
- }
-
- void
-diff --git a/src/ui/element_file_list.cc b/src/ui/element_file_list.cc
-index 75ecec0..a24f429 100644
---- a/src/ui/element_file_list.cc
-+++ b/src/ui/element_file_list.cc
-@@ -65,7 +65,9 @@ ElementFileList::ElementFileList(core::Download* d) :
- m_collapsed(false) {
-
- m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-+ m_bindings['h'] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
- m_bindings[KEY_RIGHT] = m_bindings['F' - '@'] = sigc::mem_fun(*this, &ElementFileList::receive_select);
-+ m_bindings['l'] = m_bindings['F' - '@'] = sigc::mem_fun(*this, &ElementFileList::receive_select);
-
- m_bindings[' '] = sigc::mem_fun(*this, &ElementFileList::receive_priority);
- m_bindings['*'] = sigc::mem_fun(*this, &ElementFileList::receive_change_all);
-@@ -74,7 +76,9 @@ ElementFileList::ElementFileList(core::Download* d) :
- m_bindings[KEY_PPAGE] = sigc::mem_fun(*this, &ElementFileList::receive_pageprev);
-
- m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = sigc::mem_fun(*this, &ElementFileList::receive_next);
-+ m_bindings['j'] = m_bindings['N' - '@'] = sigc::mem_fun(*this, &ElementFileList::receive_next);
- m_bindings[KEY_UP] = m_bindings['P' - '@'] = sigc::mem_fun(*this, &ElementFileList::receive_prev);
-+ m_bindings['k'] = m_bindings['P' - '@'] = sigc::mem_fun(*this, &ElementFileList::receive_prev);
- }
-
- inline ElementText*
-diff --git a/src/ui/element_menu.cc b/src/ui/element_menu.cc
-index 04130f3..b6b3ee9 100644
---- a/src/ui/element_menu.cc
-+++ b/src/ui/element_menu.cc
-@@ -72,11 +72,15 @@ ElementMenu::ElementMenu() :
- m_entry(entry_invalid) {
-
- // Move bindings into a function that defines default bindings.
-- m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-+ m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-+ m_bindings['h'] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
- m_bindings[KEY_RIGHT] = m_bindings['F' - '@'] = sigc::mem_fun(this, &ElementMenu::entry_select);
-+ m_bindings['l'] = m_bindings['F' - '@'] = sigc::mem_fun(this, &ElementMenu::entry_select);
-
- m_bindings[KEY_UP] = m_bindings['P' - '@'] = sigc::mem_fun(this, &ElementMenu::entry_prev);
-+ m_bindings['k'] = m_bindings['P' - '@'] = sigc::mem_fun(this, &ElementMenu::entry_prev);
- m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = sigc::mem_fun(this, &ElementMenu::entry_next);
-+ m_bindings['j'] = m_bindings['N' - '@'] = sigc::mem_fun(this, &ElementMenu::entry_next);
- }
-
- ElementMenu::~ElementMenu() {
-diff --git a/src/ui/element_peer_list.cc b/src/ui/element_peer_list.cc
-index be0e0b4..8b7303e 100644
---- a/src/ui/element_peer_list.cc
-+++ b/src/ui/element_peer_list.cc
-@@ -73,14 +73,18 @@ ElementPeerList::ElementPeerList(core::Download* d) :
-
- m_elementInfo->slot_exit(sigc::bind(sigc::mem_fun(this, &ElementPeerList::activate_display), DISPLAY_LIST));
-
-- m_bindings['k'] = sigc::mem_fun(this, &ElementPeerList::receive_disconnect_peer);
-+ m_bindings['K'] = sigc::mem_fun(this, &ElementPeerList::receive_disconnect_peer);
- m_bindings['*'] = sigc::mem_fun(this, &ElementPeerList::receive_snub_peer);
- m_bindings['B'] = sigc::mem_fun(this, &ElementPeerList::receive_ban_peer);
-- m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-+ m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-+ m_bindings['h'] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
- m_bindings[KEY_RIGHT] = m_bindings['F' - '@'] = sigc::bind(sigc::mem_fun(this, &ElementPeerList::activate_display), DISPLAY_INFO);
-+ m_bindings['l'] = m_bindings['F' - '@'] = sigc::bind(sigc::mem_fun(this, &ElementPeerList::activate_display), DISPLAY_INFO);
-
- m_bindings[KEY_UP] = m_bindings['P' - '@'] = sigc::mem_fun(this, &ElementPeerList::receive_prev);
-+ m_bindings['k'] = m_bindings['P' - '@'] = sigc::mem_fun(this, &ElementPeerList::receive_prev);
- m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = sigc::mem_fun(this, &ElementPeerList::receive_next);
-+ m_bindings['j'] = m_bindings['N' - '@'] = sigc::mem_fun(this, &ElementPeerList::receive_next);
- }
-
- ElementPeerList::~ElementPeerList() {
-diff --git a/src/ui/element_text.cc b/src/ui/element_text.cc
-index a7496f2..4c2e171 100644
---- a/src/ui/element_text.cc
-+++ b/src/ui/element_text.cc
-@@ -54,7 +54,9 @@ ElementText::ElementText(rpc::target_type target) :
- m_columnWidth(0) {
-
- // Move bindings into a function that defines default bindings.
-- m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-+ m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-+
-+ m_bindings['h'] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-
- // m_bindings[KEY_UP] = sigc::mem_fun(this, &ElementText::entry_prev);
- // m_bindings[KEY_DOWN] = sigc::mem_fun(this, &ElementText::entry_next);
-diff --git a/src/ui/element_tracker_list.cc b/src/ui/element_tracker_list.cc
-index 7d81b89..5584653 100644
---- a/src/ui/element_tracker_list.cc
-+++ b/src/ui/element_tracker_list.cc
-@@ -55,12 +55,15 @@ ElementTrackerList::ElementTrackerList(core::Download* d) :
- m_focus(0) {
-
- m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-+ m_bindings['h'] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-
- m_bindings[' '] = sigc::mem_fun(*this, &ElementTrackerList::receive_cycle_group);
- m_bindings['*'] = sigc::mem_fun(*this, &ElementTrackerList::receive_disable);
-
- m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = sigc::mem_fun(*this, &ElementTrackerList::receive_next);
-+ m_bindings['j'] = m_bindings['N' - '@'] = sigc::mem_fun(*this, &ElementTrackerList::receive_next);
- m_bindings[KEY_UP] = m_bindings['P' - '@'] = sigc::mem_fun(*this, &ElementTrackerList::receive_prev);
-+ m_bindings['k'] = m_bindings['P' - '@'] = sigc::mem_fun(*this, &ElementTrackerList::receive_prev);
- }
-
- void
-diff --git a/src/ui/element_transfer_list.cc b/src/ui/element_transfer_list.cc
-index 50eaec6..f14a2d2 100644
---- a/src/ui/element_transfer_list.cc
-+++ b/src/ui/element_transfer_list.cc
-@@ -54,8 +54,12 @@ ElementTransferList::ElementTransferList(core::Download* d) :
-
- m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-
-+ m_bindings['h'] = m_bindings['B' - '@'] = sigc::mem_fun(&m_slotExit, &slot_type::operator());
-+
- m_bindings[KEY_DOWN] = sigc::mem_fun(*this, &ElementTransferList::receive_next);
-+ m_bindings['j'] = sigc::mem_fun(*this, &ElementTransferList::receive_next);
- m_bindings[KEY_UP] = sigc::mem_fun(*this, &ElementTransferList::receive_prev);
-+ m_bindings['k'] = sigc::mem_fun(*this, &ElementTransferList::receive_prev);
- m_bindings[KEY_NPAGE] = sigc::mem_fun(*this, &ElementTransferList::receive_pagenext);
- m_bindings[KEY_PPAGE] = sigc::mem_fun(*this, &ElementTransferList::receive_pageprev);
- }