From 1d1b5710fa29d56cf34ee1e8bb616f06e5fe95d5 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sat, 20 Jan 2007 19:42:22 +0000 Subject: [PATCH] * Added "create_link" and "delete_link" options for creating and deleting symbolic links to downloads. * Added "on_*" options for calling commands on state changes. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@849 e378c898-3ddf-0310-93e7-cc216c733640 --- doc/rtorrent.1.xml | 83 ++++++-- rak/functional_fun.h | 20 ++ src/control.cc | 2 + src/control.h | 3 + src/core/download.cc | 75 +------- src/core/download.h | 29 ++- src/core/download_factory.cc | 1 + src/core/download_list.cc | 4 +- src/core/manager.cc | 3 +- src/core/scheduler.cc | 1 + src/core/view.cc | 1 + src/core/view_manager.cc | 1 + src/display/utils.cc | 1 + src/globals.h | 2 +- src/main.cc | 3 +- src/option_handler_rules.cc | 328 +++++++++++++++++++++++--------- src/option_handler_rules.h | 3 +- src/ui/download_list.cc | 2 + src/ui/element_download_list.cc | 1 + src/utils/variable_generic.cc | 4 +- src/utils/variable_generic.h | 12 ++ src/utils/variable_map.cc | 29 +++ src/utils/variable_map.h | 8 +- 23 files changed, 416 insertions(+), 200 deletions(-) diff --git a/doc/rtorrent.1.xml b/doc/rtorrent.1.xml index 6be07fa7..6ac3f513 100644 --- a/doc/rtorrent.1.xml +++ b/doc/rtorrent.1.xml @@ -584,23 +584,6 @@ the schedule option. - - stop_on_ratio = min_ratio - stop_on_ratio = min_ratio,min_upload - stop_on_ratio = min_ratio,min_upload,max_ratio - -Stop torrents when they reach the given upload ratio -min_ratio in percent. If the optional -min_upload is given, require a total -upload amount of this many bytes as well. If the optional -max_ratio is given, stop the torrent -when reaching this ratio regardless of the total upload -amount. Exclude certain torrent by pressing -Shift+I in the downlist list. -Use with the schedule option. - - - load = file load_verbose = file @@ -624,6 +607,40 @@ torrent::input_error exception on bad input. + + stop_on_ratio = min_ratio + stop_on_ratio = min_ratio,min_upload + stop_on_ratio = min_ratio,min_upload,max_ratio + +Stop torrents when they reach the given upload ratio +min_ratio in percent. If the optional +min_upload is given, require a total +upload amount of this many bytes as well. If the optional +max_ratio is given, stop the torrent +when reaching this ratio regardless of the total upload +amount. Exclude certain torrent by pressing +Shift+I in the downlist list. +Use with the schedule option. + + + + + on_insert = id,command + on_erase = id,command + on_open = id,command + on_close = id,command + on_start = id,command + on_stop = id,command + on_hash_queued = id,command + on_hash_removed = id,command + on_hash_done = id,command + on_finished = id,command + +Call a command on a download when its state changes. Only a subset of +commands are available. + + + @@ -789,6 +806,38 @@ to .part. + + DOWNLOAD SETTINGS + +Settings that require a download as a target, requireing it to be +called through f.ex on_finished. + + + + + + create_link = type,path,suffix + delete_link = type,path,suffix + + +Create or delete a symbolic link. The link path is the concatenation +of path, the result of +the type on the download, +and suffix. + + + +Available types are; tied is the path of the file +this download is tied to, see start_tied. + + + + + + + + + ADVANCED SETTINGS diff --git a/rak/functional_fun.h b/rak/functional_fun.h index 336f6725..37297917 100644 --- a/rak/functional_fun.h +++ b/rak/functional_fun.h @@ -159,6 +159,20 @@ private: Func m_func; }; +template +class ptr_fn2_t : public function_base2 { +public: + typedef Result (*Func)(Arg1, Arg2); + + ptr_fn2_t(Func func) : m_func(func) {} + virtual ~ptr_fn2_t() {} + + virtual Result operator () (Arg1 arg1, Arg2 arg2) { return m_func(arg1, arg2); } + +private: + Func m_func; +}; + template class mem_fn0_t : public function_base0 { public: @@ -384,6 +398,12 @@ ptr_fn(Result (*func)(Arg1)) { return new ptr_fn1_t(func); } +template +inline function_base2* +ptr_fn(Result (*func)(Arg1, Arg2)) { + return new ptr_fn2_t(func); +} + template inline function_base0* mem_fn(Object* object, Result (Object::*func)()) { diff --git a/src/control.cc b/src/control.cc index bcdd8d3a..e5b451cb 100644 --- a/src/control.cc +++ b/src/control.cc @@ -68,6 +68,7 @@ Control::Control() : m_commandScheduler(new CommandScheduler()), m_variables(new utils::VariableMap()), + m_downloadVariables(new utils::VariableMap()), m_tick(0) { @@ -89,6 +90,7 @@ Control::~Control() { delete m_commandScheduler; delete m_variables; + delete m_downloadVariables; delete m_viewManager; diff --git a/src/control.h b/src/control.h index a97ed8ca..feddc9bf 100644 --- a/src/control.h +++ b/src/control.h @@ -95,7 +95,9 @@ public: input::InputEvent* input_stdin() { return m_inputStdin; } CommandScheduler* command_scheduler() { return m_commandScheduler; } + utils::VariableMap* variable() { return m_variables; } + utils::VariableMap* download_variables() { return m_downloadVariables; } uint64_t tick() const { return m_tick; } void inc_tick() { m_tick++; } @@ -124,6 +126,7 @@ private: CommandScheduler* m_commandScheduler; utils::VariableMap* m_variables; + utils::VariableMap* m_downloadVariables; uint64_t m_tick; diff --git a/src/core/download.cc b/src/core/download.cc index 38548a6b..6ba8f1f3 100644 --- a/src/core/download.cc +++ b/src/core/download.cc @@ -49,31 +49,13 @@ #include #include "utils/variable_generic.h" +#include "utils/variable_map.h" +#include "control.h" #include "download.h" namespace core { -template -utils::Variable* -var_d_value(Target target, GetFunc getFunc, SetFunc setFunc) { - return new utils::VariableDownloadValueSlot(rak::ftor_fn1(rak::on(std::mem_fun(target), std::mem_fun(getFunc))), - rak::ftor_fn2(rak::on2(std::mem_fun(target), std::mem_fun(setFunc)))); -} - -template -utils::Variable* -var_d2_value(Target target, GetFunc getFunc, SetFunc setFunc) { - return new utils::VariableDownloadValueSlot(rak::ftor_fn1(rak::on(rak::on(std::mem_fun(&Download::download), std::mem_fun(target)), std::mem_fun(getFunc))), - rak::ftor_fn2(rak::on2(rak::on(std::mem_fun(&Download::download), std::mem_fun(target)), std::mem_fun(setFunc)))); -} - -template -utils::Variable* -var_d2_get_value(Target target, GetFunc getFunc) { - return new utils::VariableDownloadValueSlot(rak::ftor_fn1(rak::on(rak::on(std::mem_fun(&Download::download), std::mem_fun(target)), std::mem_fun(getFunc))), NULL); -} - Download::Download(download_type d) : m_download(d), m_trackerList(d.tracker_list()), @@ -87,51 +69,6 @@ Download::Download(download_type d) : m_connStorageError = m_download.signal_storage_error(sigc::mem_fun(*this, &Download::receive_storage_error)); m_download.signal_chunk_failed(sigc::mem_fun(*this, &Download::receive_chunk_failed)); - - m_variables.insert("connection_current", new utils::VariableDownloadStringSlot(rak::ftor_fn1(std::mem_fun(&Download::connection_current)), - rak::ftor_fn2(std::mem_fun(&Download::set_connection_current)))); - - m_variables.insert("connection_leech", new utils::VariableAny(connection_type_to_string(download_type::CONNECTION_LEECH))); - m_variables.insert("connection_seed", new utils::VariableAny(connection_type_to_string(download_type::CONNECTION_SEED))); - - // 0 - stopped - // 1 - started - m_variables.insert("state", new utils::VariableObject("rtorrent", "state", torrent::Object::TYPE_VALUE)); - m_variables.insert("complete", new utils::VariableObject("rtorrent", "complete", torrent::Object::TYPE_VALUE)); - - // 0 - Not hashing - // 1 - Normal hashing - // 2 - Download finished, hashing - m_variables.insert("hashing", new utils::VariableObject("rtorrent", "hashing", torrent::Object::TYPE_VALUE)); - m_variables.insert("tied_to_file", new utils::VariableObject("rtorrent", "tied_to_file", torrent::Object::TYPE_STRING)); - - // The "state_changed" variable is required to be a valid unix time - // value, it indicates the last time the torrent changed its state, - // resume/pause. - m_variables.insert("state_changed", new utils::VariableObject("rtorrent", "state_changed", torrent::Object::TYPE_VALUE)); - - m_variables.insert("directory", new utils::VariableDownloadStringSlot(rak::ftor_fn1(rak::on(std::mem_fun(&Download::file_list), std::mem_fun(&torrent::FileList::root_dir))), - rak::ftor_fn2(std::mem_fun(&Download::set_root_directory)))); - m_variables.insert("min_peers", var_d_value(&Download::download, &download_type::peers_min, &download_type::set_peers_min)); - m_variables.insert("max_peers", var_d_value(&Download::download, &download_type::peers_max, &download_type::set_peers_max)); - m_variables.insert("max_uploads", var_d_value(&Download::download, &download_type::uploads_max, &download_type::set_uploads_max)); - - m_variables.insert("max_file_size", var_d_value(&Download::file_list, &file_list_type::max_file_size, &file_list_type::set_max_file_size)); - -// m_variables.insert("split_file_size", new utils::VariableValueSlot(rak::mem_fn(file_list(), &file_list_type::split_file_size), rak::mem_fn(file_list(), &file_list_type::set_split_file_size))); -// m_variables.insert("split_suffix", new utils::VariableStringSlot(rak::mem_fn(file_list(), &file_list_type::split_suffix), rak::mem_fn(file_list(), &file_list_type::set_split_suffix))); - - m_variables.insert("up_rate", var_d2_get_value(&download_type::mutable_up_rate, &torrent::Rate::rate)); - m_variables.insert("up_total", var_d2_get_value(&download_type::mutable_up_rate, &torrent::Rate::total)); - m_variables.insert("down_rate", var_d2_get_value(&download_type::mutable_down_rate, &torrent::Rate::rate)); - m_variables.insert("down_total", var_d2_get_value(&download_type::mutable_down_rate, &torrent::Rate::total)); - m_variables.insert("skip_rate", var_d2_get_value(&download_type::mutable_skip_rate, &torrent::Rate::rate)); - m_variables.insert("skip_total", var_d2_get_value(&download_type::mutable_skip_rate, &torrent::Rate::total)); - - m_variables.insert("priority", new utils::VariableDownloadValueSlot(rak::ftor_fn1(std::mem_fun(&Download::priority)), rak::ftor_fn2(std::mem_fun(&Download::set_priority)))); - m_variables.insert("tracker_numwant", var_d_value(&Download::tracker_list, &tracker_list_type::numwant, &tracker_list_type::set_numwant)); - - m_variables.insert("ignore_commands", new utils::VariableObject("rtorrent", "ignore_commands", torrent::Object::TYPE_VALUE)); } Download::~Download() { @@ -269,6 +206,14 @@ Download::receive_chunk_failed(__UNUSED uint32_t idx) { m_chunksFailed++; } +int64_t Download::get_value(const char* key) { return control->download_variables()->get_d_value(this, key); } +const std::string& Download::get_string(const char* key) { return control->download_variables()->get_d_string(this, key); } +int64_t Download::get_std_value(const std::string& key) { return control->download_variables()->get_d_value(this, key.c_str()); } +const std::string& Download::get_std_string(const std::string& key) { return control->download_variables()->get_d_string(this, key.c_str()); } +void Download::set(const char* key, const torrent::Object& value) { return control->download_variables()->set_d(this, key, value); } +void Download::set_value(const char* key, int64_t value) { return control->download_variables()->set_d_value(this, key, value); } +void Download::set_string(const char* key, const std::string& value) { return control->download_variables()->set_d_string(this, key, value); } + // Clean up. void Download::set_root_directory(const std::string& path) { diff --git a/src/core/download.h b/src/core/download.h index e092b5b2..adacfc85 100644 --- a/src/core/download.h +++ b/src/core/download.h @@ -43,7 +43,7 @@ #include #include -#include "utils/variable_map.h" +#include "globals.h" namespace torrent { class TrackerList; @@ -57,7 +57,6 @@ public: typedef torrent::FileList file_list_type; typedef torrent::TrackerList tracker_list_type; typedef download_type::ConnectionType connection_type; - typedef utils::VariableMap variable_map_type; static const int variable_hashing_stopped = 0; static const int variable_hashing_initial = 1; @@ -101,18 +100,18 @@ public: uint32_t priority(); void set_priority(uint32_t p); -// variable_map_type* variable() { return &m_variables; } + int64_t get_value(const char* key); + const std::string& get_string(const char* key); - int64_t get_value(const char* key) { return m_variables.get_d_value(this, key); } - const std::string& get_string(const char* key) { return m_variables.get_d_string(this, key); } + int64_t get_std_value(const std::string& key); + const std::string& get_std_string(const std::string& key); - int64_t get_std_value(const std::string& key) { return m_variables.get_d_value(this, key.c_str()); } - const std::string& get_std_string(const std::string& key) { return m_variables.get_d_string(this, key.c_str()); } + void set(const char* key, const torrent::Object& value); - void set(const char* key, const torrent::Object& value) { return m_variables.set_d(this, key, value); } + void set_value(const char* key, int64_t value); + void set_string(const char* key, const std::string& value); - void set_value(const char* key, int64_t value) { return m_variables.set_d_value(this, key, value); } - void set_string(const char* key, const std::string& value) { return m_variables.set_d_string(this, key, value); } + void set_root_directory(const std::string& path); bool operator == (const std::string& str) const; @@ -121,6 +120,9 @@ public: static connection_type string_to_connection_type(const std::string& name); static const char* connection_type_to_string(connection_type t); + const char* connection_current() const { return connection_type_to_string(m_download.connection_type()); } + void set_connection_current(const std::string& t) { return m_download.set_connection_type(string_to_connection_type(t.c_str())); } + static uint32_t string_to_priority(const std::string& name); static const char* priority_to_string(uint32_t p); @@ -135,11 +137,6 @@ private: void receive_chunk_failed(uint32_t idx); - const char* connection_current() const { return connection_type_to_string(m_download.connection_type()); } - void set_connection_current(const std::string& t) { return m_download.set_connection_type(string_to_connection_type(t.c_str())); } - - void set_root_directory(const std::string& path); - // Store the FileList instance so we can use slots etc on it. download_type m_download; tracker_list_type m_trackerList; @@ -149,8 +146,6 @@ private: std::string m_message; uint32_t m_chunksFailed; - variable_map_type m_variables; - sigc::connection m_connTrackerSucceded; sigc::connection m_connTrackerFailed; sigc::connection m_connStorageError; diff --git a/src/core/download_factory.cc b/src/core/download_factory.cc index 2820e437..28900b8f 100644 --- a/src/core/download_factory.cc +++ b/src/core/download_factory.cc @@ -50,6 +50,7 @@ #include "utils/variable_generic.h" #include "curl_get.h" +#include "control.h" #include "http_queue.h" #include "globals.h" #include "manager.h" diff --git a/src/core/download_list.cc b/src/core/download_list.cc index b000650f..eab35a58 100644 --- a/src/core/download_list.cc +++ b/src/core/download_list.cc @@ -39,14 +39,16 @@ #include #include #include +#include #include #include #include #include #include -#include "rak/functional.h" +#include "utils/variable_map.h" +#include "control.h" #include "globals.h" #include "manager.h" diff --git a/src/core/manager.cc b/src/core/manager.cc index 7770228d..8e8a0a69 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -59,6 +59,7 @@ #include "globals.h" #include "curl_get.h" +#include "control.h" #include "download.h" #include "download_factory.h" #include "download_store.h" @@ -241,7 +242,7 @@ Manager::initialize_second() { m_downloadList->slot_map_insert()["1_connect_storage_log"] = sigc::bind(sigc::ptr_fun(&connect_signal_storage_log), sigc::mem_fun(m_logComplete, &Log::push_front)); m_downloadList->slot_map_insert()["1_connect_tracker_dump"] = sigc::bind(sigc::ptr_fun(&connect_signal_tracker_dump), sigc::ptr_fun(&receive_tracker_dump)); - m_downloadList->slot_map_erase()["1_delete_tied"] = sigc::mem_fun(this, &Manager::delete_tied); + m_downloadList->slot_map_erase()["9_delete_tied"] = sigc::mem_fun(this, &Manager::delete_tied); torrent::connection_manager()->set_signal_handshake_log(sigc::mem_fun(this, &Manager::handshake_log)); } diff --git a/src/core/scheduler.cc b/src/core/scheduler.cc index 5b078938..c5abc644 100644 --- a/src/core/scheduler.cc +++ b/src/core/scheduler.cc @@ -38,6 +38,7 @@ #include #include +#include #include "download.h" #include "download_list.h" diff --git a/src/core/view.cc b/src/core/view.cc index 70661667..c8bdb810 100644 --- a/src/core/view.cc +++ b/src/core/view.cc @@ -41,6 +41,7 @@ #include #include #include +#include #include "download.h" #include "download_list.h" diff --git a/src/core/view_manager.cc b/src/core/view_manager.cc index eb2f24a9..0975223e 100644 --- a/src/core/view_manager.cc +++ b/src/core/view_manager.cc @@ -39,6 +39,7 @@ #include #include #include +#include #include "globals.h" diff --git a/src/display/utils.cc b/src/display/utils.cc index 1bef4e6f..aacf3266 100644 --- a/src/display/utils.cc +++ b/src/display/utils.cc @@ -53,6 +53,7 @@ #include "core/download.h" #include "core/manager.h" +#include "control.h" #include "globals.h" #include "utils.h" diff --git a/src/globals.h b/src/globals.h index 526e0a0e..d83af5cc 100644 --- a/src/globals.h +++ b/src/globals.h @@ -40,7 +40,7 @@ #include #include -#include "control.h" +class Control; extern rak::priority_queue_default taskScheduler; extern rak::timer cachedTime; diff --git a/src/main.cc b/src/main.cc index a3f687c1..10670d65 100644 --- a/src/main.cc +++ b/src/main.cc @@ -163,7 +163,8 @@ main(int argc, char** argv) { // Initialize option handlers after libtorrent to ensure // torrent::ConnectionManager* is valid etc. - initialize_option_handler(control); + initialize_variables(); + initialize_download_variables(); control->variable()->process_multiple ( diff --git a/src/option_handler_rules.cc b/src/option_handler_rules.cc index e4443133..5b36e37d 100644 --- a/src/option_handler_rules.cc +++ b/src/option_handler_rules.cc @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -90,49 +91,49 @@ namespace core { // } void -apply_hash_read_ahead(__UNUSED Control* m, int arg) { +apply_hash_read_ahead(int arg) { torrent::set_hash_read_ahead(arg << 20); } void -apply_hash_interval(__UNUSED Control* m, int arg) { +apply_hash_interval(int arg) { torrent::set_hash_interval(arg * 1000); } // The arg string *must* have been checked with validate_port_range // first. void -apply_port_range(Control* m, const std::string& arg) { +apply_port_range(const std::string& arg) { int a = 0, b = 0; std::sscanf(arg.c_str(), "%i-%i", &a, &b); - m->core()->set_port_range(a, b); + control->core()->set_port_range(a, b); } void -apply_load(Control* m, const std::string& arg) { - m->core()->try_create_download_expand(arg, false, false, true); +apply_load(const std::string& arg) { + control->core()->try_create_download_expand(arg, false, false, true); } void -apply_load_verbose(Control* m, const std::string& arg) { - m->core()->try_create_download_expand(arg, false, true, true); +apply_load_verbose(const std::string& arg) { + control->core()->try_create_download_expand(arg, false, true, true); } void -apply_load_start(Control* m, const std::string& arg) { - m->core()->try_create_download_expand(arg, true, false, true); +apply_load_start(const std::string& arg) { + control->core()->try_create_download_expand(arg, true, false, true); } void -apply_load_start_verbose(Control* m, const std::string& arg) { - m->core()->try_create_download_expand(arg, true, true, true); +apply_load_start_verbose(const std::string& arg) { + control->core()->try_create_download_expand(arg, true, true, true); } void -apply_start_tied(Control* m) { - for (core::DownloadList::iterator itr = m->core()->download_list()->begin(); itr != m->core()->download_list()->end(); ++itr) { +apply_start_tied() { + for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) { if ((*itr)->get_value("state") == 1) continue; @@ -140,13 +141,13 @@ apply_start_tied(Control* m) { const std::string& tiedToFile = (*itr)->get_string("tied_to_file"); if (!tiedToFile.empty() && fs.update(rak::path_expand(tiedToFile))) - m->core()->download_list()->start_try(*itr); + control->core()->download_list()->start_try(*itr); } } void -apply_stop_untied(Control* m) { - for (core::DownloadList::iterator itr = m->core()->download_list()->begin(); itr != m->core()->download_list()->end(); ++itr) { +apply_stop_untied() { + for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) { if ((*itr)->get_value("state") == 0) continue; @@ -154,41 +155,41 @@ apply_stop_untied(Control* m) { const std::string& tiedToFile = (*itr)->get_string("tied_to_file"); if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile))) - m->core()->download_list()->stop_try(*itr); + control->core()->download_list()->stop_try(*itr); } } void -apply_close_untied(Control* m) { - for (core::DownloadList::iterator itr = m->core()->download_list()->begin(); itr != m->core()->download_list()->end(); ++itr) { +apply_close_untied() { + for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) { rak::file_stat fs; const std::string& tiedToFile = (*itr)->get_string("tied_to_file"); - if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile)) && m->core()->download_list()->stop_try(*itr)) - m->core()->download_list()->close(*itr); + if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile)) && control->core()->download_list()->stop_try(*itr)) + control->core()->download_list()->close(*itr); } } void -apply_remove_untied(Control* m) { - for (core::DownloadList::iterator itr = m->core()->download_list()->begin(); itr != m->core()->download_list()->end(); ) { +apply_remove_untied() { + for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ) { rak::file_stat fs; const std::string& tiedToFile = (*itr)->get_string("tied_to_file"); - if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile)) && m->core()->download_list()->stop_try(*itr)) - itr = m->core()->download_list()->erase(itr); + if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile)) && control->core()->download_list()->stop_try(*itr)) + itr = control->core()->download_list()->erase(itr); else ++itr; } } void -apply_close_low_diskspace(Control* m, int64_t arg) { - core::Manager::DListItr itr = m->core()->download_list()->begin(); +apply_close_low_diskspace(int64_t arg) { + core::Manager::DListItr itr = control->core()->download_list()->begin(); - while ((itr = std::find_if(itr, m->core()->download_list()->end(), std::mem_fun(&core::Download::is_downloading))) != m->core()->download_list()->end()) { + while ((itr = std::find_if(itr, control->core()->download_list()->end(), std::mem_fun(&core::Download::is_downloading))) != control->core()->download_list()->end()) { if ((*itr)->file_list()->free_diskspace() < (uint64_t)arg) { - m->core()->download_list()->close(*itr); + control->core()->download_list()->close(*itr); (*itr)->set_hash_failed(true); (*itr)->set_message(std::string("Low diskspace.")); @@ -199,7 +200,7 @@ apply_close_low_diskspace(Control* m, int64_t arg) { } void -apply_stop_on_ratio(Control* m, const std::string& arg) { +apply_stop_on_ratio(const std::string& arg) { int64_t minRatio = 0; // first argument: minimum ratio to reach int64_t minUpload = 0; // second argument: minimum upload amount to reach [optional] int64_t maxRatio = 0; // third argument: maximum ratio to reach [optional] @@ -214,14 +215,14 @@ apply_stop_on_ratio(Control* m, const std::string& arg) { if (++sitr != rak::split_iterator(arg)) utils::Variable::string_to_value_unit(rak::trim(*sitr).c_str(), &maxRatio, 0, 1); - core::Manager::DListItr itr = m->core()->download_list()->begin(); + core::Manager::DListItr itr = control->core()->download_list()->begin(); - while ((itr = std::find_if(itr, m->core()->download_list()->end(), std::mem_fun(&core::Download::is_seeding))) != m->core()->download_list()->end()) { + while ((itr = std::find_if(itr, control->core()->download_list()->end(), std::mem_fun(&core::Download::is_seeding))) != control->core()->download_list()->end()) { int64_t totalUpload = (*itr)->download()->up_rate()->total(); int64_t totalDone = (*itr)->download()->bytes_done(); if ((totalUpload >= minUpload && totalUpload * 100 >= totalDone * minRatio) || (maxRatio > 0 && totalUpload * 100 > totalDone * maxRatio)) { - m->core()->download_list()->stop_try(*itr); + control->core()->download_list()->stop_try(*itr); (*itr)->set("ignore_commands", (int64_t)1); } @@ -229,25 +230,24 @@ apply_stop_on_ratio(Control* m, const std::string& arg) { } } -// void -// apply_on_finished(const std::string& arg) { -// std::string::const_iterator itr = std::find(arg.begin(), arg.end(), ','); +void +apply_on_state_change(core::DownloadList::slot_map* slotMap, const std::string& arg) { + std::string::const_iterator itr = std::find(arg.begin(), arg.end(), ','); -// std::string key = rak::trim(std::string(arg.begin(), itr)); -// std::string value = rak::trim(std::string(itr != arg.end() ? itr + 1 : itr, arg.end())); + std::string key = rak::trim(std::string(arg.begin(), itr)); + std::string value = rak::trim(std::string(itr != arg.end() ? itr + 1 : itr, arg.end())); -// if (key.empty()) -// throw torrent::input_error("Empty key."); + if (key.empty()) + throw torrent::input_error("Empty key."); -// if (value.empty()) -// control->core()->download_list()->slot_map_finished().erase("0_finished_" + key); -// else -// control->core()->download_list()->slot_map_finished().insert("0_finished_" + key, ); -// ->process_std_single(value); -// } + if (value.empty()) + slotMap->erase("1_start_" + key); + else + (*slotMap)["1_start_" + key] = sigc::bind(sigc::mem_fun(control->download_variables(), &utils::VariableMap::process_d_std_single), value); +} void -apply_encoding_list(__UNUSED Control* m, const std::string& arg) { +apply_encoding_list(const std::string& arg) { torrent::encoding_list()->push_back(arg); } @@ -282,10 +282,10 @@ apply_encryption(const std::string& arg) { } void -apply_enable_trackers(Control* m, __UNUSED const std::string& arg) { +apply_enable_trackers(__UNUSED const std::string& arg) { bool state = (arg != "no"); - for (core::Manager::DListItr itr = m->core()->download_list()->begin(), last = m->core()->download_list()->end(); itr != last; ++itr) { + for (core::Manager::DListItr itr = control->core()->download_list()->begin(), last = control->core()->download_list()->end(); itr != last; ++itr) { torrent::TrackerList tl = (*itr)->download()->tracker_list(); @@ -327,7 +327,7 @@ apply_tos(const std::string& arg) { } void -apply_view_filter(Control* control, const std::string& arg) { +apply_view_filter(const std::string& arg) { rak::split_iterator_t itr = rak::split_iterator(arg, ','); std::string name = rak::trim(*itr); @@ -348,7 +348,7 @@ apply_view_filter(Control* control, const std::string& arg) { } void -apply_view_filter_on(Control* control, const std::string& arg) { +apply_view_filter_on(const std::string& arg) { rak::split_iterator_t itr = rak::split_iterator(arg, ','); std::string name = rak::trim(*itr); @@ -369,7 +369,7 @@ apply_view_filter_on(Control* control, const std::string& arg) { } void -apply_view_sort(Control* control, const std::string& arg) { +apply_view_sort(const std::string& arg) { rak::split_iterator_t itr = rak::split_iterator(arg, ','); std::string name = rak::trim(*itr); @@ -394,7 +394,7 @@ apply_view_sort(Control* control, const std::string& arg) { } void -apply_view_sort_current(Control* control, const std::string& arg) { +apply_view_sort_current(const std::string& arg) { rak::split_iterator_t itr = rak::split_iterator(arg, ','); std::string name = rak::trim(*itr); @@ -415,7 +415,7 @@ apply_view_sort_current(Control* control, const std::string& arg) { } void -apply_view_sort_new(Control* control, const std::string& arg) { +apply_view_sort_new(const std::string& arg) { rak::split_iterator_t itr = rak::split_iterator(arg, ','); std::string name = rak::trim(*itr); @@ -448,7 +448,7 @@ apply_try_import(const std::string& path) { } void -initialize_option_handler(Control* c) { +initialize_variables() { utils::VariableMap* variables = control->variable(); variables->insert("check_hash", new utils::VariableBool(true)); @@ -462,14 +462,14 @@ initialize_option_handler(Control* c) { rak::mem_fn(control->core()->download_store(), &core::DownloadStore::set_path))); variables->insert("session_lock", new utils::VariableBool(true)); variables->insert("session_on_completion", new utils::VariableBool(true)); - variables->insert("session_save", new utils::VariableVoidSlot(rak::mem_fn(c->core()->download_list(), &core::DownloadList::session_save))); + variables->insert("session_save", new utils::VariableVoidSlot(rak::mem_fn(control->core()->download_list(), &core::DownloadList::session_save))); variables->insert("connection_leech", new utils::VariableAny("leech")); variables->insert("connection_seed", new utils::VariableAny("seed")); variables->insert("directory", new utils::VariableAny("./")); - variables->insert("tos", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::ptr_fn(&apply_tos))); + variables->insert("tos", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_tos))); variables->insert("bind", new utils::VariableStringSlot(rak::mem_fn(control->core(), &core::Manager::bind_address), rak::mem_fn(control->core(), &core::Manager::set_bind_address))); @@ -478,8 +478,8 @@ initialize_option_handler(Control* c) { variables->insert("connection_proxy", new utils::VariableStringSlot(rak::mem_fn(control->core(), &core::Manager::proxy_address), rak::mem_fn(control->core(), &core::Manager::set_proxy_address))); - variables->insert("http_proxy", new utils::VariableStringSlot(rak::mem_fn(c->core()->get_poll_manager()->get_http_stack(), &core::CurlStack::http_proxy), - rak::mem_fn(c->core()->get_poll_manager()->get_http_stack(), &core::CurlStack::set_http_proxy))); + variables->insert("http_proxy", new utils::VariableStringSlot(rak::mem_fn(control->core()->get_poll_manager()->get_http_stack(), &core::CurlStack::http_proxy), + rak::mem_fn(control->core()->get_poll_manager()->get_http_stack(), &core::CurlStack::set_http_proxy))); variables->insert("min_peers", new utils::VariableValue(40)); variables->insert("max_peers", new utils::VariableValue(100)); @@ -499,26 +499,26 @@ initialize_option_handler(Control* c) { variables->insert("max_open_files", new utils::VariableValueSlot(rak::ptr_fn(&torrent::max_open_files), rak::ptr_fn(&torrent::set_max_open_files))); variables->insert("max_open_sockets", new utils::VariableValueSlot(rak::mem_fn(torrent::connection_manager(), &torrent::ConnectionManager::max_size), rak::mem_fn(torrent::connection_manager(), &torrent::ConnectionManager::set_max_size))); - variables->insert("max_open_http", new utils::VariableValueSlot(rak::mem_fn(c->core()->get_poll_manager()->get_http_stack(), &core::CurlStack::max_active), - rak::mem_fn(c->core()->get_poll_manager()->get_http_stack(), &core::CurlStack::set_max_active))); + variables->insert("max_open_http", new utils::VariableValueSlot(rak::mem_fn(control->core()->get_poll_manager()->get_http_stack(), &core::CurlStack::max_active), + rak::mem_fn(control->core()->get_poll_manager()->get_http_stack(), &core::CurlStack::set_max_active))); - variables->insert("print", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::mem_fn(control->core(), &core::Manager::push_log))); - variables->insert("import", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::ptr_fn(&apply_import))); - variables->insert("try_import", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::ptr_fn(&apply_try_import))); + variables->insert("print", new utils::VariableStringSlot(NULL, rak::mem_fn(control->core(), &core::Manager::push_log))); + variables->insert("import", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_import))); + variables->insert("try_import", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_try_import))); - variables->insert("view_add", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::mem_fn(c->view_manager(), &core::ViewManager::insert_throw))); - variables->insert("view_filter", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_view_filter, c))); - variables->insert("view_filter_on", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_view_filter_on, c))); + variables->insert("view_add", new utils::VariableStringSlot(NULL, rak::mem_fn(control->view_manager(), &core::ViewManager::insert_throw))); + variables->insert("view_filter", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_view_filter))); + variables->insert("view_filter_on", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_view_filter_on))); - variables->insert("view_sort", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_view_sort, c))); - variables->insert("view_sort_new", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_view_sort_new, c))); - variables->insert("view_sort_current", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_view_sort_current, c))); + variables->insert("view_sort", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_view_sort))); + variables->insert("view_sort_new", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_view_sort_new))); + variables->insert("view_sort_current", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_view_sort_current))); variables->insert("key_layout", new utils::VariableAny(std::string("qwerty"))); - variables->insert("schedule", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::mem_fn(c->command_scheduler(), &CommandScheduler::parse))); - variables->insert("schedule_remove", new utils::VariableStringSlot(rak::value_fn(std::string()), - rak::mem_fn(c->command_scheduler(), &CommandScheduler::erase))); + variables->insert("schedule", new utils::VariableStringSlot(NULL, rak::mem_fn(control->command_scheduler(), &CommandScheduler::parse))); + variables->insert("schedule_remove", new utils::VariableStringSlot(NULL, + rak::mem_fn(control->command_scheduler(), &CommandScheduler::erase))); variables->insert("download_scheduler", new utils::VariableVoidSlot(rak::mem_fn(control->scheduler(), &core::Scheduler::update))); @@ -554,33 +554,179 @@ initialize_option_handler(Control* c) { variables->insert("split_file_size", new utils::VariableValue(-1)); variables->insert("split_suffix", new utils::VariableAny(".part")); - variables->insert("port_range", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_port_range, c))); + variables->insert("port_range", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_port_range))); - variables->insert("hash_read_ahead", new utils::VariableValueSlot(rak::ptr_fn(torrent::hash_read_ahead), rak::bind_ptr_fn(&apply_hash_read_ahead, c))); - variables->insert("hash_interval", new utils::VariableValueSlot(rak::ptr_fn(torrent::hash_interval), rak::bind_ptr_fn(&apply_hash_interval, c))); + variables->insert("hash_read_ahead", new utils::VariableValueSlot(rak::ptr_fn(torrent::hash_read_ahead), rak::ptr_fn(&apply_hash_read_ahead))); + variables->insert("hash_interval", new utils::VariableValueSlot(rak::ptr_fn(torrent::hash_interval), rak::ptr_fn(&apply_hash_interval))); variables->insert("umask", new utils::VariableValueSlot(rak::mem_fn(control, &Control::umask), rak::mem_fn(control, &Control::set_umask), 8)); variables->insert("working_directory", new utils::VariableStringSlot(rak::mem_fn(control, &Control::working_directory), rak::mem_fn(control, &Control::set_working_directory))); - variables->insert("load", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_load, c))); - variables->insert("load_verbose", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_load_verbose, c))); - variables->insert("load_start", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_load_start, c))); - variables->insert("load_start_verbose", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_load_start_verbose, c))); + variables->insert("load", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_load))); + variables->insert("load_verbose", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_load_verbose))); + variables->insert("load_start", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_load_start))); + variables->insert("load_start_verbose", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_load_start_verbose))); - variables->insert("start_tied", new utils::VariableVoidSlot(rak::bind_ptr_fn(&apply_start_tied, c))); - variables->insert("stop_untied", new utils::VariableVoidSlot(rak::bind_ptr_fn(&apply_stop_untied, c))); - variables->insert("close_untied", new utils::VariableVoidSlot(rak::bind_ptr_fn(&apply_close_untied, c))); - variables->insert("remove_untied", new utils::VariableVoidSlot(rak::bind_ptr_fn(&apply_remove_untied, c))); + variables->insert("start_tied", new utils::VariableVoidSlot(rak::ptr_fn(&apply_start_tied))); + variables->insert("stop_untied", new utils::VariableVoidSlot(rak::ptr_fn(&apply_stop_untied))); + variables->insert("close_untied", new utils::VariableVoidSlot(rak::ptr_fn(&apply_close_untied))); + variables->insert("remove_untied", new utils::VariableVoidSlot(rak::ptr_fn(&apply_remove_untied))); - variables->insert("close_low_diskspace", new utils::VariableValueSlot(rak::value_fn(int64_t()), rak::bind_ptr_fn(&apply_close_low_diskspace, c))); - variables->insert("stop_on_ratio", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_stop_on_ratio, c))); + variables->insert("close_low_diskspace", new utils::VariableValueSlot(rak::value_fn(int64_t()), rak::ptr_fn(&apply_close_low_diskspace))); + variables->insert("stop_on_ratio", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_stop_on_ratio))); -// variables->insert("on_finished", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::ptr_fn(&apply_on_finished))); + variables->insert("on_insert", new utils::VariableStringSlot(NULL, rak::bind_ptr_fn(&apply_on_state_change, &control->core()->download_list()->slot_map_insert()))); + variables->insert("on_erase", new utils::VariableStringSlot(NULL, rak::bind_ptr_fn(&apply_on_state_change, &control->core()->download_list()->slot_map_erase()))); + variables->insert("on_open", new utils::VariableStringSlot(NULL, rak::bind_ptr_fn(&apply_on_state_change, &control->core()->download_list()->slot_map_open()))); + variables->insert("on_close", new utils::VariableStringSlot(NULL, rak::bind_ptr_fn(&apply_on_state_change, &control->core()->download_list()->slot_map_close()))); + variables->insert("on_start", new utils::VariableStringSlot(NULL, rak::bind_ptr_fn(&apply_on_state_change, &control->core()->download_list()->slot_map_start()))); + variables->insert("on_stop", new utils::VariableStringSlot(NULL, rak::bind_ptr_fn(&apply_on_state_change, &control->core()->download_list()->slot_map_stop()))); + variables->insert("on_hash_queued", new utils::VariableStringSlot(NULL, rak::bind_ptr_fn(&apply_on_state_change, &control->core()->download_list()->slot_map_hash_queued()))); + variables->insert("on_hash_removed", new utils::VariableStringSlot(NULL, rak::bind_ptr_fn(&apply_on_state_change, &control->core()->download_list()->slot_map_hash_removed()))); + variables->insert("on_hash_done", new utils::VariableStringSlot(NULL, rak::bind_ptr_fn(&apply_on_state_change, &control->core()->download_list()->slot_map_hash_done()))); + variables->insert("on_finished", new utils::VariableStringSlot(NULL, rak::bind_ptr_fn(&apply_on_state_change, &control->core()->download_list()->slot_map_finished()))); - variables->insert("enable_trackers", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_enable_trackers, c))); - variables->insert("encoding_list", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_encoding_list, c))); + variables->insert("enable_trackers", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_enable_trackers))); + variables->insert("encoding_list", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_encoding_list))); - variables->insert("encryption", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::ptr_fn(&apply_encryption))); + variables->insert("encryption", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_encryption))); variables->insert("handshake_log", new utils::VariableBool(false)); } + +template +utils::Variable* +var_d_value(Target target, GetFunc getFunc, SetFunc setFunc) { + return new utils::VariableDownloadValueSlot(rak::ftor_fn1(rak::on(std::mem_fun(target), std::mem_fun(getFunc))), + rak::ftor_fn2(rak::on2(std::mem_fun(target), std::mem_fun(setFunc)))); +} + +template +utils::Variable* +var_d2_value(Target target, GetFunc getFunc, SetFunc setFunc) { + return new utils::VariableDownloadValueSlot(rak::ftor_fn1(rak::on(rak::on(std::mem_fun(&core::Download::download), std::mem_fun(target)), std::mem_fun(getFunc))), + rak::ftor_fn2(rak::on2(rak::on(std::mem_fun(&core::Download::download), std::mem_fun(target)), std::mem_fun(setFunc)))); +} + +template +utils::Variable* +var_d2_get_value(Target target, GetFunc getFunc) { + return new utils::VariableDownloadValueSlot(rak::ftor_fn1(rak::on(rak::on(std::mem_fun(&core::Download::download), std::mem_fun(target)), std::mem_fun(getFunc))), NULL); +} + +void +apply_d_create_link(core::Download* download, const std::string& args) { + rak::split_iterator_t itr = rak::split_iterator(args, ','); + + std::string type = rak::trim(*itr); ++itr; + std::string prefix = rak::trim(*itr); ++itr; + std::string postfix = rak::trim(*itr); ++itr; + + if (type.empty()) + throw torrent::input_error("Invalid arguments."); + + std::string target; + std::string link; + + if (type == "tied") { + target = rak::path_expand(download->get_string("tied_to_file")); + link = rak::path_expand(prefix + target.substr(target.rfind('/') != std::string::npos ? target.rfind('/') + 1 : 0) + postfix); + } else { + throw torrent::input_error("Unknown type argument."); + } + + if (target.empty()) + return; + + if (symlink(target.c_str(), link.c_str()) == -1) + ; // control->core()->push_log("create_link failed: " + std::string(rak::error_number::current().c_str())); +} + +void +apply_d_delete_link(core::Download* download, const std::string& args) { + rak::split_iterator_t itr = rak::split_iterator(args, ','); + + std::string type = rak::trim(*itr); ++itr; + std::string prefix = rak::trim(*itr); ++itr; + std::string postfix = rak::trim(*itr); ++itr; + + if (type.empty()) + throw torrent::input_error("Invalid arguments."); + + std::string target; + std::string link; + + if (type == "tied") { + target = rak::path_expand(download->get_string("tied_to_file")); + link = rak::path_expand(prefix + target.substr(target.rfind('/') != std::string::npos ? target.rfind('/') + 1 : 0) + postfix); + } else { + throw torrent::input_error("Unknown type argument."); + } + + if (target.empty()) + return; + + rak::file_stat fileStat; + rak::error_number::clear_global(); + + if (!fileStat.update_link(link) || !fileStat.is_link() || + unlink(link.c_str()) == -1) + ; // control->core()->push_log("delete_link failed: " + std::string(rak::error_number::current().c_str())); +} + +void +initialize_download_variables() { + utils::VariableMap* variables = control->download_variables(); + + variables->insert("connection_current", new utils::VariableDownloadStringSlot(rak::ftor_fn1(std::mem_fun(&core::Download::connection_current)), + rak::ftor_fn2(std::mem_fun(&core::Download::set_connection_current)))); + + variables->insert("connection_leech", new utils::VariableAny(core::Download::connection_type_to_string(torrent::Download::CONNECTION_LEECH))); + variables->insert("connection_seed", new utils::VariableAny(core::Download::connection_type_to_string(torrent::Download::CONNECTION_SEED))); + + // 0 - stopped + // 1 - started + variables->insert("state", new utils::VariableObject("rtorrent", "state", torrent::Object::TYPE_VALUE)); + variables->insert("complete", new utils::VariableObject("rtorrent", "complete", torrent::Object::TYPE_VALUE)); + + // 0 - Not hashing + // 1 - Normal hashing + // 2 - Download finished, hashing + variables->insert("hashing", new utils::VariableObject("rtorrent", "hashing", torrent::Object::TYPE_VALUE)); + variables->insert("tied_to_file", new utils::VariableObject("rtorrent", "tied_to_file", torrent::Object::TYPE_STRING)); + + // The "state_changed" variable is required to be a valid unix time + // value, it indicates the last time the torrent changed its state, + // resume/pause. + variables->insert("state_changed", new utils::VariableObject("rtorrent", "state_changed", torrent::Object::TYPE_VALUE)); + + variables->insert("directory", new utils::VariableDownloadStringSlot(rak::ftor_fn1(rak::on(std::mem_fun(&core::Download::file_list), std::mem_fun(&torrent::FileList::root_dir))), + rak::ftor_fn2(std::mem_fun(&core::Download::set_root_directory)))); + variables->insert("min_peers", var_d_value(&core::Download::download, &torrent::Download::peers_min, &torrent::Download::set_peers_min)); + variables->insert("max_peers", var_d_value(&core::Download::download, &torrent::Download::peers_max, &torrent::Download::set_peers_max)); + variables->insert("max_uploads", var_d_value(&core::Download::download, &torrent::Download::uploads_max, &torrent::Download::set_uploads_max)); + + variables->insert("max_file_size", var_d_value(&core::Download::file_list, &torrent::FileList::max_file_size, &torrent::FileList::set_max_file_size)); + + // variables->insert("split_file_size", new utils::VariableValueSlot(rak::mem_fn(file_list(), &torrent::FileList::split_file_size), + // rak::mem_fn(file_list(), &torrent::FileList::set_split_file_size))); + // variables->insert("split_suffix", new utils::VariableStringSlot(rak::mem_fn(file_list(), &torrent::FileList::split_suffix), + // rak::mem_fn(file_list(), &torrent::FileList::set_split_suffix))); + + variables->insert("up_rate", var_d2_get_value(&torrent::Download::mutable_up_rate, &torrent::Rate::rate)); + variables->insert("up_total", var_d2_get_value(&torrent::Download::mutable_up_rate, &torrent::Rate::total)); + variables->insert("down_rate", var_d2_get_value(&torrent::Download::mutable_down_rate, &torrent::Rate::rate)); + variables->insert("down_total", var_d2_get_value(&torrent::Download::mutable_down_rate, &torrent::Rate::total)); + variables->insert("skip_rate", var_d2_get_value(&torrent::Download::mutable_skip_rate, &torrent::Rate::rate)); + variables->insert("skip_total", var_d2_get_value(&torrent::Download::mutable_skip_rate, &torrent::Rate::total)); + + variables->insert("priority", new utils::VariableDownloadValueSlot(rak::ftor_fn1(std::mem_fun(&core::Download::priority)), rak::ftor_fn2(std::mem_fun(&core::Download::set_priority)))); + variables->insert("tracker_numwant", var_d_value(&core::Download::tracker_list, &torrent::TrackerList::numwant, &torrent::TrackerList::set_numwant)); + + variables->insert("ignore_commands", new utils::VariableObject("rtorrent", "ignore_commands", torrent::Object::TYPE_VALUE)); + + // Hmm... do we need dupicates? + variables->insert("print", new utils::VariableStringSlot(NULL, rak::mem_fn(control->core(), &core::Manager::push_log))); + variables->insert("create_link", new utils::VariableDownloadStringSlot(NULL, rak::ptr_fn(&apply_d_create_link))); + variables->insert("delete_link", new utils::VariableDownloadStringSlot(NULL, rak::ptr_fn(&apply_d_delete_link))); +} diff --git a/src/option_handler_rules.h b/src/option_handler_rules.h index 61432253..c07f76bc 100644 --- a/src/option_handler_rules.h +++ b/src/option_handler_rules.h @@ -39,6 +39,7 @@ class Control; -void initialize_option_handler(Control* c); +void initialize_variables(); +void initialize_download_variables(); #endif diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc index 4c2616a5..47e68454 100644 --- a/src/ui/download_list.cc +++ b/src/ui/download_list.cc @@ -56,6 +56,8 @@ #include "display/window_log.h" #include "display/window_title.h" +#include "utils/variable_map.h" + #include "control.h" #include "download.h" #include "download_list.h" diff --git a/src/ui/element_download_list.cc b/src/ui/element_download_list.cc index c4867aee..9d2d3735 100644 --- a/src/ui/element_download_list.cc +++ b/src/ui/element_download_list.cc @@ -38,6 +38,7 @@ #include #include +#include #include "core/download.h" #include "core/manager.h" diff --git a/src/utils/variable_generic.cc b/src/utils/variable_generic.cc index def7ca46..6aeba4d7 100644 --- a/src/utils/variable_generic.cc +++ b/src/utils/variable_generic.cc @@ -234,9 +234,7 @@ VariableStringSlot::get() { if (!m_slotGet.is_valid()) return m_cache = torrent::Object(); - m_cache = m_slotGet(); - - return m_cache; + return m_cache = m_slotGet(); } void diff --git a/src/utils/variable_generic.h b/src/utils/variable_generic.h index 45d9d458..ea37307e 100644 --- a/src/utils/variable_generic.h +++ b/src/utils/variable_generic.h @@ -234,6 +234,12 @@ public: typedef rak::function0 slot_get_type; typedef rak::function1 slot_set_type; + template + VariableStringSlot(void* slotGet, SlotSet* slotSet) { + m_slotGet.set(NULL); + m_slotSet.set(rak::convert_fn(slotSet)); + } + template VariableStringSlot(SlotGet* slotGet, SlotSet* slotSet) { m_slotGet.set(rak::convert_fn(slotGet)); @@ -258,6 +264,12 @@ public: typedef rak::function1 slot_get_d_type; typedef rak::function2 slot_set_d_type; + template + VariableDownloadStringSlot(void* slotGetDownload, SlotSetDownload* slotSetDownload) { + m_slotGetDownload.set(NULL); + m_slotSetDownload.set(rak::convert_fn(slotSetDownload)); + } + template VariableDownloadStringSlot(SlotGetDownload* slotGetDownload, SlotSetDownload* slotSetDownload) { m_slotGetDownload.set(rak::convert_fn(slotGetDownload)); diff --git a/src/utils/variable_map.cc b/src/utils/variable_map.cc index 00e623e7..d6afd496 100644 --- a/src/utils/variable_map.cc +++ b/src/utils/variable_map.cc @@ -205,6 +205,35 @@ VariableMap::process_single(const char* first, const char* last) { return std::find_if(first, last, std::not1(variable_map_is_space())); } +const char* +VariableMap::process_d_single(core::Download* download, const char* first, const char* last) { + first = std::find_if(first, last, std::not1(variable_map_is_space())); + + if (first == last || *first == '#') + return last; + + std::string key; + first = parse_name(first, last, &key); + first = std::find_if(first, last, std::not1(variable_map_is_space())); + + if (first == last || *first != '=') + throw torrent::input_error("Could not find '='."); + + mapped_type args(mapped_type::TYPE_LIST); + first = parse_args(first + 1, last, &args.as_list()); + + if (args.as_list().empty()) + set_d(download, key.c_str(), mapped_type()); + + else if (++args.as_list().begin() == args.as_list().end()) + set_d(download, key.c_str(), *args.as_list().begin()); + + else + set_d(download, key.c_str(), args); + + return std::find_if(first, last, std::not1(variable_map_is_space())); +} + // void // VariableMap::process_command(const std::string& command) { // std::string::const_iterator pos = command.begin(); diff --git a/src/utils/variable_map.h b/src/utils/variable_map.h index 6091c5d5..085bfcfa 100644 --- a/src/utils/variable_map.h +++ b/src/utils/variable_map.h @@ -96,8 +96,9 @@ public: void set(key_type key, const mapped_type& arg); void set_d(core::Download* download, key_type key, const mapped_type& arg); - void set_string(key_type key, const std::string& arg) { set(key, mapped_type(arg)); } - void set_d_string(core::Download* download, key_type key, const std::string& arg) { set_d(download, key, mapped_type(arg)); } + void set_string(key_type key, const std::string& arg) { set(key, mapped_type(arg)); } + void set_d_string(core::Download* download, key_type key, const std::string& arg) { set_d(download, key, mapped_type(arg)); } + void set_d_std_string(core::Download* download, const std::string& key, const std::string& arg) { set_d(download, key.c_str(), mapped_type(arg)); } void set_value(key_type key, mapped_value_type arg) { set(key, mapped_type(arg)); } void set_d_value(core::Download* download, key_type key, mapped_value_type arg) { set_d(download, key, mapped_type(arg)); } @@ -108,6 +109,9 @@ public: const char* process_single(const char* first, const char* last); void process_std_single(const std::string& cmd) { process_single(cmd.c_str(), cmd.c_str() + cmd.size()); } + const char* process_d_single(core::Download* download, const char* first, const char* last); + void process_d_std_single(core::Download* download, const std::string& cmd) { process_d_single(download, cmd.c_str(), cmd.c_str() + cmd.size()); } + void process_multiple(const char* first); void process_stream(std::istream* str);