fix: sonarcloud (#2327)
This commit is contained in:
parent
37a8046ed5
commit
7ca0b4cc25
72
cli/cli.cc
72
cli/cli.cc
|
@ -20,6 +20,7 @@
|
|||
* DEALINGS IN THE SOFTWARE.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <array>
|
||||
#include <stdio.h> /* fprintf () */
|
||||
#include <stdlib.h> /* atoi () */
|
||||
#include <string.h> /* memcmp () */
|
||||
|
@ -63,8 +64,13 @@
|
|||
***/
|
||||
|
||||
#define LINEWIDTH 80
|
||||
#define MY_CONFIG_NAME "transmission"
|
||||
#define MY_READABLE_NAME "transmission-cli"
|
||||
|
||||
static char constexpr MyConfigName[] = "transmission";
|
||||
static char constexpr MyReadableName[] = "transmission-cli";
|
||||
static char constexpr Usage
|
||||
[] = "A fast and easy BitTorrent client\n"
|
||||
"\n"
|
||||
"Usage: transmission-cli [options] <file|url|magnet>";
|
||||
|
||||
static bool showVersion = false;
|
||||
static bool verify = false;
|
||||
|
@ -73,38 +79,28 @@ static sig_atomic_t manualUpdate = false;
|
|||
|
||||
static char const* torrentPath = nullptr;
|
||||
|
||||
static struct tr_option const options[] = {
|
||||
{ 'b', "blocklist", "Enable peer blocklists", "b", false, nullptr },
|
||||
{ 'B', "no-blocklist", "Disable peer blocklists", "B", false, nullptr },
|
||||
{ 'd', "downlimit", "Set max download speed in " SPEED_K_STR, "d", true, "<speed>" },
|
||||
{ 'D', "no-downlimit", "Don't limit the download speed", "D", false, nullptr },
|
||||
{ 910, "encryption-required", "Encrypt all peer connections", "er", false, nullptr },
|
||||
{ 911, "encryption-preferred", "Prefer encrypted peer connections", "ep", false, nullptr },
|
||||
{ 912, "encryption-tolerated", "Prefer unencrypted peer connections", "et", false, nullptr },
|
||||
{ 'f', "finish", "Run a script when the torrent finishes", "f", true, "<script>" },
|
||||
{ 'g', "config-dir", "Where to find configuration files", "g", true, "<path>" },
|
||||
{ 'm', "portmap", "Enable portmapping via NAT-PMP or UPnP", "m", false, nullptr },
|
||||
{ 'M', "no-portmap", "Disable portmapping", "M", false, nullptr },
|
||||
{ 'p', "port", "Port for incoming peers (Default: " TR_DEFAULT_PEER_PORT_STR ")", "p", true, "<port>" },
|
||||
{ 't', "tos", "Peer socket TOS (0 to 255, default=" TR_DEFAULT_PEER_SOCKET_TOS_STR ")", "t", true, "<tos>" },
|
||||
{ 'u', "uplimit", "Set max upload speed in " SPEED_K_STR, "u", true, "<speed>" },
|
||||
{ 'U', "no-uplimit", "Don't limit the upload speed", "U", false, nullptr },
|
||||
{ 'v', "verify", "Verify the specified torrent", "v", false, nullptr },
|
||||
{ 'V', "version", "Show version number and exit", "V", false, nullptr },
|
||||
{ 'w', "download-dir", "Where to save downloaded data", "w", true, "<path>" },
|
||||
{ 0, nullptr, nullptr, nullptr, false, nullptr }
|
||||
static auto constexpr Options = std::array<tr_option, 19>{
|
||||
{ { 'b', "blocklist", "Enable peer blocklists", "b", false, nullptr },
|
||||
{ 'B', "no-blocklist", "Disable peer blocklists", "B", false, nullptr },
|
||||
{ 'd', "downlimit", "Set max download speed in " SPEED_K_STR, "d", true, "<speed>" },
|
||||
{ 'D', "no-downlimit", "Don't limit the download speed", "D", false, nullptr },
|
||||
{ 910, "encryption-required", "Encrypt all peer connections", "er", false, nullptr },
|
||||
{ 911, "encryption-preferred", "Prefer encrypted peer connections", "ep", false, nullptr },
|
||||
{ 912, "encryption-tolerated", "Prefer unencrypted peer connections", "et", false, nullptr },
|
||||
{ 'f', "finish", "Run a script when the torrent finishes", "f", true, "<script>" },
|
||||
{ 'g', "config-dir", "Where to find configuration files", "g", true, "<path>" },
|
||||
{ 'm', "portmap", "Enable portmapping via NAT-PMP or UPnP", "m", false, nullptr },
|
||||
{ 'M', "no-portmap", "Disable portmapping", "M", false, nullptr },
|
||||
{ 'p', "port", "Port for incoming peers (Default: " TR_DEFAULT_PEER_PORT_STR ")", "p", true, "<port>" },
|
||||
{ 't', "tos", "Peer socket TOS (0 to 255, default=" TR_DEFAULT_PEER_SOCKET_TOS_STR ")", "t", true, "<tos>" },
|
||||
{ 'u', "uplimit", "Set max upload speed in " SPEED_K_STR, "u", true, "<speed>" },
|
||||
{ 'U', "no-uplimit", "Don't limit the upload speed", "U", false, nullptr },
|
||||
{ 'v', "verify", "Verify the specified torrent", "v", false, nullptr },
|
||||
{ 'V', "version", "Show version number and exit", "V", false, nullptr },
|
||||
{ 'w', "download-dir", "Where to save downloaded data", "w", true, "<path>" },
|
||||
{ 0, nullptr, nullptr, nullptr, false, nullptr } }
|
||||
};
|
||||
|
||||
static char const* getUsage(void)
|
||||
{
|
||||
// clang-format off
|
||||
return
|
||||
"A fast and easy BitTorrent client\n"
|
||||
"\n"
|
||||
"Usage: " MY_READABLE_NAME " [options] <file|url|magnet>";
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
static int parseCommandLine(tr_variant*, int argc, char const** argv);
|
||||
|
||||
static void sigHandler(int signal);
|
||||
|
@ -217,7 +213,7 @@ static char const* getConfigDir(int argc, char const** argv)
|
|||
char const* my_optarg;
|
||||
int const ind = tr_optind;
|
||||
|
||||
while ((c = tr_getopt(getUsage(), argc, argv, options, &my_optarg)) != TR_OPT_DONE)
|
||||
while ((c = tr_getopt(Usage, argc, argv, std::data(Options), &my_optarg)) != TR_OPT_DONE)
|
||||
{
|
||||
if (c == 'g')
|
||||
{
|
||||
|
@ -230,7 +226,7 @@ static char const* getConfigDir(int argc, char const** argv)
|
|||
|
||||
if (configDir == nullptr)
|
||||
{
|
||||
configDir = tr_getDefaultConfigDir(MY_CONFIG_NAME);
|
||||
configDir = tr_getDefaultConfigDir(MyConfigName);
|
||||
}
|
||||
|
||||
return configDir;
|
||||
|
@ -248,19 +244,19 @@ int tr_main(int argc, char* argv[])
|
|||
tr_formatter_size_init(DISK_K, DISK_K_STR, DISK_M_STR, DISK_G_STR, DISK_T_STR);
|
||||
tr_formatter_speed_init(SPEED_K, SPEED_K_STR, SPEED_M_STR, SPEED_G_STR, SPEED_T_STR);
|
||||
|
||||
printf("%s %s\n", MY_READABLE_NAME, LONG_VERSION_STRING);
|
||||
printf("%s %s\n", MyReadableName, LONG_VERSION_STRING);
|
||||
|
||||
/* user needs to pass in at least one argument */
|
||||
if (argc < 2)
|
||||
{
|
||||
tr_getopt_usage(MY_READABLE_NAME, getUsage(), options);
|
||||
tr_getopt_usage(MyReadableName, Usage, std::data(Options));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* load the defaults from config file + libtransmission defaults */
|
||||
tr_variantInitDict(&settings, 0);
|
||||
configDir = getConfigDir(argc, (char const**)argv);
|
||||
tr_sessionLoadSettings(&settings, configDir, MY_CONFIG_NAME);
|
||||
tr_sessionLoadSettings(&settings, configDir, MyConfigName);
|
||||
|
||||
/* the command line overrides defaults */
|
||||
if (parseCommandLine(&settings, argc, (char const**)argv) != 0)
|
||||
|
@ -422,7 +418,7 @@ static int parseCommandLine(tr_variant* d, int argc, char const** argv)
|
|||
int c;
|
||||
char const* my_optarg;
|
||||
|
||||
while ((c = tr_getopt(getUsage(), argc, argv, options, &my_optarg)) != TR_OPT_DONE)
|
||||
while ((c = tr_getopt(Usage, argc, argv, std::data(Options), &my_optarg)) != TR_OPT_DONE)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
|
|
178
daemon/daemon.cc
178
daemon/daemon.cc
|
@ -6,6 +6,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <array>
|
||||
#include <errno.h>
|
||||
#include <stdio.h> /* printf */
|
||||
#include <stdlib.h> /* atoi */
|
||||
|
@ -54,6 +55,16 @@ static void sd_notifyf(int /*status*/, char const* /*fmt*/, ...)
|
|||
|
||||
#include "daemon.h"
|
||||
|
||||
static char constexpr MyName[] = "transmission-daemon";
|
||||
static char constexpr Usage[] = "Transmission " LONG_VERSION_STRING
|
||||
" https://transmissionbt.com/\n"
|
||||
"A fast and easy BitTorrent client\n"
|
||||
"\n"
|
||||
"transmission-daemon is a headless Transmission session that can be\n"
|
||||
"controlled via transmission-qt, transmission-remote, or its web interface.\n"
|
||||
"\n"
|
||||
"Usage: transmission-daemon [options]";
|
||||
|
||||
#define MY_NAME "transmission-daemon"
|
||||
|
||||
#define MEM_K 1024
|
||||
|
@ -88,85 +99,70 @@ static struct event_base* ev_base = nullptr;
|
|||
**** Config File
|
||||
***/
|
||||
|
||||
static char const* getUsage(void)
|
||||
{
|
||||
// clang-format off
|
||||
return
|
||||
"Transmission " LONG_VERSION_STRING " https://transmissionbt.com/\n"
|
||||
"A fast and easy BitTorrent client\n"
|
||||
"\n"
|
||||
MY_NAME " is a headless Transmission session\n"
|
||||
"that can be controlled via transmission-remote\n"
|
||||
"or the web interface.\n"
|
||||
"\n"
|
||||
"Usage: " MY_NAME " [options]";
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
static struct tr_option const options[] = {
|
||||
{ 'a', "allowed", "Allowed IP addresses. (Default: " TR_DEFAULT_RPC_WHITELIST ")", "a", true, "<list>" },
|
||||
{ 'b', "blocklist", "Enable peer blocklists", "b", false, nullptr },
|
||||
{ 'B', "no-blocklist", "Disable peer blocklists", "B", false, nullptr },
|
||||
{ 'c', "watch-dir", "Where to watch for new .torrent files", "c", true, "<directory>" },
|
||||
{ 'C', "no-watch-dir", "Disable the watch-dir", "C", false, nullptr },
|
||||
{ 941, "incomplete-dir", "Where to store new torrents until they're complete", nullptr, true, "<directory>" },
|
||||
{ 942, "no-incomplete-dir", "Don't store incomplete torrents in a different location", nullptr, false, nullptr },
|
||||
{ 'd', "dump-settings", "Dump the settings and exit", "d", false, nullptr },
|
||||
{ 'e', "logfile", "Dump the log messages to this filename", "e", true, "<filename>" },
|
||||
{ 'f', "foreground", "Run in the foreground instead of daemonizing", "f", false, nullptr },
|
||||
{ 'g', "config-dir", "Where to look for configuration files", "g", true, "<path>" },
|
||||
{ 'p', "port", "RPC port (Default: " TR_DEFAULT_RPC_PORT_STR ")", "p", true, "<port>" },
|
||||
{ 't', "auth", "Require authentication", "t", false, nullptr },
|
||||
{ 'T', "no-auth", "Don't require authentication", "T", false, nullptr },
|
||||
{ 'u', "username", "Set username for authentication", "u", true, "<username>" },
|
||||
{ 'v', "password", "Set password for authentication", "v", true, "<password>" },
|
||||
{ 'V', "version", "Show version number and exit", "V", false, nullptr },
|
||||
{ 810, "log-error", "Show error messages", nullptr, false, nullptr },
|
||||
{ 811, "log-info", "Show error and info messages", nullptr, false, nullptr },
|
||||
{ 812, "log-debug", "Show error, info, and debug messages", nullptr, false, nullptr },
|
||||
{ 'w', "download-dir", "Where to save downloaded data", "w", true, "<path>" },
|
||||
{ 800, "paused", "Pause all torrents on startup", nullptr, false, nullptr },
|
||||
{ 'o', "dht", "Enable distributed hash tables (DHT)", "o", false, nullptr },
|
||||
{ 'O', "no-dht", "Disable distributed hash tables (DHT)", "O", false, nullptr },
|
||||
{ 'y', "lpd", "Enable local peer discovery (LPD)", "y", false, nullptr },
|
||||
{ 'Y', "no-lpd", "Disable local peer discovery (LPD)", "Y", false, nullptr },
|
||||
{ 830, "utp", "Enable uTP for peer connections", nullptr, false, nullptr },
|
||||
{ 831, "no-utp", "Disable uTP for peer connections", nullptr, false, nullptr },
|
||||
{ 'P', "peerport", "Port for incoming peers (Default: " TR_DEFAULT_PEER_PORT_STR ")", "P", true, "<port>" },
|
||||
{ 'm', "portmap", "Enable portmapping via NAT-PMP or UPnP", "m", false, nullptr },
|
||||
{ 'M', "no-portmap", "Disable portmapping", "M", false, nullptr },
|
||||
{ 'L',
|
||||
"peerlimit-global",
|
||||
"Maximum overall number of peers (Default: " TR_DEFAULT_PEER_LIMIT_GLOBAL_STR ")",
|
||||
"L",
|
||||
true,
|
||||
"<limit>" },
|
||||
{ 'l',
|
||||
"peerlimit-torrent",
|
||||
"Maximum number of peers per torrent (Default: " TR_DEFAULT_PEER_LIMIT_TORRENT_STR ")",
|
||||
"l",
|
||||
true,
|
||||
"<limit>" },
|
||||
{ 910, "encryption-required", "Encrypt all peer connections", "er", false, nullptr },
|
||||
{ 911, "encryption-preferred", "Prefer encrypted peer connections", "ep", false, nullptr },
|
||||
{ 912, "encryption-tolerated", "Prefer unencrypted peer connections", "et", false, nullptr },
|
||||
{ 'i', "bind-address-ipv4", "Where to listen for peer connections", "i", true, "<ipv4 addr>" },
|
||||
{ 'I', "bind-address-ipv6", "Where to listen for peer connections", "I", true, "<ipv6 addr>" },
|
||||
{ 'r', "rpc-bind-address", "Where to listen for RPC connections", "r", true, "<ip addr>" },
|
||||
{ 953,
|
||||
"global-seedratio",
|
||||
"All torrents, unless overridden by a per-torrent setting, should seed until a specific ratio",
|
||||
"gsr",
|
||||
true,
|
||||
"ratio" },
|
||||
{ 954,
|
||||
"no-global-seedratio",
|
||||
"All torrents, unless overridden by a per-torrent setting, should seed regardless of ratio",
|
||||
"GSR",
|
||||
false,
|
||||
nullptr },
|
||||
{ 'x', "pid-file", "Enable PID file", "x", true, "<pid-file>" },
|
||||
{ 0, nullptr, nullptr, nullptr, false, nullptr }
|
||||
static auto constexpr Options = std::array<tr_option, 43>{
|
||||
{ { 'a', "allowed", "Allowed IP addresses. (Default: " TR_DEFAULT_RPC_WHITELIST ")", "a", true, "<list>" },
|
||||
{ 'b', "blocklist", "Enable peer blocklists", "b", false, nullptr },
|
||||
{ 'B', "no-blocklist", "Disable peer blocklists", "B", false, nullptr },
|
||||
{ 'c', "watch-dir", "Where to watch for new .torrent files", "c", true, "<directory>" },
|
||||
{ 'C', "no-watch-dir", "Disable the watch-dir", "C", false, nullptr },
|
||||
{ 941, "incomplete-dir", "Where to store new torrents until they're complete", nullptr, true, "<directory>" },
|
||||
{ 942, "no-incomplete-dir", "Don't store incomplete torrents in a different location", nullptr, false, nullptr },
|
||||
{ 'd', "dump-settings", "Dump the settings and exit", "d", false, nullptr },
|
||||
{ 'e', "logfile", "Dump the log messages to this filename", "e", true, "<filename>" },
|
||||
{ 'f', "foreground", "Run in the foreground instead of daemonizing", "f", false, nullptr },
|
||||
{ 'g', "config-dir", "Where to look for configuration files", "g", true, "<path>" },
|
||||
{ 'p', "port", "RPC port (Default: " TR_DEFAULT_RPC_PORT_STR ")", "p", true, "<port>" },
|
||||
{ 't', "auth", "Require authentication", "t", false, nullptr },
|
||||
{ 'T', "no-auth", "Don't require authentication", "T", false, nullptr },
|
||||
{ 'u', "username", "Set username for authentication", "u", true, "<username>" },
|
||||
{ 'v', "password", "Set password for authentication", "v", true, "<password>" },
|
||||
{ 'V', "version", "Show version number and exit", "V", false, nullptr },
|
||||
{ 810, "log-error", "Show error messages", nullptr, false, nullptr },
|
||||
{ 811, "log-info", "Show error and info messages", nullptr, false, nullptr },
|
||||
{ 812, "log-debug", "Show error, info, and debug messages", nullptr, false, nullptr },
|
||||
{ 'w', "download-dir", "Where to save downloaded data", "w", true, "<path>" },
|
||||
{ 800, "paused", "Pause all torrents on startup", nullptr, false, nullptr },
|
||||
{ 'o', "dht", "Enable distributed hash tables (DHT)", "o", false, nullptr },
|
||||
{ 'O', "no-dht", "Disable distributed hash tables (DHT)", "O", false, nullptr },
|
||||
{ 'y', "lpd", "Enable local peer discovery (LPD)", "y", false, nullptr },
|
||||
{ 'Y', "no-lpd", "Disable local peer discovery (LPD)", "Y", false, nullptr },
|
||||
{ 830, "utp", "Enable uTP for peer connections", nullptr, false, nullptr },
|
||||
{ 831, "no-utp", "Disable uTP for peer connections", nullptr, false, nullptr },
|
||||
{ 'P', "peerport", "Port for incoming peers (Default: " TR_DEFAULT_PEER_PORT_STR ")", "P", true, "<port>" },
|
||||
{ 'm', "portmap", "Enable portmapping via NAT-PMP or UPnP", "m", false, nullptr },
|
||||
{ 'M', "no-portmap", "Disable portmapping", "M", false, nullptr },
|
||||
{ 'L',
|
||||
"peerlimit-global",
|
||||
"Maximum overall number of peers (Default: " TR_DEFAULT_PEER_LIMIT_GLOBAL_STR ")",
|
||||
"L",
|
||||
true,
|
||||
"<limit>" },
|
||||
{ 'l',
|
||||
"peerlimit-torrent",
|
||||
"Maximum number of peers per torrent (Default: " TR_DEFAULT_PEER_LIMIT_TORRENT_STR ")",
|
||||
"l",
|
||||
true,
|
||||
"<limit>" },
|
||||
{ 910, "encryption-required", "Encrypt all peer connections", "er", false, nullptr },
|
||||
{ 911, "encryption-preferred", "Prefer encrypted peer connections", "ep", false, nullptr },
|
||||
{ 912, "encryption-tolerated", "Prefer unencrypted peer connections", "et", false, nullptr },
|
||||
{ 'i', "bind-address-ipv4", "Where to listen for peer connections", "i", true, "<ipv4 addr>" },
|
||||
{ 'I', "bind-address-ipv6", "Where to listen for peer connections", "I", true, "<ipv6 addr>" },
|
||||
{ 'r', "rpc-bind-address", "Where to listen for RPC connections", "r", true, "<ip addr>" },
|
||||
{ 953,
|
||||
"global-seedratio",
|
||||
"All torrents, unless overridden by a per-torrent setting, should seed until a specific ratio",
|
||||
"gsr",
|
||||
true,
|
||||
"ratio" },
|
||||
{ 954,
|
||||
"no-global-seedratio",
|
||||
"All torrents, unless overridden by a per-torrent setting, should seed regardless of ratio",
|
||||
"GSR",
|
||||
false,
|
||||
nullptr },
|
||||
{ 'x', "pid-file", "Enable PID file", "x", true, "<pid-file>" },
|
||||
{ 0, nullptr, nullptr, nullptr, false, nullptr } }
|
||||
};
|
||||
|
||||
static bool reopen_log_file(char const* filename)
|
||||
|
@ -203,7 +199,7 @@ static char const* getConfigDir(int argc, char const* const* argv)
|
|||
char const* optstr;
|
||||
int const ind = tr_optind;
|
||||
|
||||
while ((c = tr_getopt(getUsage(), argc, argv, options, &optstr)) != TR_OPT_DONE)
|
||||
while ((c = tr_getopt(Usage, argc, argv, std::data(Options), &optstr)) != TR_OPT_DONE)
|
||||
{
|
||||
if (c == 'g')
|
||||
{
|
||||
|
@ -216,7 +212,7 @@ static char const* getConfigDir(int argc, char const* const* argv)
|
|||
|
||||
if (configDir == nullptr)
|
||||
{
|
||||
configDir = tr_getDefaultConfigDir(MY_NAME);
|
||||
configDir = tr_getDefaultConfigDir(MyName);
|
||||
}
|
||||
|
||||
return configDir;
|
||||
|
@ -415,7 +411,7 @@ static bool parse_args(
|
|||
|
||||
tr_optind = 1;
|
||||
|
||||
while ((c = tr_getopt(getUsage(), argc, argv, options, &optstr)) != TR_OPT_DONE)
|
||||
while ((c = tr_getopt(Usage, argc, argv, std::data(Options), &optstr)) != TR_OPT_DONE)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
|
@ -470,7 +466,7 @@ static bool parse_args(
|
|||
break;
|
||||
|
||||
case 'V': /* version */
|
||||
fprintf(stderr, "%s %s\n", MY_NAME, LONG_VERSION_STRING);
|
||||
fprintf(stderr, "%s %s\n", MyName, LONG_VERSION_STRING);
|
||||
*exit_code = 0;
|
||||
return false;
|
||||
|
||||
|
@ -596,7 +592,7 @@ static bool parse_args(
|
|||
break;
|
||||
|
||||
default:
|
||||
tr_getopt_usage(MY_NAME, getUsage(), options);
|
||||
tr_getopt_usage(MyName, Usage, std::data(Options));
|
||||
*exit_code = 0;
|
||||
return false;
|
||||
}
|
||||
|
@ -634,7 +630,7 @@ static void daemon_reconfigure(void* /*arg*/)
|
|||
tr_logAddInfo("Reloading settings from \"%s\"", configDir);
|
||||
tr_variantInitDict(&settings, 0);
|
||||
tr_variantDictAddBool(&settings, TR_KEY_rpc_enabled, true);
|
||||
tr_sessionLoadSettings(&settings, configDir, MY_NAME);
|
||||
tr_sessionLoadSettings(&settings, configDir, MyName);
|
||||
tr_sessionSet(mySession, &settings);
|
||||
tr_variantFree(&settings);
|
||||
tr_sessionReloadBlocklists(mySession);
|
||||
|
@ -670,7 +666,7 @@ static int daemon_start(void* varg, [[maybe_unused]] bool foreground)
|
|||
{
|
||||
char buf[256];
|
||||
tr_snprintf(buf, sizeof(buf), "Failed to init daemon event state: %s", tr_strerror(errno));
|
||||
printMessage(logfile, TR_LOG_ERROR, MY_NAME, buf, __FILE__, __LINE__);
|
||||
printMessage(logfile, TR_LOG_ERROR, MyName, buf, __FILE__, __LINE__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -711,7 +707,7 @@ static int daemon_start(void* varg, [[maybe_unused]] bool foreground)
|
|||
|
||||
if (tr_variantDictFindBool(settings, TR_KEY_rpc_authentication_required, &boolVal) && boolVal)
|
||||
{
|
||||
tr_logAddNamedInfo(MY_NAME, "requiring authentication");
|
||||
tr_logAddNamedInfo(MyName, "requiring authentication");
|
||||
}
|
||||
|
||||
mySession = session;
|
||||
|
@ -761,7 +757,7 @@ static int daemon_start(void* varg, [[maybe_unused]] bool foreground)
|
|||
|
||||
if (!foreground)
|
||||
{
|
||||
openlog(MY_NAME, LOG_CONS | LOG_PID, LOG_DAEMON);
|
||||
openlog(MyName, LOG_CONS | LOG_PID, LOG_DAEMON);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -841,7 +837,7 @@ static bool init_daemon_data(int argc, char* argv[], struct daemon_data* data, b
|
|||
/* load settings from defaults + config file */
|
||||
tr_variantInitDict(&data->settings, 0);
|
||||
tr_variantDictAddBool(&data->settings, TR_KEY_rpc_enabled, true);
|
||||
bool const loaded = tr_sessionLoadSettings(&data->settings, data->configDir, MY_NAME);
|
||||
bool const loaded = tr_sessionLoadSettings(&data->settings, data->configDir, MyName);
|
||||
|
||||
bool dumpSettings;
|
||||
|
||||
|
@ -860,7 +856,7 @@ static bool init_daemon_data(int argc, char* argv[], struct daemon_data* data, b
|
|||
|
||||
if (!loaded)
|
||||
{
|
||||
printMessage(logfile, TR_LOG_ERROR, MY_NAME, "Error loading config file -- exiting.", __FILE__, __LINE__);
|
||||
printMessage(logfile, TR_LOG_ERROR, MyName, "Error loading config file -- exiting.", __FILE__, __LINE__);
|
||||
*ret = 1;
|
||||
goto EXIT_EARLY;
|
||||
}
|
||||
|
@ -906,7 +902,7 @@ int tr_main(int argc, char* argv[])
|
|||
{
|
||||
char buf[256];
|
||||
tr_snprintf(buf, sizeof(buf), "Failed to daemonize: %s", error->message);
|
||||
printMessage(logfile, TR_LOG_ERROR, MY_NAME, buf, __FILE__, __LINE__);
|
||||
printMessage(logfile, TR_LOG_ERROR, MyName, buf, __FILE__, __LINE__);
|
||||
tr_error_free(error);
|
||||
}
|
||||
|
||||
|
|
113
utils/create.cc
113
utils/create.cc
|
@ -6,6 +6,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <array>
|
||||
#include <stdio.h> /* fprintf() */
|
||||
#include <stdlib.h> /* strtoul(), EXIT_FAILURE */
|
||||
#include <inttypes.h> /* PRIu32 */
|
||||
|
@ -22,91 +23,83 @@
|
|||
|
||||
using namespace std::literals;
|
||||
|
||||
#define MY_NAME "transmission-create"
|
||||
static char constexpr MyName[] = "transmission-create";
|
||||
static char constexpr Usage[] = "Usage: transmission-create [options] <file|directory>";
|
||||
|
||||
#define MAX_TRACKERS 128
|
||||
static uint32_t const KiB = 1024;
|
||||
static tr_tracker_info trackers[MAX_TRACKERS];
|
||||
static int trackerCount = 0;
|
||||
static bool isPrivate = false;
|
||||
static bool showVersion = false;
|
||||
static char const* comment = nullptr;
|
||||
static char const* outfile = nullptr;
|
||||
static char const* infile = nullptr;
|
||||
static uint32_t piecesize_kib = 0;
|
||||
static char const* source = NULL;
|
||||
static uint32_t constexpr KiB = 1024;
|
||||
|
||||
static tr_option options[] = {
|
||||
{ 'p', "private", "Allow this torrent to only be used with the specified tracker(s)", "p", false, nullptr },
|
||||
{ 'r', "source", "Set the source for private trackers", "r", true, "<source>" },
|
||||
{ 'o', "outfile", "Save the generated .torrent to this filename", "o", true, "<file>" },
|
||||
{ 's', "piecesize", "Set how many KiB each piece should be, overriding the preferred default", "s", true, "<size in KiB>" },
|
||||
{ 'c', "comment", "Add a comment", "c", true, "<comment>" },
|
||||
{ 't', "tracker", "Add a tracker's announce URL", "t", true, "<url>" },
|
||||
{ 'V', "version", "Show version number and exit", "V", false, nullptr },
|
||||
{ 0, nullptr, nullptr, nullptr, false, nullptr }
|
||||
static auto constexpr Options = std::array<tr_option, 8>{
|
||||
{ { 'p', "private", "Allow this torrent to only be used with the specified tracker(s)", "p", false, nullptr },
|
||||
{ 'r', "source", "Set the source for private trackers", "r", true, "<source>" },
|
||||
{ 'o', "outfile", "Save the generated .torrent to this filename", "o", true, "<file>" },
|
||||
{ 's', "piecesize", "Set the piece size in KiB, overriding the preferred default", "s", true, "<KiB>" },
|
||||
{ 'c', "comment", "Add a comment", "c", true, "<comment>" },
|
||||
{ 't', "tracker", "Add a tracker's announce URL", "t", true, "<url>" },
|
||||
{ 'V', "version", "Show version number and exit", "V", false, nullptr },
|
||||
{ 0, nullptr, nullptr, nullptr, false, nullptr } }
|
||||
};
|
||||
|
||||
static char const* getUsage(void)
|
||||
struct app_options
|
||||
{
|
||||
return "Usage: " MY_NAME " [options] <file|directory>";
|
||||
}
|
||||
std::vector<tr_tracker_info> trackers;
|
||||
bool is_private = false;
|
||||
bool show_version = false;
|
||||
char const* comment = nullptr;
|
||||
char const* outfile = nullptr;
|
||||
char const* infile = nullptr;
|
||||
uint32_t piecesize_kib = 0;
|
||||
char const* source = nullptr;
|
||||
};
|
||||
|
||||
static int parseCommandLine(int argc, char const* const* argv)
|
||||
static int parseCommandLine(app_options& options, int argc, char const* const* argv)
|
||||
{
|
||||
int c;
|
||||
char const* optarg;
|
||||
|
||||
while ((c = tr_getopt(getUsage(), argc, argv, options, &optarg)) != TR_OPT_DONE)
|
||||
while ((c = tr_getopt(Usage, argc, argv, std::data(Options), &optarg)) != TR_OPT_DONE)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'V':
|
||||
showVersion = true;
|
||||
options.show_version = true;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
isPrivate = true;
|
||||
options.is_private = true;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
outfile = optarg;
|
||||
options.outfile = optarg;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
comment = optarg;
|
||||
options.comment = optarg;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
if (trackerCount + 1 < MAX_TRACKERS)
|
||||
{
|
||||
trackers[trackerCount].tier = trackerCount;
|
||||
trackers[trackerCount].announce = (char*)optarg;
|
||||
++trackerCount;
|
||||
}
|
||||
|
||||
options.trackers.push_back(tr_tracker_info{ 0, const_cast<char*>(optarg), nullptr, 0 });
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (optarg != nullptr)
|
||||
{
|
||||
char* endptr = nullptr;
|
||||
piecesize_kib = strtoul(optarg, &endptr, 10);
|
||||
options.piecesize_kib = strtoul(optarg, &endptr, 10);
|
||||
|
||||
if (endptr != nullptr && *endptr == 'M')
|
||||
{
|
||||
piecesize_kib *= KiB;
|
||||
options.piecesize_kib *= KiB;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
source = optarg;
|
||||
options.source = optarg;
|
||||
break;
|
||||
|
||||
case TR_OPT_UNK:
|
||||
infile = optarg;
|
||||
options.infile = optarg;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -144,29 +137,30 @@ int tr_main(int argc, char* argv[])
|
|||
tr_formatter_size_init(DISK_K, DISK_K_STR, DISK_M_STR, DISK_G_STR, DISK_T_STR);
|
||||
tr_formatter_speed_init(SPEED_K, SPEED_K_STR, SPEED_M_STR, SPEED_G_STR, SPEED_T_STR);
|
||||
|
||||
if (parseCommandLine(argc, (char const* const*)argv) != 0)
|
||||
auto options = app_options{};
|
||||
if (parseCommandLine(options, argc, (char const* const*)argv) != 0)
|
||||
{
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (showVersion)
|
||||
if (options.show_version)
|
||||
{
|
||||
fprintf(stderr, MY_NAME " " LONG_VERSION_STRING "\n");
|
||||
fprintf(stderr, "%s %s\n", MyName, LONG_VERSION_STRING);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (infile == nullptr)
|
||||
if (options.infile == nullptr)
|
||||
{
|
||||
fprintf(stderr, "ERROR: No input file or directory specified.\n");
|
||||
tr_getopt_usage(MY_NAME, getUsage(), options);
|
||||
tr_getopt_usage(MyName, Usage, std::data(Options));
|
||||
fprintf(stderr, "\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (outfile == nullptr)
|
||||
if (options.outfile == nullptr)
|
||||
{
|
||||
tr_error* error = nullptr;
|
||||
char* base = tr_sys_path_basename(infile, &error);
|
||||
char* base = tr_sys_path_basename(options.infile, &error);
|
||||
|
||||
if (base == nullptr)
|
||||
{
|
||||
|
@ -176,14 +170,14 @@ int tr_main(int argc, char* argv[])
|
|||
|
||||
auto const end = tr_strvJoin(base, ".torrent"sv);
|
||||
char* cwd = tr_getcwd();
|
||||
outfile = out2 = tr_buildPath(cwd, end.c_str(), nullptr);
|
||||
options.outfile = out2 = tr_buildPath(cwd, end.c_str(), nullptr);
|
||||
tr_free(cwd);
|
||||
tr_free(base);
|
||||
}
|
||||
|
||||
if (trackerCount == 0)
|
||||
if (std::empty(options.trackers))
|
||||
{
|
||||
if (isPrivate)
|
||||
if (options.is_private)
|
||||
{
|
||||
fprintf(stderr, "ERROR: no trackers specified for a private torrent\n");
|
||||
return EXIT_FAILURE;
|
||||
|
@ -194,9 +188,9 @@ int tr_main(int argc, char* argv[])
|
|||
}
|
||||
}
|
||||
|
||||
printf("Creating torrent \"%s\"\n", outfile);
|
||||
printf("Creating torrent \"%s\"\n", options.outfile);
|
||||
|
||||
b = tr_metaInfoBuilderCreate(infile);
|
||||
b = tr_metaInfoBuilderCreate(options.infile);
|
||||
|
||||
if (b == nullptr)
|
||||
{
|
||||
|
@ -204,9 +198,9 @@ int tr_main(int argc, char* argv[])
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (piecesize_kib != 0)
|
||||
if (options.piecesize_kib != 0)
|
||||
{
|
||||
tr_metaInfoBuilderSetPieceSize(b, piecesize_kib * KiB);
|
||||
tr_metaInfoBuilderSetPieceSize(b, options.piecesize_kib * KiB);
|
||||
}
|
||||
|
||||
char buf[128];
|
||||
|
@ -219,7 +213,14 @@ int tr_main(int argc, char* argv[])
|
|||
b->pieceCount,
|
||||
tr_formatter_size_B(buf, b->pieceSize, sizeof(buf)));
|
||||
|
||||
tr_makeMetaInfo(b, outfile, trackers, trackerCount, comment, isPrivate, source);
|
||||
tr_makeMetaInfo(
|
||||
b,
|
||||
options.outfile,
|
||||
std::data(options.trackers),
|
||||
std::size(options.trackers),
|
||||
options.comment,
|
||||
options.is_private,
|
||||
options.source);
|
||||
|
||||
uint32_t last = UINT32_MAX;
|
||||
while (!b->isDone)
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <array>
|
||||
#include <stdio.h> /* fprintf() */
|
||||
#include <stdlib.h> /* EXIT_FAILURE */
|
||||
#include <vector>
|
||||
|
||||
#include <event2/buffer.h>
|
||||
|
||||
|
@ -18,63 +20,61 @@
|
|||
#include <libtransmission/variant.h>
|
||||
#include <libtransmission/version.h>
|
||||
|
||||
#define MY_NAME "transmission-edit"
|
||||
static char constexpr MyName[] = "transmission-edit";
|
||||
static char constexpr Usage[] = "Usage: transmission-edit [options] torrent-file(s)";
|
||||
|
||||
static int fileCount = 0;
|
||||
static bool showVersion = false;
|
||||
static char const** files = nullptr;
|
||||
static char const* add = nullptr;
|
||||
static char const* deleteme = nullptr;
|
||||
static char const* replace[2] = { nullptr, nullptr };
|
||||
|
||||
static tr_option options[] = {
|
||||
{ 'a', "add", "Add a tracker's announce URL", "a", true, "<url>" },
|
||||
{ 'd', "delete", "Delete a tracker's announce URL", "d", true, "<url>" },
|
||||
{ 'r', "replace", "Search and replace a substring in the announce URLs", "r", true, "<old> <new>" },
|
||||
{ 'V', "version", "Show version number and exit", "V", false, nullptr },
|
||||
{ 0, nullptr, nullptr, nullptr, false, nullptr }
|
||||
struct app_options
|
||||
{
|
||||
std::vector<char const*> files;
|
||||
char const* add = nullptr;
|
||||
char const* deleteme = nullptr;
|
||||
std::array<char const*, 2> replace;
|
||||
bool show_version = false;
|
||||
};
|
||||
|
||||
static char const* getUsage(void)
|
||||
{
|
||||
return "Usage: " MY_NAME " [options] torrent-file(s)";
|
||||
}
|
||||
static auto constexpr Options = std::array<tr_option, 5>{
|
||||
{ { 'a', "add", "Add a tracker's announce URL", "a", true, "<url>" },
|
||||
{ 'd', "delete", "Delete a tracker's announce URL", "d", true, "<url>" },
|
||||
{ 'r', "replace", "Search and replace a substring in the announce URLs", "r", true, "<old> <new>" },
|
||||
{ 'V', "version", "Show version number and exit", "V", false, nullptr },
|
||||
{ 0, nullptr, nullptr, nullptr, false, nullptr } }
|
||||
};
|
||||
|
||||
static int parseCommandLine(int argc, char const* const* argv)
|
||||
static int parseCommandLine(app_options& opts, int argc, char const* const* argv)
|
||||
{
|
||||
int c;
|
||||
char const* optarg;
|
||||
|
||||
while ((c = tr_getopt(getUsage(), argc, argv, options, &optarg)) != TR_OPT_DONE)
|
||||
while ((c = tr_getopt(Usage, argc, argv, std::data(Options), &optarg)) != TR_OPT_DONE)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'a':
|
||||
add = optarg;
|
||||
opts.add = optarg;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
deleteme = optarg;
|
||||
opts.deleteme = optarg;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
replace[0] = optarg;
|
||||
c = tr_getopt(getUsage(), argc, argv, options, &optarg);
|
||||
opts.replace[0] = optarg;
|
||||
c = tr_getopt(Usage, argc, argv, std::data(Options), &optarg);
|
||||
|
||||
if (c != TR_OPT_UNK)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
replace[1] = optarg;
|
||||
opts.replace[1] = optarg;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
showVersion = true;
|
||||
opts.show_version = true;
|
||||
break;
|
||||
|
||||
case TR_OPT_UNK:
|
||||
files[fileCount++] = optarg;
|
||||
opts.files.push_back(optarg);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -166,11 +166,11 @@ static std::string replaceSubstr(std::string_view str, std::string_view oldval,
|
|||
{
|
||||
auto const pos = str.find(oldval);
|
||||
ret += str.substr(0, pos);
|
||||
ret += newval;
|
||||
if (pos == str.npos)
|
||||
{
|
||||
break;
|
||||
}
|
||||
ret += newval;
|
||||
str.remove_prefix(pos + std::size(oldval));
|
||||
}
|
||||
|
||||
|
@ -301,42 +301,40 @@ int tr_main(int argc, char* argv[])
|
|||
{
|
||||
int changedCount = 0;
|
||||
|
||||
files = tr_new0(char const*, argc);
|
||||
|
||||
tr_logSetLevel(TR_LOG_ERROR);
|
||||
|
||||
if (parseCommandLine(argc, (char const* const*)argv) != 0)
|
||||
auto options = app_options{};
|
||||
if (parseCommandLine(options, argc, (char const* const*)argv) != 0)
|
||||
{
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (showVersion)
|
||||
if (options.show_version)
|
||||
{
|
||||
fprintf(stderr, MY_NAME " " LONG_VERSION_STRING "\n");
|
||||
fprintf(stderr, "%s %s\n", MyName, LONG_VERSION_STRING);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (fileCount < 1)
|
||||
if (std::empty(options.files))
|
||||
{
|
||||
fprintf(stderr, "ERROR: No torrent files specified.\n");
|
||||
tr_getopt_usage(MY_NAME, getUsage(), options);
|
||||
tr_getopt_usage(MyName, Usage, std::data(Options));
|
||||
fprintf(stderr, "\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (add == nullptr && deleteme == nullptr && replace[0] == 0)
|
||||
if (options.add == nullptr && options.deleteme == nullptr && options.replace[0] == 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR: Must specify -a, -d or -r\n");
|
||||
tr_getopt_usage(MY_NAME, getUsage(), options);
|
||||
tr_getopt_usage(MyName, Usage, std::data(Options));
|
||||
fprintf(stderr, "\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < fileCount; ++i)
|
||||
for (auto const& filename : options.files)
|
||||
{
|
||||
tr_variant top;
|
||||
bool changed = false;
|
||||
char const* filename = files[i];
|
||||
tr_error* error = nullptr;
|
||||
|
||||
printf("%s\n", filename);
|
||||
|
@ -348,19 +346,19 @@ int tr_main(int argc, char* argv[])
|
|||
continue;
|
||||
}
|
||||
|
||||
if (deleteme != nullptr)
|
||||
if (options.deleteme != nullptr)
|
||||
{
|
||||
changed |= removeURL(&top, deleteme);
|
||||
changed |= removeURL(&top, options.deleteme);
|
||||
}
|
||||
|
||||
if (add != nullptr)
|
||||
if (options.add != nullptr)
|
||||
{
|
||||
changed = addURL(&top, add);
|
||||
changed = addURL(&top, options.add);
|
||||
}
|
||||
|
||||
if (replace[0] != nullptr && replace[1] != nullptr)
|
||||
if (options.replace[0] != nullptr && options.replace[1] != nullptr)
|
||||
{
|
||||
changed |= replaceURL(&top, replace[0], replace[1]);
|
||||
changed |= replaceURL(&top, options.replace[0], options.replace[1]);
|
||||
}
|
||||
|
||||
if (changed)
|
||||
|
@ -374,6 +372,5 @@ int tr_main(int argc, char* argv[])
|
|||
|
||||
printf("Changed %d files\n", changedCount);
|
||||
|
||||
tr_free((void*)files);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
384
utils/remote.cc
384
utils/remote.cc
|
@ -6,6 +6,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <array>
|
||||
#include <assert.h>
|
||||
#include <ctype.h> /* isspace */
|
||||
#include <errno.h>
|
||||
|
@ -33,31 +34,45 @@
|
|||
|
||||
using namespace std::literals;
|
||||
|
||||
static auto constexpr DefaultHost = "localhost"sv;
|
||||
static auto constexpr DefaultPort = int{ TR_DEFAULT_RPC_PORT };
|
||||
|
||||
#define MY_NAME "transmission-remote"
|
||||
#define DEFAULT_URL TR_DEFAULT_RPC_URL_STR "rpc/"
|
||||
|
||||
#define ARGUMENTS TR_KEY_arguments
|
||||
|
||||
#define MEM_K 1024
|
||||
#define MEM_K_STR "KiB"
|
||||
#define MEM_M_STR "MiB"
|
||||
#define MEM_G_STR "GiB"
|
||||
#define MEM_T_STR "TiB"
|
||||
|
||||
#define DISK_K 1000
|
||||
#define DISK_K_STR "kB"
|
||||
#define DISK_M_STR "MB"
|
||||
#define DISK_G_STR "GB"
|
||||
#define DISK_T_STR "TB"
|
||||
|
||||
#define SPEED_K 1000
|
||||
#define SPEED_K_STR "kB/s"
|
||||
#define SPEED_M_STR "MB/s"
|
||||
#define SPEED_G_STR "GB/s"
|
||||
#define SPEED_T_STR "TB/s"
|
||||
#define MEM_M_STR "MiB"
|
||||
|
||||
static auto constexpr DefaultPort = int{ TR_DEFAULT_RPC_PORT };
|
||||
static char constexpr DefaultHost[] = "localhost";
|
||||
static char constexpr DefaultUrl[] = TR_DEFAULT_RPC_URL_STR "rpc/";
|
||||
|
||||
static char constexpr MyName[] = "transmission-remote";
|
||||
static char constexpr Usage[] = "transmission-remote " LONG_VERSION_STRING
|
||||
"\n"
|
||||
"A fast and easy BitTorrent client\n"
|
||||
"https://transmissionbt.com/\n"
|
||||
"\n"
|
||||
"Usage: transmission-remote [host] [options]\n"
|
||||
" transmission-remote [port] [options]\n"
|
||||
" transmission-remote [host:port] [options]\n"
|
||||
" transmission-remote [http(s?)://host:port/transmission/] [options]\n"
|
||||
"\n"
|
||||
"See the man page for detailed explanations and many examples.";
|
||||
|
||||
static auto constexpr Arguments = TR_KEY_arguments;
|
||||
|
||||
static auto constexpr MemK = size_t{ 1024 };
|
||||
static char constexpr MemKStr[] = "KiB";
|
||||
static char constexpr MemMStr[] = MEM_M_STR;
|
||||
static char constexpr MemGStr[] = "GiB";
|
||||
static char constexpr MemTStr[] = "TiB";
|
||||
|
||||
static auto constexpr DiskK = size_t{ 1000 };
|
||||
static char constexpr DiskKStr[] = "kB";
|
||||
static char constexpr DiskMStr[] = "MB";
|
||||
static char constexpr DiskGStr[] = "GB";
|
||||
static char constexpr DiskTStr[] = "TB";
|
||||
|
||||
static auto constexpr SpeedK = size_t{ 1000 };
|
||||
static auto constexpr SpeedKStr = SPEED_K_STR;
|
||||
static char constexpr SpeedMStr[] = "MB/s";
|
||||
static char constexpr SpeedGStr[] = "GB/s";
|
||||
static char constexpr SpeedTStr[] = "TB/s";
|
||||
|
||||
/***
|
||||
****
|
||||
|
@ -237,153 +252,136 @@ enum
|
|||
TAG_TRACKERS
|
||||
};
|
||||
|
||||
static char const* getUsage(void)
|
||||
{
|
||||
// clang-format off
|
||||
return
|
||||
MY_NAME " " LONG_VERSION_STRING "\n"
|
||||
"A fast and easy BitTorrent client\n"
|
||||
"https://transmissionbt.com/\n"
|
||||
"\n"
|
||||
"Usage: " MY_NAME " [host] [options]\n"
|
||||
" " MY_NAME " [port] [options]\n"
|
||||
" " MY_NAME " [host:port] [options]\n"
|
||||
" " MY_NAME " [http(s?)://host:port/transmission/] [options]\n"
|
||||
"\n"
|
||||
"See the man page for detailed explanations and many examples.";
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
**** Command-Line Arguments
|
||||
****
|
||||
***/
|
||||
|
||||
static tr_option opts[] = {
|
||||
{ 'a', "add", "Add torrent files by filename or URL", "a", false, nullptr },
|
||||
{ 970, "alt-speed", "Use the alternate Limits", "as", false, nullptr },
|
||||
{ 971, "no-alt-speed", "Don't use the alternate Limits", "AS", false, nullptr },
|
||||
{ 972, "alt-speed-downlimit", "max alternate download speed (in " SPEED_K_STR ")", "asd", true, "<speed>" },
|
||||
{ 973, "alt-speed-uplimit", "max alternate upload speed (in " SPEED_K_STR ")", "asu", true, "<speed>" },
|
||||
{ 974, "alt-speed-scheduler", "Use the scheduled on/off times", "asc", false, nullptr },
|
||||
{ 975, "no-alt-speed-scheduler", "Don't use the scheduled on/off times", "ASC", false, nullptr },
|
||||
{ 976, "alt-speed-time-begin", "Time to start using the alt speed limits (in hhmm)", nullptr, true, "<time>" },
|
||||
{ 977, "alt-speed-time-end", "Time to stop using the alt speed limits (in hhmm)", nullptr, true, "<time>" },
|
||||
{ 978, "alt-speed-days", "Numbers for any/all days of the week - eg. \"1-7\"", nullptr, true, "<days>" },
|
||||
{ 963, "blocklist-update", "Blocklist update", nullptr, false, nullptr },
|
||||
{ 'c', "incomplete-dir", "Where to store new torrents until they're complete", "c", true, "<dir>" },
|
||||
{ 'C', "no-incomplete-dir", "Don't store incomplete torrents in a different location", "C", false, nullptr },
|
||||
{ 'b', "debug", "Print debugging information", "b", false, nullptr },
|
||||
{ 'd',
|
||||
"downlimit",
|
||||
"Set the max download speed in " SPEED_K_STR " for the current torrent(s) or globally",
|
||||
"d",
|
||||
true,
|
||||
"<speed>" },
|
||||
{ 'D', "no-downlimit", "Disable max download speed for the current torrent(s) or globally", "D", false, nullptr },
|
||||
{ 'e', "cache", "Set the maximum size of the session's memory cache (in " MEM_M_STR ")", "e", true, "<size>" },
|
||||
{ 910, "encryption-required", "Encrypt all peer connections", "er", false, nullptr },
|
||||
{ 911, "encryption-preferred", "Prefer encrypted peer connections", "ep", false, nullptr },
|
||||
{ 912, "encryption-tolerated", "Prefer unencrypted peer connections", "et", false, nullptr },
|
||||
{ 850, "exit", "Tell the transmission session to shut down", nullptr, false, nullptr },
|
||||
{ 940, "files", "List the current torrent(s)' files", "f", false, nullptr },
|
||||
{ 'g', "get", "Mark files for download", "g", true, "<files>" },
|
||||
{ 'G', "no-get", "Mark files for not downloading", "G", true, "<files>" },
|
||||
{ 'i', "info", "Show the current torrent(s)' details", "i", false, nullptr },
|
||||
{ 940, "info-files", "List the current torrent(s)' files", "if", false, nullptr },
|
||||
{ 941, "info-peers", "List the current torrent(s)' peers", "ip", false, nullptr },
|
||||
{ 942, "info-pieces", "List the current torrent(s)' pieces", "ic", false, nullptr },
|
||||
{ 943, "info-trackers", "List the current torrent(s)' trackers", "it", false, nullptr },
|
||||
{ 920, "session-info", "Show the session's details", "si", false, nullptr },
|
||||
{ 921, "session-stats", "Show the session's statistics", "st", false, nullptr },
|
||||
{ 'l', "list", "List all torrents", "l", false, nullptr },
|
||||
{ 'L', "labels", "Set the current torrents' labels", "L", true, "<label[,label...]>" },
|
||||
{ 960, "move", "Move current torrent's data to a new folder", nullptr, true, "<path>" },
|
||||
{ 961, "find", "Tell Transmission where to find a torrent's data", nullptr, true, "<path>" },
|
||||
{ 'm', "portmap", "Enable portmapping via NAT-PMP or UPnP", "m", false, nullptr },
|
||||
{ 'M', "no-portmap", "Disable portmapping", "M", false, nullptr },
|
||||
{ 'n', "auth", "Set username and password", "n", true, "<user:pw>" },
|
||||
{ 810, "authenv", "Set authentication info from the TR_AUTH environment variable (user:pw)", "ne", false, nullptr },
|
||||
{ 'N', "netrc", "Set authentication info from a .netrc file", "N", true, "<file>" },
|
||||
{ 820, "ssl", "Use SSL when talking to daemon", nullptr, false, nullptr },
|
||||
{ 'o', "dht", "Enable distributed hash tables (DHT)", "o", false, nullptr },
|
||||
{ 'O', "no-dht", "Disable distributed hash tables (DHT)", "O", false, nullptr },
|
||||
{ 'p', "port", "Port for incoming peers (Default: " TR_DEFAULT_PEER_PORT_STR ")", "p", true, "<port>" },
|
||||
{ 962, "port-test", "Port testing", "pt", false, nullptr },
|
||||
{ 'P', "random-port", "Random port for incoming peers", "P", false, nullptr },
|
||||
{ 900, "priority-high", "Try to download these file(s) first", "ph", true, "<files>" },
|
||||
{ 901, "priority-normal", "Try to download these file(s) normally", "pn", true, "<files>" },
|
||||
{ 902, "priority-low", "Try to download these file(s) last", "pl", true, "<files>" },
|
||||
{ 700, "bandwidth-high", "Give this torrent first chance at available bandwidth", "Bh", false, nullptr },
|
||||
{ 701, "bandwidth-normal", "Give this torrent bandwidth left over by high priority torrents", "Bn", false, nullptr },
|
||||
{ 702,
|
||||
"bandwidth-low",
|
||||
"Give this torrent bandwidth left over by high and normal priority torrents",
|
||||
"Bl",
|
||||
false,
|
||||
nullptr },
|
||||
{ 600, "reannounce", "Reannounce the current torrent(s)", nullptr, false, nullptr },
|
||||
{ 'r', "remove", "Remove the current torrent(s)", "r", false, nullptr },
|
||||
{ 930, "peers", "Set the maximum number of peers for the current torrent(s) or globally", "pr", true, "<max>" },
|
||||
{ 840, "remove-and-delete", "Remove the current torrent(s) and delete local data", "rad", false, nullptr },
|
||||
{ 800, "torrent-done-script", "Specify a script to run when a torrent finishes", nullptr, true, "<file>" },
|
||||
{ 801, "no-torrent-done-script", "Don't run a script when torrents finish", nullptr, false, nullptr },
|
||||
{ 950, "seedratio", "Let the current torrent(s) seed until a specific ratio", "sr", true, "ratio" },
|
||||
{ 951, "seedratio-default", "Let the current torrent(s) use the global seedratio settings", "srd", false, nullptr },
|
||||
{ 952, "no-seedratio", "Let the current torrent(s) seed regardless of ratio", "SR", false, nullptr },
|
||||
{ 953,
|
||||
"global-seedratio",
|
||||
"All torrents, unless overridden by a per-torrent setting, should seed until a specific ratio",
|
||||
"gsr",
|
||||
true,
|
||||
"ratio" },
|
||||
{ 954,
|
||||
"no-global-seedratio",
|
||||
"All torrents, unless overridden by a per-torrent setting, should seed regardless of ratio",
|
||||
"GSR",
|
||||
false,
|
||||
nullptr },
|
||||
{ 710, "tracker-add", "Add a tracker to a torrent", "td", true, "<tracker>" },
|
||||
{ 712, "tracker-remove", "Remove a tracker from a torrent", "tr", true, "<trackerId>" },
|
||||
{ 's', "start", "Start the current torrent(s)", "s", false, nullptr },
|
||||
{ 'S', "stop", "Stop the current torrent(s)", "S", false, nullptr },
|
||||
{ 't', "torrent", "Set the current torrent(s)", "t", true, "<torrent>" },
|
||||
{ 990, "start-paused", "Start added torrents paused", nullptr, false, nullptr },
|
||||
{ 991, "no-start-paused", "Start added torrents unpaused", nullptr, false, nullptr },
|
||||
{ 992, "trash-torrent", "Delete torrents after adding", nullptr, false, nullptr },
|
||||
{ 993, "no-trash-torrent", "Do not delete torrents after adding", nullptr, false, nullptr },
|
||||
{ 984, "honor-session", "Make the current torrent(s) honor the session limits", "hl", false, nullptr },
|
||||
{ 985, "no-honor-session", "Make the current torrent(s) not honor the session limits", "HL", false, nullptr },
|
||||
{ 'u',
|
||||
"uplimit",
|
||||
"Set the max upload speed in " SPEED_K_STR " for the current torrent(s) or globally",
|
||||
"u",
|
||||
true,
|
||||
"<speed>" },
|
||||
{ 'U', "no-uplimit", "Disable max upload speed for the current torrent(s) or globally", "U", false, nullptr },
|
||||
{ 830, "utp", "Enable uTP for peer connections", nullptr, false, nullptr },
|
||||
{ 831, "no-utp", "Disable uTP for peer connections", nullptr, false, nullptr },
|
||||
{ 'v', "verify", "Verify the current torrent(s)", "v", false, nullptr },
|
||||
{ 'V', "version", "Show version number and exit", "V", false, nullptr },
|
||||
{ 'w',
|
||||
"download-dir",
|
||||
"When used in conjunction with --add, set the new torrent's download folder. "
|
||||
"Otherwise, set the default download folder",
|
||||
"w",
|
||||
true,
|
||||
"<path>" },
|
||||
{ 'x', "pex", "Enable peer exchange (PEX)", "x", false, nullptr },
|
||||
{ 'X', "no-pex", "Disable peer exchange (PEX)", "X", false, nullptr },
|
||||
{ 'y', "lpd", "Enable local peer discovery (LPD)", "y", false, nullptr },
|
||||
{ 'Y', "no-lpd", "Disable local peer discovery (LPD)", "Y", false, nullptr },
|
||||
{ 941, "peer-info", "List the current torrent(s)' peers", "pi", false, nullptr },
|
||||
{ 0, nullptr, nullptr, nullptr, false, nullptr }
|
||||
static auto constexpr Options = std::array<tr_option, 87>{
|
||||
{ { 'a', "add", "Add torrent files by filename or URL", "a", false, nullptr },
|
||||
{ 970, "alt-speed", "Use the alternate Limits", "as", false, nullptr },
|
||||
{ 971, "no-alt-speed", "Don't use the alternate Limits", "AS", false, nullptr },
|
||||
{ 972, "alt-speed-downlimit", "max alternate download speed (in " SPEED_K_STR ")", "asd", true, "<speed>" },
|
||||
{ 973, "alt-speed-uplimit", "max alternate upload speed (in " SPEED_K_STR ")", "asu", true, "<speed>" },
|
||||
{ 974, "alt-speed-scheduler", "Use the scheduled on/off times", "asc", false, nullptr },
|
||||
{ 975, "no-alt-speed-scheduler", "Don't use the scheduled on/off times", "ASC", false, nullptr },
|
||||
{ 976, "alt-speed-time-begin", "Time to start using the alt speed limits (in hhmm)", nullptr, true, "<time>" },
|
||||
{ 977, "alt-speed-time-end", "Time to stop using the alt speed limits (in hhmm)", nullptr, true, "<time>" },
|
||||
{ 978, "alt-speed-days", "Numbers for any/all days of the week - eg. \"1-7\"", nullptr, true, "<days>" },
|
||||
{ 963, "blocklist-update", "Blocklist update", nullptr, false, nullptr },
|
||||
{ 'c', "incomplete-dir", "Where to store new torrents until they're complete", "c", true, "<dir>" },
|
||||
{ 'C', "no-incomplete-dir", "Don't store incomplete torrents in a different location", "C", false, nullptr },
|
||||
{ 'b', "debug", "Print debugging information", "b", false, nullptr },
|
||||
{ 'd',
|
||||
"downlimit",
|
||||
"Set the max download speed in " SPEED_K_STR " for the current torrent(s) or globally",
|
||||
"d",
|
||||
true,
|
||||
"<speed>" },
|
||||
{ 'D', "no-downlimit", "Disable max download speed for the current torrent(s) or globally", "D", false, nullptr },
|
||||
{ 'e', "cache", "Set the maximum size of the session's memory cache (in " MEM_M_STR ")", "e", true, "<size>" },
|
||||
{ 910, "encryption-required", "Encrypt all peer connections", "er", false, nullptr },
|
||||
{ 911, "encryption-preferred", "Prefer encrypted peer connections", "ep", false, nullptr },
|
||||
{ 912, "encryption-tolerated", "Prefer unencrypted peer connections", "et", false, nullptr },
|
||||
{ 850, "exit", "Tell the transmission session to shut down", nullptr, false, nullptr },
|
||||
{ 940, "files", "List the current torrent(s)' files", "f", false, nullptr },
|
||||
{ 'g', "get", "Mark files for download", "g", true, "<files>" },
|
||||
{ 'G', "no-get", "Mark files for not downloading", "G", true, "<files>" },
|
||||
{ 'i', "info", "Show the current torrent(s)' details", "i", false, nullptr },
|
||||
{ 940, "info-files", "List the current torrent(s)' files", "if", false, nullptr },
|
||||
{ 941, "info-peers", "List the current torrent(s)' peers", "ip", false, nullptr },
|
||||
{ 942, "info-pieces", "List the current torrent(s)' pieces", "ic", false, nullptr },
|
||||
{ 943, "info-trackers", "List the current torrent(s)' trackers", "it", false, nullptr },
|
||||
{ 920, "session-info", "Show the session's details", "si", false, nullptr },
|
||||
{ 921, "session-stats", "Show the session's statistics", "st", false, nullptr },
|
||||
{ 'l', "list", "List all torrents", "l", false, nullptr },
|
||||
{ 'L', "labels", "Set the current torrents' labels", "L", true, "<label[,label...]>" },
|
||||
{ 960, "move", "Move current torrent's data to a new folder", nullptr, true, "<path>" },
|
||||
{ 961, "find", "Tell Transmission where to find a torrent's data", nullptr, true, "<path>" },
|
||||
{ 'm', "portmap", "Enable portmapping via NAT-PMP or UPnP", "m", false, nullptr },
|
||||
{ 'M', "no-portmap", "Disable portmapping", "M", false, nullptr },
|
||||
{ 'n', "auth", "Set username and password", "n", true, "<user:pw>" },
|
||||
{ 810, "authenv", "Set authentication info from the TR_AUTH environment variable (user:pw)", "ne", false, nullptr },
|
||||
{ 'N', "netrc", "Set authentication info from a .netrc file", "N", true, "<file>" },
|
||||
{ 820, "ssl", "Use SSL when talking to daemon", nullptr, false, nullptr },
|
||||
{ 'o', "dht", "Enable distributed hash tables (DHT)", "o", false, nullptr },
|
||||
{ 'O', "no-dht", "Disable distributed hash tables (DHT)", "O", false, nullptr },
|
||||
{ 'p', "port", "Port for incoming peers (Default: " TR_DEFAULT_PEER_PORT_STR ")", "p", true, "<port>" },
|
||||
{ 962, "port-test", "Port testing", "pt", false, nullptr },
|
||||
{ 'P', "random-port", "Random port for incoming peers", "P", false, nullptr },
|
||||
{ 900, "priority-high", "Try to download these file(s) first", "ph", true, "<files>" },
|
||||
{ 901, "priority-normal", "Try to download these file(s) normally", "pn", true, "<files>" },
|
||||
{ 902, "priority-low", "Try to download these file(s) last", "pl", true, "<files>" },
|
||||
{ 700, "bandwidth-high", "Give this torrent first chance at available bandwidth", "Bh", false, nullptr },
|
||||
{ 701, "bandwidth-normal", "Give this torrent bandwidth left over by high priority torrents", "Bn", false, nullptr },
|
||||
{ 702,
|
||||
"bandwidth-low",
|
||||
"Give this torrent bandwidth left over by high and normal priority torrents",
|
||||
"Bl",
|
||||
false,
|
||||
nullptr },
|
||||
{ 600, "reannounce", "Reannounce the current torrent(s)", nullptr, false, nullptr },
|
||||
{ 'r', "remove", "Remove the current torrent(s)", "r", false, nullptr },
|
||||
{ 930, "peers", "Set the maximum number of peers for the current torrent(s) or globally", "pr", true, "<max>" },
|
||||
{ 840, "remove-and-delete", "Remove the current torrent(s) and delete local data", "rad", false, nullptr },
|
||||
{ 800, "torrent-done-script", "Specify a script to run when a torrent finishes", nullptr, true, "<file>" },
|
||||
{ 801, "no-torrent-done-script", "Don't run a script when torrents finish", nullptr, false, nullptr },
|
||||
{ 950, "seedratio", "Let the current torrent(s) seed until a specific ratio", "sr", true, "ratio" },
|
||||
{ 951, "seedratio-default", "Let the current torrent(s) use the global seedratio settings", "srd", false, nullptr },
|
||||
{ 952, "no-seedratio", "Let the current torrent(s) seed regardless of ratio", "SR", false, nullptr },
|
||||
{ 953,
|
||||
"global-seedratio",
|
||||
"All torrents, unless overridden by a per-torrent setting, should seed until a specific ratio",
|
||||
"gsr",
|
||||
true,
|
||||
"ratio" },
|
||||
{ 954,
|
||||
"no-global-seedratio",
|
||||
"All torrents, unless overridden by a per-torrent setting, should seed regardless of ratio",
|
||||
"GSR",
|
||||
false,
|
||||
nullptr },
|
||||
{ 710, "tracker-add", "Add a tracker to a torrent", "td", true, "<tracker>" },
|
||||
{ 712, "tracker-remove", "Remove a tracker from a torrent", "tr", true, "<trackerId>" },
|
||||
{ 's', "start", "Start the current torrent(s)", "s", false, nullptr },
|
||||
{ 'S', "stop", "Stop the current torrent(s)", "S", false, nullptr },
|
||||
{ 't', "torrent", "Set the current torrent(s)", "t", true, "<torrent>" },
|
||||
{ 990, "start-paused", "Start added torrents paused", nullptr, false, nullptr },
|
||||
{ 991, "no-start-paused", "Start added torrents unpaused", nullptr, false, nullptr },
|
||||
{ 992, "trash-torrent", "Delete torrents after adding", nullptr, false, nullptr },
|
||||
{ 993, "no-trash-torrent", "Do not delete torrents after adding", nullptr, false, nullptr },
|
||||
{ 984, "honor-session", "Make the current torrent(s) honor the session limits", "hl", false, nullptr },
|
||||
{ 985, "no-honor-session", "Make the current torrent(s) not honor the session limits", "HL", false, nullptr },
|
||||
{ 'u',
|
||||
"uplimit",
|
||||
"Set the max upload speed in " SPEED_K_STR " for the current torrent(s) or globally",
|
||||
"u",
|
||||
true,
|
||||
"<speed>" },
|
||||
{ 'U', "no-uplimit", "Disable max upload speed for the current torrent(s) or globally", "U", false, nullptr },
|
||||
{ 830, "utp", "Enable uTP for peer connections", nullptr, false, nullptr },
|
||||
{ 831, "no-utp", "Disable uTP for peer connections", nullptr, false, nullptr },
|
||||
{ 'v', "verify", "Verify the current torrent(s)", "v", false, nullptr },
|
||||
{ 'V', "version", "Show version number and exit", "V", false, nullptr },
|
||||
{ 'w',
|
||||
"download-dir",
|
||||
"When used in conjunction with --add, set the new torrent's download folder. "
|
||||
"Otherwise, set the default download folder",
|
||||
"w",
|
||||
true,
|
||||
"<path>" },
|
||||
{ 'x', "pex", "Enable peer exchange (PEX)", "x", false, nullptr },
|
||||
{ 'X', "no-pex", "Disable peer exchange (PEX)", "X", false, nullptr },
|
||||
{ 'y', "lpd", "Enable local peer discovery (LPD)", "y", false, nullptr },
|
||||
{ 'Y', "no-lpd", "Disable local peer discovery (LPD)", "Y", false, nullptr },
|
||||
{ 941, "peer-info", "List the current torrent(s)' peers", "pi", false, nullptr },
|
||||
{ 0, nullptr, nullptr, nullptr, false, nullptr } }
|
||||
};
|
||||
|
||||
static void showUsage(void)
|
||||
{
|
||||
tr_getopt_usage(MY_NAME, getUsage(), opts);
|
||||
tr_getopt_usage(MyName, Usage, std::data(Options));
|
||||
}
|
||||
|
||||
static int numarg(char const* arg)
|
||||
|
@ -2041,7 +2039,7 @@ static int processResponse(char const* rpcurl, std::string_view response)
|
|||
|
||||
if (!tr_variantFromBuf(&top, TR_VARIANT_PARSE_JSON | TR_VARIANT_PARSE_INPLACE, response))
|
||||
{
|
||||
tr_logAddNamedError(MY_NAME, "Unable to parse response \"%" TR_PRIsv "\"", TR_PRIsv_ARG(response));
|
||||
tr_logAddNamedError(MyName, "Unable to parse response \"%" TR_PRIsv "\"", TR_PRIsv_ARG(response));
|
||||
status |= EXIT_FAILURE;
|
||||
}
|
||||
else
|
||||
|
@ -2103,7 +2101,7 @@ static int processResponse(char const* rpcurl, std::string_view response)
|
|||
int64_t i;
|
||||
tr_variant* b = ⊤
|
||||
|
||||
if (tr_variantDictFindDict(&top, ARGUMENTS, &b) &&
|
||||
if (tr_variantDictFindDict(&top, Arguments, &b) &&
|
||||
tr_variantDictFindDict(b, TR_KEY_torrent_added, &b) && tr_variantDictFindInt(b, TR_KEY_id, &i))
|
||||
{
|
||||
tr_snprintf(id, sizeof(id), "%" PRId64, i);
|
||||
|
@ -2142,7 +2140,7 @@ static int processResponse(char const* rpcurl, std::string_view response)
|
|||
static CURL* tr_curl_easy_init(struct evbuffer* writebuf)
|
||||
{
|
||||
CURL* curl = curl_easy_init();
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, MY_NAME "/" LONG_VERSION_STRING);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, tr_strvJoin(MyName, "/", LONG_VERSION_STRING).c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunc);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, writebuf);
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, parseResponseHeader);
|
||||
|
@ -2214,7 +2212,7 @@ static int flush(char const* rpcurl, tr_variant** benc)
|
|||
|
||||
if ((res = curl_easy_perform(curl)) != CURLE_OK)
|
||||
{
|
||||
tr_logAddNamedError(MY_NAME, " (%s) %s", rpcurl_http.c_str(), curl_easy_strerror(res));
|
||||
tr_logAddNamedError(MyName, " (%s) %s", rpcurl_http.c_str(), curl_easy_strerror(res));
|
||||
status |= EXIT_FAILURE;
|
||||
}
|
||||
else
|
||||
|
@ -2273,14 +2271,14 @@ static tr_variant* ensure_sset(tr_variant** sset)
|
|||
|
||||
if (*sset != nullptr)
|
||||
{
|
||||
args = tr_variantDictFind(*sset, ARGUMENTS);
|
||||
args = tr_variantDictFind(*sset, Arguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
*sset = tr_new0(tr_variant, 1);
|
||||
tr_variantInitDict(*sset, 3);
|
||||
tr_variantDictAddStrView(*sset, TR_KEY_method, "session-set"sv);
|
||||
args = tr_variantDictAddDict(*sset, ARGUMENTS, 0);
|
||||
args = tr_variantDictAddDict(*sset, Arguments, 0);
|
||||
}
|
||||
|
||||
return args;
|
||||
|
@ -2292,14 +2290,14 @@ static tr_variant* ensure_tset(tr_variant** tset)
|
|||
|
||||
if (*tset != nullptr)
|
||||
{
|
||||
args = tr_variantDictFind(*tset, ARGUMENTS);
|
||||
args = tr_variantDictFind(*tset, Arguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
*tset = tr_new0(tr_variant, 1);
|
||||
tr_variantInitDict(*tset, 3);
|
||||
tr_variantDictAddStrView(*tset, TR_KEY_method, "torrent-set"sv);
|
||||
args = tr_variantDictAddDict(*tset, ARGUMENTS, 1);
|
||||
args = tr_variantDictAddDict(*tset, Arguments, 1);
|
||||
}
|
||||
|
||||
return args;
|
||||
|
@ -2316,7 +2314,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
|
||||
*id = '\0';
|
||||
|
||||
while ((c = tr_getopt(getUsage(), argc, argv, opts, &optarg)) != TR_OPT_DONE)
|
||||
while ((c = tr_getopt(Usage, argc, argv, std::data(Options), &optarg)) != TR_OPT_DONE)
|
||||
{
|
||||
int const stepMode = getOptMode(c);
|
||||
|
||||
|
@ -2337,7 +2335,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
|
||||
if (tset != nullptr)
|
||||
{
|
||||
addIdArg(tr_variantDictFind(tset, ARGUMENTS), id, nullptr);
|
||||
addIdArg(tr_variantDictFind(tset, Arguments), id, nullptr);
|
||||
status |= flush(rpcurl, &tset);
|
||||
}
|
||||
|
||||
|
@ -2345,7 +2343,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
tr_variantInitDict(tadd, 3);
|
||||
tr_variantDictAddStrView(tadd, TR_KEY_method, "torrent-add"sv);
|
||||
tr_variantDictAddInt(tadd, TR_KEY_tag, TAG_TORRENT_ADD);
|
||||
tr_variantDictAddDict(tadd, ARGUMENTS, 0);
|
||||
tr_variantDictAddDict(tadd, Arguments, 0);
|
||||
break;
|
||||
|
||||
case 'b': /* debug */
|
||||
|
@ -2383,7 +2381,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
|
||||
if (tset != nullptr)
|
||||
{
|
||||
addIdArg(tr_variantDictFind(tset, ARGUMENTS), id, nullptr);
|
||||
addIdArg(tr_variantDictFind(tset, Arguments), id, nullptr);
|
||||
status |= flush(rpcurl, &tset);
|
||||
}
|
||||
|
||||
|
@ -2391,7 +2389,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
break;
|
||||
|
||||
case 'V': /* show version number */
|
||||
fprintf(stderr, "%s %s\n", MY_NAME, LONG_VERSION_STRING);
|
||||
fprintf(stderr, "%s %s\n", MyName, LONG_VERSION_STRING);
|
||||
exit(0);
|
||||
|
||||
case TR_OPT_ERR:
|
||||
|
@ -2403,7 +2401,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
case TR_OPT_UNK:
|
||||
if (tadd != nullptr)
|
||||
{
|
||||
tr_variant* args = tr_variantDictFind(tadd, ARGUMENTS);
|
||||
tr_variant* args = tr_variantDictFind(tadd, Arguments);
|
||||
char* tmp = getEncodedMetainfo(optarg);
|
||||
|
||||
if (tmp != nullptr)
|
||||
|
@ -2433,12 +2431,12 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
tr_variant* fields;
|
||||
tr_variantInitDict(top, 3);
|
||||
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-get"sv);
|
||||
args = tr_variantDictAddDict(top, ARGUMENTS, 0);
|
||||
args = tr_variantDictAddDict(top, Arguments, 0);
|
||||
fields = tr_variantDictAddList(args, TR_KEY_fields, 0);
|
||||
|
||||
if (tset != nullptr)
|
||||
{
|
||||
addIdArg(tr_variantDictFind(tset, ARGUMENTS), id, nullptr);
|
||||
addIdArg(tr_variantDictFind(tset, Arguments), id, nullptr);
|
||||
status |= flush(rpcurl, &tset);
|
||||
}
|
||||
|
||||
|
@ -2794,7 +2792,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
|
||||
if (tadd != nullptr)
|
||||
{
|
||||
args = tr_variantDictFind(tadd, ARGUMENTS);
|
||||
args = tr_variantDictFind(tadd, Arguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2855,7 +2853,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
{
|
||||
if (tadd != nullptr)
|
||||
{
|
||||
tr_variant* args = tr_variantDictFind(tadd, ARGUMENTS);
|
||||
tr_variant* args = tr_variantDictFind(tadd, Arguments);
|
||||
tr_variantDictAddStr(args, TR_KEY_download_dir, optarg);
|
||||
}
|
||||
else
|
||||
|
@ -2864,7 +2862,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
tr_variant* top = tr_new0(tr_variant, 1);
|
||||
tr_variantInitDict(top, 2);
|
||||
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-set-location"sv);
|
||||
args = tr_variantDictAddDict(top, ARGUMENTS, 3);
|
||||
args = tr_variantDictAddDict(top, Arguments, 3);
|
||||
tr_variantDictAddStr(args, TR_KEY_location, optarg);
|
||||
tr_variantDictAddBool(args, TR_KEY_move, false);
|
||||
addIdArg(args, id, nullptr);
|
||||
|
@ -2897,7 +2895,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
tr_variant* top = tr_new0(tr_variant, 1);
|
||||
tr_variantInitDict(top, 2);
|
||||
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-start"sv);
|
||||
addIdArg(tr_variantDictAddDict(top, ARGUMENTS, 1), id, nullptr);
|
||||
addIdArg(tr_variantDictAddDict(top, Arguments, 1), id, nullptr);
|
||||
status |= flush(rpcurl, &top);
|
||||
}
|
||||
|
||||
|
@ -2915,7 +2913,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
tr_variant* top = tr_new0(tr_variant, 1);
|
||||
tr_variantInitDict(top, 2);
|
||||
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-stop"sv);
|
||||
addIdArg(tr_variantDictAddDict(top, ARGUMENTS, 1), id, nullptr);
|
||||
addIdArg(tr_variantDictAddDict(top, Arguments, 1), id, nullptr);
|
||||
status |= flush(rpcurl, &top);
|
||||
}
|
||||
|
||||
|
@ -2973,14 +2971,14 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
|
||||
if (tset != nullptr)
|
||||
{
|
||||
addIdArg(tr_variantDictFind(tset, ARGUMENTS), id, nullptr);
|
||||
addIdArg(tr_variantDictFind(tset, Arguments), id, nullptr);
|
||||
status |= flush(rpcurl, &tset);
|
||||
}
|
||||
|
||||
top = tr_new0(tr_variant, 1);
|
||||
tr_variantInitDict(top, 2);
|
||||
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-reannounce"sv);
|
||||
addIdArg(tr_variantDictAddDict(top, ARGUMENTS, 1), id, nullptr);
|
||||
addIdArg(tr_variantDictAddDict(top, Arguments, 1), id, nullptr);
|
||||
status |= flush(rpcurl, &top);
|
||||
break;
|
||||
}
|
||||
|
@ -2991,14 +2989,14 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
|
||||
if (tset != nullptr)
|
||||
{
|
||||
addIdArg(tr_variantDictFind(tset, ARGUMENTS), id, nullptr);
|
||||
addIdArg(tr_variantDictFind(tset, Arguments), id, nullptr);
|
||||
status |= flush(rpcurl, &tset);
|
||||
}
|
||||
|
||||
top = tr_new0(tr_variant, 1);
|
||||
tr_variantInitDict(top, 2);
|
||||
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-verify"sv);
|
||||
addIdArg(tr_variantDictAddDict(top, ARGUMENTS, 1), id, nullptr);
|
||||
addIdArg(tr_variantDictAddDict(top, Arguments, 1), id, nullptr);
|
||||
status |= flush(rpcurl, &top);
|
||||
break;
|
||||
}
|
||||
|
@ -3010,7 +3008,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
tr_variant* top = tr_new0(tr_variant, 1);
|
||||
tr_variantInitDict(top, 2);
|
||||
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-remove"sv);
|
||||
args = tr_variantDictAddDict(top, ARGUMENTS, 2);
|
||||
args = tr_variantDictAddDict(top, Arguments, 2);
|
||||
tr_variantDictAddBool(args, TR_KEY_delete_local_data, c == 840);
|
||||
addIdArg(args, id, nullptr);
|
||||
status |= flush(rpcurl, &top);
|
||||
|
@ -3023,7 +3021,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
tr_variant* top = tr_new0(tr_variant, 1);
|
||||
tr_variantInitDict(top, 2);
|
||||
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-set-location"sv);
|
||||
args = tr_variantDictAddDict(top, ARGUMENTS, 3);
|
||||
args = tr_variantDictAddDict(top, Arguments, 3);
|
||||
tr_variantDictAddStr(args, TR_KEY_location, optarg);
|
||||
tr_variantDictAddBool(args, TR_KEY_move, true);
|
||||
addIdArg(args, id, nullptr);
|
||||
|
@ -3048,7 +3046,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
|
||||
if (tset != nullptr)
|
||||
{
|
||||
addIdArg(tr_variantDictFind(tset, ARGUMENTS), id, nullptr);
|
||||
addIdArg(tr_variantDictFind(tset, Arguments), id, nullptr);
|
||||
status |= flush(rpcurl, &tset);
|
||||
}
|
||||
|
||||
|
@ -3146,9 +3144,9 @@ int tr_main(int argc, char* argv[])
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
tr_formatter_mem_init(MEM_K, MEM_K_STR, MEM_M_STR, MEM_G_STR, MEM_T_STR);
|
||||
tr_formatter_size_init(DISK_K, DISK_K_STR, DISK_M_STR, DISK_G_STR, DISK_T_STR);
|
||||
tr_formatter_speed_init(SPEED_K, SPEED_K_STR, SPEED_M_STR, SPEED_G_STR, SPEED_T_STR);
|
||||
tr_formatter_mem_init(MemK, MemKStr, MemMStr, MemGStr, MemTStr);
|
||||
tr_formatter_size_init(DiskK, DiskKStr, DiskMStr, DiskGStr, DiskTStr);
|
||||
tr_formatter_speed_init(SpeedK, SpeedKStr, SpeedMStr, SpeedGStr, SpeedTStr);
|
||||
|
||||
getHostAndPortAndRpcUrl(&argc, argv, &host, &port, &rpcurl);
|
||||
|
||||
|
@ -3159,7 +3157,7 @@ int tr_main(int argc, char* argv[])
|
|||
|
||||
if (std::empty(rpcurl))
|
||||
{
|
||||
rpcurl = tr_strvJoin(host, ":", std::to_string(port), DEFAULT_URL);
|
||||
rpcurl = tr_strvJoin(host, ":", std::to_string(port), DefaultUrl);
|
||||
}
|
||||
|
||||
return processArgs(rpcurl.c_str(), argc, (char const* const*)argv);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <array>
|
||||
#include <stdio.h> /* fprintf() */
|
||||
#include <string.h> /* strcmp(), strchr(), memcmp() */
|
||||
#include <stdlib.h> /* qsort() */
|
||||
|
@ -24,23 +25,20 @@
|
|||
|
||||
#include "units.h"
|
||||
|
||||
#define MY_NAME "transmission-show"
|
||||
#define TIMEOUT_SECS 30
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
static tr_option options[] = {
|
||||
{ 'm', "magnet", "Give a magnet link for the specified torrent", "m", false, nullptr },
|
||||
{ 's', "scrape", "Ask the torrent's trackers how many peers are in the torrent's swarm", "s", false, nullptr },
|
||||
{ 'u', "unsorted", "Do not sort files by name", "u", false, nullptr },
|
||||
{ 'V', "version", "Show version number and exit", "V", false, nullptr },
|
||||
{ 0, nullptr, nullptr, nullptr, false, nullptr }
|
||||
};
|
||||
static char constexpr MyName[] = "transmission-show";
|
||||
static char constexpr Usage[] = "Usage: transmission-show [options] <.torrent file>";
|
||||
|
||||
static char const* getUsage(void)
|
||||
{
|
||||
return "Usage: " MY_NAME " [options] <.torrent file>";
|
||||
}
|
||||
static auto constexpr TimeoutSecs = long{ 30 };
|
||||
|
||||
static auto constexpr Options = std::array<tr_option, 5>{
|
||||
{ { 'm', "magnet", "Give a magnet link for the specified torrent", "m", false, nullptr },
|
||||
{ 's', "scrape", "Ask the torrent's trackers how many peers are in the torrent's swarm", "s", false, nullptr },
|
||||
{ 'u', "unsorted", "Do not sort files by name", "u", false, nullptr },
|
||||
{ 'V', "version", "Show version number and exit", "V", false, nullptr },
|
||||
{ 0, nullptr, nullptr, nullptr, false, nullptr } }
|
||||
};
|
||||
|
||||
static bool magnetFlag = false;
|
||||
static bool scrapeFlag = false;
|
||||
|
@ -53,7 +51,7 @@ static int parseCommandLine(int argc, char const* const* argv)
|
|||
int c;
|
||||
char const* optarg;
|
||||
|
||||
while ((c = tr_getopt(getUsage(), argc, argv, options, &optarg)) != TR_OPT_DONE)
|
||||
while ((c = tr_getopt(Usage, argc, argv, std::data(Options), &optarg)) != TR_OPT_DONE)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
|
@ -207,7 +205,7 @@ static size_t writeFunc(void* ptr, size_t size, size_t nmemb, void* vbuf)
|
|||
static CURL* tr_curl_easy_init(struct evbuffer* writebuf)
|
||||
{
|
||||
CURL* curl = curl_easy_init();
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, MY_NAME "/" LONG_VERSION_STRING);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, tr_strvJoin(MyName, "/", LONG_VERSION_STRING).c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunc);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, writebuf);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
|
||||
|
@ -236,7 +234,7 @@ static void doScrape(tr_info const* inf)
|
|||
auto* const buf = evbuffer_new();
|
||||
auto* const curl = tr_curl_easy_init(buf);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, TIMEOUT_SECS);
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, TimeoutSecs);
|
||||
|
||||
auto const res = curl_easy_perform(curl);
|
||||
if (res != CURLE_OK)
|
||||
|
@ -324,7 +322,7 @@ int tr_main(int argc, char* argv[])
|
|||
|
||||
if (showVersion)
|
||||
{
|
||||
fprintf(stderr, "%s %s\n", MY_NAME, LONG_VERSION_STRING);
|
||||
fprintf(stderr, "%s %s\n", MyName, LONG_VERSION_STRING);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -332,7 +330,7 @@ int tr_main(int argc, char* argv[])
|
|||
if (filename == nullptr)
|
||||
{
|
||||
fprintf(stderr, "ERROR: No .torrent file specified.\n");
|
||||
tr_getopt_usage(MY_NAME, getUsage(), options);
|
||||
tr_getopt_usage(MyName, Usage, std::data(Options));
|
||||
fprintf(stderr, "\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue