diff --git a/libtransmission/session.c b/libtransmission/session.c index 398ce7d76..faeda5dd0 100644 --- a/libtransmission/session.c +++ b/libtransmission/session.c @@ -373,7 +373,7 @@ void tr_sessionGetDefaultSettings(tr_variant* d) tr_variantDictAddBool(d, TR_KEY_rpc_whitelist_enabled, true); tr_variantDictAddStr(d, TR_KEY_rpc_host_whitelist, TR_DEFAULT_RPC_HOST_WHITELIST); tr_variantDictAddBool(d, TR_KEY_rpc_host_whitelist_enabled, true); - tr_variantDictAddInt(d, TR_KEY_rpc_port, atoi(TR_DEFAULT_RPC_PORT_STR)); + tr_variantDictAddInt(d, TR_KEY_rpc_port, TR_DEFAULT_RPC_PORT); tr_variantDictAddStr(d, TR_KEY_rpc_url, TR_DEFAULT_RPC_URL_STR); tr_variantDictAddBool(d, TR_KEY_scrape_paused_torrents_enabled, true); tr_variantDictAddStr(d, TR_KEY_script_torrent_done_filename, ""); diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index 7ee6f8b79..f5e82129c 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -113,6 +113,7 @@ char const* tr_getDefaultDownloadDir(void); #define TR_DEFAULT_RPC_WHITELIST "127.0.0.1,::1" #define TR_DEFAULT_RPC_HOST_WHITELIST "" #define TR_DEFAULT_RPC_PORT_STR "9091" +#define TR_DEFAULT_RPC_PORT 9091 #define TR_DEFAULT_RPC_URL_STR "/transmission/" #define TR_DEFAULT_PEER_PORT_STR "51413" #define TR_DEFAULT_PEER_SOCKET_TOS_STR "default" diff --git a/qt/CMakeLists.txt b/qt/CMakeLists.txt index 65f170066..f883d483f 100644 --- a/qt/CMakeLists.txt +++ b/qt/CMakeLists.txt @@ -47,6 +47,7 @@ set(${PROJECT_NAME}_SOURCES TrackerModel.cc TrackerModelFilter.cc Utils.cc + VariantHelpers.cc WatchDir.cc ) @@ -108,6 +109,7 @@ set(${PROJECT_NAME}_HEADERS TrackerModelFilter.h Typedefs.h Utils.h + VariantHelpers.h WatchDir.h ) diff --git a/qt/FreeSpaceLabel.cc b/qt/FreeSpaceLabel.cc index 83038d967..3bf0379b4 100644 --- a/qt/FreeSpaceLabel.cc +++ b/qt/FreeSpaceLabel.cc @@ -15,6 +15,10 @@ #include "FreeSpaceLabel.h" #include "RpcQueue.h" #include "Session.h" +#include "VariantHelpers.h" + +using ::trqt::variant_helpers::dictAdd; +using ::trqt::variant_helpers::dictFind; namespace { @@ -65,7 +69,7 @@ void FreeSpaceLabel::onTimer() tr_variant args; tr_variantInitDict(&args, 1); - tr_variantDictAddStr(&args, TR_KEY_path, path_.toUtf8().constData()); + dictAdd(&args, TR_KEY_path, path_); auto* q = new RpcQueue(); @@ -76,14 +80,11 @@ void FreeSpaceLabel::onTimer() q->add([this](RpcResponse const& r) { - QString str; - // update the label - int64_t bytes = -1; - - if (tr_variantDictFindInt(r.args.get(), TR_KEY_size_bytes, &bytes) && bytes >= 0) + auto const bytes = dictFind(r.args.get(), TR_KEY_size_bytes); + if (bytes && *bytes > 1) { - setText(tr("%1 free").arg(Formatter::sizeToString(bytes))); + setText(tr("%1 free").arg(Formatter::sizeToString(*bytes))); } else { @@ -91,11 +92,8 @@ void FreeSpaceLabel::onTimer() } // update the tooltip - size_t len = 0; - char const* path = nullptr; - tr_variantDictFindStr(r.args.get(), TR_KEY_path, &path, &len); - str = QString::fromUtf8(path, len); - setToolTip(QDir::toNativeSeparators(str)); + auto const path = dictFind(r.args.get(), TR_KEY_path); + setToolTip(QDir::toNativeSeparators(path ? *path : QString())); timer_.start(); }); diff --git a/qt/OptionsDialog.cc b/qt/OptionsDialog.cc index 8c0e792d5..60c1c3f4e 100644 --- a/qt/OptionsDialog.cc +++ b/qt/OptionsDialog.cc @@ -20,6 +20,10 @@ #include "Session.h" #include "Torrent.h" #include "Utils.h" +#include "VariantHelpers.h" + +using ::trqt::variant_helpers::dictAdd; +using ::trqt::variant_helpers::listAdd; /*** **** @@ -260,15 +264,15 @@ void OptionsDialog::onAccepted() download_dir = ui_.destinationEdit->text(); } - tr_variantDictAddStr(&args, TR_KEY_download_dir, download_dir.toUtf8().constData()); + dictAdd(&args, TR_KEY_download_dir, download_dir); // paused - tr_variantDictAddBool(&args, TR_KEY_paused, !ui_.startCheck->isChecked()); + dictAdd(&args, TR_KEY_paused, !ui_.startCheck->isChecked()); // priority int const index = ui_.priorityCombo->currentIndex(); int const priority = ui_.priorityCombo->itemData(index).toInt(); - tr_variantDictAddInt(&args, TR_KEY_bandwidthPriority, priority); + dictAdd(&args, TR_KEY_bandwidthPriority, priority); // files-unwanted int count = wanted_.count(false); @@ -281,7 +285,7 @@ void OptionsDialog::onAccepted() { if (!wanted_.at(i)) { - tr_variantListAddInt(l, i); + listAdd(l, i); } } } @@ -297,7 +301,7 @@ void OptionsDialog::onAccepted() { if (priorities_.at(i) == TR_PRI_LOW) { - tr_variantListAddInt(l, i); + listAdd(l, i); } } } @@ -313,7 +317,7 @@ void OptionsDialog::onAccepted() { if (priorities_.at(i) == TR_PRI_HIGH) { - tr_variantListAddInt(l, i); + listAdd(l, i); } } } diff --git a/qt/Prefs.cc b/qt/Prefs.cc index 6a8823894..c332e83d7 100644 --- a/qt/Prefs.cc +++ b/qt/Prefs.cc @@ -20,6 +20,10 @@ #include "CustomVariantType.h" #include "Prefs.h" #include "Utils.h" +#include "VariantHelpers.h" + +using ::trqt::variant_helpers::dictAdd; +using ::trqt::variant_helpers::getValue; /*** **** @@ -150,69 +154,78 @@ Prefs::Prefs(QString config_dir) : for (int i = 0; i < PREFS_COUNT; ++i) { - double d; - bool bool_val; - int64_t int_val; - char const* str; - size_t str_len; tr_variant* b(tr_variantDictFind(&top, Items[i].key)); switch (Items[i].type) { case QVariant::Int: - if (tr_variantGetInt(b, &int_val)) { - values_[i].setValue(static_cast(int_val)); + auto const value = getValue(b); + if (value) + { + values_[i].setValue(*value); + } } - break; case CustomVariantType::SortModeType: - if (tr_variantGetStr(b, &str, nullptr)) { - values_[i] = QVariant::fromValue(SortMode(QString::fromUtf8(str))); + auto const value = getValue(b); + if (value) + { + values_[i] = QVariant::fromValue(SortMode(*value)); + } } - break; case CustomVariantType::FilterModeType: - if (tr_variantGetStr(b, &str, nullptr)) { - values_[i] = QVariant::fromValue(FilterMode(QString::fromUtf8(str))); + auto const value = getValue(b); + if (value) + { + values_[i] = QVariant::fromValue(FilterMode(*value)); + } } - break; case QVariant::String: - if (tr_variantGetStr(b, &str, &str_len)) { - values_[i].setValue(QString::fromUtf8(str, str_len)); + auto const value = getValue(b); + if (value) + { + values_[i].setValue(*value); + } } - break; case QVariant::Bool: - if (tr_variantGetBool(b, &bool_val)) { - values_[i].setValue(static_cast(bool_val)); + auto const value = getValue(b); + if (value) + { + values_[i].setValue(*value); + } } - break; case QVariant::Double: - if (tr_variantGetReal(b, &d)) { - values_[i].setValue(d); + auto const value = getValue(b); + if (value) + { + values_[i].setValue(*value); + } } - break; case QVariant::DateTime: - if (tr_variantGetInt(b, &int_val)) { - values_[i].setValue(QDateTime::fromTime_t(int_val)); + auto const value = getValue(b); + if (value) + { + values_[i].setValue(QDateTime::fromTime_t(*value)); + } } - break; default: @@ -243,44 +256,31 @@ Prefs::~Prefs() switch (Items[i].type) { case QVariant::Int: - tr_variantDictAddInt(¤t_settings, key, val.toInt()); + dictAdd(¤t_settings, key, val.toInt()); break; case CustomVariantType::SortModeType: - tr_variantDictAddStr(¤t_settings, key, val.value().name().toUtf8().constData()); + dictAdd(¤t_settings, key, val.value().name()); break; case CustomVariantType::FilterModeType: - tr_variantDictAddStr(¤t_settings, key, val.value().name().toUtf8().constData()); + dictAdd(¤t_settings, key, val.value().name()); break; case QVariant::String: - { - QByteArray const ba(val.toByteArray()); - char const* s = ba.constData(); - - if (Utils::isValidUtf8(s)) - { - tr_variantDictAddStr(¤t_settings, key, s); - } - else - { - tr_variantDictAddStr(¤t_settings, key, val.toString().toUtf8().constData()); - } - - break; - } + dictAdd(¤t_settings, key, val.toString()); + break; case QVariant::Bool: - tr_variantDictAddBool(¤t_settings, key, val.toBool()); + dictAdd(¤t_settings, key, val.toBool()); break; case QVariant::Double: - tr_variantDictAddReal(¤t_settings, key, val.toDouble()); + dictAdd(¤t_settings, key, val.toDouble()); break; case QVariant::DateTime: - tr_variantDictAddInt(¤t_settings, key, val.toDateTime().toTime_t()); + dictAdd(¤t_settings, key, val.toDateTime().toTime_t()); break; default: @@ -313,45 +313,45 @@ Prefs::~Prefs() void Prefs::initDefaults(tr_variant* d) { tr_variantDictReserve(d, 38); - tr_variantDictAddBool(d, TR_KEY_blocklist_updates_enabled, true); - tr_variantDictAddBool(d, TR_KEY_compact_view, false); - tr_variantDictAddBool(d, TR_KEY_inhibit_desktop_hibernation, false); - tr_variantDictAddBool(d, TR_KEY_prompt_before_exit, true); - tr_variantDictAddBool(d, TR_KEY_remote_session_enabled, false); - tr_variantDictAddBool(d, TR_KEY_remote_session_requres_authentication, false); - tr_variantDictAddBool(d, TR_KEY_show_backup_trackers, false); - tr_variantDictAddBool(d, TR_KEY_show_extra_peer_details, false); - tr_variantDictAddBool(d, TR_KEY_show_filterbar, true); - tr_variantDictAddBool(d, TR_KEY_show_notification_area_icon, false); - tr_variantDictAddBool(d, TR_KEY_start_minimized, false); - tr_variantDictAddBool(d, TR_KEY_show_options_window, true); - tr_variantDictAddBool(d, TR_KEY_show_statusbar, true); - tr_variantDictAddBool(d, TR_KEY_show_toolbar, true); - tr_variantDictAddBool(d, TR_KEY_show_tracker_scrapes, false); - tr_variantDictAddBool(d, TR_KEY_sort_reversed, false); - tr_variantDictAddBool(d, TR_KEY_torrent_added_notification_enabled, true); - tr_variantDictAddBool(d, TR_KEY_torrent_complete_notification_enabled, true); - tr_variantDictAddStr(d, TR_KEY_torrent_complete_sound_command, + dictAdd(d, TR_KEY_blocklist_updates_enabled, true); + dictAdd(d, TR_KEY_compact_view, false); + dictAdd(d, TR_KEY_inhibit_desktop_hibernation, false); + dictAdd(d, TR_KEY_prompt_before_exit, true); + dictAdd(d, TR_KEY_remote_session_enabled, false); + dictAdd(d, TR_KEY_remote_session_requres_authentication, false); + dictAdd(d, TR_KEY_show_backup_trackers, false); + dictAdd(d, TR_KEY_show_extra_peer_details, false); + dictAdd(d, TR_KEY_show_filterbar, true); + dictAdd(d, TR_KEY_show_notification_area_icon, false); + dictAdd(d, TR_KEY_start_minimized, false); + dictAdd(d, TR_KEY_show_options_window, true); + dictAdd(d, TR_KEY_show_statusbar, true); + dictAdd(d, TR_KEY_show_toolbar, true); + dictAdd(d, TR_KEY_show_tracker_scrapes, false); + dictAdd(d, TR_KEY_sort_reversed, false); + dictAdd(d, TR_KEY_torrent_added_notification_enabled, true); + dictAdd(d, TR_KEY_torrent_complete_notification_enabled, true); + dictAdd(d, TR_KEY_torrent_complete_sound_command, "canberra-gtk-play -i complete-download -d 'transmission torrent downloaded'"); - tr_variantDictAddBool(d, TR_KEY_torrent_complete_sound_enabled, true); - tr_variantDictAddBool(d, TR_KEY_user_has_given_informed_consent, false); - tr_variantDictAddBool(d, TR_KEY_watch_dir_enabled, false); - tr_variantDictAddInt(d, TR_KEY_blocklist_date, 0); - tr_variantDictAddInt(d, TR_KEY_main_window_height, 500); - tr_variantDictAddInt(d, TR_KEY_main_window_width, 300); - tr_variantDictAddInt(d, TR_KEY_main_window_x, 50); - tr_variantDictAddInt(d, TR_KEY_main_window_y, 50); - tr_variantDictAddInt(d, TR_KEY_remote_session_port, strtol(TR_DEFAULT_RPC_PORT_STR, nullptr, 0)); - tr_variantDictAddStr(d, TR_KEY_download_dir, tr_getDefaultDownloadDir()); - tr_variantDictAddStr(d, TR_KEY_filter_mode, "all"); - tr_variantDictAddStr(d, TR_KEY_main_window_layout_order, "menu,toolbar,filter,list,statusbar"); - tr_variantDictAddStr(d, TR_KEY_open_dialog_dir, QDir::home().absolutePath().toUtf8()); - tr_variantDictAddStr(d, TR_KEY_remote_session_host, "localhost"); - tr_variantDictAddStr(d, TR_KEY_remote_session_password, ""); - tr_variantDictAddStr(d, TR_KEY_remote_session_username, ""); - tr_variantDictAddStr(d, TR_KEY_sort_mode, "sort-by-name"); - tr_variantDictAddStr(d, TR_KEY_statusbar_stats, "total-ratio"); - tr_variantDictAddStr(d, TR_KEY_watch_dir, tr_getDefaultDownloadDir()); + dictAdd(d, TR_KEY_torrent_complete_sound_enabled, true); + dictAdd(d, TR_KEY_user_has_given_informed_consent, false); + dictAdd(d, TR_KEY_watch_dir_enabled, false); + dictAdd(d, TR_KEY_blocklist_date, 0); + dictAdd(d, TR_KEY_main_window_height, 500); + dictAdd(d, TR_KEY_main_window_width, 300); + dictAdd(d, TR_KEY_main_window_x, 50); + dictAdd(d, TR_KEY_main_window_y, 50); + dictAdd(d, TR_KEY_remote_session_port, TR_DEFAULT_RPC_PORT); + dictAdd(d, TR_KEY_download_dir, tr_getDefaultDownloadDir()); + dictAdd(d, TR_KEY_filter_mode, "all"); + dictAdd(d, TR_KEY_main_window_layout_order, "menu,toolbar,filter,list,statusbar"); + dictAdd(d, TR_KEY_open_dialog_dir, QDir::home().absolutePath().toUtf8()); + dictAdd(d, TR_KEY_remote_session_host, "localhost"); + dictAdd(d, TR_KEY_remote_session_password, ""); + dictAdd(d, TR_KEY_remote_session_username, ""); + dictAdd(d, TR_KEY_sort_mode, "sort-by-name"); + dictAdd(d, TR_KEY_statusbar_stats, "total-ratio"); + dictAdd(d, TR_KEY_watch_dir, tr_getDefaultDownloadDir()); } /*** diff --git a/qt/Prefs.h b/qt/Prefs.h index 0e8615b41..24040ac8c 100644 --- a/qt/Prefs.h +++ b/qt/Prefs.h @@ -144,11 +144,6 @@ public: return !isCore(key); } - char const* keyStr(int i) const - { - return tr_quark_get_string(Items[i].key, nullptr); - } - tr_quark getKey(int i) const { return Items[i].key; @@ -204,8 +199,7 @@ private: void initDefaults(tr_variant*); - // Intentionally not implemented - void set(int key, char const* value); + void set(int key, char const* value) = delete; QString const config_dir_; diff --git a/qt/RpcClient.cc b/qt/RpcClient.cc index ce44f7ce3..63b94cbad 100644 --- a/qt/RpcClient.cc +++ b/qt/RpcClient.cc @@ -21,12 +21,17 @@ #include // LONG_VERSION_STRING #include "RpcClient.h" +#include "VariantHelpers.h" // #define DEBUG_HTTP #define REQUEST_DATA_PROPERTY_KEY "requestData" #define REQUEST_FUTUREINTERFACE_PROPERTY_KEY "requestReplyFutureInterface" +using ::trqt::variant_helpers::dictAdd; +using ::trqt::variant_helpers::dictFind; +using ::trqt::variant_helpers::variantInit; + namespace { @@ -94,14 +99,16 @@ QUrl const& RpcClient::url() const RpcResponseFuture RpcClient::exec(tr_quark method, tr_variant* args) { - return exec(tr_quark_get_string(method, nullptr), args); + auto len = size_t{}; + auto const* str = tr_quark_get_string(method, &len); + return exec(std::string_view(str, len), args); } -RpcResponseFuture RpcClient::exec(char const* method, tr_variant* args) +RpcResponseFuture RpcClient::exec(std::string_view method, tr_variant* args) { TrVariantPtr json = createVariant(); tr_variantInitDict(json.get(), 3); - tr_variantDictAddStr(json.get(), TR_KEY_method, method); + dictAdd(json.get(), TR_KEY_method, method); if (args != nullptr) { @@ -162,7 +169,7 @@ void RpcClient::sendLocalRequest(TrVariantPtr json, QFutureInterface promise; promise.setExpectedResultCount(1); @@ -205,7 +212,7 @@ void RpcClient::localSessionCallback(tr_session* s, tr_variant* response, void* TrVariantPtr json = createVariant(); *json = *response; - tr_variantInitBool(response, false); + variantInit(response, false); // this callback is invoked in the libtransmission thread, so we don't want // to process the response here... let's push it over to the Qt thread. @@ -281,26 +288,19 @@ void RpcClient::localRequestFinished(TrVariantPtr response) int64_t RpcClient::parseResponseTag(tr_variant& json) { - int64_t tag; - - if (!tr_variantDictFindInt(&json, TR_KEY_tag, &tag)) - { - tag = -1; - } - - return tag; + auto const tag = dictFind(&json, TR_KEY_tag); + return tag ? *tag : -1; } RpcResponse RpcClient::parseResponseData(tr_variant& json) { RpcResponse ret; - char const* result; - - if (tr_variantDictFindStr(&json, TR_KEY_result, &result, nullptr)) + auto const result = dictFind(&json, TR_KEY_result); + if (result) { - ret.result = QString::fromUtf8(result); - ret.success = std::strcmp(result, "success") == 0; + ret.result = *result; + ret.success = *result == QStringLiteral("success"); } tr_variant* args; @@ -309,7 +309,7 @@ RpcResponse RpcClient::parseResponseData(tr_variant& json) { ret.args = createVariant(); *ret.args = *args; - tr_variantInitBool(args, false); + variantInit(args, false); } return ret; diff --git a/qt/RpcClient.h b/qt/RpcClient.h index 99048cccf..8e134241f 100644 --- a/qt/RpcClient.h +++ b/qt/RpcClient.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include @@ -62,7 +63,7 @@ public: QUrl const& url() const; RpcResponseFuture exec(tr_quark method, tr_variant* args); - RpcResponseFuture exec(char const* method, tr_variant* args); + RpcResponseFuture exec(std::string_view method, tr_variant* args); signals: void httpAuthenticationRequired(); diff --git a/qt/Session.cc b/qt/Session.cc index 07ef738d2..ac2512b3f 100644 --- a/qt/Session.cc +++ b/qt/Session.cc @@ -34,6 +34,12 @@ #include "SessionDialog.h" #include "Torrent.h" #include "Utils.h" +#include "VariantHelpers.h" + +using ::trqt::variant_helpers::dictAdd; +using ::trqt::variant_helpers::dictFind; +using ::trqt::variant_helpers::getValue; +using ::trqt::variant_helpers::listAdd; /*** **** @@ -44,16 +50,6 @@ namespace using KeyList = Torrent::KeyList; -void addList(tr_variant* list, KeyList const& keys) -{ - tr_variantListReserve(list, keys.size()); - - for (tr_quark const key : keys) - { - tr_variantListAddQuark(list, key); - } -} - // If this object is passed as "ids" (compared by address), then recently active torrents are queried. auto const RecentlyActiveIDs = torrent_ids_t{ -1 }; @@ -70,19 +66,19 @@ void Session::sessionSet(tr_quark const key, QVariant const& value) switch (value.type()) { case QVariant::Bool: - tr_variantDictAddBool(&args, key, value.toBool()); + dictAdd(&args, key, value.toBool()); break; case QVariant::Int: - tr_variantDictAddInt(&args, key, value.toInt()); + dictAdd(&args, key, value.toInt()); break; case QVariant::Double: - tr_variantDictAddReal(&args, key, value.toDouble()); + dictAdd(&args, key, value.toDouble()); break; case QVariant::String: - tr_variantDictAddStr(&args, key, value.toString().toUtf8().constData()); + dictAdd(&args, key, value.toString()); break; default: @@ -107,7 +103,11 @@ void Session::portTest() if (r.success) { - (void)tr_variantDictFindBool(r.args.get(), TR_KEY_port_is_open, &is_open); + auto const value = dictFind(r.args.get(), TR_KEY_port_is_open); + if (value) + { + is_open = *value; + } } emit portTested(is_open); @@ -120,8 +120,8 @@ void Session::copyMagnetLinkToClipboard(int torrent_id) { tr_variant args; tr_variantInitDict(&args, 2); - tr_variantListAddInt(tr_variantDictAddList(&args, TR_KEY_ids, 1), torrent_id); - tr_variantListAddStr(tr_variantDictAddList(&args, TR_KEY_fields, 1), "magnetLink"); + dictAdd(&args, TR_KEY_ids, std::array{ torrent_id }); + dictAdd(&args, TR_KEY_fields, std::array{ "magnetLink" }); auto* q = new RpcQueue(); @@ -140,11 +140,13 @@ void Session::copyMagnetLinkToClipboard(int torrent_id) } tr_variant* const child = tr_variantListChild(torrents, 0); - char const* str; - - if (child != nullptr && tr_variantDictFindStr(child, TR_KEY_magnetLink, &str, nullptr)) + if (child != nullptr) { - qApp->clipboard()->setText(QString::fromUtf8(str)); + auto const link = dictFind(child, TR_KEY_magnetLink); + if (link) + { + qApp->clipboard()->setText(*link); + } } }); @@ -407,16 +409,11 @@ void addOptionalIds(tr_variant* args, torrent_ids_t const& ids) { if (&ids == &RecentlyActiveIDs) { - tr_variantDictAddStr(args, TR_KEY_ids, "recently-active"); + dictAdd(args, TR_KEY_ids, "recently-active"); } else if (!ids.empty()) { - tr_variant* id_list(tr_variantDictAddList(args, TR_KEY_ids, ids.size())); - - for (int const i : ids) - { - tr_variantListAddInt(id_list, i); - } + dictAdd(args, TR_KEY_ids, ids); } } @@ -426,8 +423,8 @@ void Session::torrentSet(torrent_ids_t const& ids, tr_quark const key, double va { tr_variant args; tr_variantInitDict(&args, 2); - tr_variantDictAddReal(&args, key, value); addOptionalIds(&args, ids); + dictAdd(&args, key, value); exec(TR_KEY_torrent_set, &args); } @@ -436,8 +433,8 @@ void Session::torrentSet(torrent_ids_t const& ids, tr_quark const key, int value { tr_variant args; tr_variantInitDict(&args, 2); - tr_variantDictAddInt(&args, key, value); addOptionalIds(&args, ids); + dictAdd(&args, key, value); exec(TR_KEY_torrent_set, &args); } @@ -446,8 +443,8 @@ void Session::torrentSet(torrent_ids_t const& ids, tr_quark const key, bool valu { tr_variant args; tr_variantInitDict(&args, 2); - tr_variantDictAddBool(&args, key, value); addOptionalIds(&args, ids); + dictAdd(&args, key, value); exec(TR_KEY_torrent_set, &args); } @@ -457,12 +454,7 @@ void Session::torrentSet(torrent_ids_t const& ids, tr_quark const key, QStringLi tr_variant args; tr_variantInitDict(&args, 2); addOptionalIds(&args, ids); - tr_variant* list(tr_variantDictAddList(&args, key, value.size())); - - for (QString const& str : value) - { - tr_variantListAddStr(list, str.toUtf8().constData()); - } + dictAdd(&args, key, value); exec(TR_KEY_torrent_set, &args); } @@ -472,12 +464,7 @@ void Session::torrentSet(torrent_ids_t const& ids, tr_quark const key, QList(r.args.get(), TR_KEY_path); + auto const path = str ? *str : QStringLiteral("(unknown)"); + str = dictFind(r.args.get(), TR_KEY_name); + auto const name = str ? *str : QStringLiteral("(unknown)"); auto* d = new QMessageBox(QMessageBox::Information, tr("Error Renaming Path"), tr(R"(

Unable to rename "%1" as "%2": %3.

Please correct the errors and try again.

)"). - arg(QString::fromUtf8(path)).arg(QString::fromUtf8(name)).arg(r.result), QMessageBox::Close, + arg(path).arg(name).arg(r.result), QMessageBox::Close, qApp->activeWindow()); QObject::connect(d, &QMessageBox::rejected, d, &QMessageBox::deleteLater); d->show(); @@ -546,8 +533,18 @@ void Session::refreshTorrents(torrent_ids_t const& ids, KeyList const& keys) { tr_variant args; tr_variantInitDict(&args, 3); - tr_variantDictAddStr(&args, TR_KEY_format, "table"); - addList(tr_variantDictAddList(&args, TR_KEY_fields, 0), keys); + dictAdd(&args, TR_KEY_format, "table"); + + std::vector keystrs; + keystrs.reserve(keys.size()); + for (auto const& key : keys) + { + auto len = size_t{}; + auto const* str = tr_quark_get_string(key, &len); + keystrs.emplace_back(str, len); + } + + dictAdd(&args, TR_KEY_fields, keystrs); addOptionalIds(&args, ids); auto* q = new RpcQueue(); @@ -587,7 +584,7 @@ void Session::refreshExtraStats(torrent_ids_t const& ids) refreshTorrents(ids, Torrent::MainStatKeys + Torrent::DetailStatKeys); } -void Session::sendTorrentRequest(char const* request, torrent_ids_t const& ids) +void Session::sendTorrentRequest(std::string_view request, torrent_ids_t const& ids) { tr_variant args; tr_variantInitDict(&args, 1); @@ -703,11 +700,10 @@ void Session::updateBlocklist() q->add([this](RpcResponse const& r) { - int64_t blocklist_size; - - if (tr_variantDictFindInt(r.args.get(), TR_KEY_blocklist_size, &blocklist_size)) + auto const size = dictFind(r.args.get(), TR_KEY_blocklist_size); + if (size) { - setBlocklistSize(blocklist_size); + setBlocklistSize(*size); } }); @@ -723,38 +719,37 @@ RpcResponseFuture Session::exec(tr_quark method, tr_variant* args) return rpc_.exec(method, args); } -RpcResponseFuture Session::exec(char const* method, tr_variant* args) +RpcResponseFuture Session::exec(std::string_view method, tr_variant* args) { return rpc_.exec(method, args); } void Session::updateStats(tr_variant* d, tr_session_stats* stats) { - int64_t i; - - if (tr_variantDictFindInt(d, TR_KEY_uploadedBytes, &i)) + auto value = dictFind(d, TR_KEY_uploadedBytes); + if (value) { - stats->uploadedBytes = i; + stats->uploadedBytes = *value; } - if (tr_variantDictFindInt(d, TR_KEY_downloadedBytes, &i)) + if ((value = dictFind(d, TR_KEY_downloadedBytes))) { - stats->downloadedBytes = i; + stats->downloadedBytes = *value; } - if (tr_variantDictFindInt(d, TR_KEY_filesAdded, &i)) + if ((value = dictFind(d, TR_KEY_filesAdded))) { - stats->filesAdded = i; + stats->filesAdded = *value; } - if (tr_variantDictFindInt(d, TR_KEY_sessionCount, &i)) + if ((value = dictFind(d, TR_KEY_sessionCount))) { - stats->sessionCount = i; + stats->sessionCount = *value; } - if (tr_variantDictFindInt(d, TR_KEY_secondsActive, &i)) + if ((value = dictFind(d, TR_KEY_secondsActive))) { - stats->secondsActive = i; + stats->secondsActive = *value; } stats->ratio = tr_getRatio(stats->uploadedBytes, stats->downloadedBytes); @@ -779,9 +774,6 @@ void Session::updateStats(tr_variant* d) void Session::updateInfo(tr_variant* d) { - int64_t i; - char const* str; - disconnect(&prefs_, SIGNAL(changed(int)), this, SLOT(updatePref(int))); for (int i = Prefs::FIRST_CORE_PREF; i <= Prefs::LAST_CORE_PREF; ++i) @@ -795,19 +787,19 @@ void Session::updateInfo(tr_variant* d) if (i == Prefs::ENCRYPTION) { - char const* val; + auto const str = getValue(b); - if (tr_variantGetStr(b, &val, nullptr)) + if (str) { - if (qstrcmp(val, "required") == 0) + if (*str == QStringLiteral("required")) { prefs_.set(i, 2); } - else if (qstrcmp(val, "preferred") == 0) + else if (*str == QStringLiteral("preferred")) { prefs_.set(i, 1); } - else if (qstrcmp(val, "tolerated") == 0) + else if (*str == QStringLiteral("tolerated")) { prefs_.set(i, 0); } @@ -820,11 +812,11 @@ void Session::updateInfo(tr_variant* d) { case QVariant::Int: { - int64_t val; + auto const value = getValue(b); - if (tr_variantGetInt(b, &val)) + if (value) { - prefs_.set(i, static_cast(val)); + prefs_.set(i, *value); } break; @@ -832,11 +824,11 @@ void Session::updateInfo(tr_variant* d) case QVariant::Double: { - double val; + auto const value = getValue(b); - if (tr_variantGetReal(b, &val)) + if (value) { - prefs_.set(i, val); + prefs_.set(i, *value); } break; @@ -844,11 +836,11 @@ void Session::updateInfo(tr_variant* d) case QVariant::Bool: { - bool val; + auto const value = getValue(b); - if (tr_variantGetBool(b, &val)) + if (value) { - prefs_.set(i, val); + prefs_.set(i, *value); } break; @@ -858,11 +850,11 @@ void Session::updateInfo(tr_variant* d) case CustomVariantType::SortModeType: case QVariant::String: { - char const* val; + auto const value = getValue(b); - if (tr_variantGetStr(b, &val, nullptr)) + if (value) { - prefs_.set(i, QString::fromUtf8(val)); + prefs_.set(i, *value); } break; @@ -873,17 +865,16 @@ void Session::updateInfo(tr_variant* d) } } - bool b; - double x; - - if (tr_variantDictFindBool(d, TR_KEY_seedRatioLimited, &b)) + auto const b = dictFind(d, TR_KEY_seedRatioLimited); + if (b) { - prefs_.set(Prefs::RATIO_ENABLED, b); + prefs_.set(Prefs::RATIO_ENABLED, *b); } - if (tr_variantDictFindReal(d, TR_KEY_seedRatioLimit, &x)) + auto const x = dictFind(d, TR_KEY_seedRatioLimit); + if (x) { - prefs_.set(Prefs::RATIO, x); + prefs_.set(Prefs::RATIO, *x); } /* Use the C API to get settings that, for security reasons, aren't supported by RPC */ @@ -898,25 +889,23 @@ void Session::updateInfo(tr_variant* d) prefs_.set(Prefs::RPC_WHITELIST, QString::fromUtf8(tr_sessionGetRPCWhitelist(session_))); } - if (tr_variantDictFindInt(d, TR_KEY_blocklist_size, &i) && i != blocklistSize()) + auto const size = dictFind(d, TR_KEY_blocklist_size); + if (size && *size != blocklistSize()) { - setBlocklistSize(i); + setBlocklistSize(*size); } - if (tr_variantDictFindStr(d, TR_KEY_version, &str, nullptr) && session_version_ != QString::fromUtf8(str)) + auto str = dictFind(d, TR_KEY_version); + if (str) { - session_version_ = QString::fromUtf8(str); + session_version_ = *str; } - if (tr_variantDictFindStr(d, TR_KEY_session_id, &str, nullptr)) + str = dictFind(d, TR_KEY_session_id); + if (str) { - QString const session_id = QString::fromUtf8(str); - - if (session_id_ != session_id) - { - session_id_ = session_id; - is_definitely_local_session_ = tr_session_id_is_local(str); - } + session_id_ = *str; + is_definitely_local_session_ = tr_session_id_is_local(session_id_.toUtf8().constData()); } else { @@ -943,26 +932,23 @@ void Session::addTorrent(AddData const& add_me, tr_variant* args, bool trash_ori if (tr_variantDictFind(args, TR_KEY_paused) == nullptr) { - tr_variantDictAddBool(args, TR_KEY_paused, !prefs_.getBool(Prefs::START)); + dictAdd(args, TR_KEY_paused, !prefs_.getBool(Prefs::START)); } switch (add_me.type) { case AddData::MAGNET: - tr_variantDictAddStr(args, TR_KEY_filename, add_me.magnet.toUtf8().constData()); + dictAdd(args, TR_KEY_filename, add_me.magnet); break; case AddData::URL: - tr_variantDictAddStr(args, TR_KEY_filename, add_me.url.toString().toUtf8().constData()); + dictAdd(args, TR_KEY_filename, add_me.url.toString()); break; case AddData::FILENAME: /* fall-through */ case AddData::METAINFO: - { - QByteArray const b64 = add_me.toBase64(); - tr_variantDictAddRaw(args, TR_KEY_metainfo, b64.constData(), b64.size()); - break; - } + dictAdd(args, TR_KEY_metainfo, add_me.toBase64()); + break; default: qWarning() << "Unhandled AddData type: " << add_me.type; @@ -993,14 +979,12 @@ void Session::addTorrent(AddData const& add_me, tr_variant* args, bool trash_ori return; } - char const* str; - - if (tr_variantDictFindStr(dup, TR_KEY_name, &str, nullptr)) + auto const name = dictFind(dup, TR_KEY_name); + if (name) { - QString const name = QString::fromUtf8(str); auto* d = new QMessageBox(QMessageBox::Warning, tr("Add Torrent"), tr(R"(

Unable to add "%1".

It is a duplicate of "%2" which is already added.

)"). - arg(add_me.readableShortName()).arg(name), QMessageBox::Close, qApp->activeWindow()); + arg(add_me.readableShortName()).arg(*name), QMessageBox::Close, qApp->activeWindow()); QObject::connect(d, &QMessageBox::rejected, d, &QMessageBox::deleteLater); d->show(); } @@ -1033,9 +1017,9 @@ void Session::addNewlyCreatedTorrent(QString const& filename, QString const& loc tr_variant args; tr_variantInitDict(&args, 3); - tr_variantDictAddStr(&args, TR_KEY_download_dir, local_path.toUtf8().constData()); - tr_variantDictAddBool(&args, TR_KEY_paused, !prefs_.getBool(Prefs::START)); - tr_variantDictAddRaw(&args, TR_KEY_metainfo, b64.constData(), b64.size()); + dictAdd(&args, TR_KEY_download_dir, local_path); + dictAdd(&args, TR_KEY_paused, !prefs_.getBool(Prefs::START)); + dictAdd(&args, TR_KEY_metainfo, b64); exec("torrent-add", &args); } @@ -1047,7 +1031,7 @@ void Session::removeTorrents(torrent_ids_t const& ids, bool delete_files) tr_variant args; tr_variantInitDict(&args, 2); addOptionalIds(&args, ids); - tr_variantDictAddInt(&args, TR_KEY_delete_local_data, delete_files); + dictAdd(&args, TR_KEY_delete_local_data, delete_files); exec("torrent-remove", &args); } diff --git a/qt/Session.h b/qt/Session.h index a0eb06b76..9a1584ad7 100644 --- a/qt/Session.h +++ b/qt/Session.h @@ -8,6 +8,8 @@ #pragma once +#include + #include #include #include @@ -75,7 +77,7 @@ public: bool isLocal() const; RpcResponseFuture exec(tr_quark method, tr_variant* args); - RpcResponseFuture exec(char const* method, tr_variant* args); + RpcResponseFuture exec(std::string_view method, tr_variant* args); void torrentSet(torrent_ids_t const& ids, tr_quark const key, bool val); void torrentSet(torrent_ids_t const& ids, tr_quark const key, int val); @@ -131,7 +133,7 @@ private: void sessionSet(tr_quark const key, QVariant const& variant); void pumpRequests(); - void sendTorrentRequest(char const* request, torrent_ids_t const& torrent_ids); + void sendTorrentRequest(std::string_view request, torrent_ids_t const& torrent_ids); void refreshTorrents(torrent_ids_t const& torrent_ids, Torrent::KeyList const& keys); static void updateStats(tr_variant* d, tr_session_stats* stats); diff --git a/qt/Torrent.cc b/qt/Torrent.cc index 4d996293f..7b28b6490 100644 --- a/qt/Torrent.cc +++ b/qt/Torrent.cc @@ -22,6 +22,9 @@ #include "Prefs.h" #include "Torrent.h" #include "Utils.h" +#include "VariantHelpers.h" + +using ::trqt::variant_helpers::change; /*** **** @@ -120,248 +123,6 @@ Torrent::Torrent(Prefs const& prefs, int id) : **** ***/ -namespace -{ - -template -bool change(T& setme, T const& value) -{ - bool const changed = setme != value; - - if (changed) - { - setme = value; - } - - return changed; -} - -bool change(double& setme, double const& value) -{ - bool const changed = !qFuzzyCompare(setme + 1, value + 1); - - if (changed) - { - setme = value; - } - - return changed; -} - -bool change(double& setme, tr_variant const* value) -{ - double d; - return tr_variantGetReal(value, &d) && change(setme, d); -} - -bool change(int& setme, tr_variant const* value) -{ - int64_t i; - return tr_variantGetInt(value, &i) && change(setme, static_cast(i)); -} - -bool change(uint64_t& setme, tr_variant const* value) -{ - int64_t i; - return tr_variantGetInt(value, &i) && change(setme, static_cast(i)); -} - -bool change(time_t& setme, tr_variant const* value) -{ - int64_t i; - return tr_variantGetInt(value, &i) && change(setme, static_cast(i)); -} - -bool change(Speed& setme, tr_variant const* value) -{ - int64_t i; - return tr_variantGetInt(value, &i) && change(setme, Speed::fromBps(i)); -} - -bool change(bool& setme, tr_variant const* value) -{ - bool b; - return tr_variantGetBool(value, &b) && change(setme, b); -} - -bool change(QString& setme, tr_variant const* value) -{ - bool changed = false; - char const* str; - size_t len; - - if (!tr_variantGetStr(value, &str, &len)) - { - return changed; - } - - if (len == 0) - { - changed = !setme.isEmpty(); - setme.clear(); - return changed; - } - - return change(setme, QString::fromUtf8(str, len)); -} - -bool change(Peer& setme, tr_variant const* value) -{ - bool changed = false; - - size_t pos = 0; - tr_quark key; - tr_variant* child; - while (tr_variantDictChild(const_cast(value), pos++, &key, &child)) - { - switch (key) - { -#define HANDLE_KEY(key, field) case TR_KEY_ ## key: \ - changed = change(setme.field, child) || changed; break; - - HANDLE_KEY(address, address) - HANDLE_KEY(clientIsChoked, client_is_choked) - HANDLE_KEY(clientIsInterested, client_is_interested) - HANDLE_KEY(clientName, client_name) - HANDLE_KEY(flagStr, flags) - HANDLE_KEY(isDownloadingFrom, is_downloading_from) - HANDLE_KEY(isEncrypted, is_encrypted) - HANDLE_KEY(isIncoming, is_incoming) - HANDLE_KEY(isUploadingTo, is_uploading_to) - HANDLE_KEY(peerIsChoked, peer_is_choked) - HANDLE_KEY(peerIsInterested, peer_is_interested) - HANDLE_KEY(port, port) - HANDLE_KEY(progress, progress) - HANDLE_KEY(rateToClient, rate_to_client) - HANDLE_KEY(rateToPeer, rate_to_peer) -#undef HANDLE_KEY - default: - break; - } - } - - return changed; -} - -bool change(TorrentFile& setme, tr_variant const* value) -{ - bool changed = false; - - size_t pos = 0; - tr_quark key; - tr_variant* child; - while (tr_variantDictChild(const_cast(value), pos++, &key, &child)) - { - switch (key) - { -#define HANDLE_KEY(key) case TR_KEY_ ## key: \ - changed = change(setme.key, child) || changed; break; - - HANDLE_KEY(have) - HANDLE_KEY(priority) - HANDLE_KEY(wanted) -#undef HANDLE_KEY -#define HANDLE_KEY(key, field) case TR_KEY_ ## key: \ - changed = change(setme.field, child) || changed; break; - - HANDLE_KEY(bytesCompleted, have) - HANDLE_KEY(length, size) - HANDLE_KEY(name, filename) -#undef HANDLE_KEY - default: - break; - } - } - - return changed; -} - -bool change(TrackerStat& setme, tr_variant const* value) -{ - bool changed = false; - - size_t pos = 0; - tr_quark key; - tr_variant* child; - while (tr_variantDictChild(const_cast(value), pos++, &key, &child)) - { - bool field_changed = false; - - switch (key) - { -#define HANDLE_KEY(key, field) case TR_KEY_ ## key: \ - field_changed = change(setme.field, child); break; - HANDLE_KEY(announce, announce) - HANDLE_KEY(announceState, announce_state) - HANDLE_KEY(downloadCount, download_count) - HANDLE_KEY(hasAnnounced, has_announced) - HANDLE_KEY(hasScraped, has_scraped) - HANDLE_KEY(host, host); - HANDLE_KEY(id, id); - HANDLE_KEY(isBackup, is_backup); - HANDLE_KEY(lastAnnouncePeerCount, last_announce_peer_count); - HANDLE_KEY(lastAnnounceResult, last_announce_result); - HANDLE_KEY(lastAnnounceStartTime, last_announce_start_time) - HANDLE_KEY(lastAnnounceSucceeded, last_announce_succeeded) - HANDLE_KEY(lastAnnounceTime, last_announce_time) - HANDLE_KEY(lastAnnounceTimedOut, last_announce_timed_out) - HANDLE_KEY(lastScrapeResult, last_scrape_result) - HANDLE_KEY(lastScrapeStartTime, last_scrape_start_time) - HANDLE_KEY(lastScrapeSucceeded, last_scrape_succeeded) - HANDLE_KEY(lastScrapeTime, last_scrape_time) - HANDLE_KEY(lastScrapeTimedOut, last_scrape_timed_out) - HANDLE_KEY(leecherCount, leecher_count) - HANDLE_KEY(nextAnnounceTime, next_announce_time) - HANDLE_KEY(nextScrapeTime, next_scrape_time) - HANDLE_KEY(scrapeState, scrape_state) - HANDLE_KEY(seederCount, seeder_count) - HANDLE_KEY(tier, tier) - -#undef HANDLE_KEY - default: - break; - } - - if (field_changed) - { - if (key == TR_KEY_announce) - { - setme.favicon_key = qApp->faviconCache().add(QUrl(setme.announce)); - } - - changed = true; - } - } - - return changed; -} - -template -bool change(QVector& setme, tr_variant const* value) -{ - bool changed = false; - - int const n = tr_variantListSize(value); - if (setme.size() != n) - { - setme.resize(n); - changed = true; - } - - for (int i = 0; i < n; ++i) - { - changed = change(setme[i], tr_variantListChild(const_cast(value), i)) || changed; - } - - return changed; -} - -} // anonymous namespace - -/*** -**** -***/ - bool Torrent::getSeedRatio(double& setmeRatio) const { bool is_limited; diff --git a/qt/TorrentModel.cc b/qt/TorrentModel.cc index 9f15e1b1f..5758de8fa 100644 --- a/qt/TorrentModel.cc +++ b/qt/TorrentModel.cc @@ -17,6 +17,9 @@ #include "Torrent.h" #include "TorrentDelegate.h" #include "TorrentModel.h" +#include "VariantHelpers.h" + +using ::trqt::variant_helpers::getValue; /*** **** @@ -131,17 +134,14 @@ void TorrentModel::removeTorrents(tr_variant* list) tr_variant* child; while ((child = tr_variantListChild(list, i++)) != nullptr) { - int64_t id; - Torrent* torrent = nullptr; - - if (tr_variantGetInt(child, &id)) + auto const id = getValue(child); + if (id) { - torrent = getTorrentFromId(id); - } - - if (torrent != nullptr) - { - torrents.push_back(torrent); + auto* torrent = getTorrentFromId(*id); + if (torrent != nullptr) + { + torrents.push_back(torrent); + } } } @@ -242,18 +242,18 @@ void TorrentModel::updateTorrents(tr_variant* torrents, bool is_complete_list) } // Find the torrent id - int64_t id; - if (!tr_variantGetInt(values[id_pos], &id)) + auto const id = getValue(values[id_pos]); + if (!id) { continue; } - Torrent* tor = getTorrentFromId(id); + Torrent* tor = getTorrentFromId(*id); bool is_new = false; if (tor == nullptr) { - tor = new Torrent(prefs_, id); + tor = new Torrent(prefs_, *id); instantiated.push_back(tor); is_new = true; } @@ -263,28 +263,28 @@ void TorrentModel::updateTorrents(tr_variant* torrents, bool is_complete_list) if (fields.any()) { changed_fields |= fields; - changed.insert(id); + changed.insert(*id); } if (fields.test(Torrent::EDIT_DATE)) { - edited.insert(id); + edited.insert(*id); } if (is_new && !tor->hasName()) { - needinfo.insert(id); + needinfo.insert(*id); } - if (recently_added(tor) && tor->hasName() && !already_added_.count(id)) + if (recently_added(tor) && tor->hasName() && !already_added_.count(*id)) { - added.insert(id); - already_added_.insert(id); + added.insert(*id); + already_added_.insert(*id); } if (fields.test(Torrent::LEFT_UNTIL_DONE) && (tor->leftUntilDone() == 0) && (tor->downloadedEver() > 0)) { - completed.insert(id); + completed.insert(*id); } processed.push_back(tor); diff --git a/qt/VariantHelpers.cc b/qt/VariantHelpers.cc new file mode 100644 index 000000000..00e7494c5 --- /dev/null +++ b/qt/VariantHelpers.cc @@ -0,0 +1,213 @@ +/* + * This file Copyright (C) 2020 Mnemosyne LLC + * + * It may be used under the GNU GPL versions 2 or 3 + * or any future license endorsed by Mnemosyne LLC. + * + */ + +#include "VariantHelpers.h" + +#include // qFuzzyCompare +#include + +#include "Application.h" // qApp +#include "Filters.h" +#include "Speed.h" +#include "Torrent.h" + +namespace trqt::variant_helpers +{ + +bool change(double& setme, double const& value) +{ + bool const changed = !qFuzzyCompare(setme + 1, value + 1); + + if (changed) + { + setme = value; + } + + return changed; +} + +bool change(Speed& setme, tr_variant const* variant) +{ + auto const value = getValue(variant); + return value && change(setme, Speed::fromBps(*value)); +} + +bool change(Peer& setme, tr_variant const* value) +{ + bool changed = false; + + size_t pos = 0; + tr_quark key; + tr_variant* child; + while (tr_variantDictChild(const_cast(value), pos++, &key, &child)) + { + switch (key) + { +#define HANDLE_KEY(key, field) case TR_KEY_ ## key: \ + changed = change(setme.field, child) || changed; break; + + HANDLE_KEY(address, address) + HANDLE_KEY(clientIsChoked, client_is_choked) + HANDLE_KEY(clientIsInterested, client_is_interested) + HANDLE_KEY(clientName, client_name) + HANDLE_KEY(flagStr, flags) + HANDLE_KEY(isDownloadingFrom, is_downloading_from) + HANDLE_KEY(isEncrypted, is_encrypted) + HANDLE_KEY(isIncoming, is_incoming) + HANDLE_KEY(isUploadingTo, is_uploading_to) + HANDLE_KEY(peerIsChoked, peer_is_choked) + HANDLE_KEY(peerIsInterested, peer_is_interested) + HANDLE_KEY(port, port) + HANDLE_KEY(progress, progress) + HANDLE_KEY(rateToClient, rate_to_client) + HANDLE_KEY(rateToPeer, rate_to_peer) +#undef HANDLE_KEY + default: + break; + } + } + + return changed; +} + +bool change(TorrentFile& setme, tr_variant const* value) +{ + bool changed = false; + + size_t pos = 0; + tr_quark key; + tr_variant* child; + while (tr_variantDictChild(const_cast(value), pos++, &key, &child)) + { + switch (key) + { +#define HANDLE_KEY(key) case TR_KEY_ ## key: \ + changed = change(setme.key, child) || changed; break; + + HANDLE_KEY(have) + HANDLE_KEY(priority) + HANDLE_KEY(wanted) +#undef HANDLE_KEY +#define HANDLE_KEY(key, field) case TR_KEY_ ## key: \ + changed = change(setme.field, child) || changed; break; + + HANDLE_KEY(bytesCompleted, have) + HANDLE_KEY(length, size) + HANDLE_KEY(name, filename) +#undef HANDLE_KEY + default: + break; + } + } + + return changed; +} + +bool change(TrackerStat& setme, tr_variant const* value) +{ + bool changed = false; + + size_t pos = 0; + tr_quark key; + tr_variant* child; + while (tr_variantDictChild(const_cast(value), pos++, &key, &child)) + { + bool field_changed = false; + + switch (key) + { +#define HANDLE_KEY(key, field) case TR_KEY_ ## key: \ + field_changed = change(setme.field, child); break; + HANDLE_KEY(announce, announce) + HANDLE_KEY(announceState, announce_state) + HANDLE_KEY(downloadCount, download_count) + HANDLE_KEY(hasAnnounced, has_announced) + HANDLE_KEY(hasScraped, has_scraped) + HANDLE_KEY(host, host); + HANDLE_KEY(id, id); + HANDLE_KEY(isBackup, is_backup); + HANDLE_KEY(lastAnnouncePeerCount, last_announce_peer_count); + HANDLE_KEY(lastAnnounceResult, last_announce_result); + HANDLE_KEY(lastAnnounceStartTime, last_announce_start_time) + HANDLE_KEY(lastAnnounceSucceeded, last_announce_succeeded) + HANDLE_KEY(lastAnnounceTime, last_announce_time) + HANDLE_KEY(lastAnnounceTimedOut, last_announce_timed_out) + HANDLE_KEY(lastScrapeResult, last_scrape_result) + HANDLE_KEY(lastScrapeStartTime, last_scrape_start_time) + HANDLE_KEY(lastScrapeSucceeded, last_scrape_succeeded) + HANDLE_KEY(lastScrapeTime, last_scrape_time) + HANDLE_KEY(lastScrapeTimedOut, last_scrape_timed_out) + HANDLE_KEY(leecherCount, leecher_count) + HANDLE_KEY(nextAnnounceTime, next_announce_time) + HANDLE_KEY(nextScrapeTime, next_scrape_time) + HANDLE_KEY(scrapeState, scrape_state) + HANDLE_KEY(seederCount, seeder_count) + HANDLE_KEY(tier, tier) + +#undef HANDLE_KEY + default: + break; + } + + if (field_changed) + { + if (key == TR_KEY_announce) + { + setme.favicon_key = qApp->faviconCache().add(QUrl(setme.announce)); + } + + changed = true; + } + } + + return changed; +} + +/// + +void variantInit(tr_variant* init_me, bool value) +{ + tr_variantInitBool(init_me, value); +} + +void variantInit(tr_variant* init_me, int64_t value) +{ + tr_variantInitInt(init_me, value); +} + +void variantInit(tr_variant* init_me, int value) +{ + tr_variantInitInt(init_me, value); +} + +void variantInit(tr_variant* init_me, unsigned int value) +{ + tr_variantInitInt(init_me, value); +} + +void variantInit(tr_variant* init_me, double value) +{ + tr_variantInitReal(init_me, value); +} + +void variantInit(tr_variant* init_me, QByteArray const& value) +{ + tr_variantInitRaw(init_me, value.constData(), value.size()); +} + +void variantInit(tr_variant* init_me, QString const& value) +{ + variantInit(init_me, value.toUtf8()); +} + +void variantInit(tr_variant* init_me, std::string_view value) +{ + tr_variantInitStr(init_me, std::data(value), std::size(value)); +} + +} // namespace trqt::variant_helpers diff --git a/qt/VariantHelpers.h b/qt/VariantHelpers.h new file mode 100644 index 000000000..4c49a4842 --- /dev/null +++ b/qt/VariantHelpers.h @@ -0,0 +1,187 @@ +/* + * This file Copyright (C) 2020 Mnemosyne LLC + * + * It may be used under the GNU GPL versions 2 or 3 + * or any future license endorsed by Mnemosyne LLC. + * + */ + +#pragma once + +#include +#include + +#include +#include + +#include + +class QByteArray; + +class Speed; +struct Peer; +struct TorrentFile; +struct TrackerStat; + +namespace trqt +{ + +namespace variant_helpers +{ + +template>::type* = nullptr> +auto getValue(tr_variant const* variant) +{ + std::optional ret; + auto value = T {}; + if (tr_variantGetBool(variant, &value)) + { + ret = value; + } + + return ret; +} + +template|| + std::is_same_v|| + std::is_same_v|| + std::is_same_v>::type* = nullptr> +auto getValue(tr_variant const* variant) +{ + std::optional ret; + auto value = int64_t {}; + if (tr_variantGetInt(variant, &value)) + { + ret = value; + } + + return ret; +} + +template>::type* = nullptr> +auto getValue(tr_variant const* variant) +{ + std::optional ret; + auto value = T {}; + if (tr_variantGetReal(variant, &value)) + { + ret = value; + } + + return ret; +} + +template>::type* = nullptr> +auto getValue(tr_variant const* variant) +{ + std::optional ret; + char const* str; + size_t len; + if (tr_variantGetStr(variant, &str, &len)) + { + ret = QString::fromUtf8(str, len); + } + + return ret; +} + +template +bool change(T& setme, T const& value) +{ + bool const changed = setme != value; + + if (changed) + { + setme = value; + } + + return changed; +} + +bool change(double& setme, double const& value); +bool change(Speed& setme, tr_variant const* value); +bool change(Peer& setme, tr_variant const* value); +bool change(TorrentFile& setme, tr_variant const* value); +bool change(TrackerStat& setme, tr_variant const* value); + +template +bool change(T& setme, tr_variant const* variant) +{ + auto const value = getValue(variant); + return value && change(setme, *value); +} + +template +bool change(QVector& setme, tr_variant const* value) +{ + bool changed = false; + + int const n = tr_variantListSize(value); + if (setme.size() != n) + { + setme.resize(n); + changed = true; + } + + for (int i = 0; i < n; ++i) + { + changed = change(setme[i], tr_variantListChild(const_cast(value), i)) || changed; + } + + return changed; +} + +/// + +template +auto dictFind(tr_variant* dict, tr_quark key) +{ + std::optional ret; + auto const* child = tr_variantDictFind(dict, key); + if (child != nullptr) + { + ret = getValue(child); + } + + return ret; +} + +/// + +void variantInit(tr_variant* init_me, bool value); +void variantInit(tr_variant* init_me, int64_t value); +void variantInit(tr_variant* init_me, int value); +void variantInit(tr_variant* init_me, unsigned int value); +void variantInit(tr_variant* init_me, double value); +void variantInit(tr_variant* init_me, QByteArray const& value); +void variantInit(tr_variant* init_me, QString const& value); +void variantInit(tr_variant* init_me, std::string_view value); + +template +void variantInit(tr_variant* init_me, C const& value) +{ + tr_variantInitList(init_me, std::size(value)); + for (auto const& item : value) + { + variantInit(tr_variantListAdd(init_me), item); + } +} + +template +void listAdd(tr_variant* list, T const& value) +{ + variantInit(tr_variantListAdd(list), value); +} + +template +void dictAdd(tr_variant* dict, tr_quark key, T const& value) +{ + variantInit(tr_variantDictAdd(dict, key), value); +} + +} // namespace variant_helpers + +} // trqt diff --git a/qt/qtr.pro b/qt/qtr.pro index 2042350c5..84ce813f5 100644 --- a/qt/qtr.pro +++ b/qt/qtr.pro @@ -119,6 +119,7 @@ SOURCES += AboutDialog.cc \ TrackerModel.cc \ TrackerModelFilter.cc \ Utils.cc \ + VariantHelpers.cc \ WatchDir.cc HEADERS += $$replace(SOURCES, .cc, .h) HEADERS += BaseDialog.h CustomVariantType.h Speed.h Typedefs.h diff --git a/utils/remote.c b/utils/remote.c index 2f089dc05..7af3ed33c 100644 --- a/utils/remote.c +++ b/utils/remote.c @@ -32,7 +32,7 @@ #define MY_NAME "transmission-remote" #define DEFAULT_HOST "localhost" -#define DEFAULT_PORT atoi(TR_DEFAULT_RPC_PORT_STR) +#define DEFAULT_PORT TR_DEFAULT_RPC_PORT #define DEFAULT_URL TR_DEFAULT_RPC_URL_STR "rpc/" #define ARGUMENTS TR_KEY_arguments