/* * This file Copyright (C) 2008-2014 Mnemosyne LLC * * It may be used under the GNU GPL versions 2 or 3 * or any future license endorsed by Mnemosyne LLC. * */ #include #include #include /* isspace */ #include #include #include #include #include /* strcmp */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std::literals; #define SPEED_K_STR "kB/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"; /*** **** **** Display Utilities **** ***/ static void etaToString(char* buf, size_t buflen, int64_t eta) { if (eta < 0) { tr_snprintf(buf, buflen, "Unknown"); } else if (eta < 60) { tr_snprintf(buf, buflen, "%" PRId64 " sec", eta); } else if (eta < (60 * 60)) { tr_snprintf(buf, buflen, "%" PRId64 " min", eta / 60); } else if (eta < (60 * 60 * 24)) { tr_snprintf(buf, buflen, "%" PRId64 " hrs", eta / (60 * 60)); } else { tr_snprintf(buf, buflen, "%" PRId64 " days", eta / (60 * 60 * 24)); } } static char* tr_strltime(char* buf, int seconds, size_t buflen) { char b[128]; char h[128]; char m[128]; char s[128]; char t[128]; if (seconds < 0) { seconds = 0; } auto const total_seconds = seconds; auto const days = seconds / 86400; auto const hours = (seconds % 86400) / 3600; auto const minutes = (seconds % 3600) / 60; seconds = (seconds % 3600) % 60; tr_snprintf(h, sizeof(h), "%d %s", hours, hours == 1 ? "hour" : "hours"); tr_snprintf(m, sizeof(m), "%d %s", minutes, minutes == 1 ? "minute" : "minutes"); tr_snprintf(s, sizeof(s), "%d %s", seconds, seconds == 1 ? "second" : "seconds"); tr_snprintf(t, sizeof(t), "%d %s", total_seconds, total_seconds == 1 ? "second" : "seconds"); if (days != 0) { char d[128]; tr_snprintf(d, sizeof(d), "%d %s", days, days == 1 ? "day" : "days"); if (days >= 4 || hours == 0) { tr_strlcpy(b, d, sizeof(b)); } else { tr_snprintf(b, sizeof(b), "%s, %s", d, h); } } else if (hours != 0) { if (hours >= 4 || minutes == 0) { tr_strlcpy(b, h, sizeof(b)); } else { tr_snprintf(b, sizeof(b), "%s, %s", h, m); } } else if (minutes != 0) { if (minutes >= 4 || seconds == 0) { tr_strlcpy(b, m, sizeof(b)); } else { tr_snprintf(b, sizeof(b), "%s, %s", m, s); } } else { tr_strlcpy(b, s, sizeof(b)); } tr_snprintf(buf, buflen, "%s (%s)", b, t); return buf; } static char* strlpercent(char* buf, double x, size_t buflen) { return tr_strpercent(buf, x, buflen); } static char* strlratio2(char* buf, double ratio, size_t buflen) { return tr_strratio(buf, buflen, ratio, "Inf"); } static char* strlratio(char* buf, int64_t numerator, int64_t denominator, size_t buflen) { double ratio; if (denominator != 0) { ratio = numerator / (double)denominator; } else if (numerator != 0) { ratio = TR_RATIO_INF; } else { ratio = TR_RATIO_NA; } return strlratio2(buf, ratio, buflen); } static char* strlmem(char* buf, int64_t bytes, size_t buflen) { if (bytes == 0) { tr_strlcpy(buf, "None", buflen); } else { tr_formatter_mem_B(buf, bytes, buflen); } return buf; } static char* strlsize(char* buf, int64_t bytes, size_t buflen) { if (bytes < 0) { tr_strlcpy(buf, "Unknown", buflen); } else if (bytes == 0) { tr_strlcpy(buf, "None", buflen); } else { tr_formatter_size_B(buf, bytes, buflen); } return buf; } enum { TAG_SESSION, TAG_STATS, TAG_DETAILS, TAG_FILES, TAG_LIST, TAG_PEERS, TAG_PIECES, TAG_PORTTEST, TAG_TORRENT_ADD, TAG_TRACKERS }; /*** **** **** Command-Line Arguments **** ***/ static auto constexpr Options = std::array{ { { '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, "" }, { 973, "alt-speed-uplimit", "max alternate upload speed (in " SPEED_K_STR ")", "asu", true, "" }, { 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, "