Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package rtorrent for openSUSE:Factory checked in at 2026-07-06 12:33:11 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rtorrent (Old) and /work/SRC/openSUSE:Factory/.rtorrent.new.1982 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rtorrent" Mon Jul 6 12:33:11 2026 rev:35 rq:1363889 version:0.16.16 Changes: -------- --- /work/SRC/openSUSE:Factory/rtorrent/rtorrent.changes 2026-07-01 16:39:10.406356070 +0200 +++ /work/SRC/openSUSE:Factory/.rtorrent.new.1982/rtorrent.changes 2026-07-06 12:35:55.814911837 +0200 @@ -1,0 +2,7 @@ +Sun Jul 5 18:23:00 UTC 2026 - Jan Engelhardt <[email protected]> + +- Update to release 0.16.16 + * Added max http request size and limited redirect protocols to + http/https. + +------------------------------------------------------------------- Old: ---- rtorrent-0.16.15.tar.gz New: ---- rtorrent-0.16.16.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rtorrent.spec ++++++ --- /var/tmp/diff_new_pack.bGFhIm/_old 2026-07-06 12:35:56.518936300 +0200 +++ /var/tmp/diff_new_pack.bGFhIm/_new 2026-07-06 12:35:56.522936439 +0200 @@ -17,7 +17,7 @@ Name: rtorrent -Version: 0.16.15 +Version: 0.16.16 Release: 0 Summary: Console-based BitTorrent client License: SUSE-GPL-2.0+-with-openssl-exception ++++++ _scmsync.obsinfo ++++++ --- /var/tmp/diff_new_pack.bGFhIm/_old 2026-07-06 12:35:56.574938246 +0200 +++ /var/tmp/diff_new_pack.bGFhIm/_new 2026-07-06 12:35:56.578938385 +0200 @@ -1,5 +1,5 @@ -mtime: 1782854052 -commit: 6e53d80fc4ed98c92abed75aab664a0b23cf717c6e65d31daeff000d98782cd3 +mtime: 1783276162 +commit: 95828eb58f3bcd696c17dc87550c5b6e2b67c6473d31aed1e5fda34746dff7b6 url: https://src.opensuse.org/jengelh/rtorrent revision: master ++++++ build.specials.obscpio ++++++ ++++++ build.specials.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.gitignore new/.gitignore --- old/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/.gitignore 2026-07-05 20:29:22.000000000 +0200 @@ -0,0 +1 @@ +.osc ++++++ rtorrent-0.16.15.tar.gz -> rtorrent-0.16.16.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/Makefile.am new/rtorrent-0.16.16/Makefile.am --- old/rtorrent-0.16.15/Makefile.am 2026-06-22 11:01:51.000000000 +0200 +++ new/rtorrent-0.16.16/Makefile.am 2026-07-03 16:40:11.000000000 +0200 @@ -7,7 +7,6 @@ lua/rtorrent.lua EXTRA_DIST= \ - rak/regex.h \ scripts/checks.m4 \ scripts/common.m4 \ scripts/attributes.m4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/Makefile.in new/rtorrent-0.16.16/Makefile.in --- old/rtorrent-0.16.15/Makefile.in 2026-06-22 11:17:07.000000000 +0200 +++ new/rtorrent-0.16.16/Makefile.in 2026-07-03 17:14:23.000000000 +0200 @@ -418,7 +418,6 @@ lua/rtorrent.lua EXTRA_DIST = \ - rak/regex.h \ scripts/checks.m4 \ scripts/common.m4 \ scripts/attributes.m4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/config.h.in new/rtorrent-0.16.16/config.h.in --- old/rtorrent-0.16.15/config.h.in 2026-06-22 11:17:07.000000000 +0200 +++ new/rtorrent-0.16.16/config.h.in 2026-07-03 17:14:23.000000000 +0200 @@ -72,6 +72,9 @@ /* Define to 1 if building without ncurses */ #undef HAVE_NO_NCURSES +/* Define if posix_spawn_file_actions_addclosefrom_np is available. */ +#undef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP + /* Define if you have POSIX threads libraries and header files. */ #undef HAVE_PTHREAD diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/configure new/rtorrent-0.16.16/configure --- old/rtorrent-0.16.15/configure 2026-06-22 11:17:06.000000000 +0200 +++ new/rtorrent-0.16.16/configure 2026-07-03 17:14:22.000000000 +0200 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.72 for rtorrent 0.16.15. +# Generated by GNU Autoconf 2.72 for rtorrent 0.16.16. # # Report bugs to <[email protected]>. # @@ -614,8 +614,8 @@ # Identity of this package. PACKAGE_NAME='rtorrent' PACKAGE_TARNAME='rtorrent' -PACKAGE_VERSION='0.16.15' -PACKAGE_STRING='rtorrent 0.16.15' +PACKAGE_VERSION='0.16.16' +PACKAGE_STRING='rtorrent 0.16.16' PACKAGE_BUGREPORT='[email protected]' PACKAGE_URL='' @@ -1421,7 +1421,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -'configure' configures rtorrent 0.16.15 to adapt to many kinds of systems. +'configure' configures rtorrent 0.16.16 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1492,7 +1492,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of rtorrent 0.16.15:";; + short | recursive ) echo "Configuration of rtorrent 0.16.16:";; esac cat <<\_ACEOF @@ -1644,7 +1644,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -rtorrent configure 0.16.15 +rtorrent configure 0.16.16 generated by GNU Autoconf 2.72 Copyright (C) 2023 Free Software Foundation, Inc. @@ -2273,7 +2273,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by rtorrent $as_me 0.16.15, which was +It was created by rtorrent $as_me 0.16.16, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw @@ -3966,7 +3966,7 @@ # Define the identity of the package. PACKAGE='rtorrent' - VERSION='0.16.15' + VERSION='0.16.16' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -21491,19 +21491,19 @@ fi pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libtorrent >= 0.16.15" >&5 -printf %s "checking for libtorrent >= 0.16.15... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libtorrent >= 0.16.16" >&5 +printf %s "checking for libtorrent >= 0.16.16... " >&6; } if test -n "$DEPENDENCIES_CFLAGS"; then pkg_cv_DEPENDENCIES_CFLAGS="$DEPENDENCIES_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent >= 0.16.15\""; } >&5 - ($PKG_CONFIG --exists --print-errors "libtorrent >= 0.16.15") 2>&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent >= 0.16.16\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libtorrent >= 0.16.16") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_DEPENDENCIES_CFLAGS=`$PKG_CONFIG --cflags "libtorrent >= 0.16.15" 2>/dev/null` + pkg_cv_DEPENDENCIES_CFLAGS=`$PKG_CONFIG --cflags "libtorrent >= 0.16.16" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -21515,12 +21515,12 @@ pkg_cv_DEPENDENCIES_LIBS="$DEPENDENCIES_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent >= 0.16.15\""; } >&5 - ($PKG_CONFIG --exists --print-errors "libtorrent >= 0.16.15") 2>&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtorrent >= 0.16.16\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libtorrent >= 0.16.16") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_DEPENDENCIES_LIBS=`$PKG_CONFIG --libs "libtorrent >= 0.16.15" 2>/dev/null` + pkg_cv_DEPENDENCIES_LIBS=`$PKG_CONFIG --libs "libtorrent >= 0.16.16" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -21541,14 +21541,14 @@ _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then - DEPENDENCIES_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libtorrent >= 0.16.15" 2>&1` + DEPENDENCIES_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libtorrent >= 0.16.16" 2>&1` else - DEPENDENCIES_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libtorrent >= 0.16.15" 2>&1` + DEPENDENCIES_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libtorrent >= 0.16.16" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$DEPENDENCIES_PKG_ERRORS" >&5 - as_fn_error $? "Package requirements (libtorrent >= 0.16.15) were not met: + as_fn_error $? "Package requirements (libtorrent >= 0.16.16) were not met: $DEPENDENCIES_PKG_ERRORS @@ -22941,6 +22941,46 @@ esac + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for posix_spawn_file_actions_addclosefrom_np" >&5 +printf %s "checking for posix_spawn_file_actions_addclosefrom_np... " >&6; } + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #define _GNU_SOURCE + #include <spawn.h> + +int +main (void) +{ + + posix_spawn_file_actions_t actions; + posix_spawn_file_actions_addclosefrom_np(&actions, 3); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + +printf "%s\n" "#define HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +else case e in #( + e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + + ac_config_files="$ac_config_files Makefile doc/Makefile src/Makefile test/Makefile" @@ -23494,7 +23534,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by rtorrent $as_me 0.16.15, which was +This file was extended by rtorrent $as_me 0.16.16, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -23562,7 +23602,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -rtorrent config.status 0.16.15 +rtorrent config.status 0.16.16 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/configure.ac new/rtorrent-0.16.16/configure.ac --- old/rtorrent-0.16.15/configure.ac 2026-06-22 11:01:51.000000000 +0200 +++ new/rtorrent-0.16.16/configure.ac 2026-07-03 16:40:11.000000000 +0200 @@ -1,6 +1,6 @@ m4_pattern_allow([PKG_CHECK_EXISTS]) -AC_INIT([rtorrent],[0.16.15],[[email protected]]) +AC_INIT([rtorrent],[0.16.16],[[email protected]]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIRS([scripts]) @@ -47,7 +47,7 @@ PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"]) PKG_CHECK_MODULES([ZLIB], [zlib]) -PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.15]) +PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.16]) AC_LANG_PUSH(C++) TORRENT_WITH_XMLRPC_C @@ -73,6 +73,7 @@ CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $CURSES_CFLAGS $ZLIB_CFLAGS $DEPENDENCIES_CFLAGS" TORRENT_CHECK_CACHELINE +TORRENT_CHECK_POSIX_SPAWN_ADDCLOSEFROM_NP AC_CONFIG_FILES([ Makefile diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/rak/regex.h new/rtorrent-0.16.16/rak/regex.h --- old/rtorrent-0.16.15/rak/regex.h 2026-06-22 11:01:51.000000000 +0200 +++ new/rtorrent-0.16.16/rak/regex.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,109 +0,0 @@ -// rak - Rakshasa's toolbox -// 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 <[email protected]> - - -// This is a hacked up whole string pattern matching. Replace with -// TR1's regex when that becomes widely available. It is intended for -// small strings. - -#ifndef RAK_REGEX_H -#define RAK_REGEX_H - -#include <sys/types.h> - -#include <algorithm> -#include <functional> -#include <string> -#include <list> - -namespace rak { - -class regex { -public: - regex() {} - regex(const std::string& p) : m_pattern(p) {} - - const std::string& pattern() const { return m_pattern; } - - bool operator () (const std::string& p) const; - -private: - std::string m_pattern; -}; - -// This isn't optimized, or very clean. A simple hack that should work. -inline bool -regex::operator () (const std::string& text) const { - if (m_pattern.empty() || - text.empty() || - (m_pattern[0] != '*' && m_pattern[0] != text[0])) - return false; - - // Replace with unordered_vector? - std::list<unsigned int> paths; - paths.push_front(0); - - for (std::string::const_iterator itrText = ++text.begin(), lastText = text.end(); itrText != lastText; ++itrText) { - - for (std::list<unsigned int>::iterator itrPaths = paths.begin(), lastPaths = paths.end(); itrPaths != lastPaths; ) { - - unsigned int next = *itrPaths + 1; - - if (m_pattern[*itrPaths] != '*') - itrPaths = paths.erase(itrPaths); - else - itrPaths++; - - // When we reach the end of 'm_pattern', we don't have a whole - // match of 'text'. - if (next == m_pattern.size()) - continue; - - // Push to the back so that '*' will match zero length strings. - if (m_pattern[next] == '*') - paths.push_back(next); - - if (m_pattern[next] == *itrText) - paths.push_front(next); - } - - if (paths.empty()) - return false; - } - - return std::find(paths.begin(), paths.end(), m_pattern.size() - 1) != paths.end(); -} - -} - -#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/scripts/checks.m4 new/rtorrent-0.16.16/scripts/checks.m4 --- old/rtorrent-0.16.15/scripts/checks.m4 2026-06-22 11:01:51.000000000 +0200 +++ new/rtorrent-0.16.16/scripts/checks.m4 2026-07-03 16:40:11.000000000 +0200 @@ -298,6 +298,24 @@ ]) +AC_DEFUN([TORRENT_CHECK_POSIX_SPAWN_ADDCLOSEFROM_NP], [ + AC_MSG_CHECKING(for posix_spawn_file_actions_addclosefrom_np) + + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #define _GNU_SOURCE + #include <spawn.h> + ]], [[ + posix_spawn_file_actions_t actions; + posix_spawn_file_actions_addclosefrom_np(&actions, 3); + ]])],[ + AC_DEFINE(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP, 1, [Define if posix_spawn_file_actions_addclosefrom_np is available.]) + AC_MSG_RESULT(yes) + ],[ + AC_MSG_RESULT(no) + ]) +]) + + AC_DEFUN([TORRENT_WITH_SYSTEMD], [ AC_ARG_WITH(systemd, AS_HELP_STRING([--with-systemd],[enable systemd socket activation support [[default=no]]]), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/src/command_download.cc new/rtorrent-0.16.16/src/command_download.cc --- old/rtorrent-0.16.15/src/command_download.cc 2026-06-22 11:01:51.000000000 +0200 +++ new/rtorrent-0.16.16/src/command_download.cc 2026-07-03 16:40:11.000000000 +0200 @@ -5,7 +5,7 @@ #include <functional> #include <netdb.h> #include <unistd.h> -#include <rak/regex.h> +#include <fnmatch.h> #include <torrent/rate.h> #include <torrent/throttle.h> #include <torrent/tracker/tracker.h> @@ -340,7 +340,7 @@ // parsing and searching command map for every single call. torrent::Object resultRaw = torrent::Object::create_list(); torrent::Object::list_type& result = resultRaw.as_list(); - std::vector<rak::regex> regex_list; + std::vector<std::string> regex_list; bool use_regex = true; @@ -354,7 +354,7 @@ for (const auto& file : *download->file_list()) { if (use_regex && - std::none_of(regex_list.begin(), regex_list.end(), [&file](const auto& r) { return r(file->path()->as_string()); })) + std::none_of(regex_list.begin(), regex_list.end(), [&file](const auto& pattern) { return fnmatch(pattern.c_str(), file->path()->as_string().c_str(), 0) == 0; })) continue; torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list(); @@ -378,18 +378,19 @@ // Add some pre-parsing of the commands, so we don't spend time // parsing and searching command map for every single call. - torrent::Object result_raw = torrent::Object::create_list(); - torrent::Object::list_type& result = result_raw.as_list(); + + auto result_raw = torrent::Object::create_list(); + auto& result = result_raw.as_list(); for (uint32_t idx = 0, last = download->tracker_list_size(); idx < last; idx++) { - auto& row = result.insert(result.end(), torrent::Object::create_list())->as_list(); + auto& row = result.insert(result.end(), torrent::Object::create_list())->as_list(); auto tracker = download->tracker_controller().at(idx); if (!tracker.is_valid()) continue; - for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) { - const std::string& cmd = cItr->as_string(); + for (auto cItr = ++args.begin(); cItr != args.end(); cItr++) { + auto& cmd = cItr->as_string(); row.push_back(rpc::parse_command(rpc::make_target(&tracker), cmd.c_str(), cmd.c_str() + cmd.size()).first); } @@ -408,13 +409,13 @@ // Add some pre-parsing of the commands, so we don't spend time // parsing and searching command map for every single call. - torrent::Object resultRaw = torrent::Object::create_list(); - torrent::Object::list_type& result = resultRaw.as_list(); + auto resultRaw = torrent::Object::create_list(); + auto& result = resultRaw.as_list(); for (const auto& connection : *download->connection_list()) { torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list(); - for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) { + for (auto cItr = ++args.begin(); cItr != args.end(); cItr++) { const std::string& cmd = cItr->as_string(); row.push_back(rpc::parse_command(rpc::make_target(connection), cmd.c_str(), cmd.c_str() + cmd.size()).first); @@ -972,6 +973,8 @@ rpc::rpc.mark_safe("d.size_chunks"); rpc::rpc.mark_safe("d.size_pex"); rpc::rpc.mark_safe("d.completed_bytes"); + rpc::rpc.mark_safe("d.complete"); + rpc::rpc.mark_safe("d.timestamp.finished"); rpc::rpc.mark_safe("d.bytes_done"); rpc::rpc.mark_safe("d.peers_accounted"); rpc::rpc.mark_safe("d.chunks_hashed"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/src/command_events.cc new/rtorrent-0.16.16/src/command_events.cc --- old/rtorrent-0.16.15/src/command_events.cc 2026-06-22 11:01:51.000000000 +0200 +++ new/rtorrent-0.16.16/src/command_events.cc 2026-07-03 16:40:11.000000000 +0200 @@ -258,11 +258,12 @@ d_multicall_filtered(const torrent::Object::list_type& args) { if (args.size() < 2) throw torrent::input_error("d.multicall.filtered requires at least 2 arguments."); - torrent::Object::list_const_iterator arg = args.begin(); + + auto arg = args.begin(); // Find the given view - core::ViewManager* viewManager = control->view_manager(); - core::ViewManager::iterator view_itr = viewManager->find(arg->as_string().empty() ? "default" : arg->as_string()); + auto* viewManager = control->view_manager(); + auto view_itr = viewManager->find(arg->as_string().empty() ? "default" : arg->as_string()); if (view_itr == viewManager->end()) throw torrent::input_error("Could not find view '" + arg->as_string() + "'."); @@ -272,8 +273,9 @@ (*view_itr)->filter_by(*++arg, dlist); // Generate result by iterating over all items - torrent::Object resultRaw = torrent::Object::create_list(); - torrent::Object::list_type& result = resultRaw.as_list(); + auto resultRaw = torrent::Object::create_list(); + auto& result = resultRaw.as_list(); + ++arg; // skip to first command for (const auto& item : dlist) { @@ -360,7 +362,6 @@ // TODO: Deprecate d.multicall2. (6/2026) CMD2_ANY_LIST ("d.multicall", [](auto, auto& args) { return d_multicall(args); }); - CMD2_ANY_LIST ("d.multicall2", [](auto, auto& args) { return d_multicall(args); }); CMD2_ANY_LIST ("d.multicall.filtered", [](auto, auto& args) { return d_multicall_filtered(args); }); CMD2_ANY_LIST ("directory.watch.added", [](auto, auto& args) { return directory_watch_added(args); }); @@ -375,6 +376,5 @@ rpc::rpc.mark_safe("close_low_diskspace.normal"); rpc::rpc.mark_safe("download_list"); rpc::rpc.mark_safe("d.multicall"); - rpc::rpc.mark_safe("d.multicall2"); rpc::rpc.mark_safe("d.multicall.filtered"); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/src/command_network.cc new/rtorrent-0.16.16/src/command_network.cc --- old/rtorrent-0.16.15/src/command_network.cc 2026-06-22 11:01:51.000000000 +0200 +++ new/rtorrent-0.16.16/src/command_network.cc 2026-07-03 16:40:11.000000000 +0200 @@ -10,6 +10,7 @@ #include <torrent/net/http_stack.h> #include <torrent/net/socket_address.h> #include <torrent/runtime/network_config.h> +#include <torrent/runtime/proxy_manager.h> #include <torrent/runtime/runtime.h> #include <torrent/runtime/socket_manager.h> #include <torrent/tracker/tracker.h> @@ -220,98 +221,99 @@ auto nw_config = torrent::runtime::network_config(); // Isn't port_open used? - CMD2_VAR_BOOL ("network.port_open", true); - CMD2_VAR_BOOL ("network.port_random", true); - CMD2_VAR_STRING ("network.port_range", "6881-6999"); - - CMD2_ANY ("network.listen.port", [](auto, auto) { return torrent::runtime::listen_port(); }); - CMD2_ANY ("network.listen.backlog", [nw_config](auto, auto) { return nw_config->listen_backlog(); }); - CMD2_ANY_VALUE_V ("network.listen.backlog.set", [nw_config](auto, auto& value) { return nw_config->set_listen_backlog(value); }); - - CMD2_VAR_BOOL ("protocol.pex", true); - CMD2_ANY_LIST ("protocol.encryption.set", [](auto, auto& args) { return apply_encryption(args); }); - - CMD2_VAR_STRING ("protocol.connection.leech", "leech"); - CMD2_VAR_STRING ("protocol.connection.seed", "seed"); - - CMD2_VAR_STRING ("protocol.choke_heuristics.up.leech", "upload_leech"); - CMD2_VAR_STRING ("protocol.choke_heuristics.up.seed", "upload_leech"); - CMD2_VAR_STRING ("protocol.choke_heuristics.down.leech", "download_leech"); - CMD2_VAR_STRING ("protocol.choke_heuristics.down.seed", "download_leech"); - - CMD2_ANY ("network.http.cacert", [http_stack](auto, auto) { return http_stack->http_cacert(); }); - CMD2_ANY_STRING_V("network.http.cacert.set", [http_stack](auto, auto& str) { return http_stack->set_http_cacert(str); }); - CMD2_ANY ("network.http.capath", [http_stack](auto, auto) { return http_stack->http_capath(); }); - CMD2_ANY_STRING_V("network.http.capath.set", [http_stack](auto, auto& str) { return http_stack->set_http_capath(str); }); - CMD2_ANY ("network.http.dns_cache_timeout", [http_stack](auto, auto) { return http_stack->dns_timeout(); }); - CMD2_ANY_VALUE_V ("network.http.dns_cache_timeout.set", [http_stack](auto, auto& value) { return http_stack->set_dns_timeout(value); }); - CMD2_ANY ("network.http.current_open", [http_stack](auto, auto) { return http_stack->size(); }); - CMD2_ANY ("network.http.max_cache_connections", [http_stack](auto, auto) { return http_stack->max_cache_connections(); }); - CMD2_ANY_VALUE_V ("network.http.max_cache_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_cache_connections(value); }); - CMD2_ANY ("network.http.max_host_connections", [http_stack](auto, auto) { return http_stack->max_host_connections(); }); - CMD2_ANY_VALUE_V ("network.http.max_host_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_host_connections(value); }); - CMD2_ANY ("network.http.max_total_connections", [http_stack](auto, auto) { return http_stack->max_total_connections(); }); - CMD2_ANY ("network.http.proxy_address", [http_stack](auto, auto) { return http_stack->http_proxy(); }); - CMD2_ANY_STRING_V("network.http.proxy_address.set", [http_stack](auto, auto& str) { return http_stack->set_http_proxy(str); }); - CMD2_ANY ("network.http.ssl_verify_host", [http_stack](auto, auto) { return http_stack->ssl_verify_host(); }); - CMD2_ANY_VALUE_V ("network.http.ssl_verify_host.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_host(value); }); - CMD2_ANY ("network.http.ssl_verify_peer", [http_stack](auto, auto) { return http_stack->ssl_verify_peer(); }); - CMD2_ANY_VALUE_V ("network.http.ssl_verify_peer.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_peer(value); }); - - CMD2_ANY ("network.send_buffer.size", [nw_config](auto, auto) { return nw_config->send_buffer_size(); }); - CMD2_ANY_VALUE_V ("network.send_buffer.size.set", [nw_config](auto, auto& value) { return nw_config->set_send_buffer_size(value); }); - CMD2_ANY ("network.receive_buffer.size", [nw_config](auto, auto) { return nw_config->receive_buffer_size(); }); - CMD2_ANY_VALUE_V ("network.receive_buffer.size.set", [nw_config](auto, auto& value) { return nw_config->set_receive_buffer_size(value); }); - CMD2_ANY_STRING ("network.tos.set", [](auto, auto& str) { return apply_tos(str); }); - - CMD2_ANY ("network.bind_address", [nw_config](auto, auto) { return nw_config->bind_address_best_match_str(); }); - CMD2_ANY_STRING_V("network.bind_address.set", [nw_config](auto, auto& str) { return nw_config->set_bind_address_str(str); }); - CMD2_ANY ("network.bind_address.ipv4", [nw_config](auto, auto) { return nw_config->bind_inet_address_str(); }); - CMD2_ANY_STRING_V("network.bind_address.ipv4.set", [nw_config](auto, auto& str) { return nw_config->set_bind_inet_address_str(str); }); - CMD2_ANY ("network.bind_address.ipv6", [nw_config](auto, auto) { return nw_config->bind_inet6_address_str(); }); - CMD2_ANY_STRING_V("network.bind_address.ipv6.set", [nw_config](auto, auto& str) { return nw_config->set_bind_inet6_address_str(str); }); - - CMD2_ANY ("network.local_address", [nw_config](auto, auto) { return nw_config->local_address_best_match_str(); }); - CMD2_ANY_STRING_V("network.local_address.set", [nw_config](auto, auto& str) { return nw_config->set_local_address_str(str); }); - CMD2_ANY ("network.local_address.ipv4", [nw_config](auto, auto) { return nw_config->local_inet_address_str(); }); - CMD2_ANY_STRING_V("network.local_address.ipv4.set", [nw_config](auto, auto& str) { return nw_config->set_local_inet_address_str(str); }); - CMD2_ANY ("network.local_address.ipv6", [nw_config](auto, auto) { return nw_config->local_inet6_address_str(); }); - CMD2_ANY_STRING_V("network.local_address.ipv6.set", [nw_config](auto, auto& str) { return nw_config->set_local_inet6_address_str(str); }); - - CMD2_ANY ("network.proxy_address", [nw_config](auto, auto) { return nw_config->proxy_address_str(); }); - CMD2_ANY_STRING_V("network.proxy_address.set", [](auto, auto& str) { return control->core()->set_proxy_address(str); }); - - CMD2_ANY ("network.open_files", [file_manager](auto, auto) { return file_manager->open_files(); }); - CMD2_ANY ("network.max_open_files", [file_manager](auto, auto) { return file_manager->max_open_files(); }); - CMD2_ANY ("network.total_handshakes", [](auto, auto) { return torrent::runtime::total_handshakes(); }); - - CMD2_ANY_STRING ("network.scgi.open_port", std::bind(&apply_scgi, std::placeholders::_2, 1)); - CMD2_ANY_STRING ("network.scgi.open_local", std::bind(&apply_scgi, std::placeholders::_2, 2)); - CMD2_VAR_BOOL ("network.scgi.dont_route", false); - CMD2_ANY ("network.scgi.open_systemd", [](auto, auto) { return apply_scgi_systemd(); }); - - CMD2_ANY ("network.scgi.use_gzip", [](const auto&, const auto&) { return rpc::rpc.scgi_allow_compression(); }); - CMD2_ANY_VALUE_V ("network.scgi.use_gzip.set", [](const auto&, const auto& arg) { return rpc::rpc.set_scgi_allow_compression(arg); }); - CMD2_ANY ("network.scgi.gzip.min_size", [](const auto&, const auto&) { return rpc::rpc.scgi_min_compress_size(); }); - CMD2_ANY_VALUE_V ("network.scgi.gzip.min_size.set", [](const auto&, const auto& arg) { return rpc::rpc.set_scgi_min_compress_size(arg); }); - - CMD2_ANY_STRING ("network.xmlrpc.dialect.set", [](const auto&, const auto& arg) { return apply_xmlrpc_dialect(arg); }) - CMD2_ANY ("network.xmlrpc.size_limit", [](const auto&, const auto&) { return rpc::rpc.size_limit(); }); - CMD2_ANY_VALUE_V ("network.xmlrpc.size_limit.set", [](const auto&, const auto& arg) { return rpc::rpc.set_size_limit(arg); }); - - CMD2_VAR_BOOL ("network.rpc.use_xmlrpc", true); - CMD2_VAR_BOOL ("network.rpc.use_jsonrpc", true); - - CMD2_ANY ("network.block.ipv4", [nw_config](auto, auto) { return nw_config->is_block_ipv4(); }); - CMD2_ANY_VALUE_V ("network.block.ipv4.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv4(value); }); - CMD2_ANY ("network.block.ipv6", [nw_config](auto, auto) { return nw_config->is_block_ipv6(); }); - CMD2_ANY_VALUE_V ("network.block.ipv6.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv6(value); }); - CMD2_ANY ("network.block.ipv4in6", [nw_config](auto, auto) { return nw_config->is_block_ipv4in6(); }); - CMD2_ANY_VALUE_V ("network.block.ipv4in6.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv4in6(value); }); - CMD2_ANY ("network.block.outgoing", [nw_config](auto, auto) { return nw_config->is_block_outgoing(); }); - CMD2_ANY_VALUE_V ("network.block.outgoing.set", [nw_config](auto, auto& value) { return nw_config->set_block_outgoing(value); }); - CMD2_ANY ("network.prefer.ipv6", [nw_config](auto, auto) { return nw_config->is_prefer_ipv6(); }); - CMD2_ANY_VALUE_V ("network.prefer.ipv6.set", [nw_config](auto, auto& value) { return nw_config->set_prefer_ipv6(value); }); + CMD_VAR_BOOL ("network.port_open", true); + CMD_VAR_BOOL ("network.port_random", true); + CMD_VAR_STRING ("network.port_range", "6881-6999"); + + CMD_ANY ("network.listen.port", [](auto, auto) { return torrent::runtime::listen_port(); }); + CMD_ANY ("network.listen.backlog", [nw_config](auto, auto) { return nw_config->listen_backlog(); }); + CMD_ANY_VALUE_V ("network.listen.backlog.set", [nw_config](auto, auto& value) { return nw_config->set_listen_backlog(value); }); + + CMD_VAR_BOOL ("protocol.pex", true); + CMD_ANY_LIST ("protocol.encryption.set", [](auto, auto& args) { return apply_encryption(args); }); + + CMD_VAR_STRING ("protocol.connection.leech", "leech"); + CMD_VAR_STRING ("protocol.connection.seed", "seed"); + + CMD_VAR_STRING ("protocol.choke_heuristics.up.leech", "upload_leech"); + CMD_VAR_STRING ("protocol.choke_heuristics.up.seed", "upload_leech"); + CMD_VAR_STRING ("protocol.choke_heuristics.down.leech", "download_leech"); + CMD_VAR_STRING ("protocol.choke_heuristics.down.seed", "download_leech"); + + CMD_ANY ("network.http.cacert", [http_stack](auto, auto) { return http_stack->http_cacert(); }); + CMD_ANY_STRING_V("network.http.cacert.set", [http_stack](auto, auto& str) { return http_stack->set_http_cacert(str); }); + CMD_ANY ("network.http.capath", [http_stack](auto, auto) { return http_stack->http_capath(); }); + CMD_ANY_STRING_V("network.http.capath.set", [http_stack](auto, auto& str) { return http_stack->set_http_capath(str); }); + CMD_ANY ("network.http.dns_cache_timeout", [http_stack](auto, auto) { return http_stack->dns_timeout(); }); + CMD_ANY_VALUE_V ("network.http.dns_cache_timeout.set", [http_stack](auto, auto& value) { return http_stack->set_dns_timeout(value); }); + CMD_ANY ("network.http.current_open", [http_stack](auto, auto) { return http_stack->size(); }); + CMD_ANY ("network.http.max_cache_connections", [http_stack](auto, auto) { return http_stack->max_cache_connections(); }); + CMD_ANY_VALUE_V ("network.http.max_cache_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_cache_connections(value); }); + CMD_ANY ("network.http.max_host_connections", [http_stack](auto, auto) { return http_stack->max_host_connections(); }); + CMD_ANY_VALUE_V ("network.http.max_host_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_host_connections(value); }); + CMD_ANY ("network.http.max_total_connections", [http_stack](auto, auto) { return http_stack->max_total_connections(); }); + + CMD_ANY ("network.http.ssl_verify_host", [http_stack](auto, auto) { return http_stack->ssl_verify_host(); }); + CMD_ANY_VALUE_V ("network.http.ssl_verify_host.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_host(value); }); + CMD_ANY ("network.http.ssl_verify_peer", [http_stack](auto, auto) { return http_stack->ssl_verify_peer(); }); + CMD_ANY_VALUE_V ("network.http.ssl_verify_peer.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_peer(value); }); + + CMD_ANY ("network.send_buffer.size", [nw_config](auto, auto) { return nw_config->send_buffer_size(); }); + CMD_ANY_VALUE_V ("network.send_buffer.size.set", [nw_config](auto, auto& value) { return nw_config->set_send_buffer_size(value); }); + CMD_ANY ("network.receive_buffer.size", [nw_config](auto, auto) { return nw_config->receive_buffer_size(); }); + CMD_ANY_VALUE_V ("network.receive_buffer.size.set", [nw_config](auto, auto& value) { return nw_config->set_receive_buffer_size(value); }); + CMD_ANY_STRING ("network.tos.set", [](auto, auto& str) { return apply_tos(str); }); + + CMD_ANY ("network.bind_address", [nw_config](auto, auto) { return nw_config->bind_address_best_match_str(); }); + CMD_ANY_STRING_V("network.bind_address.set", [nw_config](auto, auto& str) { return nw_config->set_bind_address_str(str); }); + CMD_ANY ("network.bind_address.ipv4", [nw_config](auto, auto) { return nw_config->bind_inet_address_str(); }); + CMD_ANY_STRING_V("network.bind_address.ipv4.set", [nw_config](auto, auto& str) { return nw_config->set_bind_inet_address_str(str); }); + CMD_ANY ("network.bind_address.ipv6", [nw_config](auto, auto) { return nw_config->bind_inet6_address_str(); }); + CMD_ANY_STRING_V("network.bind_address.ipv6.set", [nw_config](auto, auto& str) { return nw_config->set_bind_inet6_address_str(str); }); + + CMD_ANY ("network.local_address", [nw_config](auto, auto) { return nw_config->local_address_best_match_str(); }); + CMD_ANY_STRING_V("network.local_address.set", [nw_config](auto, auto& str) { return nw_config->set_local_address_str(str); }); + CMD_ANY ("network.local_address.ipv4", [nw_config](auto, auto) { return nw_config->local_inet_address_str(); }); + CMD_ANY_STRING_V("network.local_address.ipv4.set", [nw_config](auto, auto& str) { return nw_config->set_local_inet_address_str(str); }); + CMD_ANY ("network.local_address.ipv6", [nw_config](auto, auto) { return nw_config->local_inet6_address_str(); }); + CMD_ANY_STRING_V("network.local_address.ipv6.set", [nw_config](auto, auto& str) { return nw_config->set_local_inet6_address_str(str); }); + + CMD_ANY ("network.proxy.global", [](auto, auto) { return torrent::runtime::proxy_manager()->proxy_url(); }); + CMD_ANY_STRING_V("network.proxy.global.set", [](auto, auto& str) { return torrent::runtime::proxy_manager()->set_proxy_url(str); }); + CMD_ANY ("network.proxy.http", [](auto, auto) { return torrent::runtime::proxy_manager()->http_proxy_url(); }); + CMD_ANY_STRING_V("network.proxy.http.set", [](auto, auto& str) { return torrent::runtime::proxy_manager()->set_http_proxy_url(str); }); + + CMD_ANY ("network.open_files", [file_manager](auto, auto) { return file_manager->open_files(); }); + CMD_ANY ("network.max_open_files", [file_manager](auto, auto) { return file_manager->max_open_files(); }); + CMD_ANY ("network.total_handshakes", [](auto, auto) { return torrent::runtime::total_handshakes(); }); + + CMD_ANY_STRING ("network.scgi.open_port", [](auto, auto& arg) { return apply_scgi(arg, 1); }); + CMD_ANY_STRING ("network.scgi.open_local", [](auto, auto& arg) { return apply_scgi(arg, 2); }); + CMD_VAR_BOOL ("network.scgi.dont_route", false); + CMD_ANY ("network.scgi.open_systemd", [](auto, auto) { return apply_scgi_systemd(); }); + + CMD_ANY ("network.scgi.use_gzip", [](auto, auto) { return rpc::rpc.scgi_allow_compression(); }); + CMD_ANY_VALUE_V ("network.scgi.use_gzip.set", [](auto, auto& arg) { return rpc::rpc.set_scgi_allow_compression(arg); }); + CMD_ANY ("network.scgi.gzip.min_size", [](auto, auto) { return rpc::rpc.scgi_min_compress_size(); }); + CMD_ANY_VALUE_V ("network.scgi.gzip.min_size.set", [](auto, auto& arg) { return rpc::rpc.set_scgi_min_compress_size(arg); }); + + CMD_ANY_STRING ("network.xmlrpc.dialect.set", [](auto, auto& arg) { return apply_xmlrpc_dialect(arg); }) + CMD_ANY ("network.xmlrpc.size_limit", [](auto, auto) { return rpc::rpc.size_limit(); }); + CMD_ANY_VALUE_V ("network.xmlrpc.size_limit.set", [](auto, auto& arg) { return rpc::rpc.set_size_limit(arg); }); + + CMD_VAR_BOOL ("network.rpc.use_xmlrpc", true); + CMD_VAR_BOOL ("network.rpc.use_jsonrpc", true); + + CMD_ANY ("network.block.ipv4", [nw_config](auto, auto) { return nw_config->is_block_ipv4(); }); + CMD_ANY_VALUE_V ("network.block.ipv4.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv4(value); }); + CMD_ANY ("network.block.ipv6", [nw_config](auto, auto) { return nw_config->is_block_ipv6(); }); + CMD_ANY_VALUE_V ("network.block.ipv6.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv6(value); }); + CMD_ANY ("network.block.ipv4in6", [nw_config](auto, auto) { return nw_config->is_block_ipv4in6(); }); + CMD_ANY_VALUE_V ("network.block.ipv4in6.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv4in6(value); }); + CMD_ANY ("network.block.outgoing", [nw_config](auto, auto) { return nw_config->is_block_outgoing(); }); + CMD_ANY_VALUE_V ("network.block.outgoing.set", [nw_config](auto, auto& value) { return nw_config->set_block_outgoing(value); }); + CMD_ANY ("network.prefer.ipv6", [nw_config](auto, auto) { return nw_config->is_prefer_ipv6(); }); + CMD_ANY_VALUE_V ("network.prefer.ipv6.set", [nw_config](auto, auto& value) { return nw_config->set_prefer_ipv6(value); }); rpc::rpc.mark_safe("network.port_open"); rpc::rpc.mark_safe("network.port_random"); @@ -334,11 +336,13 @@ rpc::rpc.mark_safe("network.local_address"); rpc::rpc.mark_safe("network.xmlrpc.size_limit"); rpc::rpc.mark_safe("network.open_sockets"); + rpc::rpc.mark_safe("network.http.cacert"); rpc::rpc.mark_safe("network.http.capath"); - rpc::rpc.mark_safe("network.http.proxy_address"); - rpc::rpc.mark_safe("network.proxy_address"); + rpc::rpc.mark_safe("network.proxy.global"); + rpc::rpc.mark_safe("network.proxy.http"); rpc::rpc.mark_safe("network.scgi.dont_route"); + rpc::rpc.mark_safe("protocol.pex"); rpc::rpc.mark_safe("network.rpc.use_xmlrpc"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/src/control.cc new/rtorrent-0.16.16/src/control.cc --- old/rtorrent-0.16.15/src/control.cc 2026-06-22 11:01:51.000000000 +0200 +++ new/rtorrent-0.16.16/src/control.cc 2026-07-03 16:40:11.000000000 +0200 @@ -6,6 +6,7 @@ #include <sys/stat.h> #include <torrent/net/http_stack.h> #include <torrent/runtime/network_manager.h> +#include <torrent/runtime/runtime.h> #include <torrent/utils/directory_events.h> #include "core/dht_manager.h" @@ -46,7 +47,8 @@ m_inputStdin->slot_pressed(std::bind(&input::Manager::pressed, m_input.get(), std::placeholders::_1)); - m_task_shutdown.slot() = std::bind(&Control::handle_shutdown, this); + m_task_shutdown.slot() = [this] { handle_shutdown(); }; + m_task_shutdown_clear_requests.slot() = [this] { handle_shutdown_clear_requests(); }; m_commandScheduler->set_slot_error_message([this](const std::string& msg) { m_core->push_log_std(msg); }); } @@ -84,6 +86,7 @@ rpc::rpc.cleanup(); torrent::this_thread::scheduler()->erase(&m_task_shutdown); + torrent::this_thread::scheduler()->erase(&m_task_shutdown_clear_requests); if(!display::Canvas::daemon()) m_inputStdin->remove(); @@ -113,7 +116,7 @@ bool Control::is_shutdown_completed() { - if (!m_shutdownQuick) + if (!m_shutdown_quick) return false; // Tracker requests can be disowned, so wait for these to @@ -137,8 +140,9 @@ if (scgi_thread::thread()->is_active()) scgi_thread::thread()->stop_thread_wait(); - if (!m_shutdownQuick) { + if (!m_shutdown_quick) { torrent::runtime::network_manager()->listen_close(); + torrent::runtime::shutdown(); m_directory_events->close(); m_core->shutdown(false); @@ -147,9 +151,24 @@ torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_task_shutdown, 5s); } else { + torrent::runtime::quick_shutdown(); m_core->shutdown(true); } - m_shutdownQuick = true; - m_shutdownReceived = false; + if (!m_task_shutdown_clear_requests.is_scheduled()) + torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_task_shutdown_clear_requests, 10s); + + m_shutdown_quick = true; + m_shutdown_received = false; +} + +void +Control::handle_shutdown_clear_requests() { + torrent::net_thread::http_stack()->clear_requests(); + + // Use 5s for the initial wait to ensure trackers get a chance to finish both IPv4 and IPv6 requests. + if (m_clear_requests_count++ == 0) + torrent::this_thread::scheduler()->wait_for(&m_task_shutdown_clear_requests, 5s); + else + torrent::this_thread::scheduler()->wait_for(&m_task_shutdown_clear_requests, 1s); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/src/control.h new/rtorrent-0.16.16/src/control.h --- old/rtorrent-0.16.15/src/control.h 2026-06-22 11:01:51.000000000 +0200 +++ new/rtorrent-0.16.16/src/control.h 2026-07-03 16:40:11.000000000 +0200 @@ -48,17 +48,18 @@ ~Control(); bool is_shutdown_completed(); - bool is_shutdown_received() { return m_shutdownReceived; } - bool is_shutdown_started() { return m_shutdownQuick; } + bool is_shutdown_received() { return m_shutdown_received; } + bool is_shutdown_started() { return m_shutdown_quick; } void initialize(); void cleanup(); void cleanup_exception(); void handle_shutdown(); + void handle_shutdown_clear_requests(); - void receive_normal_shutdown() { m_shutdownReceived = true; } - void receive_quick_shutdown() { m_shutdownReceived = true; m_shutdownQuick = true; } + void receive_normal_shutdown() { m_shutdown_received = true; } + void receive_quick_shutdown() { m_shutdown_received = true; m_shutdown_quick = true; } core::Manager* core() { return m_core.get(); } core::ViewManager* view_manager() { return m_view_manager.get(); } @@ -107,9 +108,14 @@ std::string m_workingDirectory; torrent::utils::SchedulerEntry m_task_shutdown; + torrent::utils::SchedulerEntry m_task_shutdown_clear_requests; - std::atomic<bool> m_shutdownReceived{}; - std::atomic<bool> m_shutdownQuick{}; + int m_clear_requests_count{}; + + align_cacheline + + std::atomic<bool> m_shutdown_received{}; + std::atomic<bool> m_shutdown_quick{}; }; #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/src/core/http_queue.cc new/rtorrent-0.16.16/src/core/http_queue.cc --- old/rtorrent-0.16.15/src/core/http_queue.cc 2026-06-22 11:01:51.000000000 +0200 +++ new/rtorrent-0.16.16/src/core/http_queue.cc 2026-07-03 16:40:11.000000000 +0200 @@ -12,6 +12,9 @@ HttpQueue::insert(const std::string& url, std::shared_ptr<std::ostream> stream) { auto itr = base_type::insert(end(), torrent::net::HttpGet(url, stream)); + itr->set_max_file_size(15 << 20); + itr->set_redirect_only_http_https(); + for (auto& slot : m_signal_insert) slot(*itr); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/src/core/manager.cc new/rtorrent-0.16.16/src/core/manager.cc --- old/rtorrent-0.16.15/src/core/manager.cc 2026-06-22 11:01:51.000000000 +0200 +++ new/rtorrent-0.16.16/src/core/manager.cc 2026-07-03 16:40:11.000000000 +0200 @@ -8,7 +8,7 @@ #include <sstream> #include <unistd.h> #include <sys/select.h> -#include <rak/regex.h> +#include <fnmatch.h> #include <torrent/utils/resume.h> #include <torrent/object.h> #include <torrent/exceptions.h> @@ -151,12 +151,13 @@ void Manager::shutdown(bool force) { - if (!force) + if (!force) { for (auto d : *m_download_list) m_download_list->pause_default(d); - else + } else { for (auto d : *m_download_list) m_download_list->close_quick(d); + } } void @@ -194,37 +195,6 @@ } void -Manager::set_proxy_address(const std::string& addr) { - int port; - torrent::sa_unique_ptr sa; - - std::string buf(addr.length() + 1, '\0'); - - int err = std::sscanf(addr.c_str(), "%[^:]:%i", buf.data(), &port); - - if (err <= 0) - throw torrent::input_error("Could not parse proxy address."); - - if (err == 1) - port = 80; - - try { - sa = torrent::sa_copy(torrent::sa_lookup_address(buf, AF_INET).get()); - - } catch (torrent::input_error& e) { - throw torrent::input_error("Could not resolve proxy address: " + std::string(e.what())); - } - - try { - torrent::sa_set_port(sa.get(), port); - torrent::runtime::network_config()->set_proxy_address(sa.get()); - - } catch (torrent::input_error& e) { - throw e; - } -} - -void Manager::receive_http_failed(std::string msg) { push_log_std("Http download error: \"" + msg + "\""); } @@ -392,9 +362,9 @@ // Might be an idea to use depth-first search instead. for (; first != last; ++first) { - rak::regex r(*first); + const std::string& pattern = *first; - if (r.pattern().empty()) + if (pattern.empty()) continue; // Special case for ".."? @@ -402,8 +372,8 @@ for (auto& itr : currentCache) { // Only include filenames starting with '.' if the pattern // starts with the same. - itr.update((r.pattern()[0] != '.') ? utils::Directory::update_hide_dot : 0); - itr.erase(std::remove_if(itr.begin(), itr.end(), [r](const utils::directory_entry& entry) { return !r(entry.s_name); }), itr.end()); + itr.update((pattern[0] != '.') ? utils::Directory::update_hide_dot : 0); + itr.erase(std::remove_if(itr.begin(), itr.end(), [&pattern](const utils::directory_entry& entry) { return fnmatch(pattern.c_str(), entry.s_name.c_str(), 0) != 0; }), itr.end()); for (const auto& cache : itr) nextCache.push_back(path_expand_transform(itr.path() + (itr.path() == "/" ? "" : "/"), cache)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/src/core/manager.h new/rtorrent-0.16.16/src/core/manager.h --- old/rtorrent-0.16.15/src/core/manager.h 2026-06-22 11:01:51.000000000 +0200 +++ new/rtorrent-0.16.16/src/core/manager.h 2026-07-03 16:40:11.000000000 +0200 @@ -57,8 +57,6 @@ void listen_open(); - void set_proxy_address(const std::string& addr); - const std::string& magnet_path(); void set_magnet_path(const std::string& path); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/src/main.cc new/rtorrent-0.16.16/src/main.cc --- old/rtorrent-0.16.15/src/main.cc 2026-06-22 11:01:51.000000000 +0200 +++ new/rtorrent-0.16.16/src/main.cc 2026-07-03 16:40:11.000000000 +0200 @@ -358,11 +358,16 @@ // TODO: Deprecate these at some point a while after 1.1 release. - CMD_REDIRECT("network.open_sockets", "system.sockets.size"); - CMD_REDIRECT("network.max_open_sockets", "system.sockets.max_size"); - CMD_REDIRECT("network.max_open_sockets.set", "system.sockets.max_size.set"); + CMD_REDIRECT("d.multicall2", "d.multicall"); + CMD_REDIRECT("network.open_sockets", "system.sockets.size"); + CMD_REDIRECT("network.max_open_sockets", "system.sockets.max_size"); + CMD_REDIRECT("network.max_open_sockets.set", "system.sockets.max_size.set"); + CMD_REDIRECT("network.http.proxy_address", "network.proxy.http"); + CMD_REDIRECT("network.http.proxy_address.set", "network.proxy.http.set"); + rpc::rpc.mark_safe("d.multicall2"); rpc::rpc.mark_safe("network.max_open_sockets"); + rpc::rpc.mark_safe("network.http.proxy_address"); CMD2_ANY_VALUE_V("network.http.max_total_connections.set", [](auto, auto) { lt_log_print(torrent::LOG_WARN, "network.http.max_total_connections.set is deprecated, use system.sockets.http.min_alloc.set instead."); @@ -407,11 +412,6 @@ // Users should check their setups to see if they need to modify their use of these options. CMD_REDIRECT("max_memory_usage", "pieces.memory.max.set"); - CMD_REDIRECT("encoding_list", "encoding.add"); - - CMD_ANY_STRING_V("encoding.add", [](auto, auto) { - lt_log_print(torrent::LOG_WARN, "The 'encoding.add' command is deprecated and does nothing."); - }); CMD_ANY_LIST("throttle.ip", []( auto, auto) { lt_log_print(torrent::LOG_WARN, "The 'throttle.ip' command is deprecated and does nothing."); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/src/rpc/command.cc new/rtorrent-0.16.16/src/rpc/command.cc --- old/rtorrent-0.16.15/src/rpc/command.cc 2026-06-22 11:01:51.000000000 +0200 +++ new/rtorrent-0.16.16/src/rpc/command.cc 2026-07-03 16:40:11.000000000 +0200 @@ -6,31 +6,31 @@ #include "command.h" #define COMMAND_BASE_TEMPLATE_DEFINE(func_name) \ -template const torrent::Object func_name<target_type>(command_base* rawCommand, target_type target, const torrent::Object& args); \ -template const torrent::Object func_name<core::Download*>(command_base* rawCommand, target_type target, const torrent::Object& args); \ -template const torrent::Object func_name<torrent::Peer*>(command_base* rawCommand, target_type target, const torrent::Object& args); \ -template const torrent::Object func_name<torrent::tracker::Tracker*>(command_base* rawCommand, target_type target, const torrent::Object& args); \ -template const torrent::Object func_name<torrent::File*>(command_base* rawCommand, target_type target, const torrent::Object& args); \ -template const torrent::Object func_name<torrent::FileListIterator*>(command_base* rawCommand, target_type target, const torrent::Object& args); +template const torrent::Object func_name<target_type>(command_base* command_raw, target_type target, const torrent::Object& args); \ +template const torrent::Object func_name<core::Download*>(command_base* command_raw, target_type target, const torrent::Object& args); \ +template const torrent::Object func_name<torrent::Peer*>(command_base* command_raw, target_type target, const torrent::Object& args); \ +template const torrent::Object func_name<torrent::tracker::Tracker*>(command_base* command_raw, target_type target, const torrent::Object& args); \ +template const torrent::Object func_name<torrent::File*>(command_base* command_raw, target_type target, const torrent::Object& args); \ +template const torrent::Object func_name<torrent::FileListIterator*>(command_base* command_raw, target_type target, const torrent::Object& args); namespace rpc { template <typename T> const torrent::Object -command_base_call(command_base* rawCommand, target_type target, const torrent::Object& args) { +command_base_call(command_base* command_raw, target_type target, const torrent::Object& args) { if (!is_target_compatible<T>(target)) - throw torrent::input_error("Target of wrong type to command."); + throw torrent::input_error("Target of wrong type to generic command."); - return command_base::_call<typename command_function<T>::type, T>(rawCommand, target, args); + return command_base::_call<typename command_function<T>::type, T>(command_raw, target, args); } COMMAND_BASE_TEMPLATE_DEFINE(command_base_call); template <typename T> const torrent::Object -command_base_call_value_base(command_base* rawCommand, target_type target, const torrent::Object& rawArgs, int base, int unit) { +command_base_call_value_base(command_base* command_raw, target_type target, const torrent::Object& args_raw, int base, int unit) { if (!is_target_compatible<T>(target)) - throw torrent::input_error("Target of wrong type to command."); + throw torrent::input_error("Target of wrong type to value command."); - const torrent::Object& arg = convert_to_single_argument(rawArgs); + auto& arg = convert_to_single_argument(args_raw); if (arg.type() == torrent::Object::TYPE_STRING) { torrent::Object::value_type val; @@ -38,55 +38,55 @@ if (!parse_whole_value_nothrow(arg.as_string().c_str(), &val, base, unit)) throw torrent::input_error("Not a value."); - return command_base::_call<typename command_value_function<T>::type, T>(rawCommand, target, val); + return command_base::_call<typename command_value_function<T>::type, T>(command_raw, target, val); } - return command_base::_call<typename command_value_function<T>::type, T>(rawCommand, target, unit * arg.as_value()); + return command_base::_call<typename command_value_function<T>::type, T>(command_raw, target, unit * arg.as_value()); } template <typename T> const torrent::Object -command_base_call_value(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) { - return command_base_call_value_base<T>(rawCommand, target, rawArgs, 0, 1); +command_base_call_value(command_base* command_raw, target_type target, const torrent::Object& args_raw) { + return command_base_call_value_base<T>(command_raw, target, args_raw, 0, 1); } template <typename T> const torrent::Object -command_base_call_value_kb(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) { - return command_base_call_value_base<T>(rawCommand, target, rawArgs, 0, 1024); +command_base_call_value_kb(command_base* command_raw, target_type target, const torrent::Object& args_raw) { + return command_base_call_value_base<T>(command_raw, target, args_raw, 0, 1024); } COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_value); COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_value_kb); template <typename T> const torrent::Object -command_base_call_string(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) { +command_base_call_string(command_base* command_raw, target_type target, const torrent::Object& args_raw) { if (!is_target_compatible<T>(target)) - throw torrent::input_error("Target of wrong type to command."); + throw torrent::input_error("Target of wrong type to string command."); - const torrent::Object& arg = convert_to_single_argument(rawArgs); + auto& arg = convert_to_single_argument(args_raw); if (arg.type() == torrent::Object::TYPE_RAW_STRING) - return command_base::_call<typename command_string_function<T>::type, T>(rawCommand, target, arg.as_raw_string().as_string()); + return command_base::_call<typename command_string_function<T>::type, T>(command_raw, target, arg.as_raw_string().as_string()); - return command_base::_call<typename command_string_function<T>::type, T>(rawCommand, target, arg.as_string()); + return command_base::_call<typename command_string_function<T>::type, T>(command_raw, target, arg.as_string()); } COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_string); template <typename T> const torrent::Object -command_base_call_list(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) { +command_base_call_list(command_base* command_raw, target_type target, const torrent::Object& args_raw) { if (!is_target_compatible<T>(target)) - throw torrent::input_error("Target of wrong type to command."); + throw torrent::input_error("Target of wrong type to list command."); - if (rawArgs.type() != torrent::Object::TYPE_LIST) { + if (args_raw.type() != torrent::Object::TYPE_LIST) { torrent::Object::list_type arg; - - if (!rawArgs.is_empty()) - arg.push_back(rawArgs); - return command_base::_call<typename command_list_function<T>::type, T>(rawCommand, target, arg); + if (!args_raw.is_empty()) + arg.push_back(args_raw); + + return command_base::_call<typename command_list_function<T>::type, T>(command_raw, target, arg); } - return command_base::_call<typename command_list_function<T>::type, T>(rawCommand, target, rawArgs.as_list()); + return command_base::_call<typename command_list_function<T>::type, T>(command_raw, target, args_raw.as_list()); } COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_list); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/src/rpc/exec_file.cc new/rtorrent-0.16.16/src/rpc/exec_file.cc --- old/rtorrent-0.16.15/src/rpc/exec_file.cc 2026-06-22 11:01:51.000000000 +0200 +++ new/rtorrent-0.16.16/src/rpc/exec_file.cc 2026-07-03 16:40:11.000000000 +0200 @@ -38,24 +38,26 @@ result = write(m_log_fd, "\n---\n", sizeof("\n---\n")); } - int pipe_fd[2]; + posix_spawn_file_actions_t actions{}; - if ((flags & flag_capture) && pipe(pipe_fd)) - throw torrent::input_error("ExecFile::execute(...) Pipe creation failed."); + if (posix_spawn_file_actions_init(&actions) != 0) + throw torrent::internal_error("ExecFile::execute(...) posix_spawn_file_actions_init failed."); - auto clean_fn = [pipe_fd, flags]() { - if (flags & flag_capture) { - ::close(pipe_fd[0]); - ::close(pipe_fd[1]); - } - }; + posix_spawnattr_t attr; + posix_spawnattr_init(&attr); - posix_spawn_file_actions_t actions{}; + short spawn_flags = 0; - if (posix_spawn_file_actions_init(&actions) != 0) { - clean_fn(); - throw torrent::internal_error("ExecFile::execute(...) posix_spawn_file_actions_init failed."); - } + // Try to avoid leaking open fds to the spawned process. Prefer POSIX_SPAWN_CLOEXEC_DEFAULT + // (macOS-only) or posix_spawn_file_actions_addclosefrom_np (glibc >= 2.34, FreeBSD >= 13.1). + // + // Other platforms like musl libc, OpenBSD and NetBSD must rely on explicit O_CLOEXEC. + +#if defined(POSIX_SPAWN_CLOEXEC_DEFAULT) + spawn_flags |= POSIX_SPAWN_CLOEXEC_DEFAULT; +#elif defined(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP) + posix_spawn_file_actions_addclosefrom_np(&actions, 3); +#endif // Handle standard input redirection (/dev/null), posix_spawn_file_actions_addopen handles opening // and dup2 natively @@ -64,6 +66,11 @@ posix_spawn_file_actions_addclose(&actions, 0); } + int pipe_fd[2] = {-1, -1}; + + if ((flags & flag_capture) && pipe(pipe_fd)) + throw torrent::input_error("ExecFile::execute(...) Pipe creation failed."); + // Handle standard output redirection if (flags & flag_capture) { posix_spawn_file_actions_adddup2(&actions, pipe_fd[1], 1); @@ -85,26 +92,30 @@ posix_spawn_file_actions_addopen(&actions, 2, "/dev/null", O_RDWR, 0); } - posix_spawnattr_t attr; - posix_spawnattr_init(&attr); - - // If you are using standard close-on-exec (O_CLOEXEC) across rtorrent, posix_spawn honors it - // automatically. If you want to explicitly enforce a clean slate, modern systems support - // POSIX_SPAWN_CLOEXEC_DEFAULT. - -#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT - posix_spawnattr_setflags(&attr, POSIX_SPAWN_CLOEXEC_DEFAULT); + if (flags & flag_background) { +#ifdef POSIX_SPAWN_SETSID + spawn_flags |= POSIX_SPAWN_SETSID; +#else + spawn_flags |= POSIX_SPAWN_SETPGROUP; + posix_spawnattr_setpgroup(&attr, 0); #endif + } - pid_t child_pid{}; + posix_spawnattr_setflags(&attr, spawn_flags); - int spawn_status = posix_spawnp(&child_pid, file, &actions, &attr, argv, environ); + pid_t child_pid{}; + int spawn_status = posix_spawnp(&child_pid, file, &actions, &attr, argv, environ); posix_spawn_file_actions_destroy(&actions); posix_spawnattr_destroy(&attr); if (spawn_status != 0) { - clean_fn(); + if (pipe_fd[0] != -1) + ::close(pipe_fd[0]); + + if (pipe_fd[1] != -1) + ::close(pipe_fd[1]); + throw torrent::input_error("ExecFile::execute(...) posix_spawn failed: " + std::string(std::strerror(spawn_status))); } @@ -131,6 +142,13 @@ } } + if (flags & flag_background) { + if (m_log_fd != -1) + result = write(m_log_fd, "\n--- Running in Background ---\n", sizeof("\n--- Running in Background ---\n")); + + return 0; + } + int status; while (waitpid(child_pid, &status, 0) == -1) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/src/signal_handler.cc new/rtorrent-0.16.16/src/signal_handler.cc --- old/rtorrent-0.16.15/src/signal_handler.cc 2026-06-22 11:01:51.000000000 +0200 +++ new/rtorrent-0.16.16/src/signal_handler.cc 2026-07-03 16:40:11.000000000 +0200 @@ -82,6 +82,18 @@ } void +SignalHandler::set_sigchild_ignore() { + struct sigaction sa; + sa.sa_handler = SIG_IGN; + sa.sa_flags = SA_NOCLDWAIT | SA_RESTART; + + sigemptyset(&sa.sa_mask); + + if (sigaction(SIGCHLD, &sa, NULL) == -1) + throw std::logic_error("Could not set sigaction (ignore) for SIGCHLD: " + std::string(std::strerror(errno))); +} + +void SignalHandler::set_sigaction_handler(unsigned int signum, handler_slot slot) { if (signum >= HIGHEST_SIGNAL) throw std::logic_error("SignalHandler::set_handler(...) received invalid signal value."); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rtorrent-0.16.15/src/signal_handler.h new/rtorrent-0.16.16/src/signal_handler.h --- old/rtorrent-0.16.15/src/signal_handler.h 2026-06-22 11:01:51.000000000 +0200 +++ new/rtorrent-0.16.16/src/signal_handler.h 2026-07-03 16:40:11.000000000 +0200 @@ -25,6 +25,8 @@ static void set_block(unsigned int signum); static void set_unblock(unsigned int signum); + static void set_sigchild_ignore(); + static void set_sigaction_handler(unsigned int signum, handler_slot slot); static const char* as_string(unsigned int signum);
