diff --git a/configure.ac b/configure.ac index de8d4287..c130b212 100644 --- a/configure.ac +++ b/configure.ac @@ -28,6 +28,7 @@ PKG_CHECK_MODULES(STUFF, sigc++-2.0 libtorrent >= 0.10.1, LIBS="$LIBS $STUFF_LIBS $CURL_LIBS") AC_DEFINE(HAVE_CONFIG_H, 1, true if config.h was included) +AC_DEFINE(USER_AGENT, [std::string(PACKAGE "/" VERSION "/") + torrent::version()], Http user agent) CC_ATTRIBUTE_UNUSED( AC_DEFINE([__UNUSED], [__attribute__((unused))], [Wrapper around unused attribute]), diff --git a/src/control.cc b/src/control.cc index 03cc45de..c28d2320 100644 --- a/src/control.cc +++ b/src/control.cc @@ -107,7 +107,7 @@ Control::initialize() { display::Window::slot_unschedule(rak::make_mem_fun(m_display, &display::Manager::unschedule)); display::Window::slot_adjust(rak::make_mem_fun(m_display, &display::Manager::adjust_layout)); - m_core->get_poll_manager()->get_http_stack()->set_user_agent(std::string(PACKAGE "/" VERSION "/") + torrent::version()); + m_core->get_poll_manager()->get_http_stack()->set_user_agent(USER_AGENT); m_core->initialize_second(); m_core->listen_open(); diff --git a/src/display/Makefile.am b/src/display/Makefile.am index a6135151..21728843 100644 --- a/src/display/Makefile.am +++ b/src/display/Makefile.am @@ -14,6 +14,7 @@ libsub_display_a_SOURCES = \ utils.h \ text_element.h \ text_element_helpers.h \ + text_element_lambda.h \ text_element_list.cc \ text_element_list.h \ text_element_string.cc \ diff --git a/src/display/text_element.h b/src/display/text_element.h index a994242f..24c7cffd 100644 --- a/src/display/text_element.h +++ b/src/display/text_element.h @@ -50,6 +50,7 @@ public: static const extent_type extent_full = ~extent_type(); + TextElement() {} virtual ~TextElement() {} // The last element must point to a valid memory location into which @@ -58,6 +59,10 @@ public: virtual char* print(char* first, char* last, Canvas::attributes_list* attributes, void* object) = 0; virtual extent_type max_length() = 0; + +private: + TextElement(const TextElement&); + void operator = (const TextElement&); }; } diff --git a/src/display/text_element_helpers.h b/src/display/text_element_helpers.h index ac305155..37f34656 100644 --- a/src/display/text_element_helpers.h +++ b/src/display/text_element_helpers.h @@ -53,6 +53,11 @@ typedef TextElementValueBase value_base; // String stuff: +inline TextElementStringBase* +te_string(const char* str) { + return new display::TextElementCString(str); +} + // template // inline TextElementStringBase* // te_string(Return (Object::*fptr)() const, const Object* object, int attributes = Attributes::a_invalid) { diff --git a/src/display/text_element_lambda.h b/src/display/text_element_lambda.h new file mode 100644 index 00000000..2f370a3f --- /dev/null +++ b/src/display/text_element_lambda.h @@ -0,0 +1,116 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005-2006, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations +// including the two. +// +// You must obey the GNU General Public License in all respects for +// all of the code used other than OpenSSL. If you modify file(s) +// with this exception, you may extend this exception to your version +// of the file(s), but you are not obligated to do so. If you do not +// wish to do so, delete this exception statement from your version. +// If you delete this exception statement from all source files in the +// program, then also delete it here. +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#ifndef RTORRENT_DISPLAY_TEXT_ELEMENT_LAMBDA_H +#define RTORRENT_DISPLAY_TEXT_ELEMENT_LAMBDA_H + +#include "text_element.h" + +namespace display { + +template +class TextElementBranchVoid : public TextElement { +public: + typedef typename slot_type::result_type result_type; + + TextElementBranchVoid(const slot_type& slot, TextElement* branch1, TextElement* branch2) : + m_slot(slot), m_branch1(branch1), m_branch2(branch2) {} + + virtual char* print(char* first, char* last, Canvas::attributes_list* attributes, void* object) { + if (m_slot()) + return m_branch1 != NULL ? m_branch1->print(first, last, attributes, object) : first; + else + return m_branch2 != NULL ? m_branch2->print(first, last, attributes, object) : first; + } + + virtual extent_type max_length() { + return std::max(m_branch1 != NULL ? m_branch1->max_length() : 0, + m_branch2 != NULL ? m_branch2->max_length() : 0); + } + +private: + slot_type m_slot; + + TextElement* m_branch1; + TextElement* m_branch2; +}; + +template +class TextElementBranch : public TextElement { +public: + typedef typename slot_type::argument_type arg1_type; + typedef typename slot_type::result_type result_type; + + TextElementBranch(const slot_type& slot, TextElement* branch1, TextElement* branch2) : + m_slot(slot), m_branch1(branch1), m_branch2(branch2) {} + + virtual char* print(char* first, char* last, Canvas::attributes_list* attributes, void* object) { + if (object == NULL) + return first; + + if (m_slot(reinterpret_cast(object))) + return m_branch1 != NULL ? m_branch1->print(first, last, attributes, object) : first; + else + return m_branch2 != NULL ? m_branch2->print(first, last, attributes, object) : first; + } + + virtual extent_type max_length() { + return std::max(m_branch1 != NULL ? m_branch1->max_length() : 0, + m_branch2 != NULL ? m_branch2->max_length() : 0); + } + +private: + slot_type m_slot; + + TextElement* m_branch1; + TextElement* m_branch2; +}; + +template +inline TextElementBranchVoid* +text_element_branch_void(const slot_type& slot, TextElement* branch1, TextElement* branch2) { + return new TextElementBranchVoid(slot, branch1, branch2); +} + +template +inline TextElementBranch* +text_element_branch(const slot_type& slot, TextElement* branch1, TextElement* branch2) { + return new TextElementBranch(slot, branch1, branch2); +} + +} + +#endif diff --git a/src/display/text_element_string.h b/src/display/text_element_string.h index 9d7a2223..49c098fd 100644 --- a/src/display/text_element_string.h +++ b/src/display/text_element_string.h @@ -78,9 +78,9 @@ public: const std::string& str() const { return m_string; } void set_str(const std::string& s) { m_string = s; } -private: virtual extent_type max_length() { return m_string.size(); } +private: virtual char* copy_string(char* first, char* last, void* object); std::string m_string; @@ -93,9 +93,9 @@ public: m_attributes = attributes; } -private: virtual extent_type max_length() { return m_length; } +private: virtual char* copy_string(char* first, char* last, void* object); extent_type m_length; @@ -113,16 +113,14 @@ public: m_attributes = attributes; } -private: virtual extent_type max_length() { return m_length; } +private: virtual char* copy_string(char* first, char* last, void* object) { - arg1_type arg1 = reinterpret_cast(object); - - if (arg1 == NULL) + if (object == NULL) return first; - result_type result = m_slot(arg1); + result_type result = m_slot(reinterpret_cast(object)); extent_type length = std::min(result_length(&result), last - first); std::memcpy(first, result_buffer(&result), length); diff --git a/src/display/text_element_value.h b/src/display/text_element_value.h index e991a358..b8fac13a 100644 --- a/src/display/text_element_value.h +++ b/src/display/text_element_value.h @@ -83,9 +83,9 @@ public: int64_t value() const { return m_value; } void set_value(int64_t v) { m_value = v; } -private: virtual extent_type max_length() { return 12; } +private: virtual int64_t value(void* object) { return m_value; } int64_t m_value; @@ -101,9 +101,9 @@ public: m_attributes = attributes; } -private: virtual extent_type max_length() { return 12; } +private: virtual int64_t value(void* object) { return m_slot(); } slot_type m_slot; @@ -120,16 +120,14 @@ public: m_attributes = attributes; } -private: virtual extent_type max_length() { return 12; } +private: virtual int64_t value(void* object) { - arg1_type arg1 = reinterpret_cast(object); - - if (arg1 == NULL) + if (object == NULL) return 0; - return m_slot(arg1); + return m_slot(reinterpret_cast(object)); } slot_type m_slot; diff --git a/src/display/window_text.cc b/src/display/window_text.cc index e4b2f878..b8cff5c6 100644 --- a/src/display/window_text.cc +++ b/src/display/window_text.cc @@ -72,6 +72,9 @@ WindowText::push_back(TextElement* element) { void WindowText::redraw() { + if (m_interval != 0) + m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(m_interval)).round_seconds()); + m_canvas->erase(); unsigned int position = 0; diff --git a/src/display/window_text.h b/src/display/window_text.h index 5e26b6dc..3d36963c 100644 --- a/src/display/window_text.h +++ b/src/display/window_text.h @@ -46,7 +46,7 @@ namespace display { class WindowText : public Window, public std::vector { public: - typedef std::vector base_type; + typedef std::vector base_type; typedef base_type::value_type value_type; typedef base_type::reference reference; @@ -63,7 +63,7 @@ public: using base_type::rend; WindowText(void* object = NULL, extent_type margin = 0) : - Window(new Canvas, 0, 0, 0, extent_static, extent_static), m_object(object), m_margin(margin) {} + Window(new Canvas, 0, 0, 0, extent_static, extent_static), m_object(object), m_margin(margin), m_interval(0) {} ~WindowText() { clear(); } void clear(); @@ -71,6 +71,9 @@ public: void* object() const { return m_object; } void set_object(void* object) { m_object = object; } + uint32_t interval() const { return m_interval; } + void set_interval(uint32_t i) { m_interval = i; } + void push_back(TextElement* element); virtual void redraw(); @@ -79,6 +82,7 @@ private: void* m_object; extent_type m_margin; + uint32_t m_interval; }; } diff --git a/src/option_handler_rules.cc b/src/option_handler_rules.cc index eb7118f0..a4b9187d 100644 --- a/src/option_handler_rules.cc +++ b/src/option_handler_rules.cc @@ -466,6 +466,9 @@ initialize_option_handler(Control* c) { variables->insert("max_memory_usage", new utils::VariableValueSlot(rak::mem_fn(torrent::chunk_manager(), &torrent::ChunkManager::max_memory_usage), rak::mem_fn(torrent::chunk_manager(), &torrent::ChunkManager::set_max_memory_usage))); + variables->insert("safe_sync", new utils::VariableValueSlot(rak::mem_fn(torrent::chunk_manager(), &torrent::ChunkManager::safe_sync), + rak::mem_fn(torrent::chunk_manager(), &torrent::ChunkManager::set_safe_sync))); + variables->insert("timeout_sync", new utils::VariableValueSlot(rak::mem_fn(torrent::chunk_manager(), &torrent::ChunkManager::timeout_sync), rak::mem_fn(torrent::chunk_manager(), &torrent::ChunkManager::set_timeout_sync))); diff --git a/src/ui/download.cc b/src/ui/download.cc index a594ff72..d5c65743 100644 --- a/src/ui/download.cc +++ b/src/ui/download.cc @@ -50,6 +50,7 @@ #include "display/window_title.h" #include "display/window_download_statusbar.h" +#include "display/text_element_lambda.h" #include "display/text_element_helpers.h" #include "control.h" @@ -136,6 +137,7 @@ Download::create_info() { ElementText* element = new ElementText(m_download); element->set_column(1); + element->set_interval(1); // Get these bindings with some kind of string map. @@ -161,6 +163,7 @@ Download::create_info() { element->push_column("Safe diskspace:", te_value(&torrent::ChunkManager::safe_free_diskspace, value_base::flag_mb), " MB"); element->push_back(""); + element->push_column("Safe sync:", display::text_element_branch_void(rak::make_mem_fun(torrent::chunk_manager(), &torrent::ChunkManager::safe_sync), te_string("yes"), te_string("no"))); element->push_column("Send buffer:", te_value(&torrent::ConnectionManager::send_buffer_size, value_base::flag_kb), " KB"); element->push_column("Receive buffer:", te_value(&torrent::ConnectionManager::receive_buffer_size, value_base::flag_kb), " KB"); diff --git a/src/ui/element_peer_list.cc b/src/ui/element_peer_list.cc index 22fae740..392c737f 100644 --- a/src/ui/element_peer_list.cc +++ b/src/ui/element_peer_list.cc @@ -44,6 +44,7 @@ #include "display/frame.h" #include "display/manager.h" #include "display/text_element_helpers.h" +#include "display/text_element_lambda.h" #include "display/window_peer_list.h" #include "input/manager.h" @@ -92,6 +93,7 @@ ElementPeerList::create_info() { ElementText* element = new ElementText(NULL); element->set_column(1); + element->set_interval(1); // Get these bindings with some kind of string map. @@ -102,12 +104,14 @@ ElementPeerList::create_info() { display::text_element_string_slot(rak::on(std::mem_fun(&torrent::Peer::address), std::ptr_fun(&te_address))), ":", display::text_element_value_slot(rak::on(std::mem_fun(&torrent::Peer::address), std::ptr_fun(&te_port)))); - element->push_column("Id:", display::text_element_string_slot(std::mem_fun(&torrent::Peer::id), string_base::flag_escape_html)); - element->push_column("Client:", display::text_element_string_slot(rak::on(std::mem_fun(&torrent::Peer::id), rak::make_mem_fun(control->client_info(), &display::ClientInfo::str_str)))); - element->push_column("Options:", display::text_element_string_slot(std::mem_fun(&torrent::Peer::options), string_base::flag_escape_hex | string_base::flag_fixed_width, 0, 8)); + element->push_column("Id:", display::text_element_string_slot(std::mem_fun(&torrent::Peer::id), string_base::flag_escape_html)); + element->push_column("Client:", display::text_element_string_slot(rak::on(std::mem_fun(&torrent::Peer::id), rak::make_mem_fun(control->client_info(), &display::ClientInfo::str_str)))); + element->push_column("Options:", display::text_element_string_slot(std::mem_fun(&torrent::Peer::options), string_base::flag_escape_hex | string_base::flag_fixed_width, 0, 8)); + element->push_column("Connected:", display::text_element_branch(std::mem_fun(&torrent::Peer::is_incoming), te_string("incoming"), te_string("outgoing"))); element->push_back(""); - element->push_column("Done:", display::text_element_value_slot(rak::on(std::mem_fun(&torrent::Peer::bitfield), std::ptr_fun(&te_bitfield_percentage)))); + element->push_column("Snubbed:", display::text_element_branch(std::mem_fun(&torrent::Peer::is_snubbed), te_string("yes"), te_string("no"))); + element->push_column("Done:", display::text_element_value_slot(rak::on(std::mem_fun(&torrent::Peer::bitfield), std::ptr_fun(&te_bitfield_percentage)))); element->push_column("Rate:", display::text_element_value_slot(rak::on(std::mem_fun(&torrent::Peer::up_rate), std::mem_fun(&torrent::Rate::rate)), value_base::flag_kb), " / ", display::text_element_value_slot(rak::on(std::mem_fun(&torrent::Peer::down_rate), std::mem_fun(&torrent::Rate::rate)), value_base::flag_kb), " KB"); diff --git a/src/ui/element_text.h b/src/ui/element_text.h index 5b6dbaf5..1813bd31 100644 --- a/src/ui/element_text.h +++ b/src/ui/element_text.h @@ -66,6 +66,9 @@ public: void* object() const { return m_window->object(); } void set_object(void* object) { m_window->set_object(object); m_window->mark_dirty(); } + uint32_t interval() const { return m_window->interval(); } + void set_interval(uint32_t i) { m_window->set_interval(i); m_window->mark_dirty(); } + void activate(display::Frame* frame, bool focus = false); void disable(); diff --git a/src/utils/variable.cc b/src/utils/variable.cc index c3e534a5..161e352e 100644 --- a/src/utils/variable.cc +++ b/src/utils/variable.cc @@ -47,11 +47,16 @@ const torrent::Object Variable::m_emptyObject; const char* Variable::string_to_value_unit(const char* pos, value_type* value, int base, int unit) { char* last; - *value = strtoll(pos, &last, base); - if (last == pos) + if (last == pos) { + if (strcasecmp(pos, "no") == 0) { *value = 0; return pos + strlen("no"); } + if (strcasecmp(pos, "yes") == 0) { *value = 1; return pos + strlen("yes"); } + if (strcasecmp(pos, "true") == 0) { *value = 1; return pos + strlen("true"); } + if (strcasecmp(pos, "false") == 0) { *value = 0; return pos + strlen("false"); } + throw torrent::input_error("Could not convert string to value."); + } switch (*last) { case 'b':