From d7c2960d1ee7c2deeb828bfd28da44be18fa61f7 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sat, 27 Sep 2008 06:28:50 +0000 Subject: [PATCH] * Added system.method.{insert,erase} commands that allows user-specified commands. "system.method.insert=foo,print=Bar" git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1069 e378c898-3ddf-0310-93e7-cc216c733640 --- src/Makefile.am | 1 + src/command_dynamic.cc | 97 ++++++++++++++++++++++++++++++++++++++ src/command_helpers.cc | 2 + src/rpc/command_function.h | 2 +- src/rpc/command_map.cc | 22 ++++++++- src/rpc/command_map.h | 1 + 6 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 src/command_dynamic.cc diff --git a/src/Makefile.am b/src/Makefile.am index 3e040bbd..02c543ae 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,6 +18,7 @@ rtorrent_LDADD = \ rtorrent_SOURCES = \ command_download.cc \ + command_dynamic.cc \ command_events.cc \ command_file.cc \ command_helpers.cc \ diff --git a/src/command_dynamic.cc b/src/command_dynamic.cc new file mode 100644 index 00000000..ff2b482c --- /dev/null +++ b/src/command_dynamic.cc @@ -0,0 +1,97 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005-2007, 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 + +#include "globals.h" +#include "control.h" +#include "command_helpers.h" + +torrent::Object +system_method_insert(__UNUSED rpc::target_type target, const torrent::Object& rawArgs) { + const torrent::Object::list_type& args = rawArgs.as_list(); + + // Allow arbritary number of args, just use what ever necessary in + // order to create a function blob out of them. + + if (args.empty()) + return torrent::Object(); + + const std::string& rawKey = args.front().as_string(); + + if (rawKey.empty() || rpc::commands.has(rawKey)) + throw torrent::input_error("Invalid key."); + + std::string command; + + for (torrent::Object::list_const_iterator itr = ++args.begin(), last = args.end(); itr != last; itr++) { + if (!command.empty()) + command += " ;"; + + command += itr->as_string(); + } + + char* key = new char[rawKey.size() + 1]; + std::memcpy(key, rawKey.c_str(), rawKey.size() + 1); + + rpc::commands.insert_type(key, new rpc::CommandFunction(command), &rpc::CommandFunction::call, + rpc::CommandMap::flag_delete_key | rpc::CommandMap::flag_modifiable | rpc::CommandMap::flag_public_xmlrpc, NULL, NULL); + + return torrent::Object(); +} + +torrent::Object +system_method_erase(__UNUSED rpc::target_type target, const torrent::Object& rawArgs) { + rpc::CommandMap::iterator itr = rpc::commands.find(rawArgs.as_string().c_str()); + + if (itr == rpc::commands.end()) + return torrent::Object(); + + if (!(itr->second.m_flags & rpc::CommandMap::flag_modifiable)) + throw torrent::input_error("Command not modifiable."); + + rpc::commands.erase(itr); + + return torrent::Object(); +} + +void +initialize_command_dynamic() { + CMD_G("system.method.insert", rak::ptr_fn(&system_method_insert)); + CMD_G_STRING("system.method.erase", rak::ptr_fn(&system_method_erase)); +} diff --git a/src/command_helpers.cc b/src/command_helpers.cc index 2605119d..736d21ca 100644 --- a/src/command_helpers.cc +++ b/src/command_helpers.cc @@ -62,6 +62,7 @@ rpc::CommandSlot* commandTrackerSlotsItr = commandTr rpc::CommandSlot commandAnySlots[COMMAND_ANY_SLOTS_SIZE]; rpc::CommandSlot* commandAnySlotsItr = commandAnySlots; +void initialize_command_dynamic(); void initialize_command_download(); void initialize_command_events(); void initialize_command_file(); @@ -74,6 +75,7 @@ void initialize_command_ui(); void initialize_commands() { + initialize_command_dynamic(); initialize_command_events(); initialize_command_network(); initialize_command_local(); diff --git a/src/rpc/command_function.h b/src/rpc/command_function.h index 18f65889..6a740a9e 100644 --- a/src/rpc/command_function.h +++ b/src/rpc/command_function.h @@ -50,7 +50,7 @@ class CommandFunction : public Command { public: CommandFunction(const std::string& cmd = std::string()) : m_command(cmd) {} - const std::string& command() const { return m_command; } + const std::string& command() const { return m_command; } void set_command(const std::string& cmd) { m_command = cmd; } static const torrent::Object call(Command* rawCommand, target_type target, const torrent::Object& args); diff --git a/src/rpc/command_map.cc b/src/rpc/command_map.cc index 292b1fb2..c25c539a 100644 --- a/src/rpc/command_map.cc +++ b/src/rpc/command_map.cc @@ -36,6 +36,7 @@ #include "config.h" +#include #include #include #include @@ -46,13 +47,18 @@ namespace rpc { CommandMap::~CommandMap() { + std::vector keys; + 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; if (itr->second.m_flags & flag_delete_key) - ; // Remove from map and then delte the key. + keys.push_back(itr->first); } + + for (std::vector::iterator itr = keys.begin(), last = keys.end(); itr != last; itr++) + delete [] *itr; } CommandMap::iterator @@ -79,6 +85,20 @@ CommandMap::insert(key_type key, const command_map_data_type src) { itr->second.m_genericSlot = src.m_genericSlot; } +void +CommandMap::erase(iterator itr) { + if (itr == end()) + return; + + if (!(itr->second.m_flags & flag_dont_delete)) + delete itr->second.m_variable; + + const char* key = itr->second.m_flags & flag_delete_key ? itr->first : NULL; + + base_type::erase(itr); + delete [] key; +} + const CommandMap::mapped_type CommandMap::call_command(key_type key, const mapped_type& arg, target_type target) { const_iterator itr = base_type::find(key); diff --git a/src/rpc/command_map.h b/src/rpc/command_map.h index f67bbd45..9b443589 100644 --- a/src/rpc/command_map.h +++ b/src/rpc/command_map.h @@ -122,6 +122,7 @@ public: } void insert(key_type key, const command_map_data_type src); + void erase(iterator itr); const mapped_type call_command (key_type key, const mapped_type& arg, target_type target = target_type((int)Command::target_generic, NULL)); const mapped_type call_command (const_iterator itr, const mapped_type& arg, target_type target = target_type((int)Command::target_generic, NULL));