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);

Reply via email to