Allow to use proxy per subsystem
[qBittorrent.git] / src / webui / api / appcontroller.cpp
blob0fdfff09690dd81569f8af69f5b28efcf2215118
1 /*
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"
33 #include <algorithm>
34 #include <chrono>
36 #include <QCoreApplication>
37 #include <QDebug>
38 #include <QJsonArray>
39 #include <QJsonDocument>
40 #include <QJsonObject>
41 #include <QNetworkInterface>
42 #include <QRegularExpression>
43 #include <QStringList>
44 #include <QTimer>
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)}
89 setResult(versions);
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();
108 QJsonObject data;
110 // Behavior
111 // Language
112 data[u"locale"_qs] = pref->getLocale();
113 data[u"performance_warning"_qs] = session->isPerformanceWarningEnabled();
114 // Log file
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();
123 // Downloads
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();
132 // Saving Management
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);
157 else
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();
183 // Connection
184 // Listening Port
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();
194 // Proxy Server
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();
210 // IP Filtering
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');
216 // Speed
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();
226 // Scheduling
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());
236 // Bittorrent
237 // Privacy
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();
245 // Torrent Queueing
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();
260 // Add trackers
261 data[u"add_trackers_enabled"_qs] = session->isAddTrackersEnabled();
262 data[u"add_trackers"_qs] = session->additionalTrackers();
264 // Web UI
265 // HTTP Server
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();
273 // Authentication
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();
287 // Security
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();
295 // Reverse proxy
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();
305 // RSS settings
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');
313 // Advanced settings
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();
327 // Refresh interval
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
335 // Async IO threads
336 data[u"async_io_threads"_qs] = session->asyncIOThreads();
337 // Hashing threads
338 data[u"hashing_threads"_qs] = session->hashingThreads();
339 // File pool size
340 data[u"file_pool_size"_qs] = session->filePoolSize();
341 // Checking memory usage
342 data[u"checking_memory_use"_qs] = session->checkingMemUsage();
343 // Disk write cache
344 data[u"disk_cache"_qs] = session->diskCacheSize();
345 data[u"disk_cache_ttl"_qs] = session->diskCacheTTL();
346 // Disk queue size
347 data[u"disk_queue_size"_qs] = session->diskQueueSize();
348 // Disk IO Type
349 data[u"disk_io_type"_qs] = static_cast<int>(session->diskIOType());
350 // Disk IO read mode
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();
358 // Suggest mode
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();
368 // Outgoing ports
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();
373 // Type of service
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();
383 // SSRF mitigation
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();
387 // Embedded tracker
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();
391 // Choking algorithm
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());
395 // Announce
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();
401 // Peer Turnover
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();
408 setResult(data);
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
422 it = m.find(key);
423 return (it != m.constEnd());
426 // Behavior
427 // Language
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));
438 else
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());
449 // Log file
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());
465 // Downloads
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());
483 // Saving Management
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))
509 PathList scanDirs;
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 &params = options.addTorrentParams;
521 bool isInt = false;
522 const int intVal = i.value().toInt(&isInt);
523 if (isInt)
525 if (intVal == 0)
527 params.savePath = watchedFolder;
528 params.useAutoTMM = false;
531 else
533 const Path customSavePath {i.value().toString()};
534 params.savePath = customSavePath;
535 params.useAutoTMM = false;
538 fsWatcher->setWatchedFolder(watchedFolder, options);
539 scanDirs.append(watchedFolder);
541 catch (...)
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());
589 // Connection
590 // Listening Port
591 if (hasKey(u"random_port"_qs) && it.value().toBool()) // deprecated
593 session->setPort(0);
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());
611 // Proxy Server
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());
639 // IP Filtering
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));
649 // Speed
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());
667 // Scheduling
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()));
677 // Bittorrent
678 // Privacy
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());
692 // Torrent Queueing
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());
714 else
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());
721 else
722 session->setGlobalMaxSeedingMinutes(-1);
724 if (hasKey(u"max_ratio_act"_qs))
725 session->setMaxRatioAction(static_cast<MaxRatioAction>(it.value().toInt()));
726 // Add trackers
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());
732 // Web UI
733 // HTTP Server
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()));
748 // Authentication
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()));
773 // Security
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());
787 // Reverse proxy
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'));
817 // Advanced settings
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());
852 // Refresh interval
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
863 // Async IO threads
864 if (hasKey(u"async_io_threads"_qs))
865 session->setAsyncIOThreads(it.value().toInt());
866 // Hashing threads
867 if (hasKey(u"hashing_threads"_qs))
868 session->setHashingThreads(it.value().toInt());
869 // File pool size
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());
875 // Disk write cache
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());
880 // Disk queue size
881 if (hasKey(u"disk_queue_size"_qs))
882 session->setDiskQueueSize(it.value().toLongLong());
883 // Disk IO Type
884 if (hasKey(u"disk_io_type"_qs))
885 session->setDiskIOType(static_cast<BitTorrent::DiskIOType>(it.value().toInt()));
886 // Disk IO read mode
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());
898 // Suggest mode
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());
914 // Outgoing ports
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());
922 // Type of service
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());
937 // SSRF mitigation
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());
943 // Embedded tracker
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());
950 // Choking algorithm
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()));
956 // Announce
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());
970 // Peer Turnover
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());
981 // Save preferences
982 pref->apply();
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());
1019 else
1020 addressList.append(addr.toString());
1023 if (ifaceName.isEmpty())
1025 for (const QHostAddress &addr : asConst(QNetworkInterface::allAddresses()))
1026 appendAddress(addr);
1028 else
1030 const QNetworkInterface iface = QNetworkInterface::interfaceFromName(ifaceName);
1031 for (const QNetworkAddressEntry &entry : asConst(iface.addressEntries()))
1032 appendAddress(entry.ip());
1035 setResult(addressList);