diff --git a/src/control.cc b/src/control.cc index 94b94539..89eff59d 100644 --- a/src/control.cc +++ b/src/control.cc @@ -116,7 +116,7 @@ Control::initialize() { m_core->initialize_second(); m_core->listen_open(); - m_core->download_store()->enable(m_variables->get_value("session_lock")); + m_core->download_store()->enable(m_variables->get_value("get_session_lock")); m_core->set_hashing_view(*m_viewManager->find_throw("hashing")); m_scheduler->set_view(*m_viewManager->find_throw("scheduler")); diff --git a/src/core/download_factory.cc b/src/core/download_factory.cc index 28900b8f..385d29b2 100644 --- a/src/core/download_factory.cc +++ b/src/core/download_factory.cc @@ -176,32 +176,32 @@ DownloadFactory::receive_success() { download->set("connection_leech", m_variables.get("connection_leech")); download->set("connection_seed", m_variables.get("connection_seed")); - download->set("max_uploads", control->variable()->get("max_uploads")); - download->set("min_peers", control->variable()->get("min_peers")); - download->set("max_peers", control->variable()->get("max_peers")); - download->set("tracker_numwant", control->variable()->get("tracker_numwant")); + download->set("max_uploads", control->variable()->get("get_max_uploads")); + download->set("min_peers", control->variable()->get("get_min_peers")); + download->set("max_peers", control->variable()->get("get_max_peers")); + download->set("tracker_numwant", control->variable()->get("get_tracker_numwant")); if (download->get_value("complete") != 0) { - if (control->variable()->get_value("min_peers_seed") >= 0) - download->set("min_peers", control->variable()->get("min_peers_seed")); + if (control->variable()->get_value("get_min_peers_seed") >= 0) + download->set("min_peers", control->variable()->get("get_min_peers_seed")); - if (control->variable()->get_value("max_peers_seed") >= 0) - download->set("max_peers", control->variable()->get("max_peers_seed")); + if (control->variable()->get_value("get_max_peers_seed") >= 0) + download->set("max_peers", control->variable()->get("get_max_peers_seed")); } - if (!control->variable()->get_value("use_udp_trackers")) + if (!control->variable()->get_value("get_use_udp_trackers")) download->enable_udp_trackers(false); - if (control->variable()->get_value("max_file_size") > 0) - download->set("max_file_size", control->variable()->get("max_file_size")); + if (control->variable()->get_value("get_max_file_size") > 0) + download->set("max_file_size", control->variable()->get("get_max_file_size")); // Check first if we already have these values set in the session // torrent, so that it is safe to change the values. // // Need to also catch the exceptions. - if (control->variable()->get_value("split_file_size") >= 0) + if (control->variable()->get_value("get_split_file_size") >= 0) torrent::file_split_all(download->download()->file_list(), - control->variable()->get_value("split_file_size"), + control->variable()->get_value("get_split_file_size"), control->variable()->get_string("split_suffix")); if (!rtorrent->has_key_string("directory")) diff --git a/src/core/download_list.cc b/src/core/download_list.cc index 4965203a..dc46a63f 100644 --- a/src/core/download_list.cc +++ b/src/core/download_list.cc @@ -501,7 +501,7 @@ void DownloadList::received_finished(Download* download) { check_contains(download); - if (control->variable()->get_value("check_hash")) { + if (control->variable()->get_value("get_check_hash")) { // Set some 'checking_finished_thingie' variable to make hash_done // trigger correctly, also so it can bork on missing data. hash_queue(download, Download::variable_hashing_last); @@ -521,15 +521,15 @@ DownloadList::confirm_finished(Download* download) { download->set_connection_type(download->get_string("connection_seed")); download->set_priority(download->priority()); - if (download->get_value("min_peers") == control->variable()->get_value("min_peers") && control->variable()->get_value("min_peers_seed") >= 0) - download->set("min_peers", control->variable()->get("min_peers_seed")); + if (download->get_value("min_peers") == control->variable()->get_value("get_min_peers") && control->variable()->get_value("get_min_peers_seed") >= 0) + download->set("min_peers", control->variable()->get("get_min_peers_seed")); - if (download->get_value("max_peers") == control->variable()->get_value("max_peers") && control->variable()->get_value("max_peers_seed") >= 0) - download->set("max_peers", control->variable()->get("max_peers_seed")); + if (download->get_value("max_peers") == control->variable()->get_value("get_max_peers") && control->variable()->get_value("get_max_peers_seed") >= 0) + download->set("max_peers", control->variable()->get("get_max_peers_seed")); // Do this before the slots are called in case one of them closes // the download. - if (!download->is_active() && control->variable()->get_value("session_on_completion") != 0) { + if (!download->is_active() && control->variable()->get_value("get_session_on_completion") != 0) { torrent::resume_save_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume")); control->core()->download_store()->save(download); } diff --git a/src/core/manager.cc b/src/core/manager.cc index 69b56245..c260e888 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -108,7 +108,7 @@ receive_tracker_dump(const std::string& url, const char* data, size_t size) { void Manager::handshake_log(const sockaddr* sa, int msg, int err, const torrent::HashString* hash) { - if (!control->variable()->get_value("handshake_log")) + if (!control->variable()->get_value("get_handshake_log")) return; std::string peer; @@ -276,13 +276,13 @@ Manager::shutdown(bool force) { void Manager::listen_open() { - if (!control->variable()->get_value("port_open")) + if (!control->variable()->get_value("get_port_open")) return; if (m_portFirst > m_portLast) throw torrent::input_error("Invalid port range for listening"); - if (control->variable()->get_value("port_random")) { + if (control->variable()->get_value("get_port_random")) { int boundary = m_portFirst + random() % (m_portLast - m_portFirst + 1); if (torrent::connection_manager()->listen_open(boundary, m_portLast) || diff --git a/src/option_handler_rules.cc b/src/option_handler_rules.cc index a1626366..323080a6 100644 --- a/src/option_handler_rules.cc +++ b/src/option_handler_rules.cc @@ -67,6 +67,7 @@ #include "rpc/fast_cgi.h" #include "rpc/xmlrpc.h" #include "ui/root.h" +#include "utils/command_variable.h" #include "utils/directory.h" #include "utils/parse.h" #include "utils/variable_generic.h" @@ -274,7 +275,7 @@ apply_enable_trackers(const std::string& arg) { else tl.get(i).disable(); - if (state && !control->variable()->get_value("use_udp_trackers")) + if (state && !control->variable()->get_value("get_use_udp_trackers")) (*itr)->enable_udp_trackers(false); } } @@ -436,21 +437,50 @@ apply_schedule(const torrent::Object::list_type& args) { control->command_scheduler()->parse(arg1, arg2, arg3, utils::convert_list_to_command(itr, args.end())); } +void +add_variable(const char* getKey, const char* setKey, const char* defaultSetKey, + utils::VariableMap::generic_slot getSlot, utils::VariableMap::generic_slot setSlot, + const torrent::Object& defaultObject) { + utils::Variable* variable = new utils::CommandVariable(defaultObject); + + control->variable()->insert(getKey, variable, getSlot); + control->variable()->insert(setKey, variable, setSlot, utils::VariableMap::flag_dont_delete); + + if (defaultSetKey) + control->variable()->insert(defaultSetKey, variable, setSlot, utils::VariableMap::flag_dont_delete); +} + +inline void +add_variable_bool(const char* getKey, const char* setKey, const char* defaultSetKey, bool defaultObject) { + add_variable(getKey, setKey, defaultSetKey, &utils::CommandVariable::get_bool, &utils::CommandVariable::set_bool, (uint64_t)defaultObject); +} + +inline void +add_variable_value(const char* getKey, const char* setKey, const char* defaultSetKey, int64_t defaultObject) { + add_variable(getKey, setKey, defaultSetKey, &utils::CommandVariable::get_value, &utils::CommandVariable::set_value, defaultObject); +} + +inline void +add_variable_string(const char* getKey, const char* setKey, const char* defaultSetKey, const char* defaultObject) { + add_variable(getKey, setKey, defaultSetKey, &utils::CommandVariable::get_string, &utils::CommandVariable::set_string, std::string(defaultObject)); +} + void initialize_variables() { utils::VariableMap* variables = control->variable(); - variables->insert("check_hash", new utils::VariableBool(true)); - variables->insert("use_udp_trackers", new utils::VariableBool(true)); - variables->insert("port_open", new utils::VariableBool(true)); - variables->insert("port_random", new utils::VariableBool(true)); + add_variable_bool("get_check_hash", "set_check_hash", "check_hash", true); + add_variable_bool("get_use_udp_trackers", "set_use_udp_trackers", "use_udp_trackers", true); + add_variable_bool("get_port_open", "set_port_open", "port_open", true); + add_variable_bool("get_port_random", "set_port_random", "port_random", true); + add_variable_bool("get_handshake_log", "set_handshake_log", "handshake_log", false); + add_variable_bool("get_session_lock", "set_session_lock", "session_lock", true); + add_variable_bool("get_session_on_completion", "set_session_on_completion", "session_on_completion", true); variables->insert("tracker_dump", new utils::VariableAny(std::string())); variables->insert("session", new utils::VariableStringSlot(rak::mem_fn(control->core()->download_store(), &core::DownloadStore::path), 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(control->core()->download_list(), &core::DownloadList::session_save))); variables->insert("connection_leech", new utils::VariableAny("leech")); @@ -471,17 +501,17 @@ initialize_variables() { rak::mem_fn(control->core()->get_poll_manager()->get_http_stack(), &core::CurlStack::set_http_proxy))); variables->insert("fast_cgi", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_fast_cgi))); - variables->insert("max_chunks_queued", new utils::VariableValue(0)); - variables->insert("min_peers", new utils::VariableValue(40)); - variables->insert("max_peers", new utils::VariableValue(100)); - variables->insert("min_peers_seed", new utils::VariableValue(-1)); - variables->insert("max_peers_seed", new utils::VariableValue(-1)); +// add_variable_value("get_max_chunks_queued", "set_max_chunks_queued", "max_chunks_queued", 0); + add_variable_value("get_min_peers", "set_min_peers", "min_peers", 40); + add_variable_value("get_max_peers", "set_max_peers", "max_peers", 100); + add_variable_value("get_min_peers_seed", "set_min_peers_seed", "min_peers_seed", -1); + add_variable_value("get_max_peers_seed", "set_max_peers_seed", "max_peers_seed", -1); - variables->insert("max_uploads", new utils::VariableValue(15)); - variables->insert("max_uploads_div", new utils::VariableValue(1)); + add_variable_value("get_max_uploads", "set_max_uploads", "max_uploads", 15); + add_variable_value("get_max_uploads_div", "set_max_uploads_div", "max_uploads_div", 1); variables->insert("max_uploads_global", new utils::VariableValueSlot(rak::mem_fn(control->ui(), &ui::Root::max_uploads_global), rak::mem_fn(control->ui(), &ui::Root::set_max_uploads_global))); - variables->insert("max_downloads_div", new utils::VariableValue(0)); + add_variable_value("get_max_downloads_div", "set_max_downloads_div", "max_downloads_div", 0); variables->insert("max_downloads_global", new utils::VariableValueSlot(rak::mem_fn(control->ui(), &ui::Root::max_downloads_global), rak::mem_fn(control->ui(), &ui::Root::set_max_downloads_global))); @@ -490,7 +520,7 @@ initialize_variables() { variables->insert("upload_rate", new utils::VariableValueSlot(rak::ptr_fn(&torrent::up_throttle), rak::mem_fn(control->ui(), &ui::Root::set_up_throttle_i64), 0, (1 << 10))); - variables->insert("tracker_numwant", new utils::VariableValue(-1)); + add_variable_value("get_tracker_numwant", "set_tracker_numwant", "tracker_numwant", -1); variables->insert("hash_max_tries", new utils::VariableValueSlot(rak::ptr_fn(&torrent::hash_max_tries), rak::ptr_fn(&torrent::set_hash_max_tries))); variables->insert("max_open_files", new utils::VariableValueSlot(rak::ptr_fn(&torrent::max_open_files), rak::ptr_fn(&torrent::set_max_open_files))); @@ -546,8 +576,8 @@ initialize_variables() { rak::mem_fn(torrent::chunk_manager(), &torrent::ChunkManager::set_preload_required_rate), 0, (1 << 10))); - variables->insert("max_file_size", new utils::VariableValue(-1)); - variables->insert("split_file_size", new utils::VariableValue(-1)); + add_variable_value("get_max_file_size", "set_max_file_size", "max_file_size", -1); + add_variable_value("get_split_file_size", "set_split_file_size", "split_file_size", -1); variables->insert("split_suffix", new utils::VariableAny(".part")); variables->insert("port_range", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_port_range))); @@ -587,7 +617,6 @@ initialize_variables() { variables->insert("encoding_list", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_encoding_list))); variables->insert("encryption", new utils::VariableListSlot(rak::ptr_fn(&apply_encryption))); - variables->insert("handshake_log", new utils::VariableBool(false)); } template diff --git a/src/rpc/xmlrpc.cc b/src/rpc/xmlrpc.cc index a1a88106..7448a3b9 100644 --- a/src/rpc/xmlrpc.cc +++ b/src/rpc/xmlrpc.cc @@ -51,6 +51,69 @@ namespace rpc { #ifdef HAVE_XMLRPC_C +torrent::Object +xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value) { + switch (xmlrpc_value_type(value)) { + case XMLRPC_TYPE_INT: + int v; + xmlrpc_read_int(env, value, &v); + + return torrent::Object((int64_t)v); + + // case XMLRPC_TYPE_BOOL: + // case XMLRPC_TYPE_DOUBLE: + // case XMLRPC_TYPE_DATETIME: + + case XMLRPC_TYPE_STRING: + { + const char* valueString; + xmlrpc_read_string(env, value, &valueString); + + if (env->fault_occurred) + return torrent::Object(); + + torrent::Object result = torrent::Object(std::string(valueString)); + + // Urgh, seriously? + ::free((void*)valueString); + return result; + } + + // case XMLRPC_TYPE_BASE64: + case XMLRPC_TYPE_ARRAY: + { + torrent::Object result(torrent::Object::TYPE_LIST); + torrent::Object::list_type& listRef = result.as_list(); + + unsigned int last = xmlrpc_array_size(env, value); + + if (env->fault_occurred) + return torrent::Object(); + + // Move this into a helper function. + for (unsigned int i = 0; i != last; i++) { + xmlrpc_value* tmp; + xmlrpc_array_read_item(env, value, i, &tmp); + + if (env->fault_occurred) + return torrent::Object(); + + listRef.push_back(xmlrpc_to_object(env, tmp)); + } + + return result; + } + + // case XMLRPC_TYPE_STRUCT: + // case XMLRPC_TYPE_C_PTR: + // case XMLRPC_TYPE_NIL: + // case XMLRPC_TYPE_DEAD: + default: + xmlrpc_env_set_fault(env, XMLRPC_TYPE_ERROR, "Unsupported type found."); + return torrent::Object(); + } +} + struct server_info_t { server_info_t(const char* command, XmlRpc::slot_call_command* callCommand) : m_command(command), m_callCommand(callCommand) {} @@ -61,65 +124,11 @@ struct server_info_t { xmlrpc_value* xmlrpc_call_command(xmlrpc_env* env, xmlrpc_value* args, void* voidServerInfo) { - torrent::Object object(torrent::Object::TYPE_LIST); - torrent::Object::list_type& objectList = object.as_list(); - - if (xmlrpc_value_type(args) != XMLRPC_TYPE_ARRAY) - throw torrent::internal_error("xmlrpc_value_type(args) != XMLRPC_TYPE_ARRAY"); - - unsigned int last = xmlrpc_array_size(env, args); + torrent::Object object = xmlrpc_to_object(env, args); if (env->fault_occurred) return NULL; - // Move this into a helper function. - for (unsigned int i = 0; i != last; i++) { - xmlrpc_value* value; - xmlrpc_array_read_item(env, args, i, &value); - - if (env->fault_occurred) - return NULL; - - switch (xmlrpc_value_type(value)) { - case XMLRPC_TYPE_INT: - int v; - xmlrpc_read_int(env, value, &v); - - objectList.push_back(torrent::Object((int64_t)v)); - break; - -// case XMLRPC_TYPE_BOOL: -// case XMLRPC_TYPE_DOUBLE: -// case XMLRPC_TYPE_DATETIME: - - case XMLRPC_TYPE_STRING: - const char* valueString; - xmlrpc_read_string(env, value, &valueString); - - if (env->fault_occurred) - return NULL; - - objectList.push_back(torrent::Object(std::string(valueString))); - - // Urgh, seriously? - ::free((void*)valueString); - break; - -// case XMLRPC_TYPE_BASE64: -// case XMLRPC_TYPE_ARRAY: -// case XMLRPC_TYPE_STRUCT: -// case XMLRPC_TYPE_C_PTR: -// case XMLRPC_TYPE_NIL: -// case XMLRPC_TYPE_DEAD: - default: - xmlrpc_env_set_fault(env, XMLRPC_TYPE_ERROR, "Unsupported type found."); - return NULL; - } - - if (env->fault_occurred) - return NULL; - } - try { server_info_t* serverInfo = reinterpret_cast(voidServerInfo); diff --git a/src/ui/root.cc b/src/ui/root.cc index 8c54a4fd..3d09695e 100644 --- a/src/ui/root.cc +++ b/src/ui/root.cc @@ -185,14 +185,14 @@ Root::set_down_throttle(unsigned int throttle) { torrent::set_down_throttle(throttle * 1024); - int64_t div = control->variable()->get_value("max_downloads_div"); + int64_t div = control->variable()->get_value("get_max_downloads_div"); if (throttle == 0 || div <= 0) { torrent::set_max_download_unchoked(m_maxDownloadsGlobal); return; } - throttle /= control->variable()->get_value("max_downloads_div"); + throttle /= control->variable()->get_value("get_max_downloads_div"); unsigned int maxUnchoked; @@ -214,14 +214,14 @@ Root::set_up_throttle(unsigned int throttle) { torrent::set_up_throttle(throttle * 1024); - int64_t div = control->variable()->get_value("max_uploads_div"); + int64_t div = control->variable()->get_value("get_max_uploads_div"); if (throttle == 0 || div <= 0) { torrent::set_max_unchoked(m_maxUploadsGlobal); return; } - throttle /= control->variable()->get_value("max_uploads_div"); + throttle /= control->variable()->get_value("get_max_uploads_div"); unsigned int maxUnchoked; diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am index c05ad06a..b68ad458 100644 --- a/src/utils/Makefile.am +++ b/src/utils/Makefile.am @@ -1,6 +1,8 @@ noinst_LIBRARIES = libsub_utils.a libsub_utils_a_SOURCES = \ + command_variable.cc \ + command_variable.h \ directory.cc \ directory.h \ list_focus.h \ diff --git a/src/utils/command_variable.cc b/src/utils/command_variable.cc new file mode 100644 index 00000000..23996638 --- /dev/null +++ b/src/utils/command_variable.cc @@ -0,0 +1,150 @@ +// rTorrent - BitTorrent client +// Copyright (C) 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 + +#include "config.h" + +#include "command_variable.h" + +namespace utils { + +const torrent::Object& +CommandVariable::set_bool(Variable* rawVariable, const torrent::Object& rawArgs) { + CommandVariable* variable = static_cast(rawVariable); + + const torrent::Object& arg = to_single_argument(rawArgs); + + switch (arg.type()) { + case torrent::Object::TYPE_VALUE: + variable->m_variable = arg.as_value() ? (int64_t)1 : (int64_t)0; + break; + + case torrent::Object::TYPE_STRING: + // Move the checks into some is_true, is_false think in Variable. + if (arg.as_string() == "yes" || arg.as_string() == "true") + variable->m_variable = (int64_t)1; + + else if (arg.as_string() == "no" || arg.as_string() == "false") + variable->m_variable = (int64_t)0; + + else + throw torrent::input_error("String does not parse as a boolean."); + + break; + + default: + throw torrent::input_error("Input is not a boolean."); + } + + return variable->m_variable; +} + +const torrent::Object& +CommandVariable::get_bool(Variable* rawVariable, const torrent::Object& args) { + CommandVariable* variable = static_cast(rawVariable); + + return variable->m_variable; +} + +const torrent::Object& +CommandVariable::set_value(Variable* rawVariable, const torrent::Object& rawArgs) { + CommandVariable* variable = static_cast(rawVariable); + + const torrent::Object& arg = to_single_argument(rawArgs); + + switch (arg.type()) { + case torrent::Object::TYPE_NONE: + variable->m_variable = (int64_t)0; + break; + + case torrent::Object::TYPE_VALUE: + variable->m_variable = arg; + break; + + case torrent::Object::TYPE_STRING: + int64_t value; + string_to_value_unit(arg.as_string().c_str(), &value, 0, 1); + + variable->m_variable = value; + break; + + default: + throw torrent::input_error("VariableValue unsupported type restriction."); + } + + return variable->m_variable; +} + +const torrent::Object& +CommandVariable::get_value(Variable* rawVariable, const torrent::Object& args) { + CommandVariable* variable = static_cast(rawVariable); + + return variable->m_variable; +} + +const torrent::Object& +CommandVariable::set_string(Variable* rawVariable, const torrent::Object& rawArgs) { + CommandVariable* variable = static_cast(rawVariable); + + const torrent::Object& arg = to_single_argument(rawArgs); + + switch (arg.type()) { + case torrent::Object::TYPE_NONE: + variable->m_variable = std::string(""); + break; + +// case torrent::Object::TYPE_VALUE: +// variable->m_variable = arg; +// break; + + case torrent::Object::TYPE_STRING: + variable->m_variable = arg; + break; + + default: + throw torrent::input_error("Not a string."); + } + + return variable->m_variable; +} + +const torrent::Object& +CommandVariable::get_string(Variable* rawVariable, const torrent::Object& args) { + CommandVariable* variable = static_cast(rawVariable); + + return variable->m_variable; +} + +} diff --git a/src/utils/command_variable.h b/src/utils/command_variable.h new file mode 100644 index 00000000..4b6c1c69 --- /dev/null +++ b/src/utils/command_variable.h @@ -0,0 +1,68 @@ +// rTorrent - BitTorrent client +// Copyright (C) 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_UTILS_COMMAND_VARIABLES_H +#define RTORRENT_UTILS_COMMAND_VARIABLES_H + +#include +#include +#include +#include + +#include "variable.h" + +namespace utils { + +class CommandVariable : public Variable { +public: + CommandVariable(const torrent::Object& v = torrent::Object()) : m_variable(v) {} + + static const torrent::Object& set_bool(Variable* rawVariable, const torrent::Object& args); + static const torrent::Object& get_bool(Variable* rawVariable, const torrent::Object& args); + + static const torrent::Object& set_value(Variable* rawVariable, const torrent::Object& args); + static const torrent::Object& get_value(Variable* rawVariable, const torrent::Object& args); + + static const torrent::Object& set_string(Variable* rawVariable, const torrent::Object& args); + static const torrent::Object& get_string(Variable* rawVariable, const torrent::Object& args); + +private: + torrent::Object m_variable; +}; + +} + +#endif diff --git a/src/utils/variable.cc b/src/utils/variable.cc index 6cc89222..ee4e9923 100644 --- a/src/utils/variable.cc +++ b/src/utils/variable.cc @@ -47,11 +47,13 @@ const torrent::Object Variable::m_emptyObject; // Consider throwing an exception. const torrent::Object& Variable::get() { - return m_emptyObject; +// return m_emptyObject; + throw torrent::internal_error("Variable::get() called."); } void Variable::set(const torrent::Object& arg) { + throw torrent::internal_error("Variable::set() called."); } const torrent::Object& diff --git a/src/utils/variable.h b/src/utils/variable.h index f717334d..3579fb31 100644 --- a/src/utils/variable.h +++ b/src/utils/variable.h @@ -66,6 +66,8 @@ public: static const char* string_to_value_unit(const char* pos, value_type* value, int base, int unit); static bool string_to_value_unit_nothrow(const char* pos, value_type* value, int base, int unit); + static const torrent::Object& to_single_argument(const torrent::Object& args); + // Temporary hack, until torrent::Object is extended to allow // references so we can return a copy, not a const reference. static const torrent::Object m_emptyObject; @@ -75,6 +77,14 @@ protected: void operator = (const Variable&); }; +inline const torrent::Object& +Variable::to_single_argument(const torrent::Object& args) { + if (args.type() == torrent::Object::TYPE_LIST && args.as_list().size() == 1) + return args.as_list().front(); + else + return args; +} + } #endif diff --git a/src/utils/variable_map.cc b/src/utils/variable_map.cc index b1fd4c37..367ad7a6 100644 --- a/src/utils/variable_map.cc +++ b/src/utils/variable_map.cc @@ -51,18 +51,24 @@ namespace utils { +struct variable_map_get_ptr : std::unary_function { + Variable* operator () (VariableMap::value_type& value) { return value.second.m_variable; } +}; + VariableMap::~VariableMap() { - std::for_each(base_type::begin(), base_type::end(), rak::on(rak::mem_ref(&value_type::second), rak::call_delete())); + for (iterator itr = base_type::begin(), last = base_type::end(); itr != last; itr++) + if (!(itr->second.m_flags & flag_dont_delete)) + delete itr->second.m_variable; } void -VariableMap::insert(key_type key, Variable* v) { +VariableMap::insert(key_type key, Variable* variable, generic_slot genericSlot, int flags) { iterator itr = base_type::find(key); if (itr != base_type::end()) throw torrent::internal_error("VariableMap::insert(...) tried to insert an already existing key."); - base_type::insert(itr, value_type(key, v)); + base_type::insert(itr, value_type(key, variable_map_data_type(variable, genericSlot, NULL, flags))); } const VariableMap::mapped_type& @@ -72,7 +78,10 @@ VariableMap::get(key_type key) const { if (itr == base_type::end()) throw torrent::input_error("Variable \"" + std::string(key) + "\" does not exist."); - return itr->second->get(); + if (itr->second.m_genericSlot != NULL) + return itr->second.m_genericSlot(itr->second.m_variable, torrent::Object()); + + return itr->second.m_variable->get(); } const VariableMap::mapped_type& @@ -82,7 +91,13 @@ VariableMap::get_d(core::Download* download, key_type key) const { if (itr == base_type::end()) throw torrent::input_error("Variable \"" + std::string(key) + "\" does not exist."); - return itr->second->get_d(download); + if (itr->second.m_downloadSlot != NULL) + return itr->second.m_downloadSlot(itr->second.m_variable, download, torrent::Object()); + + if (itr->second.m_genericSlot != NULL) + return itr->second.m_genericSlot(itr->second.m_variable, torrent::Object()); + + return itr->second.m_variable->get_d(download); } void @@ -94,7 +109,12 @@ VariableMap::set(key_type key, const mapped_type& arg) { if (itr == base_type::end()) throw torrent::input_error("Variable \"" + std::string(key) + "\" does not exist."); - itr->second->set(arg); + if (itr->second.m_genericSlot != NULL) { + itr->second.m_genericSlot(itr->second.m_variable, arg); + return; + } + + itr->second.m_variable->set(arg); } void @@ -106,7 +126,17 @@ VariableMap::set_d(core::Download* download, key_type key, const mapped_type& ar if (itr == base_type::end()) throw torrent::input_error("Variable \"" + std::string(key) + "\" does not exist."); - itr->second->set_d(download, arg); + if (itr->second.m_downloadSlot != NULL) { + itr->second.m_downloadSlot(itr->second.m_variable, download, arg); + return; + } + + if (itr->second.m_genericSlot != NULL) { + itr->second.m_genericSlot(itr->second.m_variable, arg); + return; + } + + itr->second.m_variable->set_d(download, arg); } struct variable_map_is_space : std::unary_function { @@ -236,13 +266,42 @@ VariableMap::process_file(key_type path) { return true; } +const VariableMap::mapped_type& +VariableMap::call_command(key_type key, const mapped_type& arg) { + const_iterator itr = base_type::find(key); + + if (itr == base_type::end()) + throw torrent::input_error("Variable \"" + std::string(key) + "\" does not exist."); + + if (itr->second.m_genericSlot == NULL) + throw torrent::input_error("Variable does not have a generic slot."); + + return itr->second.m_genericSlot(itr->second.m_variable, arg); +} + const VariableMap::mapped_type& VariableMap::call_command_get(key_type key, const mapped_type& arg) { + const_iterator itr = base_type::find(key); + + if (itr == base_type::end()) + throw torrent::input_error("Variable \"" + std::string(key) + "\" does not exist."); + + if (itr->second.m_genericSlot != NULL) + return itr->second.m_genericSlot(itr->second.m_variable, arg); + return get(key); } const VariableMap::mapped_type& VariableMap::call_command_set(key_type key, const mapped_type& arg) { + const_iterator itr = base_type::find(key); + + if (itr == base_type::end()) + throw torrent::input_error("Variable \"" + std::string(key) + "\" does not exist."); + + if (itr->second.m_genericSlot != NULL) + return itr->second.m_genericSlot(itr->second.m_variable, arg); + set(key, arg); return Variable::m_emptyObject; diff --git a/src/utils/variable_map.h b/src/utils/variable_map.h index ad6954c7..86919036 100644 --- a/src/utils/variable_map.h +++ b/src/utils/variable_map.h @@ -59,20 +59,42 @@ struct variable_map_comp : public std::binary_function { +struct variable_map_data_type { + // Some commands will need to share data, like get/set a variable. So + // instead of using a single virtual member function, each command + // will register a member function pointer to be used instead. + typedef const torrent::Object& (*generic_slot)(Variable*, const torrent::Object&); + typedef const torrent::Object& (*download_slot)(Variable*, core::Download*, const torrent::Object&); + + variable_map_data_type(Variable* variable, generic_slot genericSlot, download_slot downloadSlot, int flags) : + m_variable(variable), m_genericSlot(genericSlot), m_downloadSlot(downloadSlot), m_flags(flags) {} + + Variable* m_variable; + generic_slot m_genericSlot; + download_slot m_downloadSlot; + + int m_flags; +}; + +class VariableMap : public std::map { public: - typedef std::map base_type; + typedef std::map base_type; + + typedef variable_map_data_type::generic_slot generic_slot; + typedef variable_map_data_type::download_slot download_slot; typedef torrent::Object mapped_type; typedef mapped_type::value_type mapped_value_type; + using base_type::iterator; + using base_type::key_type; + using base_type::value_type; + static const int max_size_key = 128; static const int max_size_opt = 1024; static const int max_size_line = max_size_key + max_size_opt + 64; - using base_type::iterator; - using base_type::key_type; - using base_type::value_type; + static const int flag_dont_delete = 0x1; VariableMap() {} ~VariableMap(); @@ -80,7 +102,9 @@ public: bool has(const char* key) const { return base_type::find(key) != base_type::end(); } bool has(const std::string& key) const { return has(key.c_str()); } - void insert(key_type key, Variable* v); + // Allow NULL slot as a temporary compatibility hack. + + void insert(key_type key, Variable* variable, generic_slot genericSlot = NULL, int flags = 0); // Consider uninlining the helper functions. @@ -119,6 +143,8 @@ public: // The new API, which is atm just a wrapper over the old and // requires seperate calls to get and set. These will be merged. + const mapped_type& call_command(key_type key, const mapped_type& arg); + const mapped_type& call_command_get(key_type key, const mapped_type& arg); const mapped_type& call_command_set(key_type key, const mapped_type& arg);