mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-06 18:22:32 +00:00
* Fix potential buffer overflows in case snprintf buffer is too
small. Patch by Josef Drexler. * Added 'view.persistance' command that makes downloads inserted into that view persist across sessions. Only call on user-created views. * Added 'ratio.*' commands that call the 'group.seeding.ratio.*' equivalents. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1080 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
@@ -25,6 +25,7 @@ rtorrent_SOURCES = \
|
||||
command_helpers.h \
|
||||
command_local.cc \
|
||||
command_network.cc \
|
||||
command_object.cc \
|
||||
command_peer.cc \
|
||||
command_tracker.cc \
|
||||
command_scheduler.cc \
|
||||
|
||||
@@ -384,6 +384,57 @@ p_multicall(core::Download* download, const torrent::Object& rawArgs) {
|
||||
return resultRaw;
|
||||
}
|
||||
|
||||
inline torrent::Object&
|
||||
d_object_wrapper(const std::pair<const char*, const char*> keyPair, core::Download* download) {
|
||||
if (keyPair.first == NULL)
|
||||
return download->bencode()->get_key(keyPair.second);
|
||||
else
|
||||
return download->bencode()->get_key(keyPair.first).get_key(keyPair.second);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
d_object_get(const std::pair<const char*, const char*> keyPair, core::Download* download, __UNUSED const torrent::Object& rawArgs) {
|
||||
return d_object_wrapper(keyPair, download);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
d_list_push_back(const std::pair<const char*, const char*> keyPair, core::Download* download, const torrent::Object& rawArgs) {
|
||||
d_object_wrapper(keyPair, download).as_list().push_back(rawArgs);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
d_list_push_back_unique(const std::pair<const char*, const char*> keyPair, core::Download* download, const torrent::Object& rawArgs) {
|
||||
const torrent::Object& args = (rawArgs.is_list() && !rawArgs.as_list().empty()) ? rawArgs.as_list().front() : rawArgs;
|
||||
torrent::Object::list_type& list = d_object_wrapper(keyPair, download).as_list();
|
||||
|
||||
if (std::find_if(list.begin(), list.end(),
|
||||
rak::bind1st(std::ptr_fun(&torrent::object_equal), args)) == list.end())
|
||||
list.push_back(rawArgs);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
d_list_has(const std::pair<const char*, const char*> keyPair, core::Download* download, const torrent::Object& rawArgs) {
|
||||
const torrent::Object& args = (rawArgs.is_list() && !rawArgs.as_list().empty()) ? rawArgs.as_list().front() : rawArgs;
|
||||
torrent::Object::list_type& list = d_object_wrapper(keyPair, download).as_list();
|
||||
|
||||
return (int64_t)(std::find_if(list.begin(), list.end(),
|
||||
rak::bind1st(std::ptr_fun(&torrent::object_equal), args)) != list.end());
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
d_list_remove(const std::pair<const char*, const char*> keyPair, core::Download* download, const torrent::Object& rawArgs) {
|
||||
const torrent::Object& args = (rawArgs.is_list() && !rawArgs.as_list().empty()) ? rawArgs.as_list().front() : rawArgs;
|
||||
torrent::Object::list_type& list = d_object_wrapper(keyPair, download).as_list();
|
||||
|
||||
list.erase(std::remove_if(list.begin(), list.end(), rak::bind1st(std::ptr_fun(&torrent::object_equal), args)), list.end());
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
#define ADD_CD_SLOT(key, function, slot, parm, doc) \
|
||||
commandDownloadSlotsItr->set_slot(slot); \
|
||||
rpc::commands.insert_type(key, commandDownloadSlotsItr++, &rpc::CommandSlot<core::Download*>::function, rpc::CommandMap::flag_dont_delete, parm, doc);
|
||||
@@ -547,6 +598,12 @@ initialize_command_download() {
|
||||
|
||||
ADD_CD_VALUE_BI("hashing_failed", std::mem_fun(&core::Download::set_hash_failed), std::mem_fun(&core::Download::is_hash_failed));
|
||||
|
||||
CMD_D("d.views", rak::bind_ptr_fn(&d_object_get, std::make_pair("rtorrent", "views")));
|
||||
CMD_D("d.views.has", rak::bind_ptr_fn(&d_list_has, std::make_pair("rtorrent", "views")));
|
||||
CMD_D("d.views.remove", rak::bind_ptr_fn(&d_list_remove, std::make_pair("rtorrent", "views")));
|
||||
CMD_D("d.views.push_back", rak::bind_ptr_fn(&d_list_push_back, std::make_pair("rtorrent", "views")));
|
||||
CMD_D("d.views.push_back_unique", rak::bind_ptr_fn(&d_list_push_back_unique, std::make_pair("rtorrent", "views")));
|
||||
|
||||
// This command really needs to be improved, so we have proper
|
||||
// logging support.
|
||||
ADD_CD_STRING_BI("message", std::mem_fun(&core::Download::set_message), std::mem_fun(&core::Download::message));
|
||||
|
||||
@@ -122,7 +122,7 @@ apply_on_ratio(const torrent::Object& rawArgs) {
|
||||
if (!(*itr)->is_seeding() || rpc::call_command_value("d.get_ignore_commands", rpc::make_target(*itr)) != 0)
|
||||
continue;
|
||||
|
||||
rpc::parse_command_single(rpc::make_target(*itr), "print={Checked ratio of download.}");
|
||||
// rpc::parse_command_single(rpc::make_target(*itr), "print={Checked ratio of download.}");
|
||||
|
||||
int64_t totalDone = (*itr)->download()->bytes_done();
|
||||
int64_t totalUpload = (*itr)->download()->up_rate()->total();
|
||||
@@ -137,7 +137,7 @@ apply_on_ratio(const torrent::Object& rawArgs) {
|
||||
std::strcpy(bufferStart, "command");
|
||||
|
||||
for (std::vector<core::Download*>::iterator itr = downloads.begin(), last = downloads.end(); itr != last; itr++) {
|
||||
rpc::commands.call("print", rpc::make_target(*itr), "Calling ratio command.");
|
||||
// rpc::commands.call("print", rpc::make_target(*itr), "Calling ratio command.");
|
||||
rpc::commands.call_catch(buffer, rpc::make_target(*itr), torrent::Object(), "Ratio reached, but command failed: ");
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ rpc::CommandSlot<torrent::Tracker*>* commandTrackerSlotsItr = commandTr
|
||||
rpc::CommandSlot<rpc::target_type> commandAnySlots[COMMAND_ANY_SLOTS_SIZE];
|
||||
rpc::CommandSlot<rpc::target_type>* commandAnySlotsItr = commandAnySlots;
|
||||
|
||||
void initialize_command_object();
|
||||
void initialize_command_dynamic();
|
||||
void initialize_command_download();
|
||||
void initialize_command_events();
|
||||
@@ -77,6 +78,7 @@ void initialize_command_ui();
|
||||
|
||||
void
|
||||
initialize_commands() {
|
||||
initialize_command_object();
|
||||
initialize_command_dynamic();
|
||||
initialize_command_events();
|
||||
initialize_command_network();
|
||||
|
||||
@@ -213,7 +213,11 @@ add_variable(key, NULL, NULL, &rpc::CommandVariable::get_string, NULL, std::stri
|
||||
|
||||
#define CMD_D_SLOT(key, function, slot, parm, doc) \
|
||||
commandDownloadSlotsItr->set_slot(slot); \
|
||||
rpc::commands.insert_type(key, commandDownloadSlotsItr++, &rpc::CommandSlot<core::Download*>::function, rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_xmlrpc, parm, doc);
|
||||
rpc::commands.insert_type(key, commandDownloadSlotsItr++, &rpc::CommandSlot<core::Download*>::function, \
|
||||
rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_xmlrpc, parm, doc);
|
||||
|
||||
#define CMD_D(key, slot) \
|
||||
CMD_D_SLOT(key, call_unknown, slot, "i:", "")
|
||||
|
||||
#define CMD_D_ANY(key, slot) \
|
||||
CMD_D_SLOT(key, call_unknown, slot, "i:", "")
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
// 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 <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "globals.h"
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
#include "rpc/command_variable.h"
|
||||
|
||||
void
|
||||
initialize_command_object() {
|
||||
// CMD_N ("system.method.insert", rak::ptr_fn(&system_method_insert));
|
||||
// CMD_N_STRING("system.method.erase", rak::ptr_fn(&system_method_erase));
|
||||
}
|
||||
@@ -394,6 +394,21 @@ cmd_view_size_not_visible(__UNUSED rpc::target_type target, const torrent::Objec
|
||||
return (*control->view_manager()->find_throw(rawArgs.as_string()))->size_not_visible();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
cmd_view_persistent(__UNUSED rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
const std::string& args = rawArgs.as_string();
|
||||
core::View* view = *control->view_manager()->find_throw(args);
|
||||
|
||||
if (!view->get_filter().empty() || !view->get_event_added().empty() || !view->get_event_removed().empty())
|
||||
throw torrent::input_error("Cannot set modified views as persitent.");
|
||||
|
||||
view->set_filter("d.views.has=" + args);
|
||||
view->set_event_added("d.views.push_back_unique=" + args);
|
||||
view->set_event_removed("d.views.remove=" + args);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
cmd_ui_set_view(__UNUSED rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
control->ui()->download_list()->set_current_view(rawArgs.as_string());
|
||||
@@ -451,6 +466,8 @@ initialize_command_ui() {
|
||||
|
||||
CMD_G_STRING("view.size", rak::ptr_fn(&cmd_view_size));
|
||||
CMD_G_STRING("view.size_not_visible", rak::ptr_fn(&cmd_view_size_not_visible));
|
||||
CMD_G_STRING("view.persistent", rak::ptr_fn(&cmd_view_persistent));
|
||||
|
||||
CMD_D_STRING("view.filter_download", rak::ptr_fn(&cmd_view_filter_download));
|
||||
CMD_D_STRING("view.set_visible", rak::ptr_fn(&cmd_view_set_visible));
|
||||
CMD_D_STRING("view.set_not_visible", rak::ptr_fn(&cmd_view_set_not_visible));
|
||||
|
||||
@@ -337,6 +337,7 @@ DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorre
|
||||
download->download()->file_list()->size_chunks()));
|
||||
|
||||
rtorrent->insert_preserve_copy("ignore_commands", (int64_t)0);
|
||||
rtorrent->insert_preserve_copy("views", torrent::Object::create_list());
|
||||
|
||||
rtorrent->insert_preserve_type("connection_leech", m_variables["connection_leech"]);
|
||||
rtorrent->insert_preserve_type("connection_seed", m_variables["connection_seed"]);
|
||||
|
||||
@@ -122,11 +122,14 @@ public:
|
||||
void filter();
|
||||
void filter_download(core::Download* download);
|
||||
|
||||
const std::string& get_filter() const { return m_filter; }
|
||||
void set_filter(const std::string& s) { m_filter = s; }
|
||||
void set_filter_on_event(const std::string& event);
|
||||
|
||||
void clear_filter_on();
|
||||
|
||||
const std::string& get_event_added() const { return m_eventAdded; }
|
||||
const std::string& get_event_removed() const { return m_eventRemoved; }
|
||||
void set_event_added(const std::string& cmd) { m_eventAdded = cmd; }
|
||||
void set_event_removed(const std::string& cmd) { m_eventRemoved = cmd; }
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ TextElementCommand::print(char* first, char* last, Canvas::attributes_list* attr
|
||||
}
|
||||
case torrent::Object::TYPE_VALUE:
|
||||
{
|
||||
first += std::max(snprintf(first, last - first + 1, "%lld", result.as_value()), 0);
|
||||
first += std::min(std::max(snprintf(first, last - first + 1, "%lld", result.as_value()), 0), last - first + 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -82,28 +82,28 @@ TextElementValueBase::print(char* first, char* last, Canvas::attributes_list* at
|
||||
|
||||
} else if (m_flags & flag_kb) {
|
||||
// Just use a default width of 5 for now.
|
||||
first += std::max(snprintf(first, last - first + 1, "%5.1f", (double)val / (1 << 10)), 0);
|
||||
first += std::min(std::max(snprintf(first, last - first + 1, "%5.1f", (double)val / (1 << 10)), 0), last - first + 1);
|
||||
|
||||
} else if (m_flags & flag_mb) {
|
||||
// Just use a default width of 8 for now.
|
||||
first += std::max(snprintf(first, last - first + 1, "%8.1f", (double)val / (1 << 20)), 0);
|
||||
first += std::min(std::max(snprintf(first, last - first + 1, "%8.1f", (double)val / (1 << 20)), 0), last - first + 1);
|
||||
|
||||
} else if (m_flags & flag_xb) {
|
||||
|
||||
if (val < (int64_t(1000) << 10))
|
||||
first += std::max(snprintf(first, last - first + 1, "%5.1f KB", (double)val / (int64_t(1) << 10)), 0);
|
||||
first += std::min(std::max(snprintf(first, last - first + 1, "%5.1f KB", (double)val / (int64_t(1) << 10)), 0), last - first + 1);
|
||||
else if (val < (int64_t(1000) << 20))
|
||||
first += std::max(snprintf(first, last - first + 1, "%5.1f MB", (double)val / (int64_t(1) << 20)), 0);
|
||||
first += std::min(std::max(snprintf(first, last - first + 1, "%5.1f MB", (double)val / (int64_t(1) << 20)), 0), last - first + 1);
|
||||
else if (val < (int64_t(1000) << 30))
|
||||
first += std::max(snprintf(first, last - first + 1, "%5.1f GB", (double)val / (int64_t(1) << 30)), 0);
|
||||
first += std::min(std::max(snprintf(first, last - first + 1, "%5.1f GB", (double)val / (int64_t(1) << 30)), 0), last - first + 1);
|
||||
else
|
||||
first += std::max(snprintf(first, last - first + 1, "%5.1f TB", (double)val / (int64_t(1) << 40)), 0);
|
||||
first += std::min(std::max(snprintf(first, last - first + 1, "%5.1f TB", (double)val / (int64_t(1) << 40)), 0), last - first + 1);
|
||||
|
||||
} else if (m_flags & flag_timer) {
|
||||
if (val == 0)
|
||||
first += std::max(snprintf(first, last - first + 1, "--:--:--"), 0);
|
||||
first += std::min(std::max(snprintf(first, last - first + 1, "--:--:--"), 0), last - first + 1);
|
||||
else
|
||||
first += std::max(snprintf(first, last - first + 1, "%2d:%02d:%02d", (int)(val / 3600), (int)((val / 60) % 60), (int)(val % 60)), 0);
|
||||
first += std::min(std::max(snprintf(first, last - first + 1, "%2d:%02d:%02d", (int)(val / 3600), (int)((val / 60) % 60), (int)(val % 60)), 0), last - first + 1);
|
||||
|
||||
} else if (m_flags & flag_date) {
|
||||
time_t t = val;
|
||||
@@ -112,7 +112,7 @@ TextElementValueBase::print(char* first, char* last, Canvas::attributes_list* at
|
||||
if (u == NULL)
|
||||
return first;
|
||||
|
||||
first += std::max(snprintf(first, last - first + 1, "%02u/%02u/%04u", u->tm_mday, (u->tm_mon + 1), (1900 + u->tm_year)), 0);
|
||||
first += std::min(std::max(snprintf(first, last - first + 1, "%02u/%02u/%04u", u->tm_mday, (u->tm_mon + 1), (1900 + u->tm_year)), 0), last - first + 1);;
|
||||
|
||||
} else if (m_flags & flag_time) {
|
||||
time_t t = val;
|
||||
@@ -121,10 +121,10 @@ TextElementValueBase::print(char* first, char* last, Canvas::attributes_list* at
|
||||
if (u == NULL)
|
||||
return first;
|
||||
|
||||
first += std::max(snprintf(first, last - first + 1, "%2d:%02d:%02d", u->tm_hour, u->tm_min, u->tm_sec), 0);
|
||||
first += std::min(std::max(snprintf(first, last - first + 1, "%2d:%02d:%02d", u->tm_hour, u->tm_min, u->tm_sec), 0), last - first + 1);
|
||||
|
||||
} else {
|
||||
first += std::max(snprintf(first, last - first + 1, "%lld", val), 0);
|
||||
first += std::min(std::max(snprintf(first, last - first + 1, "%lld", val), 0), last - first + 1);
|
||||
}
|
||||
|
||||
push_attribute(attributes, Attributes(first, baseAttribute));
|
||||
|
||||
@@ -68,7 +68,7 @@ WindowDownloadStatusbar::redraw() {
|
||||
position = print_download_info(buffer, last, m_download);
|
||||
m_canvas->print(0, 0, "%s", buffer);
|
||||
|
||||
position = buffer + std::max(snprintf(buffer, last - buffer, "Peers: %i(%i) Min/Max: %i/%i Uploads: %i U/I/C/A: %i/%i/%i/%i Failed: %i",
|
||||
position = buffer + std::min(std::max(snprintf(buffer, last - buffer, "Peers: %i(%i) Min/Max: %i/%i Uploads: %i U/I/C/A: %i/%i/%i/%i Failed: %i",
|
||||
(int)m_download->download()->connection_list()->size(),
|
||||
(int)m_download->download()->peer_list()->available_list_size(),
|
||||
(int)m_download->download()->connection_list()->min_size(),
|
||||
@@ -79,7 +79,7 @@ WindowDownloadStatusbar::redraw() {
|
||||
(int)m_download->download()->peers_complete(),
|
||||
(int)m_download->download()->peers_accounted(),
|
||||
(int)m_download->chunks_failed()),
|
||||
0);
|
||||
0), last - buffer);
|
||||
|
||||
m_canvas->print(0, 1, "%s", buffer);
|
||||
|
||||
|
||||
+9
-8
@@ -212,14 +212,15 @@ main(int argc, char** argv) {
|
||||
|
||||
"group.insert = seeding,seeding\n"
|
||||
|
||||
// "system.method.insert = group.seeding.view,string|static|const,seeding\n"
|
||||
|
||||
// "system.method.insert = group.seeding.ratio.enable ,simple,\"schedule=group.seeding.ratio,5,60,on_ratio=seeding\"\n"
|
||||
// "system.method.insert = group.seeding.ratio.disable,simple,\"schedule_remove=group.seeding.ratio\"\n"
|
||||
// "system.method.insert = group.seeding.ratio.command,simple|static,\"d.try_close= ;d.set_ignore_commands=1\"\n"
|
||||
// "system.method.insert = group.seeding.ratio.min,value,200\n"
|
||||
// "system.method.insert = group.seeding.ratio.max,value,300\n"
|
||||
// "system.method.insert = group.seeding.ratio.upload,value,20M\n"
|
||||
"system.method.insert = ratio.enable, simple|static|const,group.seeding.ratio.enable=\n"
|
||||
"system.method.insert = ratio.disable,simple|static|const,group.seeding.ratio.disable=\n"
|
||||
"system.method.insert = ratio.command,simple|static|const,group.seeding.ratio.command=\n"
|
||||
"system.method.insert = ratio.min, simple|static|const,group.seeding.ratio.min=\n"
|
||||
"system.method.insert = ratio.max, simple|static|const,group.seeding.ratio.max=\n"
|
||||
"system.method.insert = ratio.upload, simple|static|const,group.seeding.ratio.upload=\n"
|
||||
"system.method.insert = ratio.min.set, simple|static|const,group.seeding.ratio.min.set=$argument.0=\n"
|
||||
"system.method.insert = ratio.max.set, simple|static|const,group.seeding.ratio.max.set=$argument.0=\n"
|
||||
"system.method.insert = ratio.upload.set,simple|static|const,group.seeding.ratio.upload.set=$argument.0=\n"
|
||||
|
||||
"set_name = \"$cat=$system.hostname=,:,$system.pid=\"\n"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user