mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-05 17:52:29 +00:00
Merge branch 'master' into master
This commit is contained in:
+10
-6
@@ -1,13 +1,16 @@
|
||||
AC_INIT(rtorrent, 0.9.6, sundell.software@gmail.com)
|
||||
AC_INIT(rtorrent, 0.9.7, sundell.software@gmail.com)
|
||||
|
||||
AC_DEFINE(API_VERSION, 9, api version)
|
||||
|
||||
AM_INIT_AUTOMAKE
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
|
||||
AC_PROG_RANLIB
|
||||
AC_PROG_CXX
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
RAK_CHECK_CFLAGS
|
||||
RAK_CHECK_CXXFLAGS
|
||||
RAK_ENABLE_DEBUG
|
||||
RAK_ENABLE_EXTRA_DEBUG
|
||||
RAK_ENABLE_WERROR
|
||||
@@ -32,15 +35,16 @@ AX_PTHREAD([], AC_MSG_ERROR([requires pthread]))
|
||||
AX_WITH_CURSES
|
||||
|
||||
if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then
|
||||
AC_MSG_ERROR([requires either NcursesW or Ncurses library])
|
||||
AC_MSG_ERROR([requires either NcursesW or Ncurses library])
|
||||
fi
|
||||
|
||||
PKG_CHECK_MODULES([LIBCURL], [libcurl], , [LIBCURL_CHECK_CONFIG])
|
||||
PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
|
||||
PKG_CHECK_MODULES([DEPENDENCIES], [libcurl >= 7.15.4 libtorrent >= 0.13.6])
|
||||
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.13.7])
|
||||
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $CPPUNIT_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $CPPUNIT_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $CURSES_LIB $CPPUNIT_LIBS $DEPENDENCIES_LIBS $LIBS"
|
||||
LIBS="$PTHREAD_LIBS $CURSES_LIB $CPPUNIT_LIBS $LIBCURL $LIBCURL_LIBS $DEPENDENCIES_LIBS $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $CPPUNIT_CFLAGS $LIBCURL_CPPFLAGS $LIBCURL_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $CPPUNIT_CFLAGS $LIBCURL_CPPFLAGS $LIBCURL_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS"
|
||||
|
||||
AC_LANG_PUSH(C++)
|
||||
TORRENT_WITH_XMLRPC_C
|
||||
|
||||
@@ -101,3 +101,12 @@
|
||||
# Set downlad list layout style. ("full", "compact")
|
||||
#
|
||||
#ui.torrent_list.layout.set = "full"
|
||||
|
||||
# SCGI Connectivity (for alternative rtorrent interfaces, XMLRPC)
|
||||
#
|
||||
# Use a IP socket with scgi_port, or a Unix socket with scgi_local.
|
||||
# schedule can be used to set permissions on the unix socket.
|
||||
#
|
||||
#scgi_port = 127.0.0.1:5000
|
||||
#scgi_local = /home/user/rtorrent/rpc.socket
|
||||
#schedule = scgi_permission,0,0,"execute.nothrow=chmod,\"g+w,o=\",/home/user/rtorrent/rpc.socket"
|
||||
|
||||
@@ -176,6 +176,26 @@ inline int popcount_wrapper(T t) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get the median of an unordered set of numbers of arbitrary
|
||||
// type by modifing the underlying dataset
|
||||
template <typename T = double, typename _InputIter>
|
||||
T median(_InputIter __first, _InputIter __last) {
|
||||
T __med;
|
||||
|
||||
unsigned int __size = __last - __first;
|
||||
unsigned int __middle = __size / 2;
|
||||
_InputIter __target1 = __first + __middle;
|
||||
std::nth_element(__first, __target1, __last);
|
||||
__med = *__target1;
|
||||
|
||||
if (__size % 2 == 0) {
|
||||
_InputIter __target2 = std::max_element(__first, __target1);
|
||||
__med = (__med + *__target2) / 2.0;
|
||||
}
|
||||
|
||||
return __med;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -153,7 +153,7 @@ dnl Need to fix this so that it uses the stuff defined by the system.
|
||||
AC_DEFUN([TORRENT_CHECK_EXECINFO], [
|
||||
AC_MSG_CHECKING(for execinfo.h)
|
||||
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <execinfo.h>
|
||||
int main() { backtrace((void**)0, 0); backtrace_symbols((char**)0, 0); return 0;}
|
||||
])],
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
#***************************************************************************
|
||||
# _ _ ____ _
|
||||
# Project ___| | | | _ \| |
|
||||
# / __| | | | |_) | |
|
||||
# | (__| |_| | _ <| |___
|
||||
# \___|\___/|_| \_\_____|
|
||||
#
|
||||
# Copyright (C) 2006, David Shaw <dshaw@jabberwocky.com>
|
||||
#
|
||||
# This software is licensed as described in the file COPYING, which
|
||||
# you should have received as part of this distribution. The terms
|
||||
# are also available at https://curl.haxx.se/docs/copyright.html.
|
||||
#
|
||||
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
# copies of the Software, and permit persons to whom the Software is
|
||||
# furnished to do so, under the terms of the COPYING file.
|
||||
#
|
||||
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
# KIND, either express or implied.
|
||||
#
|
||||
###########################################################################
|
||||
# LIBCURL_CHECK_CONFIG ([DEFAULT-ACTION], [MINIMUM-VERSION],
|
||||
# [ACTION-IF-YES], [ACTION-IF-NO])
|
||||
# ----------------------------------------------------------
|
||||
# David Shaw <dshaw@jabberwocky.com> May-09-2006
|
||||
#
|
||||
# Checks for libcurl. DEFAULT-ACTION is the string yes or no to
|
||||
# specify whether to default to --with-libcurl or --without-libcurl.
|
||||
# If not supplied, DEFAULT-ACTION is yes. MINIMUM-VERSION is the
|
||||
# minimum version of libcurl to accept. Pass the version as a regular
|
||||
# version number like 7.10.1. If not supplied, any version is
|
||||
# accepted. ACTION-IF-YES is a list of shell commands to run if
|
||||
# libcurl was successfully found and passed the various tests.
|
||||
# ACTION-IF-NO is a list of shell commands that are run otherwise.
|
||||
# Note that using --without-libcurl does run ACTION-IF-NO.
|
||||
#
|
||||
# This macro #defines HAVE_LIBCURL if a working libcurl setup is
|
||||
# found, and sets @LIBCURL@ and @LIBCURL_CPPFLAGS@ to the necessary
|
||||
# values. Other useful defines are LIBCURL_FEATURE_xxx where xxx are
|
||||
# the various features supported by libcurl, and LIBCURL_PROTOCOL_yyy
|
||||
# where yyy are the various protocols supported by libcurl. Both xxx
|
||||
# and yyy are capitalized. See the list of AH_TEMPLATEs at the top of
|
||||
# the macro for the complete list of possible defines. Shell
|
||||
# variables $libcurl_feature_xxx and $libcurl_protocol_yyy are also
|
||||
# defined to 'yes' for those features and protocols that were found.
|
||||
# Note that xxx and yyy keep the same capitalization as in the
|
||||
# curl-config list (e.g. it's "HTTP" and not "http").
|
||||
#
|
||||
# Users may override the detected values by doing something like:
|
||||
# LIBCURL="-lcurl" LIBCURL_CPPFLAGS="-I/usr/myinclude" ./configure
|
||||
#
|
||||
# For the sake of sanity, this macro assumes that any libcurl that is
|
||||
# found is after version 7.7.2, the first version that included the
|
||||
# curl-config script. Note that it is very important for people
|
||||
# packaging binary versions of libcurl to include this script!
|
||||
# Without curl-config, we can only guess what protocols are available,
|
||||
# or use curl_version_info to figure it out at runtime.
|
||||
|
||||
AC_DEFUN([LIBCURL_CHECK_CONFIG],
|
||||
[
|
||||
AH_TEMPLATE([LIBCURL_FEATURE_SSL],[Defined if libcurl supports SSL])
|
||||
AH_TEMPLATE([LIBCURL_FEATURE_KRB4],[Defined if libcurl supports KRB4])
|
||||
AH_TEMPLATE([LIBCURL_FEATURE_IPV6],[Defined if libcurl supports IPv6])
|
||||
AH_TEMPLATE([LIBCURL_FEATURE_LIBZ],[Defined if libcurl supports libz])
|
||||
AH_TEMPLATE([LIBCURL_FEATURE_ASYNCHDNS],[Defined if libcurl supports AsynchDNS])
|
||||
AH_TEMPLATE([LIBCURL_FEATURE_IDN],[Defined if libcurl supports IDN])
|
||||
AH_TEMPLATE([LIBCURL_FEATURE_SSPI],[Defined if libcurl supports SSPI])
|
||||
AH_TEMPLATE([LIBCURL_FEATURE_NTLM],[Defined if libcurl supports NTLM])
|
||||
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_HTTP],[Defined if libcurl supports HTTP])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_HTTPS],[Defined if libcurl supports HTTPS])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_FTP],[Defined if libcurl supports FTP])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_FTPS],[Defined if libcurl supports FTPS])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_FILE],[Defined if libcurl supports FILE])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_TELNET],[Defined if libcurl supports TELNET])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_RTSP],[Defined if libcurl supports RTSP])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_POP3],[Defined if libcurl supports POP3])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_IMAP],[Defined if libcurl supports IMAP])
|
||||
AH_TEMPLATE([LIBCURL_PROTOCOL_SMTP],[Defined if libcurl supports SMTP])
|
||||
|
||||
AC_ARG_WITH(libcurl,
|
||||
AS_HELP_STRING([--with-libcurl=PREFIX],[look for the curl library in PREFIX/lib and headers in PREFIX/include]),
|
||||
[_libcurl_with=$withval],[_libcurl_with=ifelse([$1],,[yes],[$1])])
|
||||
|
||||
if test "$_libcurl_with" != "no" ; then
|
||||
|
||||
AC_PROG_AWK
|
||||
|
||||
_libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[[1]]+256*A[[2]]+A[[3]]; print X;}'"
|
||||
|
||||
_libcurl_try_link=yes
|
||||
|
||||
if test -d "$_libcurl_with" ; then
|
||||
LIBCURL_CPPFLAGS="-I$withval/include"
|
||||
_libcurl_ldflags="-L$withval/lib"
|
||||
AC_PATH_PROG([_libcurl_config],[curl-config],[],
|
||||
["$withval/bin"])
|
||||
else
|
||||
AC_PATH_PROG([_libcurl_config],[curl-config],[],[$PATH])
|
||||
fi
|
||||
|
||||
if test x$_libcurl_config != "x" ; then
|
||||
AC_CACHE_CHECK([for the version of libcurl],
|
||||
[libcurl_cv_lib_curl_version],
|
||||
[libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $[]2}'`])
|
||||
|
||||
_libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse`
|
||||
_libcurl_wanted=`echo ifelse([$2],,[0],[$2]) | $_libcurl_version_parse`
|
||||
|
||||
if test $_libcurl_wanted -gt 0 ; then
|
||||
AC_CACHE_CHECK([for libcurl >= version $2],
|
||||
[libcurl_cv_lib_version_ok],
|
||||
[
|
||||
if test $_libcurl_version -ge $_libcurl_wanted ; then
|
||||
libcurl_cv_lib_version_ok=yes
|
||||
else
|
||||
libcurl_cv_lib_version_ok=no
|
||||
fi
|
||||
])
|
||||
fi
|
||||
|
||||
if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then
|
||||
if test x"$LIBCURL_CPPFLAGS" = "x" ; then
|
||||
LIBCURL_CPPFLAGS=`$_libcurl_config --cflags`
|
||||
fi
|
||||
if test x"$LIBCURL" = "x" ; then
|
||||
LIBCURL=`$_libcurl_config --libs`
|
||||
|
||||
# This is so silly, but Apple actually has a bug in their
|
||||
# curl-config script. Fixed in Tiger, but there are still
|
||||
# lots of Panther installs around.
|
||||
case "${host}" in
|
||||
powerpc-apple-darwin7*)
|
||||
LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'`
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# All curl-config scripts support --feature
|
||||
_libcurl_features=`$_libcurl_config --feature`
|
||||
|
||||
# Is it modern enough to have --protocols? (7.12.4)
|
||||
if test $_libcurl_version -ge 461828 ; then
|
||||
_libcurl_protocols=`$_libcurl_config --protocols`
|
||||
fi
|
||||
else
|
||||
_libcurl_try_link=no
|
||||
fi
|
||||
|
||||
unset _libcurl_wanted
|
||||
fi
|
||||
|
||||
if test $_libcurl_try_link = yes ; then
|
||||
|
||||
# we didn't find curl-config, so let's see if the user-supplied
|
||||
# link line (or failing that, "-lcurl") is enough.
|
||||
LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"}
|
||||
|
||||
AC_CACHE_CHECK([whether libcurl is usable],
|
||||
[libcurl_cv_lib_curl_usable],
|
||||
[
|
||||
_libcurl_save_cppflags=$CPPFLAGS
|
||||
CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS"
|
||||
_libcurl_save_libs=$LIBS
|
||||
LIBS="$LIBCURL $LIBS"
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <curl/curl.h>]],[[
|
||||
/* Try and use a few common options to force a failure if we are
|
||||
missing symbols or can't link. */
|
||||
int x;
|
||||
curl_easy_setopt(NULL,CURLOPT_URL,NULL);
|
||||
x=CURL_ERROR_SIZE;
|
||||
x=CURLOPT_WRITEFUNCTION;
|
||||
x=CURLOPT_WRITEDATA;
|
||||
x=CURLOPT_ERRORBUFFER;
|
||||
x=CURLOPT_STDERR;
|
||||
x=CURLOPT_VERBOSE;
|
||||
if (x) {;}
|
||||
]])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no)
|
||||
|
||||
CPPFLAGS=$_libcurl_save_cppflags
|
||||
LIBS=$_libcurl_save_libs
|
||||
unset _libcurl_save_cppflags
|
||||
unset _libcurl_save_libs
|
||||
])
|
||||
|
||||
if test $libcurl_cv_lib_curl_usable = yes ; then
|
||||
|
||||
# Does curl_free() exist in this version of libcurl?
|
||||
# If not, fake it with free()
|
||||
|
||||
_libcurl_save_cppflags=$CPPFLAGS
|
||||
CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
|
||||
_libcurl_save_libs=$LIBS
|
||||
LIBS="$LIBS $LIBCURL"
|
||||
|
||||
AC_CHECK_FUNC(curl_free,,
|
||||
AC_DEFINE(curl_free,free,
|
||||
[Define curl_free() as free() if our version of curl lacks curl_free.]))
|
||||
|
||||
CPPFLAGS=$_libcurl_save_cppflags
|
||||
LIBS=$_libcurl_save_libs
|
||||
unset _libcurl_save_cppflags
|
||||
unset _libcurl_save_libs
|
||||
|
||||
AC_DEFINE(HAVE_LIBCURL,1,
|
||||
[Define to 1 if you have a functional curl library.])
|
||||
AC_SUBST(LIBCURL_CPPFLAGS)
|
||||
AC_SUBST(LIBCURL)
|
||||
|
||||
for _libcurl_feature in $_libcurl_features ; do
|
||||
AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1])
|
||||
eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes
|
||||
done
|
||||
|
||||
if test "x$_libcurl_protocols" = "x" ; then
|
||||
|
||||
# We don't have --protocols, so just assume that all
|
||||
# protocols are available
|
||||
_libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP"
|
||||
|
||||
if test x$libcurl_feature_SSL = xyes ; then
|
||||
_libcurl_protocols="$_libcurl_protocols HTTPS"
|
||||
|
||||
# FTPS wasn't standards-compliant until version
|
||||
# 7.11.0 (0x070b00 == 461568)
|
||||
if test $_libcurl_version -ge 461568; then
|
||||
_libcurl_protocols="$_libcurl_protocols FTPS"
|
||||
fi
|
||||
fi
|
||||
|
||||
# RTSP, IMAP, POP3 and SMTP were added in
|
||||
# 7.20.0 (0x071400 == 463872)
|
||||
if test $_libcurl_version -ge 463872; then
|
||||
_libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP"
|
||||
fi
|
||||
fi
|
||||
|
||||
for _libcurl_protocol in $_libcurl_protocols ; do
|
||||
AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_protocol_$_libcurl_protocol),[1])
|
||||
eval AS_TR_SH(libcurl_protocol_$_libcurl_protocol)=yes
|
||||
done
|
||||
else
|
||||
unset LIBCURL
|
||||
unset LIBCURL_CPPFLAGS
|
||||
fi
|
||||
fi
|
||||
|
||||
unset _libcurl_try_link
|
||||
unset _libcurl_version_parse
|
||||
unset _libcurl_config
|
||||
unset _libcurl_feature
|
||||
unset _libcurl_features
|
||||
unset _libcurl_protocol
|
||||
unset _libcurl_protocols
|
||||
unset _libcurl_version
|
||||
unset _libcurl_ldflags
|
||||
fi
|
||||
|
||||
if test x$_libcurl_with = xno || test x$libcurl_cv_lib_curl_usable != xyes ; then
|
||||
# This is the IF-NO path
|
||||
ifelse([$4],,:,[$4])
|
||||
else
|
||||
# This is the IF-YES path
|
||||
ifelse([$3],,:,[$3])
|
||||
fi
|
||||
|
||||
unset _libcurl_with
|
||||
])dnl
|
||||
@@ -1,3 +1,29 @@
|
||||
AC_DEFUN([RAK_CHECK_CFLAGS], [
|
||||
|
||||
AC_MSG_CHECKING([for user-defined CFLAGS])
|
||||
|
||||
if test "$CFLAGS" = ""; then
|
||||
unset CFLAGS
|
||||
AC_MSG_RESULT([undefined])
|
||||
else
|
||||
AC_MSG_RESULT([user-defined "$CFLAGS"])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([RAK_CHECK_CXXFLAGS], [
|
||||
|
||||
AC_MSG_CHECKING([for user-defined CXXFLAGS])
|
||||
|
||||
if test "$CXXFLAGS" = ""; then
|
||||
unset CXXFLAGS
|
||||
AC_MSG_RESULT([undefined])
|
||||
else
|
||||
AC_MSG_RESULT([user-defined "$CXXFLAGS"])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([RAK_ENABLE_DEBUG], [
|
||||
AC_ARG_ENABLE(debug,
|
||||
AC_HELP_STRING([--enable-debug], [enable debug information [[default=yes]]]),
|
||||
|
||||
@@ -274,6 +274,41 @@ retrieve_d_custom_throw(core::Download* download, const std::string& key) {
|
||||
}
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_d_custom_if_z(core::Download* download, const torrent::Object::list_type& args) {
|
||||
torrent::Object::list_const_iterator itr = args.begin();
|
||||
if (itr == args.end())
|
||||
throw torrent::bencode_error("d.custom.if_z: Missing key argument.");
|
||||
const std::string& key = (itr++)->as_string();
|
||||
if (key.empty())
|
||||
throw torrent::bencode_error("d.custom.if_z: Empty key argument.");
|
||||
if (itr == args.end())
|
||||
throw torrent::bencode_error("d.custom.if_z: Missing default argument.");
|
||||
|
||||
try {
|
||||
const std::string& val = download->bencode()->get_key("rtorrent").get_key("custom").get_key_string(key);
|
||||
return val.empty() ? itr->as_string() : val;
|
||||
} catch (torrent::bencode_error& e) {
|
||||
return itr->as_string();
|
||||
}
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_d_custom_map(core::Download* download, bool keys_only, const torrent::Object::list_type& args) {
|
||||
if (args.begin() != args.end())
|
||||
throw torrent::bencode_error("d.custom.keys/items takes no arguments.");
|
||||
|
||||
torrent::Object result = keys_only ? torrent::Object::create_list() : torrent::Object::create_map();
|
||||
torrent::Object::map_type& entries = download->bencode()->get_key("rtorrent").get_key("custom").as_map();
|
||||
|
||||
for (torrent::Object::map_type::const_iterator itr = entries.begin(), last = entries.end(); itr != last; itr++) {
|
||||
if (keys_only) result.as_list().push_back(itr->first);
|
||||
else result.as_map()[itr->first] = itr->second;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
retrieve_d_bitfield(core::Download* download) {
|
||||
const torrent::Bitfield* bitField = download->download()->file_list()->bitfield();
|
||||
@@ -710,6 +745,9 @@ initialize_command_download() {
|
||||
CMD2_DL_STRING("d.custom", std::bind(&retrieve_d_custom, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_STRING("d.custom_throw", std::bind(&retrieve_d_custom_throw, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_LIST ("d.custom.set", std::bind(&apply_d_custom, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_LIST ("d.custom.if_z", std::bind(&retrieve_d_custom_if_z, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL_LIST ("d.custom.keys", std::bind(&retrieve_d_custom_map, std::placeholders::_1, true, std::placeholders::_2));
|
||||
CMD2_DL_LIST ("d.custom.items", std::bind(&retrieve_d_custom_map, std::placeholders::_1, false, std::placeholders::_2));
|
||||
|
||||
CMD2_DL_VAR_STRING_PUBLIC("d.custom1", "rtorrent", "custom1");
|
||||
CMD2_DL_VAR_STRING_PUBLIC("d.custom2", "rtorrent", "custom2");
|
||||
|
||||
+207
-90
@@ -45,42 +45,14 @@
|
||||
#include "globals.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
void
|
||||
ipv4_filter_parse(const char* address, int value) {
|
||||
uint32_t ip_values[4] = { 0, 0, 0, 0 };
|
||||
unsigned int block = rpc::ipv4_table::mask_bits;
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
char ip_dot;
|
||||
int values_read;
|
||||
|
||||
if ((values_read = sscanf(address, "%u%1[.]%u%1[.]%u%1[.]%u/%u",
|
||||
ip_values + 0, &ip_dot,
|
||||
ip_values + 1, &ip_dot,
|
||||
ip_values + 2, &ip_dot,
|
||||
ip_values + 3,
|
||||
&block)) < 2 ||
|
||||
|
||||
// Make sure the dot is included.
|
||||
(values_read < 7 && values_read % 2) ||
|
||||
|
||||
ip_values[0] >= 256 ||
|
||||
ip_values[1] >= 256 ||
|
||||
ip_values[2] >= 256 ||
|
||||
ip_values[3] >= 256 ||
|
||||
|
||||
block > rpc::ipv4_table::mask_bits)
|
||||
throw torrent::input_error("Invalid address format.");
|
||||
|
||||
// E.g. '10.10.' will be '10.10.0.0/16'.
|
||||
if (values_read < 7)
|
||||
block = 8 * (values_read / 2);
|
||||
|
||||
lt_log_print(torrent::LOG_CONNECTION_DEBUG, "Adding ip filter for %u.%u.%u.%u/%u.",
|
||||
ip_values[0], ip_values[1], ip_values[2], ip_values[3], block);
|
||||
|
||||
torrent::PeerList::ipv4_filter()->insert((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3],
|
||||
rpc::ipv4_table::mask_bits - block, value);
|
||||
}
|
||||
bool ipv4_range_parse(const char* address, uint32_t* address_start, uint32_t* address_end);
|
||||
|
||||
torrent::Object
|
||||
apply_ip_tables_insert_table(const std::string& args) {
|
||||
@@ -98,7 +70,8 @@ apply_ip_tables_size_data(const std::string& args) {
|
||||
if (itr != ip_tables.end())
|
||||
throw torrent::input_error("IP table does not exist.");
|
||||
|
||||
return itr->table.sizeof_data();
|
||||
uint32_t size = itr->table.sizeof_data();
|
||||
return size;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -110,20 +83,21 @@ apply_ip_tables_get(const torrent::Object::list_type& args) {
|
||||
|
||||
const std::string& name = (args_itr++)->as_string();
|
||||
const std::string& address = (args_itr++)->as_string();
|
||||
|
||||
// Move to a helper function, add support for addresses.
|
||||
uint32_t ip_values[4];
|
||||
|
||||
if (sscanf(address.c_str(), "%u.%u.%u.%u",
|
||||
ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3) != 4)
|
||||
throw torrent::input_error("Invalid address format.");
|
||||
uint32_t address_start;
|
||||
uint32_t address_end;
|
||||
|
||||
rpc::ip_table_list::iterator table_itr = ip_tables.find(name);
|
||||
|
||||
if (table_itr == ip_tables.end())
|
||||
throw torrent::input_error("Could not find ip table.");
|
||||
|
||||
return table_itr->table.at((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3]);
|
||||
if (!ipv4_range_parse(address.c_str(), &address_start, &address_end))
|
||||
throw torrent::input_error("Invalid address format.");
|
||||
|
||||
if(!table_itr->table.defined(address_start, address_end))
|
||||
throw torrent::input_error("No value defined for specified IP(s).");
|
||||
|
||||
return table_itr->table.at(address_start, address_end);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -136,15 +110,6 @@ apply_ip_tables_add_address(const torrent::Object::list_type& args) {
|
||||
const std::string& name = (args_itr++)->as_string();
|
||||
const std::string& address = (args_itr++)->as_string();
|
||||
const std::string& value_str = (args_itr++)->as_string();
|
||||
|
||||
// Move to a helper function, add support for addresses.
|
||||
uint32_t ip_values[4];
|
||||
unsigned int block = rpc::ipv4_table::mask_bits;
|
||||
|
||||
if (sscanf(address.c_str(), "%u.%u.%u.%u/%u",
|
||||
ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3, &block) < 4 ||
|
||||
block > rpc::ipv4_table::mask_bits)
|
||||
throw torrent::input_error("Invalid address format.");
|
||||
|
||||
int value;
|
||||
|
||||
@@ -158,8 +123,13 @@ apply_ip_tables_add_address(const torrent::Object::list_type& args) {
|
||||
if (table_itr == ip_tables.end())
|
||||
throw torrent::input_error("Could not find ip table.");
|
||||
|
||||
table_itr->table.insert((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3],
|
||||
rpc::ipv4_table::mask_bits - block, value);
|
||||
uint32_t address_start;
|
||||
uint32_t address_end;
|
||||
|
||||
if (ipv4_range_parse(address.c_str(), &address_start, &address_end))
|
||||
table_itr->table.insert(address_start, address_end, value);
|
||||
else
|
||||
throw torrent::input_error("Invalid address format.");
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
@@ -168,6 +138,158 @@ apply_ip_tables_add_address(const torrent::Object::list_type& args) {
|
||||
// IPv4 filter functions:
|
||||
//
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// IPV4_RANGE_PARSE parses string into an ip range
|
||||
//
|
||||
// should be compatible with lines in p2p files
|
||||
// everything in address before colon is ignored
|
||||
//
|
||||
// ip range can be single ip in which case start=end
|
||||
// ip range can be cidr notation a.b.c.d/e
|
||||
// ip range can be explicit range like in p2p line a.b.c.d-w.x.y.z
|
||||
//
|
||||
// returns false if line does not contain valid ip or ip range
|
||||
// address_start and address_end will contain start and end ip
|
||||
//
|
||||
// addresses parsed are returned in host byte order
|
||||
// to get network byte order call htonl(address)
|
||||
///////////////////////////////////////////////////////////
|
||||
bool
|
||||
ipv4_range_parse(const char* address, uint32_t* address_start, uint32_t* address_end) {
|
||||
// same length as buffer used to do reads so no worries about overflow
|
||||
char address_copy[4096];
|
||||
bool valid = false;
|
||||
char address_start_str[20];
|
||||
int address_start_index=0;
|
||||
struct sockaddr_in sa_start;
|
||||
*address_start=0;
|
||||
*address_end=0;
|
||||
|
||||
// get rid of everything after '#' comments
|
||||
// copy everything up to '#' to address_copy and work from there
|
||||
while(address[address_start_index] != '#' && address[address_start_index] != '\r' &&
|
||||
address[address_start_index] != '\n' && address[address_start_index] != '\0' &&
|
||||
address_start_index < 4096 ) {
|
||||
|
||||
address_copy[address_start_index] = address[address_start_index];
|
||||
address_start_index++;
|
||||
}
|
||||
|
||||
address_copy[address_start_index] = '\0';
|
||||
address_start_index=0;
|
||||
|
||||
// skip everything up to and including last ':' character and whitespace
|
||||
const char* addr = strrchr(address_copy, ':');
|
||||
|
||||
addr = (addr == NULL) ? address_copy : addr + 1;
|
||||
|
||||
while(addr[0] == ' ' || addr[0] == '\t')
|
||||
addr++;
|
||||
|
||||
while(((addr[0] >= '0' && addr[0] <= '9') || addr[0] == '.') && address_start_index < 19) {
|
||||
address_start_str[address_start_index] = addr[0];
|
||||
address_start_index++;
|
||||
addr++;
|
||||
}
|
||||
|
||||
address_start_str[address_start_index] = '\0';
|
||||
|
||||
if(strchr(addr, '-') != NULL) {
|
||||
// explicit range
|
||||
char address_end_str[20];
|
||||
int address_end_index=0;
|
||||
struct sockaddr_in sa_end;
|
||||
|
||||
while(addr[0] == '-' || addr[0] == ' ' || addr[0] == '\t')
|
||||
addr++;
|
||||
|
||||
while(((addr[0] >= '0' && addr[0] <= '9') || addr[0] == '.') && address_end_index < 19) {
|
||||
address_end_str[address_end_index] = addr[0];
|
||||
address_end_index++;
|
||||
addr++;
|
||||
}
|
||||
|
||||
address_end_str[address_end_index] = '\0';
|
||||
|
||||
if(inet_pton(AF_INET, address_start_str, &(sa_start.sin_addr)) != 0 && inet_pton(AF_INET, address_end_str, &(sa_end.sin_addr)) != 0) {
|
||||
*address_start = ntohl(sa_start.sin_addr.s_addr);
|
||||
*address_end = ntohl(sa_end.sin_addr.s_addr);
|
||||
|
||||
if(*address_start <= *address_end)
|
||||
valid=true;
|
||||
}
|
||||
} else if(strchr(addr, '/') != NULL) {
|
||||
// cidr range
|
||||
char mask_bits_str[20];
|
||||
int mask_bits_index=0;
|
||||
uint32_t mask_bits;
|
||||
|
||||
while(addr[0] == '/' || addr[0] == ' ' || addr[0] == '\t')
|
||||
addr++;
|
||||
|
||||
while( (addr[0] >= '0' && addr[0] <= '9') && mask_bits_index < 19) {
|
||||
mask_bits_str[mask_bits_index] = addr[0];
|
||||
mask_bits_index++;
|
||||
addr++;
|
||||
}
|
||||
|
||||
mask_bits_str[mask_bits_index] = '\0';
|
||||
|
||||
if(inet_pton(AF_INET, address_start_str, &(sa_start.sin_addr)) != 0 && sscanf(mask_bits_str, "%u", &mask_bits) != 0) {
|
||||
if(mask_bits <=32) {
|
||||
uint32_t ip=ntohl(sa_start.sin_addr.s_addr);
|
||||
uint32_t mask=0;
|
||||
uint32_t end_mask=0;
|
||||
|
||||
mask = (~mask) << (32-mask_bits);
|
||||
*address_start = ip & mask;
|
||||
end_mask = (~end_mask) >> mask_bits;
|
||||
*address_end = (ip & mask) | end_mask;
|
||||
|
||||
valid=true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// single ip
|
||||
if(inet_pton(AF_INET, address_start_str, &(sa_start.sin_addr)) != 0) {
|
||||
*address_start = ntohl(sa_start.sin_addr.s_addr);
|
||||
*address_end = *address_start;
|
||||
|
||||
valid=true;
|
||||
}
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// IPV4_FILTER_PARSE
|
||||
//
|
||||
// should now be compatible with lines in p2p files
|
||||
//
|
||||
// addresses in table MUST be in host byte order
|
||||
// ntohl is called after parsing ip address(es)
|
||||
///////////////////////////////////////////////////////////
|
||||
void
|
||||
ipv4_filter_parse(const char* address, int value) {
|
||||
uint32_t address_start;
|
||||
uint32_t address_end;
|
||||
|
||||
if (ipv4_range_parse(address, &address_start, &address_end) ) {
|
||||
torrent::PeerList::ipv4_filter()->insert(address_start, address_end, value);
|
||||
|
||||
char start_str[INET_ADDRSTRLEN];
|
||||
char end_str[INET_ADDRSTRLEN];
|
||||
uint32_t net_start = htonl(address_start);
|
||||
uint32_t net_end = htonl(address_end);
|
||||
|
||||
inet_ntop(AF_INET, &net_start, start_str, INET_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET, &net_end, end_str, INET_ADDRSTRLEN);
|
||||
|
||||
lt_log_print(torrent::LOG_CONNECTION_DEBUG, "Adding ip filter for %s-%s.", start_str, end_str);
|
||||
}
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_ipv4_filter_size_data() {
|
||||
return torrent::PeerList::ipv4_filter()->sizeof_data();
|
||||
@@ -175,14 +297,16 @@ apply_ipv4_filter_size_data() {
|
||||
|
||||
torrent::Object
|
||||
apply_ipv4_filter_get(const std::string& args) {
|
||||
// Move to a helper function, add support for addresses.
|
||||
uint32_t ip_values[4];
|
||||
uint32_t address_start;
|
||||
uint32_t address_end;
|
||||
|
||||
if (sscanf(args.c_str(), "%u.%u.%u.%u",
|
||||
ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3) != 4)
|
||||
if (!ipv4_range_parse(args.c_str(), &address_start, &address_end))
|
||||
throw torrent::input_error("Invalid address format.");
|
||||
|
||||
return torrent::PeerList::ipv4_filter()->at((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3]);
|
||||
if(!torrent::PeerList::ipv4_filter()->defined(address_start, address_end))
|
||||
throw torrent::input_error("No value defined for specified IP(s).");
|
||||
|
||||
return torrent::PeerList::ipv4_filter()->at(address_start, address_end);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -240,41 +364,34 @@ apply_ipv4_filter_load(const torrent::Object::list_type& args) {
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
static void
|
||||
append_table(torrent::ipv4_table::base_type* extent, torrent::Object::list_type& result) {
|
||||
torrent::ipv4_table::table_type::iterator first = extent->table.begin();
|
||||
torrent::ipv4_table::table_type::iterator last = extent->table.end();
|
||||
|
||||
while (first != last) {
|
||||
if (first->first != NULL) {
|
||||
// Do something more here?...
|
||||
append_table(first->first, result);
|
||||
|
||||
} else if (first->second != 0) {
|
||||
uint32_t position = extent->partition_pos(first);
|
||||
|
||||
char buffer[256];
|
||||
snprintf(buffer, 256, "%u.%u.%u.%u/%u %s",
|
||||
(position >> 24) & 0xff,
|
||||
(position >> 16) & 0xff,
|
||||
(position >> 8) & 0xff,
|
||||
(position >> 0) & 0xff,
|
||||
extent->mask_bits,
|
||||
torrent::option_as_string(torrent::OPTION_IP_FILTER, first->second));
|
||||
|
||||
result.push_back((std::string)buffer);
|
||||
}
|
||||
|
||||
first++;
|
||||
}
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_ipv4_filter_dump() {
|
||||
torrent::Object raw_result = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = raw_result.as_list();
|
||||
|
||||
append_table(torrent::PeerList::ipv4_filter()->data(), result);
|
||||
torrent::ipv4_table::range_map_type range_map = torrent::PeerList::ipv4_filter()->range_map;
|
||||
torrent::ipv4_table::range_map_type::iterator iter = range_map.begin();
|
||||
|
||||
while(iter != range_map.end()) {
|
||||
char buffer[64];
|
||||
uint32_t address_start = iter->first;
|
||||
uint32_t address_end = (iter->second).first;
|
||||
int value = (iter->second).second;
|
||||
|
||||
char start_str[INET_ADDRSTRLEN];
|
||||
char end_str[INET_ADDRSTRLEN];
|
||||
uint32_t net_start = htonl(address_start);
|
||||
uint32_t net_end = htonl(address_end);
|
||||
|
||||
inet_ntop(AF_INET, &net_start, start_str, INET_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET, &net_end, end_str, INET_ADDRSTRLEN);
|
||||
|
||||
snprintf(buffer, 64, "%s-%s %s", start_str, end_str, torrent::option_as_string(torrent::OPTION_IP_FILTER, value));
|
||||
|
||||
result.push_back((std::string)buffer);
|
||||
|
||||
iter++;
|
||||
}
|
||||
|
||||
return raw_result;
|
||||
}
|
||||
|
||||
@@ -167,8 +167,7 @@ apply_scgi(const std::string& arg, int type) {
|
||||
sa.sa_inet()->clear();
|
||||
saPtr = &sa;
|
||||
|
||||
lt_log_print(torrent::LOG_RPC_EVENTS,
|
||||
"The SCGI socket has not been bound to any address and likely poses a security risk.");
|
||||
lt_log_print(torrent::LOG_RPC_EVENTS, "SCGI socket is open to any address and is a security risk");
|
||||
|
||||
} else if (std::sscanf(arg.c_str(), "%1023[^:]:%i%c", address, &port, &dummy) == 2 ||
|
||||
std::sscanf(arg.c_str(), "[%64[^]]]:%i%c", address, &port, &dummy) == 2) { // [xx::xx]:port format
|
||||
@@ -177,8 +176,7 @@ apply_scgi(const std::string& arg, int type) {
|
||||
|
||||
saPtr = ai->address();
|
||||
|
||||
lt_log_print(torrent::LOG_RPC_EVENTS,
|
||||
"The SCGI socket is bound to a specific network device yet may still pose a security risk, consider using 'scgi_local'.");
|
||||
lt_log_print(torrent::LOG_RPC_EVENTS, "SCGI socket is bound to an address and might be a security risk");
|
||||
|
||||
} else {
|
||||
throw torrent::input_error("Could not parse address.");
|
||||
|
||||
@@ -96,12 +96,15 @@ torrent::Object
|
||||
apply_throttle(const torrent::Object::list_type& args, bool up) {
|
||||
torrent::Object::list_const_iterator argItr = args.begin();
|
||||
|
||||
if (argItr == args.end())
|
||||
throw torrent::input_error("Missing throttle name.");
|
||||
|
||||
const std::string& name = argItr->as_string();
|
||||
if (name.empty() || name == "NULL")
|
||||
throw torrent::input_error("Invalid throttle name.");
|
||||
throw torrent::input_error("Invalid throttle name '" + name + "'.");
|
||||
|
||||
if ((++argItr)->as_string().empty())
|
||||
return torrent::Object();
|
||||
if (++argItr == args.end() || argItr->as_string().empty())
|
||||
throw torrent::input_error("Missing throttle rate for '" + name + "'.");
|
||||
|
||||
int64_t rate;
|
||||
rpc::parse_whole_value_nothrow(argItr->as_string().c_str(), &rate);
|
||||
|
||||
@@ -41,8 +41,10 @@
|
||||
#include <ctime>
|
||||
#include <regex>
|
||||
|
||||
#include <rak/algorithm.h>
|
||||
#include <rak/functional.h>
|
||||
#include <rak/functional_fun.h>
|
||||
#include <torrent/utils/log.h>
|
||||
|
||||
#include "core/manager.h"
|
||||
#include "core/view_manager.h"
|
||||
@@ -149,6 +151,41 @@ apply_cat(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
return result;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_value(rpc::target_type target, const torrent::Object::list_type& args) {
|
||||
if (args.size() < 1)
|
||||
throw torrent::input_error("'value' takes at least a number argument!");
|
||||
if (args.size() > 2)
|
||||
throw torrent::input_error("'value' takes at most two arguments!");
|
||||
|
||||
torrent::Object::value_type val = 0;
|
||||
if (args.front().is_value()) {
|
||||
val = args.front().as_value();
|
||||
} else {
|
||||
int base = args.size() > 1 ? args.back().is_value() ?
|
||||
args.back().as_value() : strtol(args.back().as_string().c_str(), NULL, 10) : 10;
|
||||
char* endptr = 0;
|
||||
|
||||
val = strtoll(args.front().as_string().c_str(), &endptr, base);
|
||||
while (*endptr == ' ' || *endptr == '\n') ++endptr;
|
||||
if (*endptr)
|
||||
throw torrent::input_error("Junk at end of number: " + args.front().as_string());
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_try(rpc::target_type target, const torrent::Object& args) {
|
||||
try {
|
||||
return rpc::call_object(args, target);
|
||||
} catch (torrent::input_error& e) {
|
||||
lt_log_print(torrent::LOG_RPC_EVENTS, "try command caught input_error: %s", e.what());
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
// Move these boolean operators to a new file.
|
||||
|
||||
inline bool
|
||||
@@ -568,6 +605,128 @@ apply_elapsed_greater(const torrent::Object::list_type& args) {
|
||||
return (int64_t)(start_time != 0 && rak::timer::current_seconds() - start_time > rpc::convert_to_value(args.back()));
|
||||
}
|
||||
|
||||
inline std::vector<int64_t>
|
||||
as_vector(const torrent::Object::list_type& args) {
|
||||
if (args.size() == 0)
|
||||
throw torrent::input_error("Wrong argument count in as_vector.");
|
||||
|
||||
std::vector<int64_t> result;
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
|
||||
|
||||
if (itr->is_value()) {
|
||||
result.push_back(itr->as_value());
|
||||
} else if (itr->is_string()) {
|
||||
result.push_back(rpc::convert_to_value(itr->as_string()));
|
||||
} else if (itr->is_list()) {
|
||||
std::vector<int64_t> subResult = as_vector(itr->as_list());
|
||||
result.insert(result.end(), subResult.begin(), subResult.end());
|
||||
} else {
|
||||
throw torrent::input_error("Wrong type supplied to as_vector.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t
|
||||
apply_math_basic(const char* name, const std::function<int64_t(int64_t,int64_t)> op, const torrent::Object::list_type& args) {
|
||||
int64_t val = 0, rhs = 0;
|
||||
bool divides = !strcmp(name, "math.div") || !strcmp(name, "math.mod");
|
||||
|
||||
if (args.size() == 0)
|
||||
throw torrent::input_error(std::string(name) + ": No arguments provided!");
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
|
||||
|
||||
if (itr->is_value()) {
|
||||
rhs = itr->as_value();
|
||||
} else if (itr->is_string()) {
|
||||
rhs = rpc::convert_to_value(itr->as_string());
|
||||
} else if (itr->is_list()) {
|
||||
rhs = apply_math_basic(name, op, itr->as_list());
|
||||
} else {
|
||||
throw torrent::input_error(std::string(name) + ": Wrong argument type");
|
||||
}
|
||||
|
||||
if (divides && !rhs && itr != args.begin())
|
||||
throw torrent::input_error(std::string(name) + ": Division by zero!");
|
||||
|
||||
val = itr == args.begin() ? rhs : op(val, rhs);
|
||||
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int64_t
|
||||
apply_arith_basic(const std::function<int64_t(int64_t,int64_t)> op, const torrent::Object::list_type& args) {
|
||||
if (args.size() == 0)
|
||||
throw torrent::input_error("Wrong argument count in apply_arith_basic.");
|
||||
|
||||
int64_t val = 0;
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
|
||||
|
||||
if (itr->is_value()) {
|
||||
val = itr == args.begin() ? itr->as_value() : (op(val, itr->as_value()) ? val : itr->as_value());
|
||||
} else if (itr->is_string()) {
|
||||
int64_t cval = rpc::convert_to_value(itr->as_string());
|
||||
val = itr == args.begin() ? cval : (op(val, cval) ? val : cval);
|
||||
} else if (itr->is_list()) {
|
||||
int64_t fval = apply_arith_basic(op, itr->as_list());
|
||||
val = itr == args.begin() ? fval : (op(val, fval) ? val : fval);
|
||||
} else {
|
||||
throw torrent::input_error("Wrong type supplied to apply_arith_basic.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int64_t
|
||||
apply_arith_count(const torrent::Object::list_type& args) {
|
||||
if (args.size() == 0)
|
||||
throw torrent::input_error("Wrong argument count in apply_arith_count.");
|
||||
|
||||
int64_t val = 0;
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
|
||||
|
||||
switch (itr->type()) {
|
||||
case torrent::Object::TYPE_VALUE:
|
||||
case torrent::Object::TYPE_STRING:
|
||||
val++;
|
||||
break;
|
||||
case torrent::Object::TYPE_LIST:
|
||||
val += apply_arith_count(itr->as_list());
|
||||
break;
|
||||
default:
|
||||
throw torrent::input_error("Wrong type supplied to apply_arith_count.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int64_t
|
||||
apply_arith_other(const char* op, const torrent::Object::list_type& args) {
|
||||
if (args.size() == 0)
|
||||
throw torrent::input_error("Wrong argument count in apply_arith_other.");
|
||||
|
||||
if (strcmp(op, "average") == 0) {
|
||||
return (int64_t)(apply_math_basic(op, std::plus<int64_t>(), args) / apply_arith_count(args));
|
||||
} else if (strcmp(op, "median") == 0) {
|
||||
std::vector<int64_t> result = as_vector(args);
|
||||
return (int64_t)rak::median(result.begin(), result.end());
|
||||
} else {
|
||||
throw torrent::input_error("Wrong operation supplied to apply_arith_other.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_ui() {
|
||||
CMD2_VAR_STRING("keys.layout", "qwerty");
|
||||
@@ -608,12 +767,18 @@ initialize_command_ui() {
|
||||
CMD2_VAR_STRING("view.temp_filter.excluded", "default,started,stopped");
|
||||
CMD2_VAR_BOOL ("view.temp_filter.log", 0);
|
||||
|
||||
CMD2_VAR_VALUE ("ui.throttle.global.step.small", 5);
|
||||
CMD2_VAR_VALUE ("ui.throttle.global.step.medium", 50);
|
||||
CMD2_VAR_VALUE ("ui.throttle.global.step.large", 500);
|
||||
|
||||
// TODO: Add 'option_string' for rtorrent-specific options.
|
||||
CMD2_VAR_STRING("ui.torrent_list.layout", "full");
|
||||
|
||||
// Move.
|
||||
CMD2_ANY("print", &apply_print);
|
||||
CMD2_ANY("cat", &apply_cat);
|
||||
CMD2_ANY_LIST("value", &apply_value);
|
||||
CMD2_ANY("try", &apply_try);
|
||||
CMD2_ANY("if", std::bind(&apply_if, std::placeholders::_1, std::placeholders::_2, 0));
|
||||
CMD2_ANY("not", &apply_not);
|
||||
CMD2_ANY("false", &apply_false);
|
||||
@@ -639,6 +804,17 @@ initialize_command_ui() {
|
||||
CMD2_ANY_VALUE("convert.xb", std::bind(&apply_to_xb, std::placeholders::_2));
|
||||
CMD2_ANY_VALUE("convert.throttle", std::bind(&apply_to_throttle, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_LIST("math.add", std::bind(&apply_math_basic, "math.add", std::plus<int64_t>(), std::placeholders::_2));
|
||||
CMD2_ANY_LIST("math.sub", std::bind(&apply_math_basic, "math.sub", std::minus<int64_t>(), std::placeholders::_2));
|
||||
CMD2_ANY_LIST("math.mul", std::bind(&apply_math_basic, "math.mul", std::multiplies<int64_t>(), std::placeholders::_2));
|
||||
CMD2_ANY_LIST("math.div", std::bind(&apply_math_basic, "math.div", std::divides<int64_t>(), std::placeholders::_2));
|
||||
CMD2_ANY_LIST("math.mod", std::bind(&apply_math_basic, "math.mod", std::modulus<int64_t>(), std::placeholders::_2));
|
||||
CMD2_ANY_LIST("math.min", std::bind(&apply_arith_basic, std::less<int64_t>(), std::placeholders::_2));
|
||||
CMD2_ANY_LIST("math.max", std::bind(&apply_arith_basic, std::greater<int64_t>(), std::placeholders::_2));
|
||||
CMD2_ANY_LIST("math.cnt", std::bind(&apply_arith_count, std::placeholders::_2));
|
||||
CMD2_ANY_LIST("math.avg", std::bind(&apply_arith_other, "average", std::placeholders::_2));
|
||||
CMD2_ANY_LIST("math.med", std::bind(&apply_arith_other, "median", std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_LIST ("elapsed.less", std::bind(&apply_elapsed_less, std::placeholders::_2));
|
||||
CMD2_ANY_LIST ("elapsed.greater", std::bind(&apply_elapsed_greater, std::placeholders::_2));
|
||||
}
|
||||
|
||||
+1
-1
@@ -416,7 +416,7 @@ path_expand(std::vector<std::string>* paths, const std::string& pattern) {
|
||||
itr->update((r.pattern()[0] != '.') ? utils::Directory::update_hide_dot : 0);
|
||||
itr->erase(std::remove_if(itr->begin(), itr->end(), rak::on(rak::mem_ref(&utils::directory_entry::d_name), std::not1(r))), itr->end());
|
||||
|
||||
std::transform(itr->begin(), itr->end(), std::back_inserter(nextCache), rak::bind1st(std::ptr_fun(&path_expand_transform), itr->path() + "/"));
|
||||
std::transform(itr->begin(), itr->end(), std::back_inserter(nextCache), rak::bind1st(std::ptr_fun(&path_expand_transform), itr->path() + (itr->path() == "/" ? "" : "/")));
|
||||
}
|
||||
|
||||
currentCache.clear();
|
||||
|
||||
@@ -86,6 +86,15 @@ WindowDownloadList::redraw() {
|
||||
if (m_view->empty_visible() || m_canvas->width() < 5 || m_canvas->height() < 2)
|
||||
return;
|
||||
|
||||
// show "X of Y"
|
||||
if (m_canvas->width() > 16 + 8 + m_view->name().length()) {
|
||||
int item_idx = m_view->focus() - m_view->begin_visible();
|
||||
if (item_idx == int(m_view->size()))
|
||||
m_canvas->print(m_canvas->width() - 16, 0, "[ none of %-5d]", m_view->size());
|
||||
else
|
||||
m_canvas->print(m_canvas->width() - 16, 0, "[%5d of %-5d]", item_idx + 1, m_view->size());
|
||||
}
|
||||
|
||||
int layout_height;
|
||||
const std::string layout_name = rpc::call_command_string("ui.torrent_list.layout");
|
||||
|
||||
|
||||
@@ -38,8 +38,7 @@
|
||||
|
||||
#include "input_event.h"
|
||||
|
||||
//ncurses.h must be included last since sys/mman.h on Solaris munges ERR.
|
||||
#include <ncurses.h>
|
||||
#include "display/attributes.h"
|
||||
|
||||
namespace input {
|
||||
|
||||
|
||||
@@ -197,6 +197,7 @@ main(int argc, char** argv) {
|
||||
|
||||
SignalHandler::set_ignore(SIGPIPE);
|
||||
SignalHandler::set_handler(SIGINT, std::bind(&Control::receive_normal_shutdown, control));
|
||||
SignalHandler::set_handler(SIGHUP, std::bind(&Control::receive_normal_shutdown, control));
|
||||
SignalHandler::set_handler(SIGTERM, std::bind(&Control::receive_quick_shutdown, control));
|
||||
SignalHandler::set_handler(SIGWINCH, std::bind(&display::Manager::force_redraw, control->display()));
|
||||
SignalHandler::set_handler(SIGSEGV, std::bind(&do_panic, SIGSEGV));
|
||||
@@ -248,6 +249,9 @@ main(int argc, char** argv) {
|
||||
|
||||
rpc::parse_command_multiple
|
||||
(rpc::make_target(),
|
||||
"method.insert = event.view.hide,multi|rlookup|static\n"
|
||||
"method.insert = event.view.show,multi|rlookup|static\n"
|
||||
|
||||
"method.insert = event.download.inserted,multi|rlookup|static\n"
|
||||
"method.insert = event.download.inserted_new,multi|rlookup|static\n"
|
||||
"method.insert = event.download.inserted_session,multi|rlookup|static\n"
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
namespace rpc {
|
||||
|
||||
typedef torrent::extents<uint32_t, int, 32, 256, 8> ipv4_table;
|
||||
typedef torrent::extents<uint32_t, int> ipv4_table;
|
||||
|
||||
struct ip_table_node {
|
||||
std::string name;
|
||||
|
||||
@@ -113,14 +113,15 @@ ThreadWorker::change_xmlrpc_log() {
|
||||
if (scgi() == NULL)
|
||||
return;
|
||||
|
||||
if (scgi()->log_fd() != -1)
|
||||
if (scgi()->log_fd() != -1) {
|
||||
::close(scgi()->log_fd());
|
||||
|
||||
if (m_xmlrpcLog.empty()) {
|
||||
scgi()->set_log_fd(-1);
|
||||
control->core()->push_log("Closed XMLRPC log.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_xmlrpcLog.empty())
|
||||
return;
|
||||
|
||||
scgi()->set_log_fd(open(rak::path_expand(m_xmlrpcLog).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644));
|
||||
|
||||
if (scgi()->log_fd() == -1) {
|
||||
|
||||
+13
-12
@@ -54,6 +54,7 @@
|
||||
#include "display/window_download_statusbar.h"
|
||||
|
||||
#include "display/text_element_string.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
#include "control.h"
|
||||
#include "download.h"
|
||||
@@ -395,20 +396,20 @@ Download::bind_keys() {
|
||||
|
||||
const char* keys = control->ui()->get_throttle_keys();
|
||||
|
||||
m_bindings[keys[ 0]] = std::bind(&Download::adjust_up_throttle, this, 1);
|
||||
m_bindings[keys[ 1]] = std::bind(&Download::adjust_up_throttle, this, -1);
|
||||
m_bindings[keys[ 2]] = std::bind(&Download::adjust_down_throttle, this, 1);
|
||||
m_bindings[keys[ 3]] = std::bind(&Download::adjust_down_throttle, this, -1);
|
||||
m_bindings[keys[ 0]] = std::bind(&Download::adjust_up_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.small"));
|
||||
m_bindings[keys[ 1]] = std::bind(&Download::adjust_up_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.small"));
|
||||
m_bindings[keys[ 2]] = std::bind(&Download::adjust_down_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.small"));
|
||||
m_bindings[keys[ 3]] = std::bind(&Download::adjust_down_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.small"));
|
||||
|
||||
m_bindings[keys[ 4]] = std::bind(&Download::adjust_up_throttle, this, 5);
|
||||
m_bindings[keys[ 5]] = std::bind(&Download::adjust_up_throttle, this, -5);
|
||||
m_bindings[keys[ 6]] = std::bind(&Download::adjust_down_throttle, this, 5);
|
||||
m_bindings[keys[ 7]] = std::bind(&Download::adjust_down_throttle, this, -5);
|
||||
m_bindings[keys[ 4]] = std::bind(&Download::adjust_up_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.medium"));
|
||||
m_bindings[keys[ 5]] = std::bind(&Download::adjust_up_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.medium"));
|
||||
m_bindings[keys[ 6]] = std::bind(&Download::adjust_down_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.medium"));
|
||||
m_bindings[keys[ 7]] = std::bind(&Download::adjust_down_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.medium"));
|
||||
|
||||
m_bindings[keys[ 8]] = std::bind(&Download::adjust_up_throttle, this, 50);
|
||||
m_bindings[keys[ 9]] = std::bind(&Download::adjust_up_throttle, this, -50);
|
||||
m_bindings[keys[10]] = std::bind(&Download::adjust_down_throttle, this, 50);
|
||||
m_bindings[keys[11]] = std::bind(&Download::adjust_down_throttle, this, -50);
|
||||
m_bindings[keys[ 8]] = std::bind(&Download::adjust_up_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.large"));
|
||||
m_bindings[keys[ 9]] = std::bind(&Download::adjust_up_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.large"));
|
||||
m_bindings[keys[10]] = std::bind(&Download::adjust_down_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.large"));
|
||||
m_bindings[keys[11]] = std::bind(&Download::adjust_down_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.large"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -89,7 +89,8 @@ public:
|
||||
void adjust_up_throttle(int throttle);
|
||||
void adjust_down_throttle(int throttle);
|
||||
|
||||
display::Window* window() { return NULL; }
|
||||
display::Window* window() { return NULL; }
|
||||
core::Download* download() { return m_download; };
|
||||
|
||||
private:
|
||||
Download(const Download&);
|
||||
|
||||
@@ -126,16 +126,13 @@ DownloadList::set_current_view(const std::string& name) {
|
||||
return dynamic_cast<ElementDownloadList*>(m_uiArray[DISPLAY_DOWNLOAD_LIST])->receive_change_view(name);
|
||||
}
|
||||
|
||||
// This should also do focus_next() or something.
|
||||
void
|
||||
DownloadList::unfocus_download(core::Download* d) {
|
||||
if (current_view()->focus() >= current_view()->end_visible() || *current_view()->focus() != d)
|
||||
return;
|
||||
|
||||
if (m_state == DISPLAY_DOWNLOAD)
|
||||
if (m_state == DISPLAY_DOWNLOAD && d == static_cast<Download*>(m_uiArray[DISPLAY_DOWNLOAD])->download())
|
||||
activate_display(DISPLAY_DOWNLOAD_LIST);
|
||||
|
||||
current_view()->next_focus();
|
||||
if (*current_view()->focus() == d && current_view()->focus() < current_view()->end_visible())
|
||||
current_view()->next_focus();
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -220,7 +220,14 @@ ElementDownloadList::receive_change_view(const std::string& name) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string old_name = view() ? view()->name() : "";
|
||||
if (!old_name.empty())
|
||||
rpc::commands.call_catch("event.view.hide", rpc::make_target(), name,
|
||||
"View hide event action failed: ");
|
||||
set_view(*itr);
|
||||
if (!old_name.empty())
|
||||
rpc::commands.call_catch("event.view.show", rpc::make_target(), old_name,
|
||||
"View show event action failed: ");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+12
-12
@@ -140,20 +140,20 @@ Root::setup_keys() {
|
||||
|
||||
const char* keys = get_throttle_keys();
|
||||
|
||||
m_bindings[keys[ 0]] = std::bind(&Root::adjust_up_throttle, this, 1);
|
||||
m_bindings[keys[ 1]] = std::bind(&Root::adjust_up_throttle, this, -1);
|
||||
m_bindings[keys[ 2]] = std::bind(&Root::adjust_down_throttle, this, 1);
|
||||
m_bindings[keys[ 3]] = std::bind(&Root::adjust_down_throttle, this, -1);
|
||||
m_bindings[keys[ 0]] = std::bind(&Root::adjust_up_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.small"));
|
||||
m_bindings[keys[ 1]] = std::bind(&Root::adjust_up_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.small"));
|
||||
m_bindings[keys[ 2]] = std::bind(&Root::adjust_down_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.small"));
|
||||
m_bindings[keys[ 3]] = std::bind(&Root::adjust_down_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.small"));
|
||||
|
||||
m_bindings[keys[ 4]] = std::bind(&Root::adjust_up_throttle, this, 5);
|
||||
m_bindings[keys[ 5]] = std::bind(&Root::adjust_up_throttle, this, -5);
|
||||
m_bindings[keys[ 6]] = std::bind(&Root::adjust_down_throttle, this, 5);
|
||||
m_bindings[keys[ 7]] = std::bind(&Root::adjust_down_throttle, this, -5);
|
||||
m_bindings[keys[ 4]] = std::bind(&Root::adjust_up_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.medium"));
|
||||
m_bindings[keys[ 5]] = std::bind(&Root::adjust_up_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.medium"));
|
||||
m_bindings[keys[ 6]] = std::bind(&Root::adjust_down_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.medium"));
|
||||
m_bindings[keys[ 7]] = std::bind(&Root::adjust_down_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.medium"));
|
||||
|
||||
m_bindings[keys[ 8]] = std::bind(&Root::adjust_up_throttle, this, 50);
|
||||
m_bindings[keys[ 9]] = std::bind(&Root::adjust_up_throttle, this, -50);
|
||||
m_bindings[keys[10]] = std::bind(&Root::adjust_down_throttle, this, 50);
|
||||
m_bindings[keys[11]] = std::bind(&Root::adjust_down_throttle, this, -50);
|
||||
m_bindings[keys[ 8]] = std::bind(&Root::adjust_up_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.large"));
|
||||
m_bindings[keys[ 9]] = std::bind(&Root::adjust_up_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.large"));
|
||||
m_bindings[keys[10]] = std::bind(&Root::adjust_down_throttle, this, (int) rpc::call_command_value("ui.throttle.global.step.large"));
|
||||
m_bindings[keys[11]] = std::bind(&Root::adjust_down_throttle, this, (int) -rpc::call_command_value("ui.throttle.global.step.large"));
|
||||
|
||||
m_bindings['\x0C'] = std::bind(&display::Manager::force_redraw, m_control->display()); // ^L
|
||||
m_bindings['\x11'] = std::bind(&Control::receive_normal_shutdown, m_control); // ^Q
|
||||
|
||||
Reference in New Issue
Block a user