2 * Bittorrent Client using Qt and libtorrent.
3 * Copyright (C) 2018 Vladimir Golovnev <glassez@yandex.ru>
4 * Copyright (C) 2006-2012 Christophe Dumez <chris@qbittorrent.org>
5 * Copyright (C) 2006-2012 Ishan Arora <ishan@qbittorrent.org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * In addition, as a special exception, the copyright holders give permission to
22 * link this program with the OpenSSL project's "OpenSSL" library (or with
23 * modified versions of it that use the same license as the "OpenSSL" library),
24 * and distribute the linked executables. You must obey the GNU General Public
25 * License in all respects for all of the code used other than "OpenSSL". If you
26 * modify file(s), you may extend this exception to your version of the file(s),
27 * but you are not obligated to do so. If you do not wish to do so, delete this
28 * exception statement from your version.
31 #include "appcontroller.h"
36 #include <QCoreApplication>
39 #include <QJsonDocument>
40 #include <QJsonObject>
41 #include <QNetworkInterface>
42 #include <QRegularExpression>
43 #include <QStringList>
45 #include <QTranslator>
47 #include "base/bittorrent/session.h"
48 #include "base/global.h"
49 #include "base/interfaces/iapplication.h"
50 #include "base/net/portforwarder.h"
51 #include "base/net/proxyconfigurationmanager.h"
52 #include "base/path.h"
53 #include "base/preferences.h"
54 #include "base/rss/rss_autodownloader.h"
55 #include "base/rss/rss_session.h"
56 #include "base/torrentfileguard.h"
57 #include "base/torrentfileswatcher.h"
58 #include "base/utils/fs.h"
59 #include "base/utils/misc.h"
60 #include "base/utils/net.h"
61 #include "base/utils/password.h"
62 #include "base/utils/string.h"
63 #include "base/version.h"
64 #include "../webapplication.h"
66 using namespace std::chrono_literals
;
68 void AppController::webapiVersionAction()
70 setResult(API_VERSION
.toString());
73 void AppController::versionAction()
75 setResult(QStringLiteral(QBT_VERSION
));
78 void AppController::buildInfoAction()
80 const QJsonObject versions
=
82 {u
"qt"_qs
, QStringLiteral(QT_VERSION_STR
)},
83 {u
"libtorrent"_qs
, Utils::Misc::libtorrentVersionString()},
84 {u
"boost"_qs
, Utils::Misc::boostVersionString()},
85 {u
"openssl"_qs
, Utils::Misc::opensslVersionString()},
86 {u
"zlib"_qs
, Utils::Misc::zlibVersionString()},
87 {u
"bitness"_qs
, (QT_POINTER_SIZE
* 8)}
92 void AppController::shutdownAction()
94 // Special handling for shutdown, we
95 // need to reply to the Web UI before
96 // actually shutting down.
97 QTimer::singleShot(100ms
, Qt::CoarseTimer
, qApp
, []
99 QCoreApplication::exit();
103 void AppController::preferencesAction()
105 const auto *pref
= Preferences::instance();
106 const auto *session
= BitTorrent::Session::instance();
112 data
[u
"locale"_qs
] = pref
->getLocale();
113 data
[u
"performance_warning"_qs
] = session
->isPerformanceWarningEnabled();
115 data
[u
"file_log_enabled"_qs
] = app()->isFileLoggerEnabled();
116 data
[u
"file_log_path"_qs
] = app()->fileLoggerPath().toString();
117 data
[u
"file_log_backup_enabled"_qs
] = app()->isFileLoggerBackup();
118 data
[u
"file_log_max_size"_qs
] = app()->fileLoggerMaxSize() / 1024;
119 data
[u
"file_log_delete_old"_qs
] = app()->isFileLoggerDeleteOld();
120 data
[u
"file_log_age"_qs
] = app()->fileLoggerAge();
121 data
[u
"file_log_age_type"_qs
] = app()->fileLoggerAgeType();
124 // When adding a torrent
125 data
[u
"torrent_content_layout"_qs
] = Utils::String::fromEnum(session
->torrentContentLayout());
126 data
[u
"add_to_top_of_queue"_qs
] = session
->isAddTorrentToQueueTop();
127 data
[u
"start_paused_enabled"_qs
] = session
->isAddTorrentPaused();
128 data
[u
"torrent_stop_condition"_qs
] = Utils::String::fromEnum(session
->torrentStopCondition());
129 data
[u
"auto_delete_mode"_qs
] = static_cast<int>(TorrentFileGuard::autoDeleteMode());
130 data
[u
"preallocate_all"_qs
] = session
->isPreallocationEnabled();
131 data
[u
"incomplete_files_ext"_qs
] = session
->isAppendExtensionEnabled();
133 data
[u
"auto_tmm_enabled"_qs
] = !session
->isAutoTMMDisabledByDefault();
134 data
[u
"torrent_changed_tmm_enabled"_qs
] = !session
->isDisableAutoTMMWhenCategoryChanged();
135 data
[u
"save_path_changed_tmm_enabled"_qs
] = !session
->isDisableAutoTMMWhenDefaultSavePathChanged();
136 data
[u
"category_changed_tmm_enabled"_qs
] = !session
->isDisableAutoTMMWhenCategorySavePathChanged();
137 data
[u
"save_path"_qs
] = session
->savePath().toString();
138 data
[u
"temp_path_enabled"_qs
] = session
->isDownloadPathEnabled();
139 data
[u
"temp_path"_qs
] = session
->downloadPath().toString();
140 data
[u
"use_category_paths_in_manual_mode"_qs
] = session
->useCategoryPathsInManualMode();
141 data
[u
"export_dir"_qs
] = session
->torrentExportDirectory().toString();
142 data
[u
"export_dir_fin"_qs
] = session
->finishedTorrentExportDirectory().toString();
144 // TODO: The following code is deprecated. Delete it once replaced by updated API method.
145 // === BEGIN DEPRECATED CODE === //
146 TorrentFilesWatcher
*fsWatcher
= TorrentFilesWatcher::instance();
147 const QHash
<Path
, TorrentFilesWatcher::WatchedFolderOptions
> watchedFolders
= fsWatcher
->folders();
148 QJsonObject nativeDirs
;
149 for (auto i
= watchedFolders
.cbegin(); i
!= watchedFolders
.cend(); ++i
)
151 const Path watchedFolder
= i
.key();
152 const BitTorrent::AddTorrentParams params
= i
.value().addTorrentParams
;
153 if (params
.savePath
.isEmpty())
154 nativeDirs
.insert(watchedFolder
.toString(), 1);
155 else if (params
.savePath
== watchedFolder
)
156 nativeDirs
.insert(watchedFolder
.toString(), 0);
158 nativeDirs
.insert(watchedFolder
.toString(), params
.savePath
.toString());
160 data
[u
"scan_dirs"_qs
] = nativeDirs
;
161 // === END DEPRECATED CODE === //
163 // Excluded file names
164 data
[u
"excluded_file_names_enabled"_qs
] = session
->isExcludedFileNamesEnabled();
165 data
[u
"excluded_file_names"_qs
] = session
->excludedFileNames().join(u
'\n');
167 // Email notification upon download completion
168 data
[u
"mail_notification_enabled"_qs
] = pref
->isMailNotificationEnabled();
169 data
[u
"mail_notification_sender"_qs
] = pref
->getMailNotificationSender();
170 data
[u
"mail_notification_email"_qs
] = pref
->getMailNotificationEmail();
171 data
[u
"mail_notification_smtp"_qs
] = pref
->getMailNotificationSMTP();
172 data
[u
"mail_notification_ssl_enabled"_qs
] = pref
->getMailNotificationSMTPSSL();
173 data
[u
"mail_notification_auth_enabled"_qs
] = pref
->getMailNotificationSMTPAuth();
174 data
[u
"mail_notification_username"_qs
] = pref
->getMailNotificationSMTPUsername();
175 data
[u
"mail_notification_password"_qs
] = pref
->getMailNotificationSMTPPassword();
176 // Run an external program on torrent added
177 data
[u
"autorun_on_torrent_added_enabled"_qs
] = pref
->isAutoRunOnTorrentAddedEnabled();
178 data
[u
"autorun_on_torrent_added_program"_qs
] = pref
->getAutoRunOnTorrentAddedProgram();
179 // Run an external program on torrent finished
180 data
[u
"autorun_enabled"_qs
] = pref
->isAutoRunOnTorrentFinishedEnabled();
181 data
[u
"autorun_program"_qs
] = pref
->getAutoRunOnTorrentFinishedProgram();
185 data
[u
"listen_port"_qs
] = session
->port();
186 data
[u
"random_port"_qs
] = (session
->port() == 0); // deprecated
187 data
[u
"upnp"_qs
] = Net::PortForwarder::instance()->isEnabled();
188 // Connections Limits
189 data
[u
"max_connec"_qs
] = session
->maxConnections();
190 data
[u
"max_connec_per_torrent"_qs
] = session
->maxConnectionsPerTorrent();
191 data
[u
"max_uploads"_qs
] = session
->maxUploads();
192 data
[u
"max_uploads_per_torrent"_qs
] = session
->maxUploadsPerTorrent();
195 const auto *proxyManager
= Net::ProxyConfigurationManager::instance();
196 Net::ProxyConfiguration proxyConf
= proxyManager
->proxyConfiguration();
197 data
[u
"proxy_type"_qs
] = Utils::String::fromEnum(proxyConf
.type
);
198 data
[u
"proxy_ip"_qs
] = proxyConf
.ip
;
199 data
[u
"proxy_port"_qs
] = proxyConf
.port
;
200 data
[u
"proxy_auth_enabled"_qs
] = proxyConf
.authEnabled
;
201 data
[u
"proxy_username"_qs
] = proxyConf
.username
;
202 data
[u
"proxy_password"_qs
] = proxyConf
.password
;
204 data
[u
"proxy_bittorrent"_qs
] = pref
->useProxyForBT();
205 data
[u
"proxy_peer_connections"_qs
] = session
->isProxyPeerConnectionsEnabled();
206 data
[u
"proxy_hostname_lookup"_qs
] = session
->isProxyHostnameLookupEnabled();
207 data
[u
"proxy_rss"_qs
] = pref
->useProxyForRSS();
208 data
[u
"proxy_misc"_qs
] = pref
->useProxyForGeneralPurposes();
211 data
[u
"ip_filter_enabled"_qs
] = session
->isIPFilteringEnabled();
212 data
[u
"ip_filter_path"_qs
] = session
->IPFilterFile().toString();
213 data
[u
"ip_filter_trackers"_qs
] = session
->isTrackerFilteringEnabled();
214 data
[u
"banned_IPs"_qs
] = session
->bannedIPs().join(u
'\n');
217 // Global Rate Limits
218 data
[u
"dl_limit"_qs
] = session
->globalDownloadSpeedLimit();
219 data
[u
"up_limit"_qs
] = session
->globalUploadSpeedLimit();
220 data
[u
"alt_dl_limit"_qs
] = session
->altGlobalDownloadSpeedLimit();
221 data
[u
"alt_up_limit"_qs
] = session
->altGlobalUploadSpeedLimit();
222 data
[u
"bittorrent_protocol"_qs
] = static_cast<int>(session
->btProtocol());
223 data
[u
"limit_utp_rate"_qs
] = session
->isUTPRateLimited();
224 data
[u
"limit_tcp_overhead"_qs
] = session
->includeOverheadInLimits();
225 data
[u
"limit_lan_peers"_qs
] = !session
->ignoreLimitsOnLAN();
227 data
[u
"scheduler_enabled"_qs
] = session
->isBandwidthSchedulerEnabled();
228 const QTime start_time
= pref
->getSchedulerStartTime();
229 data
[u
"schedule_from_hour"_qs
] = start_time
.hour();
230 data
[u
"schedule_from_min"_qs
] = start_time
.minute();
231 const QTime end_time
= pref
->getSchedulerEndTime();
232 data
[u
"schedule_to_hour"_qs
] = end_time
.hour();
233 data
[u
"schedule_to_min"_qs
] = end_time
.minute();
234 data
[u
"scheduler_days"_qs
] = static_cast<int>(pref
->getSchedulerDays());
238 data
[u
"dht"_qs
] = session
->isDHTEnabled();
239 data
[u
"pex"_qs
] = session
->isPeXEnabled();
240 data
[u
"lsd"_qs
] = session
->isLSDEnabled();
241 data
[u
"encryption"_qs
] = session
->encryption();
242 data
[u
"anonymous_mode"_qs
] = session
->isAnonymousModeEnabled();
243 // Max active checking torrents
244 data
[u
"max_active_checking_torrents"_qs
] = session
->maxActiveCheckingTorrents();
246 data
[u
"queueing_enabled"_qs
] = session
->isQueueingSystemEnabled();
247 data
[u
"max_active_downloads"_qs
] = session
->maxActiveDownloads();
248 data
[u
"max_active_torrents"_qs
] = session
->maxActiveTorrents();
249 data
[u
"max_active_uploads"_qs
] = session
->maxActiveUploads();
250 data
[u
"dont_count_slow_torrents"_qs
] = session
->ignoreSlowTorrentsForQueueing();
251 data
[u
"slow_torrent_dl_rate_threshold"_qs
] = session
->downloadRateForSlowTorrents();
252 data
[u
"slow_torrent_ul_rate_threshold"_qs
] = session
->uploadRateForSlowTorrents();
253 data
[u
"slow_torrent_inactive_timer"_qs
] = session
->slowTorrentsInactivityTimer();
254 // Share Ratio Limiting
255 data
[u
"max_ratio_enabled"_qs
] = (session
->globalMaxRatio() >= 0.);
256 data
[u
"max_ratio"_qs
] = session
->globalMaxRatio();
257 data
[u
"max_seeding_time_enabled"_qs
] = (session
->globalMaxSeedingMinutes() >= 0.);
258 data
[u
"max_seeding_time"_qs
] = session
->globalMaxSeedingMinutes();
259 data
[u
"max_ratio_act"_qs
] = session
->maxRatioAction();
261 data
[u
"add_trackers_enabled"_qs
] = session
->isAddTrackersEnabled();
262 data
[u
"add_trackers"_qs
] = session
->additionalTrackers();
266 data
[u
"web_ui_domain_list"_qs
] = pref
->getServerDomains();
267 data
[u
"web_ui_address"_qs
] = pref
->getWebUiAddress();
268 data
[u
"web_ui_port"_qs
] = pref
->getWebUiPort();
269 data
[u
"web_ui_upnp"_qs
] = pref
->useUPnPForWebUIPort();
270 data
[u
"use_https"_qs
] = pref
->isWebUiHttpsEnabled();
271 data
[u
"web_ui_https_cert_path"_qs
] = pref
->getWebUIHttpsCertificatePath().toString();
272 data
[u
"web_ui_https_key_path"_qs
] = pref
->getWebUIHttpsKeyPath().toString();
274 data
[u
"web_ui_username"_qs
] = pref
->getWebUiUsername();
275 data
[u
"bypass_local_auth"_qs
] = !pref
->isWebUiLocalAuthEnabled();
276 data
[u
"bypass_auth_subnet_whitelist_enabled"_qs
] = pref
->isWebUiAuthSubnetWhitelistEnabled();
277 QStringList authSubnetWhitelistStringList
;
278 for (const Utils::Net::Subnet
&subnet
: asConst(pref
->getWebUiAuthSubnetWhitelist()))
279 authSubnetWhitelistStringList
<< Utils::Net::subnetToString(subnet
);
280 data
[u
"bypass_auth_subnet_whitelist"_qs
] = authSubnetWhitelistStringList
.join(u
'\n');
281 data
[u
"web_ui_max_auth_fail_count"_qs
] = pref
->getWebUIMaxAuthFailCount();
282 data
[u
"web_ui_ban_duration"_qs
] = static_cast<int>(pref
->getWebUIBanDuration().count());
283 data
[u
"web_ui_session_timeout"_qs
] = pref
->getWebUISessionTimeout();
284 // Use alternative Web UI
285 data
[u
"alternative_webui_enabled"_qs
] = pref
->isAltWebUiEnabled();
286 data
[u
"alternative_webui_path"_qs
] = pref
->getWebUiRootFolder().toString();
288 data
[u
"web_ui_clickjacking_protection_enabled"_qs
] = pref
->isWebUiClickjackingProtectionEnabled();
289 data
[u
"web_ui_csrf_protection_enabled"_qs
] = pref
->isWebUiCSRFProtectionEnabled();
290 data
[u
"web_ui_secure_cookie_enabled"_qs
] = pref
->isWebUiSecureCookieEnabled();
291 data
[u
"web_ui_host_header_validation_enabled"_qs
] = pref
->isWebUIHostHeaderValidationEnabled();
292 // Custom HTTP headers
293 data
[u
"web_ui_use_custom_http_headers_enabled"_qs
] = pref
->isWebUICustomHTTPHeadersEnabled();
294 data
[u
"web_ui_custom_http_headers"_qs
] = pref
->getWebUICustomHTTPHeaders();
296 data
[u
"web_ui_reverse_proxy_enabled"_qs
] = pref
->isWebUIReverseProxySupportEnabled();
297 data
[u
"web_ui_reverse_proxies_list"_qs
] = pref
->getWebUITrustedReverseProxiesList();
298 // Update my dynamic domain name
299 data
[u
"dyndns_enabled"_qs
] = pref
->isDynDNSEnabled();
300 data
[u
"dyndns_service"_qs
] = static_cast<int>(pref
->getDynDNSService());
301 data
[u
"dyndns_username"_qs
] = pref
->getDynDNSUsername();
302 data
[u
"dyndns_password"_qs
] = pref
->getDynDNSPassword();
303 data
[u
"dyndns_domain"_qs
] = pref
->getDynDomainName();
306 data
[u
"rss_refresh_interval"_qs
] = RSS::Session::instance()->refreshInterval();
307 data
[u
"rss_max_articles_per_feed"_qs
] = RSS::Session::instance()->maxArticlesPerFeed();
308 data
[u
"rss_processing_enabled"_qs
] = RSS::Session::instance()->isProcessingEnabled();
309 data
[u
"rss_auto_downloading_enabled"_qs
] = RSS::AutoDownloader::instance()->isProcessingEnabled();
310 data
[u
"rss_download_repack_proper_episodes"_qs
] = RSS::AutoDownloader::instance()->downloadRepacks();
311 data
[u
"rss_smart_episode_filters"_qs
] = RSS::AutoDownloader::instance()->smartEpisodeFilters().join(u
'\n');
314 // qBitorrent preferences
315 // Resume data storage type
316 data
[u
"resume_data_storage_type"_qs
] = Utils::String::fromEnum(session
->resumeDataStorageType());
317 // Physical memory (RAM) usage limit
318 data
[u
"memory_working_set_limit"_qs
] = app()->memoryWorkingSetLimit();
319 // Current network interface
320 data
[u
"current_network_interface"_qs
] = session
->networkInterface();
321 // Current network interface address
322 data
[u
"current_interface_address"_qs
] = BitTorrent::Session::instance()->networkInterfaceAddress();
323 // Save resume data interval
324 data
[u
"save_resume_data_interval"_qs
] = session
->saveResumeDataInterval();
325 // Recheck completed torrents
326 data
[u
"recheck_completed_torrents"_qs
] = pref
->recheckTorrentsOnCompletion();
328 data
[u
"refresh_interval"_qs
] = session
->refreshInterval();
329 // Resolve peer countries
330 data
[u
"resolve_peer_countries"_qs
] = pref
->resolvePeerCountries();
331 // Reannounce to all trackers when ip/port changed
332 data
[u
"reannounce_when_address_changed"_qs
] = session
->isReannounceWhenAddressChangedEnabled();
334 // libtorrent preferences
336 data
[u
"async_io_threads"_qs
] = session
->asyncIOThreads();
338 data
[u
"hashing_threads"_qs
] = session
->hashingThreads();
340 data
[u
"file_pool_size"_qs
] = session
->filePoolSize();
341 // Checking memory usage
342 data
[u
"checking_memory_use"_qs
] = session
->checkingMemUsage();
344 data
[u
"disk_cache"_qs
] = session
->diskCacheSize();
345 data
[u
"disk_cache_ttl"_qs
] = session
->diskCacheTTL();
347 data
[u
"disk_queue_size"_qs
] = session
->diskQueueSize();
349 data
[u
"disk_io_type"_qs
] = static_cast<int>(session
->diskIOType());
351 data
[u
"disk_io_read_mode"_qs
] = static_cast<int>(session
->diskIOReadMode());
352 // Disk IO write mode
353 data
[u
"disk_io_write_mode"_qs
] = static_cast<int>(session
->diskIOWriteMode());
354 // Coalesce reads & writes
355 data
[u
"enable_coalesce_read_write"_qs
] = session
->isCoalesceReadWriteEnabled();
356 // Piece Extent Affinity
357 data
[u
"enable_piece_extent_affinity"_qs
] = session
->usePieceExtentAffinity();
359 data
[u
"enable_upload_suggestions"_qs
] = session
->isSuggestModeEnabled();
360 // Send buffer watermark
361 data
[u
"send_buffer_watermark"_qs
] = session
->sendBufferWatermark();
362 data
[u
"send_buffer_low_watermark"_qs
] = session
->sendBufferLowWatermark();
363 data
[u
"send_buffer_watermark_factor"_qs
] = session
->sendBufferWatermarkFactor();
364 // Outgoing connections per second
365 data
[u
"connection_speed"_qs
] = session
->connectionSpeed();
366 // Socket listen backlog size
367 data
[u
"socket_backlog_size"_qs
] = session
->socketBacklogSize();
369 data
[u
"outgoing_ports_min"_qs
] = session
->outgoingPortsMin();
370 data
[u
"outgoing_ports_max"_qs
] = session
->outgoingPortsMax();
371 // UPnP lease duration
372 data
[u
"upnp_lease_duration"_qs
] = session
->UPnPLeaseDuration();
374 data
[u
"peer_tos"_qs
] = session
->peerToS();
375 // uTP-TCP mixed mode
376 data
[u
"utp_tcp_mixed_mode"_qs
] = static_cast<int>(session
->utpMixedMode());
377 // Support internationalized domain name (IDN)
378 data
[u
"idn_support_enabled"_qs
] = session
->isIDNSupportEnabled();
379 // Multiple connections per IP
380 data
[u
"enable_multi_connections_from_same_ip"_qs
] = session
->multiConnectionsPerIpEnabled();
381 // Validate HTTPS tracker certificate
382 data
[u
"validate_https_tracker_certificate"_qs
] = session
->validateHTTPSTrackerCertificate();
384 data
[u
"ssrf_mitigation"_qs
] = session
->isSSRFMitigationEnabled();
385 // Disallow connection to peers on privileged ports
386 data
[u
"block_peers_on_privileged_ports"_qs
] = session
->blockPeersOnPrivilegedPorts();
388 data
[u
"enable_embedded_tracker"_qs
] = session
->isTrackerEnabled();
389 data
[u
"embedded_tracker_port"_qs
] = pref
->getTrackerPort();
390 data
[u
"embedded_tracker_port_forwarding"_qs
] = pref
->isTrackerPortForwardingEnabled();
392 data
[u
"upload_slots_behavior"_qs
] = static_cast<int>(session
->chokingAlgorithm());
393 // Seed choking algorithm
394 data
[u
"upload_choking_algorithm"_qs
] = static_cast<int>(session
->seedChokingAlgorithm());
396 data
[u
"announce_to_all_trackers"_qs
] = session
->announceToAllTrackers();
397 data
[u
"announce_to_all_tiers"_qs
] = session
->announceToAllTiers();
398 data
[u
"announce_ip"_qs
] = session
->announceIP();
399 data
[u
"max_concurrent_http_announces"_qs
] = session
->maxConcurrentHTTPAnnounces();
400 data
[u
"stop_tracker_timeout"_qs
] = session
->stopTrackerTimeout();
402 data
[u
"peer_turnover"_qs
] = session
->peerTurnover();
403 data
[u
"peer_turnover_cutoff"_qs
] = session
->peerTurnoverCutoff();
404 data
[u
"peer_turnover_interval"_qs
] = session
->peerTurnoverInterval();
405 // Maximum outstanding requests to a single peer
406 data
[u
"request_queue_size"_qs
] = session
->requestQueueSize();
411 void AppController::setPreferencesAction()
413 requireParams({u
"json"_qs
});
415 auto *pref
= Preferences::instance();
416 auto *session
= BitTorrent::Session::instance();
417 const QVariantHash m
= QJsonDocument::fromJson(params()[u
"json"_qs
].toUtf8()).toVariant().toHash();
419 QVariantHash::ConstIterator it
;
420 const auto hasKey
= [&it
, &m
](const QString
&key
) -> bool
423 return (it
!= m
.constEnd());
428 if (hasKey(u
"locale"_qs
))
430 QString locale
= it
.value().toString();
431 if (pref
->getLocale() != locale
)
433 auto *translator
= new QTranslator
;
434 if (translator
->load(u
":/lang/qbittorrent_"_qs
+ locale
))
436 qDebug("%s locale recognized, using translation.", qUtf8Printable(locale
));
440 qDebug("%s locale unrecognized, using default (en).", qUtf8Printable(locale
));
442 qApp
->installTranslator(translator
);
444 pref
->setLocale(locale
);
447 if (hasKey(u
"performance_warning"_qs
))
448 session
->setPerformanceWarningEnabled(it
.value().toBool());
450 if (hasKey(u
"file_log_enabled"_qs
))
451 app()->setFileLoggerEnabled(it
.value().toBool());
452 if (hasKey(u
"file_log_path"_qs
))
453 app()->setFileLoggerPath(Path(it
.value().toString()));
454 if (hasKey(u
"file_log_backup_enabled"_qs
))
455 app()->setFileLoggerBackup(it
.value().toBool());
456 if (hasKey(u
"file_log_max_size"_qs
))
457 app()->setFileLoggerMaxSize(it
.value().toInt() * 1024);
458 if (hasKey(u
"file_log_delete_old"_qs
))
459 app()->setFileLoggerDeleteOld(it
.value().toBool());
460 if (hasKey(u
"file_log_age"_qs
))
461 app()->setFileLoggerAge(it
.value().toInt());
462 if (hasKey(u
"file_log_age_type"_qs
))
463 app()->setFileLoggerAgeType(it
.value().toInt());
466 // When adding a torrent
467 if (hasKey(u
"torrent_content_layout"_qs
))
468 session
->setTorrentContentLayout(Utils::String::toEnum(it
.value().toString(), BitTorrent::TorrentContentLayout::Original
));
469 if (hasKey(u
"add_to_top_of_queue"_qs
))
470 session
->setAddTorrentToQueueTop(it
.value().toBool());
471 if (hasKey(u
"start_paused_enabled"_qs
))
472 session
->setAddTorrentPaused(it
.value().toBool());
473 if (hasKey(u
"torrent_stop_condition"_qs
))
474 session
->setTorrentStopCondition(Utils::String::toEnum(it
.value().toString(), BitTorrent::Torrent::StopCondition::None
));
475 if (hasKey(u
"auto_delete_mode"_qs
))
476 TorrentFileGuard::setAutoDeleteMode(static_cast<TorrentFileGuard::AutoDeleteMode
>(it
.value().toInt()));
478 if (hasKey(u
"preallocate_all"_qs
))
479 session
->setPreallocationEnabled(it
.value().toBool());
480 if (hasKey(u
"incomplete_files_ext"_qs
))
481 session
->setAppendExtensionEnabled(it
.value().toBool());
484 if (hasKey(u
"auto_tmm_enabled"_qs
))
485 session
->setAutoTMMDisabledByDefault(!it
.value().toBool());
486 if (hasKey(u
"torrent_changed_tmm_enabled"_qs
))
487 session
->setDisableAutoTMMWhenCategoryChanged(!it
.value().toBool());
488 if (hasKey(u
"save_path_changed_tmm_enabled"_qs
))
489 session
->setDisableAutoTMMWhenDefaultSavePathChanged(!it
.value().toBool());
490 if (hasKey(u
"category_changed_tmm_enabled"_qs
))
491 session
->setDisableAutoTMMWhenCategorySavePathChanged(!it
.value().toBool());
492 if (hasKey(u
"save_path"_qs
))
493 session
->setSavePath(Path(it
.value().toString()));
494 if (hasKey(u
"temp_path_enabled"_qs
))
495 session
->setDownloadPathEnabled(it
.value().toBool());
496 if (hasKey(u
"temp_path"_qs
))
497 session
->setDownloadPath(Path(it
.value().toString()));
498 if (hasKey(u
"use_category_paths_in_manual_mode"_qs
))
499 session
->setUseCategoryPathsInManualMode(it
.value().toBool());
500 if (hasKey(u
"export_dir"_qs
))
501 session
->setTorrentExportDirectory(Path(it
.value().toString()));
502 if (hasKey(u
"export_dir_fin"_qs
))
503 session
->setFinishedTorrentExportDirectory(Path(it
.value().toString()));
505 // TODO: The following code is deprecated. Delete it once replaced by updated API method.
506 // === BEGIN DEPRECATED CODE === //
507 if (hasKey(u
"scan_dirs"_qs
))
510 TorrentFilesWatcher
*fsWatcher
= TorrentFilesWatcher::instance();
511 const PathList oldScanDirs
= fsWatcher
->folders().keys();
512 const QVariantHash nativeDirs
= it
.value().toHash();
513 for (auto i
= nativeDirs
.cbegin(); i
!= nativeDirs
.cend(); ++i
)
517 const Path watchedFolder
{i
.key()};
518 TorrentFilesWatcher::WatchedFolderOptions options
= fsWatcher
->folders().value(watchedFolder
);
519 BitTorrent::AddTorrentParams
¶ms
= options
.addTorrentParams
;
522 const int intVal
= i
.value().toInt(&isInt
);
527 params
.savePath
= watchedFolder
;
528 params
.useAutoTMM
= false;
533 const Path customSavePath
{i
.value().toString()};
534 params
.savePath
= customSavePath
;
535 params
.useAutoTMM
= false;
538 fsWatcher
->setWatchedFolder(watchedFolder
, options
);
539 scanDirs
.append(watchedFolder
);
546 // Update deleted folders
547 for (const Path
&path
: oldScanDirs
)
549 if (!scanDirs
.contains(path
))
550 fsWatcher
->removeWatchedFolder(path
);
553 // === END DEPRECATED CODE === //
555 // Excluded file names
556 if (hasKey(u
"excluded_file_names_enabled"_qs
))
557 session
->setExcludedFileNamesEnabled(it
.value().toBool());
558 if (hasKey(u
"excluded_file_names"_qs
))
559 session
->setExcludedFileNames(it
.value().toString().split(u
'\n'));
561 // Email notification upon download completion
562 if (hasKey(u
"mail_notification_enabled"_qs
))
563 pref
->setMailNotificationEnabled(it
.value().toBool());
564 if (hasKey(u
"mail_notification_sender"_qs
))
565 pref
->setMailNotificationSender(it
.value().toString());
566 if (hasKey(u
"mail_notification_email"_qs
))
567 pref
->setMailNotificationEmail(it
.value().toString());
568 if (hasKey(u
"mail_notification_smtp"_qs
))
569 pref
->setMailNotificationSMTP(it
.value().toString());
570 if (hasKey(u
"mail_notification_ssl_enabled"_qs
))
571 pref
->setMailNotificationSMTPSSL(it
.value().toBool());
572 if (hasKey(u
"mail_notification_auth_enabled"_qs
))
573 pref
->setMailNotificationSMTPAuth(it
.value().toBool());
574 if (hasKey(u
"mail_notification_username"_qs
))
575 pref
->setMailNotificationSMTPUsername(it
.value().toString());
576 if (hasKey(u
"mail_notification_password"_qs
))
577 pref
->setMailNotificationSMTPPassword(it
.value().toString());
578 // Run an external program on torrent added
579 if (hasKey(u
"autorun_on_torrent_added_enabled"_qs
))
580 pref
->setAutoRunOnTorrentAddedEnabled(it
.value().toBool());
581 if (hasKey(u
"autorun_on_torrent_added_program"_qs
))
582 pref
->setAutoRunOnTorrentAddedProgram(it
.value().toString());
583 // Run an external program on torrent finished
584 if (hasKey(u
"autorun_enabled"_qs
))
585 pref
->setAutoRunOnTorrentFinishedEnabled(it
.value().toBool());
586 if (hasKey(u
"autorun_program"_qs
))
587 pref
->setAutoRunOnTorrentFinishedProgram(it
.value().toString());
591 if (hasKey(u
"random_port"_qs
) && it
.value().toBool()) // deprecated
595 else if (hasKey(u
"listen_port"_qs
))
597 session
->setPort(it
.value().toInt());
599 if (hasKey(u
"upnp"_qs
))
600 Net::PortForwarder::instance()->setEnabled(it
.value().toBool());
601 // Connections Limits
602 if (hasKey(u
"max_connec"_qs
))
603 session
->setMaxConnections(it
.value().toInt());
604 if (hasKey(u
"max_connec_per_torrent"_qs
))
605 session
->setMaxConnectionsPerTorrent(it
.value().toInt());
606 if (hasKey(u
"max_uploads"_qs
))
607 session
->setMaxUploads(it
.value().toInt());
608 if (hasKey(u
"max_uploads_per_torrent"_qs
))
609 session
->setMaxUploadsPerTorrent(it
.value().toInt());
612 auto proxyManager
= Net::ProxyConfigurationManager::instance();
613 Net::ProxyConfiguration proxyConf
= proxyManager
->proxyConfiguration();
614 if (hasKey(u
"proxy_type"_qs
))
615 proxyConf
.type
= Utils::String::toEnum(it
.value().toString(), Net::ProxyType::HTTP
);
616 if (hasKey(u
"proxy_ip"_qs
))
617 proxyConf
.ip
= it
.value().toString();
618 if (hasKey(u
"proxy_port"_qs
))
619 proxyConf
.port
= it
.value().toUInt();
620 if (hasKey(u
"proxy_auth_enabled"_qs
))
621 proxyConf
.authEnabled
= it
.value().toBool();
622 if (hasKey(u
"proxy_username"_qs
))
623 proxyConf
.username
= it
.value().toString();
624 if (hasKey(u
"proxy_password"_qs
))
625 proxyConf
.password
= it
.value().toString();
626 proxyManager
->setProxyConfiguration(proxyConf
);
628 if (hasKey(u
"proxy_bittorrent"_qs
))
629 pref
->setUseProxyForBT(it
.value().toBool());
630 if (hasKey(u
"proxy_peer_connections"_qs
))
631 session
->setProxyPeerConnectionsEnabled(it
.value().toBool());
632 if (hasKey(u
"proxy_hostname_lookup"_qs
))
633 session
->setProxyHostnameLookupEnabled(it
.value().toBool());
634 if (hasKey(u
"proxy_rss"_qs
))
635 pref
->setUseProxyForRSS(it
.value().toBool());
636 if (hasKey(u
"proxy_misc"_qs
))
637 pref
->setUseProxyForGeneralPurposes(it
.value().toBool());
640 if (hasKey(u
"ip_filter_enabled"_qs
))
641 session
->setIPFilteringEnabled(it
.value().toBool());
642 if (hasKey(u
"ip_filter_path"_qs
))
643 session
->setIPFilterFile(Path(it
.value().toString()));
644 if (hasKey(u
"ip_filter_trackers"_qs
))
645 session
->setTrackerFilteringEnabled(it
.value().toBool());
646 if (hasKey(u
"banned_IPs"_qs
))
647 session
->setBannedIPs(it
.value().toString().split(u
'\n', Qt::SkipEmptyParts
));
650 // Global Rate Limits
651 if (hasKey(u
"dl_limit"_qs
))
652 session
->setGlobalDownloadSpeedLimit(it
.value().toInt());
653 if (hasKey(u
"up_limit"_qs
))
654 session
->setGlobalUploadSpeedLimit(it
.value().toInt());
655 if (hasKey(u
"alt_dl_limit"_qs
))
656 session
->setAltGlobalDownloadSpeedLimit(it
.value().toInt());
657 if (hasKey(u
"alt_up_limit"_qs
))
658 session
->setAltGlobalUploadSpeedLimit(it
.value().toInt());
659 if (hasKey(u
"bittorrent_protocol"_qs
))
660 session
->setBTProtocol(static_cast<BitTorrent::BTProtocol
>(it
.value().toInt()));
661 if (hasKey(u
"limit_utp_rate"_qs
))
662 session
->setUTPRateLimited(it
.value().toBool());
663 if (hasKey(u
"limit_tcp_overhead"_qs
))
664 session
->setIncludeOverheadInLimits(it
.value().toBool());
665 if (hasKey(u
"limit_lan_peers"_qs
))
666 session
->setIgnoreLimitsOnLAN(!it
.value().toBool());
668 if (hasKey(u
"scheduler_enabled"_qs
))
669 session
->setBandwidthSchedulerEnabled(it
.value().toBool());
670 if (m
.contains(u
"schedule_from_hour"_qs
) && m
.contains(u
"schedule_from_min"_qs
))
671 pref
->setSchedulerStartTime(QTime(m
[u
"schedule_from_hour"_qs
].toInt(), m
[u
"schedule_from_min"_qs
].toInt()));
672 if (m
.contains(u
"schedule_to_hour"_qs
) && m
.contains(u
"schedule_to_min"_qs
))
673 pref
->setSchedulerEndTime(QTime(m
[u
"schedule_to_hour"_qs
].toInt(), m
[u
"schedule_to_min"_qs
].toInt()));
674 if (hasKey(u
"scheduler_days"_qs
))
675 pref
->setSchedulerDays(static_cast<Scheduler::Days
>(it
.value().toInt()));
679 if (hasKey(u
"dht"_qs
))
680 session
->setDHTEnabled(it
.value().toBool());
681 if (hasKey(u
"pex"_qs
))
682 session
->setPeXEnabled(it
.value().toBool());
683 if (hasKey(u
"lsd"_qs
))
684 session
->setLSDEnabled(it
.value().toBool());
685 if (hasKey(u
"encryption"_qs
))
686 session
->setEncryption(it
.value().toInt());
687 if (hasKey(u
"anonymous_mode"_qs
))
688 session
->setAnonymousModeEnabled(it
.value().toBool());
689 // Max active checking torrents
690 if (hasKey(u
"max_active_checking_torrents"_qs
))
691 session
->setMaxActiveCheckingTorrents(it
.value().toInt());
693 if (hasKey(u
"queueing_enabled"_qs
))
694 session
->setQueueingSystemEnabled(it
.value().toBool());
695 if (hasKey(u
"max_active_downloads"_qs
))
696 session
->setMaxActiveDownloads(it
.value().toInt());
697 if (hasKey(u
"max_active_torrents"_qs
))
698 session
->setMaxActiveTorrents(it
.value().toInt());
699 if (hasKey(u
"max_active_uploads"_qs
))
700 session
->setMaxActiveUploads(it
.value().toInt());
701 if (hasKey(u
"dont_count_slow_torrents"_qs
))
702 session
->setIgnoreSlowTorrentsForQueueing(it
.value().toBool());
703 if (hasKey(u
"slow_torrent_dl_rate_threshold"_qs
))
704 session
->setDownloadRateForSlowTorrents(it
.value().toInt());
705 if (hasKey(u
"slow_torrent_ul_rate_threshold"_qs
))
706 session
->setUploadRateForSlowTorrents(it
.value().toInt());
707 if (hasKey(u
"slow_torrent_inactive_timer"_qs
))
708 session
->setSlowTorrentsInactivityTimer(it
.value().toInt());
709 // Share Ratio Limiting
710 if (hasKey(u
"max_ratio_enabled"_qs
))
712 if (it
.value().toBool())
713 session
->setGlobalMaxRatio(m
[u
"max_ratio"_qs
].toReal());
715 session
->setGlobalMaxRatio(-1);
717 if (hasKey(u
"max_seeding_time_enabled"_qs
))
719 if (it
.value().toBool())
720 session
->setGlobalMaxSeedingMinutes(m
[u
"max_seeding_time"_qs
].toInt());
722 session
->setGlobalMaxSeedingMinutes(-1);
724 if (hasKey(u
"max_ratio_act"_qs
))
725 session
->setMaxRatioAction(static_cast<MaxRatioAction
>(it
.value().toInt()));
727 if (hasKey(u
"add_trackers_enabled"_qs
))
728 session
->setAddTrackersEnabled(it
.value().toBool());
729 if (hasKey(u
"add_trackers"_qs
))
730 session
->setAdditionalTrackers(it
.value().toString());
734 if (hasKey(u
"web_ui_domain_list"_qs
))
735 pref
->setServerDomains(it
.value().toString());
736 if (hasKey(u
"web_ui_address"_qs
))
737 pref
->setWebUiAddress(it
.value().toString());
738 if (hasKey(u
"web_ui_port"_qs
))
739 pref
->setWebUiPort(it
.value().value
<quint16
>());
740 if (hasKey(u
"web_ui_upnp"_qs
))
741 pref
->setUPnPForWebUIPort(it
.value().toBool());
742 if (hasKey(u
"use_https"_qs
))
743 pref
->setWebUiHttpsEnabled(it
.value().toBool());
744 if (hasKey(u
"web_ui_https_cert_path"_qs
))
745 pref
->setWebUIHttpsCertificatePath(Path(it
.value().toString()));
746 if (hasKey(u
"web_ui_https_key_path"_qs
))
747 pref
->setWebUIHttpsKeyPath(Path(it
.value().toString()));
749 if (hasKey(u
"web_ui_username"_qs
))
750 pref
->setWebUiUsername(it
.value().toString());
751 if (hasKey(u
"web_ui_password"_qs
))
752 pref
->setWebUIPassword(Utils::Password::PBKDF2::generate(it
.value().toByteArray()));
753 if (hasKey(u
"bypass_local_auth"_qs
))
754 pref
->setWebUiLocalAuthEnabled(!it
.value().toBool());
755 if (hasKey(u
"bypass_auth_subnet_whitelist_enabled"_qs
))
756 pref
->setWebUiAuthSubnetWhitelistEnabled(it
.value().toBool());
757 if (hasKey(u
"bypass_auth_subnet_whitelist"_qs
))
759 // recognize new lines and commas as delimiters
760 pref
->setWebUiAuthSubnetWhitelist(it
.value().toString().split(QRegularExpression(u
"\n|,"_qs
), Qt::SkipEmptyParts
));
762 if (hasKey(u
"web_ui_max_auth_fail_count"_qs
))
763 pref
->setWebUIMaxAuthFailCount(it
.value().toInt());
764 if (hasKey(u
"web_ui_ban_duration"_qs
))
765 pref
->setWebUIBanDuration(std::chrono::seconds
{it
.value().toInt()});
766 if (hasKey(u
"web_ui_session_timeout"_qs
))
767 pref
->setWebUISessionTimeout(it
.value().toInt());
768 // Use alternative Web UI
769 if (hasKey(u
"alternative_webui_enabled"_qs
))
770 pref
->setAltWebUiEnabled(it
.value().toBool());
771 if (hasKey(u
"alternative_webui_path"_qs
))
772 pref
->setWebUiRootFolder(Path(it
.value().toString()));
774 if (hasKey(u
"web_ui_clickjacking_protection_enabled"_qs
))
775 pref
->setWebUiClickjackingProtectionEnabled(it
.value().toBool());
776 if (hasKey(u
"web_ui_csrf_protection_enabled"_qs
))
777 pref
->setWebUiCSRFProtectionEnabled(it
.value().toBool());
778 if (hasKey(u
"web_ui_secure_cookie_enabled"_qs
))
779 pref
->setWebUiSecureCookieEnabled(it
.value().toBool());
780 if (hasKey(u
"web_ui_host_header_validation_enabled"_qs
))
781 pref
->setWebUIHostHeaderValidationEnabled(it
.value().toBool());
782 // Custom HTTP headers
783 if (hasKey(u
"web_ui_use_custom_http_headers_enabled"_qs
))
784 pref
->setWebUICustomHTTPHeadersEnabled(it
.value().toBool());
785 if (hasKey(u
"web_ui_custom_http_headers"_qs
))
786 pref
->setWebUICustomHTTPHeaders(it
.value().toString());
788 if (hasKey(u
"web_ui_reverse_proxy_enabled"_qs
))
789 pref
->setWebUIReverseProxySupportEnabled(it
.value().toBool());
790 if (hasKey(u
"web_ui_reverse_proxies_list"_qs
))
791 pref
->setWebUITrustedReverseProxiesList(it
.value().toString());
792 // Update my dynamic domain name
793 if (hasKey(u
"dyndns_enabled"_qs
))
794 pref
->setDynDNSEnabled(it
.value().toBool());
795 if (hasKey(u
"dyndns_service"_qs
))
796 pref
->setDynDNSService(static_cast<DNS::Service
>(it
.value().toInt()));
797 if (hasKey(u
"dyndns_username"_qs
))
798 pref
->setDynDNSUsername(it
.value().toString());
799 if (hasKey(u
"dyndns_password"_qs
))
800 pref
->setDynDNSPassword(it
.value().toString());
801 if (hasKey(u
"dyndns_domain"_qs
))
802 pref
->setDynDomainName(it
.value().toString());
804 if (hasKey(u
"rss_refresh_interval"_qs
))
805 RSS::Session::instance()->setRefreshInterval(it
.value().toInt());
806 if (hasKey(u
"rss_max_articles_per_feed"_qs
))
807 RSS::Session::instance()->setMaxArticlesPerFeed(it
.value().toInt());
808 if (hasKey(u
"rss_processing_enabled"_qs
))
809 RSS::Session::instance()->setProcessingEnabled(it
.value().toBool());
810 if (hasKey(u
"rss_auto_downloading_enabled"_qs
))
811 RSS::AutoDownloader::instance()->setProcessingEnabled(it
.value().toBool());
812 if (hasKey(u
"rss_download_repack_proper_episodes"_qs
))
813 RSS::AutoDownloader::instance()->setDownloadRepacks(it
.value().toBool());
814 if (hasKey(u
"rss_smart_episode_filters"_qs
))
815 RSS::AutoDownloader::instance()->setSmartEpisodeFilters(it
.value().toString().split(u
'\n'));
818 // qBittorrent preferences
819 // Resume data storage type
820 if (hasKey(u
"resume_data_storage_type"_qs
))
821 session
->setResumeDataStorageType(Utils::String::toEnum(it
.value().toString(), BitTorrent::ResumeDataStorageType::Legacy
));
822 // Physical memory (RAM) usage limit
823 if (hasKey(u
"memory_working_set_limit"_qs
))
824 app()->setMemoryWorkingSetLimit(it
.value().toInt());
825 // Current network interface
826 if (hasKey(u
"current_network_interface"_qs
))
828 const QString ifaceValue
{it
.value().toString()};
830 const QList
<QNetworkInterface
> ifaces
= QNetworkInterface::allInterfaces();
831 const auto ifacesIter
= std::find_if(ifaces
.cbegin(), ifaces
.cend(), [&ifaceValue
](const QNetworkInterface
&iface
)
833 return (!iface
.addressEntries().isEmpty()) && (iface
.name() == ifaceValue
);
835 const QString ifaceName
= (ifacesIter
!= ifaces
.cend()) ? ifacesIter
->humanReadableName() : QString
{};
837 session
->setNetworkInterface(ifaceValue
);
838 session
->setNetworkInterfaceName(ifaceName
);
840 // Current network interface address
841 if (hasKey(u
"current_interface_address"_qs
))
843 const QHostAddress ifaceAddress
{it
.value().toString().trimmed()};
844 session
->setNetworkInterfaceAddress(ifaceAddress
.isNull() ? QString
{} : ifaceAddress
.toString());
846 // Save resume data interval
847 if (hasKey(u
"save_resume_data_interval"_qs
))
848 session
->setSaveResumeDataInterval(it
.value().toInt());
849 // Recheck completed torrents
850 if (hasKey(u
"recheck_completed_torrents"_qs
))
851 pref
->recheckTorrentsOnCompletion(it
.value().toBool());
853 if (hasKey(u
"refresh_interval"_qs
))
854 session
->setRefreshInterval(it
.value().toInt());
855 // Resolve peer countries
856 if (hasKey(u
"resolve_peer_countries"_qs
))
857 pref
->resolvePeerCountries(it
.value().toBool());
858 // Reannounce to all trackers when ip/port changed
859 if (hasKey(u
"reannounce_when_address_changed"_qs
))
860 session
->setReannounceWhenAddressChangedEnabled(it
.value().toBool());
862 // libtorrent preferences
864 if (hasKey(u
"async_io_threads"_qs
))
865 session
->setAsyncIOThreads(it
.value().toInt());
867 if (hasKey(u
"hashing_threads"_qs
))
868 session
->setHashingThreads(it
.value().toInt());
870 if (hasKey(u
"file_pool_size"_qs
))
871 session
->setFilePoolSize(it
.value().toInt());
872 // Checking Memory Usage
873 if (hasKey(u
"checking_memory_use"_qs
))
874 session
->setCheckingMemUsage(it
.value().toInt());
876 if (hasKey(u
"disk_cache"_qs
))
877 session
->setDiskCacheSize(it
.value().toInt());
878 if (hasKey(u
"disk_cache_ttl"_qs
))
879 session
->setDiskCacheTTL(it
.value().toInt());
881 if (hasKey(u
"disk_queue_size"_qs
))
882 session
->setDiskQueueSize(it
.value().toLongLong());
884 if (hasKey(u
"disk_io_type"_qs
))
885 session
->setDiskIOType(static_cast<BitTorrent::DiskIOType
>(it
.value().toInt()));
887 if (hasKey(u
"disk_io_read_mode"_qs
))
888 session
->setDiskIOReadMode(static_cast<BitTorrent::DiskIOReadMode
>(it
.value().toInt()));
889 // Disk IO write mode
890 if (hasKey(u
"disk_io_write_mode"_qs
))
891 session
->setDiskIOWriteMode(static_cast<BitTorrent::DiskIOWriteMode
>(it
.value().toInt()));
892 // Coalesce reads & writes
893 if (hasKey(u
"enable_coalesce_read_write"_qs
))
894 session
->setCoalesceReadWriteEnabled(it
.value().toBool());
895 // Piece extent affinity
896 if (hasKey(u
"enable_piece_extent_affinity"_qs
))
897 session
->setPieceExtentAffinity(it
.value().toBool());
899 if (hasKey(u
"enable_upload_suggestions"_qs
))
900 session
->setSuggestMode(it
.value().toBool());
901 // Send buffer watermark
902 if (hasKey(u
"send_buffer_watermark"_qs
))
903 session
->setSendBufferWatermark(it
.value().toInt());
904 if (hasKey(u
"send_buffer_low_watermark"_qs
))
905 session
->setSendBufferLowWatermark(it
.value().toInt());
906 if (hasKey(u
"send_buffer_watermark_factor"_qs
))
907 session
->setSendBufferWatermarkFactor(it
.value().toInt());
908 // Outgoing connections per second
909 if (hasKey(u
"connection_speed"_qs
))
910 session
->setConnectionSpeed(it
.value().toInt());
911 // Socket listen backlog size
912 if (hasKey(u
"socket_backlog_size"_qs
))
913 session
->setSocketBacklogSize(it
.value().toInt());
915 if (hasKey(u
"outgoing_ports_min"_qs
))
916 session
->setOutgoingPortsMin(it
.value().toInt());
917 if (hasKey(u
"outgoing_ports_max"_qs
))
918 session
->setOutgoingPortsMax(it
.value().toInt());
919 // UPnP lease duration
920 if (hasKey(u
"upnp_lease_duration"_qs
))
921 session
->setUPnPLeaseDuration(it
.value().toInt());
923 if (hasKey(u
"peer_tos"_qs
))
924 session
->setPeerToS(it
.value().toInt());
925 // uTP-TCP mixed mode
926 if (hasKey(u
"utp_tcp_mixed_mode"_qs
))
927 session
->setUtpMixedMode(static_cast<BitTorrent::MixedModeAlgorithm
>(it
.value().toInt()));
928 // Support internationalized domain name (IDN)
929 if (hasKey(u
"idn_support_enabled"_qs
))
930 session
->setIDNSupportEnabled(it
.value().toBool());
931 // Multiple connections per IP
932 if (hasKey(u
"enable_multi_connections_from_same_ip"_qs
))
933 session
->setMultiConnectionsPerIpEnabled(it
.value().toBool());
934 // Validate HTTPS tracker certificate
935 if (hasKey(u
"validate_https_tracker_certificate"_qs
))
936 session
->setValidateHTTPSTrackerCertificate(it
.value().toBool());
938 if (hasKey(u
"ssrf_mitigation"_qs
))
939 session
->setSSRFMitigationEnabled(it
.value().toBool());
940 // Disallow connection to peers on privileged ports
941 if (hasKey(u
"block_peers_on_privileged_ports"_qs
))
942 session
->setBlockPeersOnPrivilegedPorts(it
.value().toBool());
944 if (hasKey(u
"embedded_tracker_port"_qs
))
945 pref
->setTrackerPort(it
.value().toInt());
946 if (hasKey(u
"embedded_tracker_port_forwarding"_qs
))
947 pref
->setTrackerPortForwardingEnabled(it
.value().toBool());
948 if (hasKey(u
"enable_embedded_tracker"_qs
))
949 session
->setTrackerEnabled(it
.value().toBool());
951 if (hasKey(u
"upload_slots_behavior"_qs
))
952 session
->setChokingAlgorithm(static_cast<BitTorrent::ChokingAlgorithm
>(it
.value().toInt()));
953 // Seed choking algorithm
954 if (hasKey(u
"upload_choking_algorithm"_qs
))
955 session
->setSeedChokingAlgorithm(static_cast<BitTorrent::SeedChokingAlgorithm
>(it
.value().toInt()));
957 if (hasKey(u
"announce_to_all_trackers"_qs
))
958 session
->setAnnounceToAllTrackers(it
.value().toBool());
959 if (hasKey(u
"announce_to_all_tiers"_qs
))
960 session
->setAnnounceToAllTiers(it
.value().toBool());
961 if (hasKey(u
"announce_ip"_qs
))
963 const QHostAddress announceAddr
{it
.value().toString().trimmed()};
964 session
->setAnnounceIP(announceAddr
.isNull() ? QString
{} : announceAddr
.toString());
966 if (hasKey(u
"max_concurrent_http_announces"_qs
))
967 session
->setMaxConcurrentHTTPAnnounces(it
.value().toInt());
968 if (hasKey(u
"stop_tracker_timeout"_qs
))
969 session
->setStopTrackerTimeout(it
.value().toInt());
971 if (hasKey(u
"peer_turnover"_qs
))
972 session
->setPeerTurnover(it
.value().toInt());
973 if (hasKey(u
"peer_turnover_cutoff"_qs
))
974 session
->setPeerTurnoverCutoff(it
.value().toInt());
975 if (hasKey(u
"peer_turnover_interval"_qs
))
976 session
->setPeerTurnoverInterval(it
.value().toInt());
977 // Maximum outstanding requests to a single peer
978 if (hasKey(u
"request_queue_size"_qs
))
979 session
->setRequestQueueSize(it
.value().toInt());
985 void AppController::defaultSavePathAction()
987 setResult(BitTorrent::Session::instance()->savePath().toString());
990 void AppController::networkInterfaceListAction()
992 QJsonArray ifaceList
;
993 for (const QNetworkInterface
&iface
: asConst(QNetworkInterface::allInterfaces()))
995 if (!iface
.addressEntries().isEmpty())
997 ifaceList
.append(QJsonObject
999 {u
"name"_qs
, iface
.humanReadableName()},
1000 {u
"value"_qs
, iface
.name()}
1005 setResult(ifaceList
);
1008 void AppController::networkInterfaceAddressListAction()
1010 requireParams({u
"iface"_qs
});
1012 const QString ifaceName
= params().value(u
"iface"_qs
);
1013 QJsonArray addressList
;
1015 const auto appendAddress
= [&addressList
](const QHostAddress
&addr
)
1017 if (addr
.protocol() == QAbstractSocket::IPv6Protocol
)
1018 addressList
.append(Utils::Net::canonicalIPv6Addr(addr
).toString());
1020 addressList
.append(addr
.toString());
1023 if (ifaceName
.isEmpty())
1025 for (const QHostAddress
&addr
: asConst(QNetworkInterface::allAddresses()))
1026 appendAddress(addr
);
1030 const QNetworkInterface iface
= QNetworkInterface::interfaceFromName(ifaceName
);
1031 for (const QNetworkAddressEntry
&entry
: asConst(iface
.addressEntries()))
1032 appendAddress(entry
.ip());
1035 setResult(addressList
);