diff --git a/cli/cli.cc b/cli/cli.cc index 0888f40cc..a5bcdff0a 100644 --- a/cli/cli.cc +++ b/cli/cli.cc @@ -321,7 +321,7 @@ int tr_main(int argc, char* argv[]) /* load the defaults from config file + libtransmission defaults */ auto const config_dir = getConfigDir(argc, (char const**)argv); - auto settings = tr_sessionLoadSettings(config_dir.c_str(), MyConfigName); + auto settings = tr_sessionLoadSettings(nullptr, config_dir.c_str(), MyConfigName); /* the command line overrides defaults */ if (parseCommandLine(&settings, argc, (char const**)argv) != 0) diff --git a/daemon/daemon.cc b/daemon/daemon.cc index 73ad54e34..dceb74702 100644 --- a/daemon/daemon.cc +++ b/daemon/daemon.cc @@ -6,7 +6,6 @@ #include #include #include /* printf */ -#include /* atoi */ #include #include /* std::back_inserter */ #include @@ -360,6 +359,14 @@ tr_rpc_callback_status on_rpc_callback(tr_session* /*session*/, tr_rpc_callback_ } return TR_RPC_OK; } + +tr_variant load_settings(char const* config_dir) +{ + auto app_defaults = tr_variant::make_map(); + tr_variantDictAddBool(&app_defaults, TR_KEY_rpc_enabled, true); + return tr_sessionLoadSettings(&app_defaults, config_dir, MyName); +} + } // namespace bool tr_daemon::reopen_log_file(char const* filename) @@ -394,7 +401,7 @@ bool tr_daemon::reopen_log_file(char const* filename) return true; } -void tr_daemon::report_status(void) +void tr_daemon::report_status() { double const up = tr_sessionGetRawSpeed_KBps(my_session_, TR_UP); double const dn = tr_sessionGetRawSpeed_KBps(my_session_, TR_DOWN); @@ -409,7 +416,7 @@ void tr_daemon::report_status(void) } } -void tr_daemon::periodic_update(void) +void tr_daemon::periodic_update() { pumpLogMessages(logfile_, logfile_flush_); report_status(); @@ -498,7 +505,10 @@ bool tr_daemon::parse_args(int argc, char const* const* argv, bool* dump_setting break; case 'p': - tr_variantDictAddInt(&settings_, TR_KEY_rpc_port, atoi(optstr)); + if (auto const rpc_port = tr_num_parse(optstr); rpc_port) + { + tr_variantDictAddInt(&settings_, TR_KEY_rpc_port, *rpc_port); + } break; case 't': @@ -522,7 +532,10 @@ bool tr_daemon::parse_args(int argc, char const* const* argv, bool* dump_setting break; case 'P': - tr_variantDictAddInt(&settings_, TR_KEY_peer_port, atoi(optstr)); + if (auto const peer_port = tr_num_parse(optstr); peer_port) + { + tr_variantDictAddInt(&settings_, TR_KEY_peer_port, *peer_port); + } break; case 'm': @@ -534,11 +547,17 @@ bool tr_daemon::parse_args(int argc, char const* const* argv, bool* dump_setting break; case 'L': - tr_variantDictAddInt(&settings_, TR_KEY_peer_limit_global, atoi(optstr)); + if (auto const peer_limit_global = tr_num_parse(optstr); peer_limit_global && *peer_limit_global >= 0) + { + tr_variantDictAddInt(&settings_, TR_KEY_peer_limit_global, *peer_limit_global); + } break; case 'l': - tr_variantDictAddInt(&settings_, TR_KEY_peer_limit_per_torrent, atoi(optstr)); + if (auto const peer_limit_tor = tr_num_parse(optstr); peer_limit_tor && *peer_limit_tor >= 0) + { + tr_variantDictAddInt(&settings_, TR_KEY_peer_limit_per_torrent, *peer_limit_tor); + } break; case 800: @@ -570,7 +589,10 @@ bool tr_daemon::parse_args(int argc, char const* const* argv, bool* dump_setting break; case 953: - tr_variantDictAddReal(&settings_, TR_KEY_ratio_limit, atof(optstr)); + if (auto const ratio_limit = tr_num_parse(optstr); optstr) + { + tr_variantDictAddReal(&settings_, TR_KEY_ratio_limit, *ratio_limit); + } tr_variantDictAddBool(&settings_, TR_KEY_ratio_limit_enabled, true); break; @@ -640,7 +662,7 @@ bool tr_daemon::parse_args(int argc, char const* const* argv, bool* dump_setting return true; } -void tr_daemon::reconfigure(void) +void tr_daemon::reconfigure() { if (my_session_ == nullptr) { @@ -660,35 +682,24 @@ void tr_daemon::reconfigure(void) configDir = tr_sessionGetConfigDir(my_session_); tr_logAddInfo(fmt::format(_("Reloading settings from '{path}'"), fmt::arg("path", configDir))); - auto newsettings = tr_variant::make_map(); - tr_variantDictAddBool(&newsettings, TR_KEY_rpc_enabled, true); - newsettings.merge(tr_sessionLoadSettings(configDir, MyName)); - - tr_sessionSet(my_session_, newsettings); + tr_sessionSet(my_session_, load_settings(configDir)); tr_sessionReloadBlocklists(my_session_); } } -void tr_daemon::stop(void) +void tr_daemon::stop() { event_base_loopexit(ev_base_, nullptr); } int tr_daemon::start([[maybe_unused]] bool foreground) { - bool boolVal; - bool pidfile_created = false; - tr_session* session = nullptr; - struct event* status_ev = nullptr; - struct event* sig_ev = nullptr; - auto watchdir = std::unique_ptr{}; - char const* const cdir = this->config_dir_.c_str(); - sd_notifyf(0, "MAINPID=%d\n", (int)getpid()); /* setup event state */ ev_base_ = event_base_new(); + event* sig_ev = nullptr; if (ev_base_ == nullptr || !setup_signals(sig_ev)) { auto const error_code = errno; @@ -702,7 +713,8 @@ int tr_daemon::start([[maybe_unused]] bool foreground) } /* start the session */ - session = tr_sessionInit(cdir, true, settings_); + auto const* const cdir = this->config_dir_.c_str(); + auto* session = tr_sessionInit(cdir, true, settings_); tr_sessionSetRPCCallback(session, on_rpc_callback, this); tr_logAddInfo(fmt::format(_("Loading settings from '{path}'"), fmt::arg("path", cdir))); tr_sessionSaveSettings(session, cdir, settings_); @@ -710,6 +722,7 @@ int tr_daemon::start([[maybe_unused]] bool foreground) auto sv = std::string_view{}; (void)tr_variantDictFindStrView(&settings_, key_pidfile_, &sv); auto const sz_pid_filename = std::string{ sv }; + auto pidfile_created = false; if (!std::empty(sz_pid_filename)) { auto error = tr_error{}; @@ -737,7 +750,7 @@ int tr_daemon::start([[maybe_unused]] bool foreground) } } - if (tr_variantDictFindBool(&settings_, TR_KEY_rpc_authentication_required, &boolVal) && boolVal) + if (auto tmp_bool = false; tr_variantDictFindBool(&settings_, TR_KEY_rpc_authentication_required, &tmp_bool) && tmp_bool) { tr_logAddInfo(_("Requiring authentication")); } @@ -751,7 +764,8 @@ int tr_daemon::start([[maybe_unused]] bool foreground) } /* maybe add a watchdir */ - if (tr_variantDictFindBool(&settings_, TR_KEY_watch_dir_enabled, &boolVal) && boolVal) + auto watchdir = std::unique_ptr{}; + if (auto tmp_bool = false; tr_variantDictFindBool(&settings_, TR_KEY_watch_dir_enabled, &tmp_bool) && tmp_bool) { auto force_generic = bool{ false }; (void)tr_variantDictFindBool(&settings_, key_watch_dir_force_generic_, &force_generic); @@ -796,6 +810,7 @@ int tr_daemon::start([[maybe_unused]] bool foreground) #endif /* Create new timer event to report daemon status */ + event* status_ev; { constexpr auto one_sec = timeval{ 1, 0 }; // 1 second status_ev = event_new(ev_base_, -1, EV_PERSIST, &::periodic_update, this); @@ -882,9 +897,7 @@ bool tr_daemon::init(int argc, char const* const argv[], bool* foreground, int* config_dir_ = getConfigDir(argc, argv); /* load settings from defaults + config file */ - settings_ = tr_variant::make_map(); - tr_variantDictAddBool(&settings_, TR_KEY_rpc_enabled, true); - settings_.merge(tr_sessionLoadSettings(config_dir_.c_str(), MyName)); + settings_ = load_settings(config_dir_.c_str()); bool dumpSettings; @@ -893,7 +906,7 @@ bool tr_daemon::init(int argc, char const* const argv[], bool* foreground, int* /* overwrite settings from the command line */ if (!parse_args(argc, argv, &dumpSettings, foreground, ret)) { - goto EXIT_EARLY; + return false; } if (*foreground && logfile_ == TR_BAD_SYS_FILE) @@ -905,13 +918,10 @@ bool tr_daemon::init(int argc, char const* const argv[], bool* foreground, int* if (dumpSettings) { fmt::print("{:s}\n", tr_variant_serde::json().to_string(settings_)); - goto EXIT_EARLY; + return false; } return true; - -EXIT_EARLY: - return false; } void tr_daemon::handle_error(tr_error const& error) const diff --git a/gtk/Prefs.cc b/gtk/Prefs.cc index de362d645..4125e9e9e 100644 --- a/gtk/Prefs.cc +++ b/gtk/Prefs.cc @@ -108,8 +108,8 @@ tr_variant& getPrefs() if (!settings.has_value()) { - settings = get_default_app_settings(); - settings.merge(tr_sessionLoadSettings(gl_confdir.c_str(), nullptr)); + auto const app_defaults = get_default_app_settings(); + settings.merge(tr_sessionLoadSettings(&app_defaults, gl_confdir.c_str(), nullptr)); ensure_sound_cmd_is_a_list(&settings); } diff --git a/libtransmission/session.cc b/libtransmission/session.cc index 2d89fc1d4..7be1ec363 100644 --- a/libtransmission/session.cc +++ b/libtransmission/session.cc @@ -476,10 +476,16 @@ tr_variant tr_sessionGetSettings(tr_session const* session) return settings; } -tr_variant tr_sessionLoadSettings(char const* config_dir, char const* app_name) +tr_variant tr_sessionLoadSettings(tr_variant const* app_defaults, char const* config_dir, char const* app_name) { auto settings = tr_sessionGetDefaultSettings(); + // if app defaults are provided, override libtransmission defaults + if (app_defaults != nullptr && app_defaults->holds_alternative()) + { + settings.merge(*app_defaults); + } + // if a settings file exists, use it to override the defaults if (auto const filename = fmt::format( "{:s}/settings.json", @@ -554,11 +560,11 @@ tr_session* tr_sessionInit(char const* config_dir, bool message_queueing_enabled // - client settings // - previous session's values in settings.json // - hardcoded defaults - auto settings = tr_sessionLoadSettings(config_dir, nullptr); + auto settings = tr_sessionLoadSettings(nullptr, config_dir, nullptr); settings.merge(client_settings); // if logging is desired, start it now before doing more work - if (auto const* settings_map = client_settings.get_if(); settings_map != nullptr) + if (auto const* settings_map = settings.get_if(); settings_map != nullptr) { if (auto const* val = settings_map->find_if(TR_KEY_message_level); val != nullptr) { diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index 7ceb95ce5..2c3730cb6 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -175,6 +175,7 @@ tr_variant tr_sessionGetSettings(tr_session const* session); * * TODO: if we ever make libtransmissionapp, this would go there. * + * @param app_defaults tr_variant containing the app defaults * @param config_dir the configuration directory to find settings.json * @param app_name if config_dir is empty, app_name is used to find the default dir. * @return the loaded settings @@ -182,7 +183,7 @@ tr_variant tr_sessionGetSettings(tr_session const* session); * @see `tr_sessionInit()` * @see `tr_sessionSaveSettings()` */ -tr_variant tr_sessionLoadSettings(char const* config_dir, char const* app_name); +tr_variant tr_sessionLoadSettings(tr_variant const* app_defaults, char const* config_dir, char const* app_name); /** * Add the session's configuration settings to the benc dictionary diff --git a/qt/Prefs.cc b/qt/Prefs.cc index 435beafbc..bedc63b91 100644 --- a/qt/Prefs.cc +++ b/qt/Prefs.cc @@ -227,13 +227,13 @@ Prefs::Prefs(QString config_dir) // when the application exits. temporary_prefs_.insert(FILTER_TEXT); - auto top = get_default_app_settings(); - top.merge(tr_sessionLoadSettings(config_dir_.toUtf8().constData(), nullptr)); - ensureSoundCommandIsAList(&top); + auto const app_defaults = get_default_app_settings(); + auto settings = tr_sessionLoadSettings(&app_defaults, config_dir_.toUtf8().constData(), nullptr); + ensureSoundCommandIsAList(&settings); for (int i = 0; i < PREFS_COUNT; ++i) { - tr_variant const* b = tr_variantDictFind(&top, Items[i].key); + tr_variant const* b = tr_variantDictFind(&settings, Items[i].key); switch (Items[i].type) { diff --git a/qt/Session.cc b/qt/Session.cc index 292d388e0..683b48b4a 100644 --- a/qt/Session.cc +++ b/qt/Session.cc @@ -357,7 +357,7 @@ void Session::start() } else { - auto const settings = tr_sessionLoadSettings(config_dir_.toUtf8().constData(), "qt"); + auto const settings = tr_sessionLoadSettings(nullptr, config_dir_.toUtf8().constData(), "qt"); session_ = tr_sessionInit(config_dir_.toUtf8().constData(), true, settings); rpc_.start(session_);