qBittorrent
appcontroller.cpp
Go to the documentation of this file.
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>
6  *
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.
11  *
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.
16  *
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.
20  *
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.
29  */
30 
31 #include "appcontroller.h"
32 
33 #include <algorithm>
34 
35 #include <QCoreApplication>
36 #include <QDebug>
37 #include <QJsonArray>
38 #include <QJsonDocument>
39 #include <QJsonObject>
40 #include <QNetworkInterface>
41 #include <QRegularExpression>
42 #include <QStringList>
43 #include <QTimer>
44 #include <QTranslator>
45 
47 #include "base/global.h"
48 #include "base/net/portforwarder.h"
50 #include "base/preferences.h"
52 #include "base/rss/rss_session.h"
53 #include "base/torrentfileguard.h"
55 #include "base/utils/fs.h"
56 #include "base/utils/misc.h"
57 #include "base/utils/net.h"
58 #include "base/utils/password.h"
59 #include "base/utils/string.h"
60 #include "base/version.h"
61 #include "../webapplication.h"
62 
64 {
65  setResult(static_cast<QString>(API_VERSION));
66 }
67 
69 {
70  setResult(QBT_VERSION);
71 }
72 
74 {
75  const QJsonObject versions =
76  {
77  {"qt", QT_VERSION_STR},
78  {"libtorrent", Utils::Misc::libtorrentVersionString()},
80  {"openssl", Utils::Misc::opensslVersionString()},
82  {"bitness", (QT_POINTER_SIZE * 8)}
83  };
84  setResult(versions);
85 }
86 
88 {
89  qDebug() << "Shutdown request from Web UI";
90 
91  // Special case handling for shutdown, we
92  // need to reply to the Web UI before
93  // actually shutting down.
94  QTimer::singleShot(100, qApp, &QCoreApplication::quit);
95 }
96 
98 {
99  const Preferences *const pref = Preferences::instance();
100  const auto *session = BitTorrent::Session::instance();
101  QJsonObject data;
102 
103  // Downloads
104  // When adding a torrent
105  data["torrent_content_layout"] = Utils::String::fromEnum(session->torrentContentLayout());
106  data["start_paused_enabled"] = session->isAddTorrentPaused();
107  data["auto_delete_mode"] = static_cast<int>(TorrentFileGuard::autoDeleteMode());
108  data["preallocate_all"] = session->isPreallocationEnabled();
109  data["incomplete_files_ext"] = session->isAppendExtensionEnabled();
110  // Saving Management
111  data["auto_tmm_enabled"] = !session->isAutoTMMDisabledByDefault();
112  data["torrent_changed_tmm_enabled"] = !session->isDisableAutoTMMWhenCategoryChanged();
113  data["save_path_changed_tmm_enabled"] = !session->isDisableAutoTMMWhenDefaultSavePathChanged();
114  data["category_changed_tmm_enabled"] = !session->isDisableAutoTMMWhenCategorySavePathChanged();
115  data["save_path"] = Utils::Fs::toNativePath(session->savePath());
116  data["temp_path_enabled"] = session->isDownloadPathEnabled();
117  data["temp_path"] = Utils::Fs::toNativePath(session->downloadPath());
118  data["export_dir"] = Utils::Fs::toNativePath(session->torrentExportDirectory());
119  data["export_dir_fin"] = Utils::Fs::toNativePath(session->finishedTorrentExportDirectory());
120 
121  // TODO: The following code is deprecated. Delete it once replaced by updated API method.
122  // === BEGIN DEPRECATED CODE === //
124  const QHash<QString, TorrentFilesWatcher::WatchedFolderOptions> watchedFolders = fsWatcher->folders();
125  QJsonObject nativeDirs;
126  for (auto i = watchedFolders.cbegin(); i != watchedFolders.cend(); ++i)
127  {
128  const QString watchedFolder = i.key();
129  const BitTorrent::AddTorrentParams params = i.value().addTorrentParams;
130  if (params.savePath.isEmpty())
131  nativeDirs.insert(Utils::Fs::toNativePath(watchedFolder), 1);
132  else if (params.savePath == watchedFolder)
133  nativeDirs.insert(Utils::Fs::toNativePath(watchedFolder), 0);
134  else
135  nativeDirs.insert(Utils::Fs::toNativePath(watchedFolder), Utils::Fs::toNativePath(params.savePath));
136  }
137  data["scan_dirs"] = nativeDirs;
138  // === END DEPRECATED CODE === //
139 
140  // Email notification upon download completion
141  data["mail_notification_enabled"] = pref->isMailNotificationEnabled();
142  data["mail_notification_sender"] = pref->getMailNotificationSender();
143  data["mail_notification_email"] = pref->getMailNotificationEmail();
144  data["mail_notification_smtp"] = pref->getMailNotificationSMTP();
145  data["mail_notification_ssl_enabled"] = pref->getMailNotificationSMTPSSL();
146  data["mail_notification_auth_enabled"] = pref->getMailNotificationSMTPAuth();
147  data["mail_notification_username"] = pref->getMailNotificationSMTPUsername();
148  data["mail_notification_password"] = pref->getMailNotificationSMTPPassword();
149  // Run an external program on torrent completion
150  data["autorun_enabled"] = pref->isAutoRunEnabled();
151  data["autorun_program"] = Utils::Fs::toNativePath(pref->getAutoRunProgram());
152 
153  // Connection
154  // Listening Port
155  data["listen_port"] = session->port();
156  data["random_port"] = (session->port() == 0); // deprecated
158  // Connections Limits
159  data["max_connec"] = session->maxConnections();
160  data["max_connec_per_torrent"] = session->maxConnectionsPerTorrent();
161  data["max_uploads"] = session->maxUploads();
162  data["max_uploads_per_torrent"] = session->maxUploadsPerTorrent();
163 
164  // Proxy Server
165  const auto *proxyManager = Net::ProxyConfigurationManager::instance();
166  Net::ProxyConfiguration proxyConf = proxyManager->proxyConfiguration();
167  data["proxy_type"] = static_cast<int>(proxyConf.type);
168  data["proxy_ip"] = proxyConf.ip;
169  data["proxy_port"] = proxyConf.port;
170  data["proxy_auth_enabled"] = proxyManager->isAuthenticationRequired(); // deprecated
171  data["proxy_username"] = proxyConf.username;
172  data["proxy_password"] = proxyConf.password;
173 
174  data["proxy_peer_connections"] = session->isProxyPeerConnectionsEnabled();
175  data["proxy_torrents_only"] = proxyManager->isProxyOnlyForTorrents();
176 
177  // IP Filtering
178  data["ip_filter_enabled"] = session->isIPFilteringEnabled();
179  data["ip_filter_path"] = Utils::Fs::toNativePath(session->IPFilterFile());
180  data["ip_filter_trackers"] = session->isTrackerFilteringEnabled();
181  data["banned_IPs"] = session->bannedIPs().join('\n');
182 
183  // Speed
184  // Global Rate Limits
185  data["dl_limit"] = session->globalDownloadSpeedLimit();
186  data["up_limit"] = session->globalUploadSpeedLimit();
187  data["alt_dl_limit"] = session->altGlobalDownloadSpeedLimit();
188  data["alt_up_limit"] = session->altGlobalUploadSpeedLimit();
189  data["bittorrent_protocol"] = static_cast<int>(session->btProtocol());
190  data["limit_utp_rate"] = session->isUTPRateLimited();
191  data["limit_tcp_overhead"] = session->includeOverheadInLimits();
192  data["limit_lan_peers"] = !session->ignoreLimitsOnLAN();
193  // Scheduling
194  data["scheduler_enabled"] = session->isBandwidthSchedulerEnabled();
195  const QTime start_time = pref->getSchedulerStartTime();
196  data["schedule_from_hour"] = start_time.hour();
197  data["schedule_from_min"] = start_time.minute();
198  const QTime end_time = pref->getSchedulerEndTime();
199  data["schedule_to_hour"] = end_time.hour();
200  data["schedule_to_min"] = end_time.minute();
201  data["scheduler_days"] = static_cast<int>(pref->getSchedulerDays());
202 
203  // Bittorrent
204  // Privacy
205  data["dht"] = session->isDHTEnabled();
206  data["pex"] = session->isPeXEnabled();
207  data["lsd"] = session->isLSDEnabled();
208  data["encryption"] = session->encryption();
209  data["anonymous_mode"] = session->isAnonymousModeEnabled();
210  // Torrent Queueing
211  data["queueing_enabled"] = session->isQueueingSystemEnabled();
212  data["max_active_downloads"] = session->maxActiveDownloads();
213  data["max_active_torrents"] = session->maxActiveTorrents();
214  data["max_active_uploads"] = session->maxActiveUploads();
215  data["dont_count_slow_torrents"] = session->ignoreSlowTorrentsForQueueing();
216  data["slow_torrent_dl_rate_threshold"] = session->downloadRateForSlowTorrents();
217  data["slow_torrent_ul_rate_threshold"] = session->uploadRateForSlowTorrents();
218  data["slow_torrent_inactive_timer"] = session->slowTorrentsInactivityTimer();
219  // Share Ratio Limiting
220  data["max_ratio_enabled"] = (session->globalMaxRatio() >= 0.);
221  data["max_ratio"] = session->globalMaxRatio();
222  data["max_seeding_time_enabled"] = (session->globalMaxSeedingMinutes() >= 0.);
223  data["max_seeding_time"] = session->globalMaxSeedingMinutes();
224  data["max_ratio_act"] = session->maxRatioAction();
225  // Add trackers
226  data["add_trackers_enabled"] = session->isAddTrackersEnabled();
227  data["add_trackers"] = session->additionalTrackers();
228 
229  // Web UI
230  // Language
231  data["locale"] = pref->getLocale();
232  // HTTP Server
233  data["web_ui_domain_list"] = pref->getServerDomains();
234  data["web_ui_address"] = pref->getWebUiAddress();
235  data["web_ui_port"] = pref->getWebUiPort();
236  data["web_ui_upnp"] = pref->useUPnPForWebUIPort();
237  data["use_https"] = pref->isWebUiHttpsEnabled();
238  data["web_ui_https_cert_path"] = pref->getWebUIHttpsCertificatePath();
239  data["web_ui_https_key_path"] = pref->getWebUIHttpsKeyPath();
240  // Authentication
241  data["web_ui_username"] = pref->getWebUiUsername();
242  data["bypass_local_auth"] = !pref->isWebUiLocalAuthEnabled();
243  data["bypass_auth_subnet_whitelist_enabled"] = pref->isWebUiAuthSubnetWhitelistEnabled();
244  QStringList authSubnetWhitelistStringList;
245  for (const Utils::Net::Subnet &subnet : asConst(pref->getWebUiAuthSubnetWhitelist()))
246  authSubnetWhitelistStringList << Utils::Net::subnetToString(subnet);
247  data["bypass_auth_subnet_whitelist"] = authSubnetWhitelistStringList.join('\n');
248  data["web_ui_max_auth_fail_count"] = pref->getWebUIMaxAuthFailCount();
249  data["web_ui_ban_duration"] = static_cast<int>(pref->getWebUIBanDuration().count());
250  data["web_ui_session_timeout"] = pref->getWebUISessionTimeout();
251  // Use alternative Web UI
252  data["alternative_webui_enabled"] = pref->isAltWebUiEnabled();
253  data["alternative_webui_path"] = pref->getWebUiRootFolder();
254  // Security
255  data["web_ui_clickjacking_protection_enabled"] = pref->isWebUiClickjackingProtectionEnabled();
256  data["web_ui_csrf_protection_enabled"] = pref->isWebUiCSRFProtectionEnabled();
257  data["web_ui_secure_cookie_enabled"] = pref->isWebUiSecureCookieEnabled();
258  data["web_ui_host_header_validation_enabled"] = pref->isWebUIHostHeaderValidationEnabled();
259  // Custom HTTP headers
260  data["web_ui_use_custom_http_headers_enabled"] = pref->isWebUICustomHTTPHeadersEnabled();
261  data["web_ui_custom_http_headers"] = pref->getWebUICustomHTTPHeaders();
262  // Reverse proxy
263  data["web_ui_reverse_proxy_enabled"] = pref->isWebUIReverseProxySupportEnabled();
264  data["web_ui_reverse_proxies_list"] = pref->getWebUITrustedReverseProxiesList();
265  // Update my dynamic domain name
266  data["dyndns_enabled"] = pref->isDynDNSEnabled();
267  data["dyndns_service"] = static_cast<int>(pref->getDynDNSService());
268  data["dyndns_username"] = pref->getDynDNSUsername();
269  data["dyndns_password"] = pref->getDynDNSPassword();
270  data["dyndns_domain"] = pref->getDynDomainName();
271 
272  // RSS settings
273  data["rss_refresh_interval"] = RSS::Session::instance()->refreshInterval();
274  data["rss_max_articles_per_feed"] = RSS::Session::instance()->maxArticlesPerFeed();
275  data["rss_processing_enabled"] = RSS::Session::instance()->isProcessingEnabled();
276  data["rss_auto_downloading_enabled"] = RSS::AutoDownloader::instance()->isProcessingEnabled();
277  data["rss_download_repack_proper_episodes"] = RSS::AutoDownloader::instance()->downloadRepacks();
278  data["rss_smart_episode_filters"] = RSS::AutoDownloader::instance()->smartEpisodeFilters().join('\n');
279 
280  // Advanced settings
281  // qBitorrent preferences
282  // Current network interface
283  data["current_network_interface"] = session->networkInterface();
284  // Current network interface address
285  data["current_interface_address"] = BitTorrent::Session::instance()->networkInterfaceAddress();
286  // Save resume data interval
287  data["save_resume_data_interval"] = session->saveResumeDataInterval();
288  // Recheck completed torrents
289  data["recheck_completed_torrents"] = pref->recheckTorrentsOnCompletion();
290  // Resolve peer countries
291  data["resolve_peer_countries"] = pref->resolvePeerCountries();
292  // Reannounce to all trackers when ip/port changed
293  data["reannounce_when_address_changed"] = session->isReannounceWhenAddressChangedEnabled();
294 
295  // libtorrent preferences
296  // Async IO threads
297  data["async_io_threads"] = session->asyncIOThreads();
298  // Hashing threads
299  data["hashing_threads"] = session->hashingThreads();
300  // File pool size
301  data["file_pool_size"] = session->filePoolSize();
302  // Checking memory usage
303  data["checking_memory_use"] = session->checkingMemUsage();
304  // Disk write cache
305  data["disk_cache"] = session->diskCacheSize();
306  data["disk_cache_ttl"] = session->diskCacheTTL();
307  // Enable OS cache
308  data["enable_os_cache"] = session->useOSCache();
309  // Coalesce reads & writes
310  data["enable_coalesce_read_write"] = session->isCoalesceReadWriteEnabled();
311  // Piece Extent Affinity
312  data["enable_piece_extent_affinity"] = session->usePieceExtentAffinity();
313  // Suggest mode
314  data["enable_upload_suggestions"] = session->isSuggestModeEnabled();
315  // Send buffer watermark
316  data["send_buffer_watermark"] = session->sendBufferWatermark();
317  data["send_buffer_low_watermark"] = session->sendBufferLowWatermark();
318  data["send_buffer_watermark_factor"] = session->sendBufferWatermarkFactor();
319  // Outgoing connections per second
320  data["connection_speed"] = session->connectionSpeed();
321  // Socket listen backlog size
322  data["socket_backlog_size"] = session->socketBacklogSize();
323  // Outgoing ports
324  data["outgoing_ports_min"] = session->outgoingPortsMin();
325  data["outgoing_ports_max"] = session->outgoingPortsMax();
326  // UPnP lease duration
327  data["upnp_lease_duration"] = session->UPnPLeaseDuration();
328  // Type of service
329  data["peer_tos"] = session->peerToS();
330  // uTP-TCP mixed mode
331  data["utp_tcp_mixed_mode"] = static_cast<int>(session->utpMixedMode());
332  // Support internationalized domain name (IDN)
333  data["idn_support_enabled"] = session->isIDNSupportEnabled();
334  // Multiple connections per IP
335  data["enable_multi_connections_from_same_ip"] = session->multiConnectionsPerIpEnabled();
336  // Validate HTTPS tracker certificate
337  data["validate_https_tracker_certificate"] = session->validateHTTPSTrackerCertificate();
338  // SSRF mitigation
339  data["ssrf_mitigation"] = session->isSSRFMitigationEnabled();
340  // Disallow connection to peers on privileged ports
341  data["block_peers_on_privileged_ports"] = session->blockPeersOnPrivilegedPorts();
342  // Embedded tracker
343  data["enable_embedded_tracker"] = session->isTrackerEnabled();
344  data["embedded_tracker_port"] = pref->getTrackerPort();
345  // Choking algorithm
346  data["upload_slots_behavior"] = static_cast<int>(session->chokingAlgorithm());
347  // Seed choking algorithm
348  data["upload_choking_algorithm"] = static_cast<int>(session->seedChokingAlgorithm());
349  // Announce
350  data["announce_to_all_trackers"] = session->announceToAllTrackers();
351  data["announce_to_all_tiers"] = session->announceToAllTiers();
352  data["announce_ip"] = session->announceIP();
353  data["max_concurrent_http_announces"] = session->maxConcurrentHTTPAnnounces();
354  data["stop_tracker_timeout"] = session->stopTrackerTimeout();
355  // Peer Turnover
356  data["peer_turnover"] = session->peerTurnover();
357  data["peer_turnover_cutoff"] = session->peerTurnoverCutoff();
358  data["peer_turnover_interval"] = session->peerTurnoverInterval();
359 
360  setResult(data);
361 }
362 
364 {
365  requireParams({"json"});
366 
367  Preferences *const pref = Preferences::instance();
368  auto session = BitTorrent::Session::instance();
369  const QVariantHash m = QJsonDocument::fromJson(params()["json"].toUtf8()).toVariant().toHash();
370 
371  QVariantHash::ConstIterator it;
372  const auto hasKey = [&it, &m](const char *key) -> bool
373  {
374  it = m.find(QLatin1String(key));
375  return (it != m.constEnd());
376  };
377 
378  // Downloads
379  // When adding a torrent
380  if (hasKey("torrent_content_layout"))
381  session->setTorrentContentLayout(Utils::String::toEnum(it.value().toString(), BitTorrent::TorrentContentLayout::Original));
382  if (hasKey("start_paused_enabled"))
383  session->setAddTorrentPaused(it.value().toBool());
384  if (hasKey("auto_delete_mode"))
386 
387  if (hasKey("preallocate_all"))
388  session->setPreallocationEnabled(it.value().toBool());
389  if (hasKey("incomplete_files_ext"))
390  session->setAppendExtensionEnabled(it.value().toBool());
391 
392  // Saving Management
393  if (hasKey("auto_tmm_enabled"))
394  session->setAutoTMMDisabledByDefault(!it.value().toBool());
395  if (hasKey("torrent_changed_tmm_enabled"))
396  session->setDisableAutoTMMWhenCategoryChanged(!it.value().toBool());
397  if (hasKey("save_path_changed_tmm_enabled"))
398  session->setDisableAutoTMMWhenDefaultSavePathChanged(!it.value().toBool());
399  if (hasKey("category_changed_tmm_enabled"))
400  session->setDisableAutoTMMWhenCategorySavePathChanged(!it.value().toBool());
401  if (hasKey("save_path"))
402  session->setSavePath(it.value().toString());
403  if (hasKey("temp_path_enabled"))
404  session->setDownloadPathEnabled(it.value().toBool());
405  if (hasKey("temp_path"))
406  session->setDownloadPath(it.value().toString());
407  if (hasKey("export_dir"))
408  session->setTorrentExportDirectory(it.value().toString());
409  if (hasKey("export_dir_fin"))
410  session->setFinishedTorrentExportDirectory(it.value().toString());
411 
412  // TODO: The following code is deprecated. Delete it once replaced by updated API method.
413  // === BEGIN DEPRECATED CODE === //
414  if (hasKey("scan_dirs"))
415  {
416  QStringList scanDirs;
418  const QStringList oldScanDirs = fsWatcher->folders().keys();
419  const QVariantHash nativeDirs = it.value().toHash();
420  for (auto i = nativeDirs.cbegin(); i != nativeDirs.cend(); ++i)
421  {
422  try
423  {
424  const QString watchedFolder = TorrentFilesWatcher::makeCleanPath(i.key());
425  TorrentFilesWatcher::WatchedFolderOptions options = fsWatcher->folders().value(watchedFolder);
427 
428  bool isInt = false;
429  const int intVal = i.value().toInt(&isInt);
430  if (isInt)
431  {
432  if (intVal == 0)
433  {
434  params.savePath = watchedFolder;
435  params.useAutoTMM = false;
436  }
437  }
438  else
439  {
440  const QString customSavePath = i.value().toString();
441  params.savePath = customSavePath;
442  params.useAutoTMM = false;
443  }
444 
445  fsWatcher->setWatchedFolder(watchedFolder, options);
446  scanDirs.append(watchedFolder);
447  }
448  catch (...)
449  {
450  }
451  }
452 
453  // Update deleted folders
454  for (const QString &path : oldScanDirs)
455  {
456  if (!scanDirs.contains(path))
457  fsWatcher->removeWatchedFolder(path);
458  }
459  }
460  // === END DEPRECATED CODE === //
461 
462  // Email notification upon download completion
463  if (hasKey("mail_notification_enabled"))
464  pref->setMailNotificationEnabled(it.value().toBool());
465  if (hasKey("mail_notification_sender"))
466  pref->setMailNotificationSender(it.value().toString());
467  if (hasKey("mail_notification_email"))
468  pref->setMailNotificationEmail(it.value().toString());
469  if (hasKey("mail_notification_smtp"))
470  pref->setMailNotificationSMTP(it.value().toString());
471  if (hasKey("mail_notification_ssl_enabled"))
472  pref->setMailNotificationSMTPSSL(it.value().toBool());
473  if (hasKey("mail_notification_auth_enabled"))
474  pref->setMailNotificationSMTPAuth(it.value().toBool());
475  if (hasKey("mail_notification_username"))
476  pref->setMailNotificationSMTPUsername(it.value().toString());
477  if (hasKey("mail_notification_password"))
478  pref->setMailNotificationSMTPPassword(it.value().toString());
479  // Run an external program on torrent completion
480  if (hasKey("autorun_enabled"))
481  pref->setAutoRunEnabled(it.value().toBool());
482  if (hasKey("autorun_program"))
483  pref->setAutoRunProgram(it.value().toString());
484 
485  // Connection
486  // Listening Port
487  if (hasKey("random_port") && it.value().toBool()) // deprecated
488  {
489  session->setPort(0);
490  }
491  else if (hasKey("listen_port"))
492  {
493  session->setPort(it.value().toInt());
494  }
495  if (hasKey("upnp"))
496  Net::PortForwarder::instance()->setEnabled(it.value().toBool());
497  // Connections Limits
498  if (hasKey("max_connec"))
499  session->setMaxConnections(it.value().toInt());
500  if (hasKey("max_connec_per_torrent"))
501  session->setMaxConnectionsPerTorrent(it.value().toInt());
502  if (hasKey("max_uploads"))
503  session->setMaxUploads(it.value().toInt());
504  if (hasKey("max_uploads_per_torrent"))
505  session->setMaxUploadsPerTorrent(it.value().toInt());
506 
507  // Proxy Server
508  auto proxyManager = Net::ProxyConfigurationManager::instance();
509  Net::ProxyConfiguration proxyConf = proxyManager->proxyConfiguration();
510  if (hasKey("proxy_type"))
511  proxyConf.type = static_cast<Net::ProxyType>(it.value().toInt());
512  if (hasKey("proxy_ip"))
513  proxyConf.ip = it.value().toString();
514  if (hasKey("proxy_port"))
515  proxyConf.port = it.value().toUInt();
516  if (hasKey("proxy_username"))
517  proxyConf.username = it.value().toString();
518  if (hasKey("proxy_password"))
519  proxyConf.password = it.value().toString();
520  proxyManager->setProxyConfiguration(proxyConf);
521 
522  if (hasKey("proxy_peer_connections"))
523  session->setProxyPeerConnectionsEnabled(it.value().toBool());
524  if (hasKey("proxy_torrents_only"))
525  proxyManager->setProxyOnlyForTorrents(it.value().toBool());
526 
527  // IP Filtering
528  if (hasKey("ip_filter_enabled"))
529  session->setIPFilteringEnabled(it.value().toBool());
530  if (hasKey("ip_filter_path"))
531  session->setIPFilterFile(it.value().toString());
532  if (hasKey("ip_filter_trackers"))
533  session->setTrackerFilteringEnabled(it.value().toBool());
534  if (hasKey("banned_IPs"))
535  session->setBannedIPs(it.value().toString().split('\n', Qt::SkipEmptyParts));
536 
537  // Speed
538  // Global Rate Limits
539  if (hasKey("dl_limit"))
540  session->setGlobalDownloadSpeedLimit(it.value().toInt());
541  if (hasKey("up_limit"))
542  session->setGlobalUploadSpeedLimit(it.value().toInt());
543  if (hasKey("alt_dl_limit"))
544  session->setAltGlobalDownloadSpeedLimit(it.value().toInt());
545  if (hasKey("alt_up_limit"))
546  session->setAltGlobalUploadSpeedLimit(it.value().toInt());
547  if (hasKey("bittorrent_protocol"))
548  session->setBTProtocol(static_cast<BitTorrent::BTProtocol>(it.value().toInt()));
549  if (hasKey("limit_utp_rate"))
550  session->setUTPRateLimited(it.value().toBool());
551  if (hasKey("limit_tcp_overhead"))
552  session->setIncludeOverheadInLimits(it.value().toBool());
553  if (hasKey("limit_lan_peers"))
554  session->setIgnoreLimitsOnLAN(!it.value().toBool());
555  // Scheduling
556  if (hasKey("scheduler_enabled"))
557  session->setBandwidthSchedulerEnabled(it.value().toBool());
558  if (m.contains("schedule_from_hour") && m.contains("schedule_from_min"))
559  pref->setSchedulerStartTime(QTime(m["schedule_from_hour"].toInt(), m["schedule_from_min"].toInt()));
560  if (m.contains("schedule_to_hour") && m.contains("schedule_to_min"))
561  pref->setSchedulerEndTime(QTime(m["schedule_to_hour"].toInt(), m["schedule_to_min"].toInt()));
562  if (hasKey("scheduler_days"))
563  pref->setSchedulerDays(static_cast<Scheduler::Days>(it.value().toInt()));
564 
565  // Bittorrent
566  // Privacy
567  if (hasKey("dht"))
568  session->setDHTEnabled(it.value().toBool());
569  if (hasKey("pex"))
570  session->setPeXEnabled(it.value().toBool());
571  if (hasKey("lsd"))
572  session->setLSDEnabled(it.value().toBool());
573  if (hasKey("encryption"))
574  session->setEncryption(it.value().toInt());
575  if (hasKey("anonymous_mode"))
576  session->setAnonymousModeEnabled(it.value().toBool());
577  // Torrent Queueing
578  if (hasKey("queueing_enabled"))
579  session->setQueueingSystemEnabled(it.value().toBool());
580  if (hasKey("max_active_downloads"))
581  session->setMaxActiveDownloads(it.value().toInt());
582  if (hasKey("max_active_torrents"))
583  session->setMaxActiveTorrents(it.value().toInt());
584  if (hasKey("max_active_uploads"))
585  session->setMaxActiveUploads(it.value().toInt());
586  if (hasKey("dont_count_slow_torrents"))
587  session->setIgnoreSlowTorrentsForQueueing(it.value().toBool());
588  if (hasKey("slow_torrent_dl_rate_threshold"))
589  session->setDownloadRateForSlowTorrents(it.value().toInt());
590  if (hasKey("slow_torrent_ul_rate_threshold"))
591  session->setUploadRateForSlowTorrents(it.value().toInt());
592  if (hasKey("slow_torrent_inactive_timer"))
593  session->setSlowTorrentsInactivityTimer(it.value().toInt());
594  // Share Ratio Limiting
595  if (hasKey("max_ratio_enabled"))
596  {
597  if (it.value().toBool())
598  session->setGlobalMaxRatio(m["max_ratio"].toReal());
599  else
600  session->setGlobalMaxRatio(-1);
601  }
602  if (hasKey("max_seeding_time_enabled"))
603  {
604  if (it.value().toBool())
605  session->setGlobalMaxSeedingMinutes(m["max_seeding_time"].toInt());
606  else
607  session->setGlobalMaxSeedingMinutes(-1);
608  }
609  if (hasKey("max_ratio_act"))
610  session->setMaxRatioAction(static_cast<MaxRatioAction>(it.value().toInt()));
611  // Add trackers
612  if (hasKey("add_trackers_enabled"))
613  session->setAddTrackersEnabled(it.value().toBool());
614  if (hasKey("add_trackers"))
615  session->setAdditionalTrackers(it.value().toString());
616 
617  // Web UI
618  // Language
619  if (hasKey("locale"))
620  {
621  QString locale = it.value().toString();
622  if (pref->getLocale() != locale)
623  {
624  auto *translator = new QTranslator;
625  if (translator->load(QLatin1String(":/lang/qbittorrent_") + locale))
626  {
627  qDebug("%s locale recognized, using translation.", qUtf8Printable(locale));
628  }
629  else
630  {
631  qDebug("%s locale unrecognized, using default (en).", qUtf8Printable(locale));
632  }
633  qApp->installTranslator(translator);
634 
635  pref->setLocale(locale);
636  }
637  }
638  // HTTP Server
639  if (hasKey("web_ui_domain_list"))
640  pref->setServerDomains(it.value().toString());
641  if (hasKey("web_ui_address"))
642  pref->setWebUiAddress(it.value().toString());
643  if (hasKey("web_ui_port"))
644  pref->setWebUiPort(it.value().toUInt());
645  if (hasKey("web_ui_upnp"))
646  pref->setUPnPForWebUIPort(it.value().toBool());
647  if (hasKey("use_https"))
648  pref->setWebUiHttpsEnabled(it.value().toBool());
649  if (hasKey("web_ui_https_cert_path"))
650  pref->setWebUIHttpsCertificatePath(it.value().toString());
651  if (hasKey("web_ui_https_key_path"))
652  pref->setWebUIHttpsKeyPath(it.value().toString());
653  // Authentication
654  if (hasKey("web_ui_username"))
655  pref->setWebUiUsername(it.value().toString());
656  if (hasKey("web_ui_password"))
657  pref->setWebUIPassword(Utils::Password::PBKDF2::generate(it.value().toByteArray()));
658  if (hasKey("bypass_local_auth"))
659  pref->setWebUiLocalAuthEnabled(!it.value().toBool());
660  if (hasKey("bypass_auth_subnet_whitelist_enabled"))
661  pref->setWebUiAuthSubnetWhitelistEnabled(it.value().toBool());
662  if (hasKey("bypass_auth_subnet_whitelist"))
663  {
664  // recognize new lines and commas as delimiters
665  pref->setWebUiAuthSubnetWhitelist(it.value().toString().split(QRegularExpression("\n|,"), Qt::SkipEmptyParts));
666  }
667  if (hasKey("web_ui_max_auth_fail_count"))
668  pref->setWebUIMaxAuthFailCount(it.value().toInt());
669  if (hasKey("web_ui_ban_duration"))
670  pref->setWebUIBanDuration(std::chrono::seconds {it.value().toInt()});
671  if (hasKey("web_ui_session_timeout"))
672  pref->setWebUISessionTimeout(it.value().toInt());
673  // Use alternative Web UI
674  if (hasKey("alternative_webui_enabled"))
675  pref->setAltWebUiEnabled(it.value().toBool());
676  if (hasKey("alternative_webui_path"))
677  pref->setWebUiRootFolder(it.value().toString());
678  // Security
679  if (hasKey("web_ui_clickjacking_protection_enabled"))
680  pref->setWebUiClickjackingProtectionEnabled(it.value().toBool());
681  if (hasKey("web_ui_csrf_protection_enabled"))
682  pref->setWebUiCSRFProtectionEnabled(it.value().toBool());
683  if (hasKey("web_ui_secure_cookie_enabled"))
684  pref->setWebUiSecureCookieEnabled(it.value().toBool());
685  if (hasKey("web_ui_host_header_validation_enabled"))
686  pref->setWebUIHostHeaderValidationEnabled(it.value().toBool());
687  // Custom HTTP headers
688  if (hasKey("web_ui_use_custom_http_headers_enabled"))
689  pref->setWebUICustomHTTPHeadersEnabled(it.value().toBool());
690  if (hasKey("web_ui_custom_http_headers"))
691  pref->setWebUICustomHTTPHeaders(it.value().toString());
692  // Reverse proxy
693  if (hasKey("web_ui_reverse_proxy_enabled"))
694  pref->setWebUIReverseProxySupportEnabled(it.value().toBool());
695  if (hasKey("web_ui_reverse_proxies_list"))
696  pref->setWebUITrustedReverseProxiesList(it.value().toString());
697  // Update my dynamic domain name
698  if (hasKey("dyndns_enabled"))
699  pref->setDynDNSEnabled(it.value().toBool());
700  if (hasKey("dyndns_service"))
701  pref->setDynDNSService(static_cast<DNS::Service>(it.value().toInt()));
702  if (hasKey("dyndns_username"))
703  pref->setDynDNSUsername(it.value().toString());
704  if (hasKey("dyndns_password"))
705  pref->setDynDNSPassword(it.value().toString());
706  if (hasKey("dyndns_domain"))
707  pref->setDynDomainName(it.value().toString());
708 
709  if (hasKey("rss_refresh_interval"))
710  RSS::Session::instance()->setRefreshInterval(it.value().toInt());
711  if (hasKey("rss_max_articles_per_feed"))
712  RSS::Session::instance()->setMaxArticlesPerFeed(it.value().toInt());
713  if (hasKey("rss_processing_enabled"))
714  RSS::Session::instance()->setProcessingEnabled(it.value().toBool());
715  if (hasKey("rss_auto_downloading_enabled"))
716  RSS::AutoDownloader::instance()->setProcessingEnabled(it.value().toBool());
717  if (hasKey("rss_download_repack_proper_episodes"))
718  RSS::AutoDownloader::instance()->setDownloadRepacks(it.value().toBool());
719  if (hasKey("rss_smart_episode_filters"))
720  RSS::AutoDownloader::instance()->setSmartEpisodeFilters(it.value().toString().split('\n'));
721 
722  // Advanced settings
723  // qBittorrent preferences
724  // Current network interface
725  if (hasKey("current_network_interface"))
726  {
727  const QString ifaceValue {it.value().toString()};
728 
729  const QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
730  const auto ifacesIter = std::find_if(ifaces.cbegin(), ifaces.cend(), [&ifaceValue](const QNetworkInterface &iface)
731  {
732  return (!iface.addressEntries().isEmpty()) && (iface.name() == ifaceValue);
733  });
734  const QString ifaceName = (ifacesIter != ifaces.cend()) ? ifacesIter->humanReadableName() : QString {};
735 
736  session->setNetworkInterface(ifaceValue);
737  session->setNetworkInterfaceName(ifaceName);
738  }
739  // Current network interface address
740  if (hasKey("current_interface_address"))
741  {
742  const QHostAddress ifaceAddress {it.value().toString().trimmed()};
743  session->setNetworkInterfaceAddress(ifaceAddress.isNull() ? QString {} : ifaceAddress.toString());
744  }
745  // Save resume data interval
746  if (hasKey("save_resume_data_interval"))
747  session->setSaveResumeDataInterval(it.value().toInt());
748  // Recheck completed torrents
749  if (hasKey("recheck_completed_torrents"))
750  pref->recheckTorrentsOnCompletion(it.value().toBool());
751  // Resolve peer countries
752  if (hasKey("resolve_peer_countries"))
753  pref->resolvePeerCountries(it.value().toBool());
754  // Reannounce to all trackers when ip/port changed
755  if (hasKey("reannounce_when_address_changed"))
756  session->setReannounceWhenAddressChangedEnabled(it.value().toBool());
757 
758  // libtorrent preferences
759  // Async IO threads
760  if (hasKey("async_io_threads"))
761  session->setAsyncIOThreads(it.value().toInt());
762  // Hashing threads
763  if (hasKey("hashing_threads"))
764  session->setHashingThreads(it.value().toInt());
765  // File pool size
766  if (hasKey("file_pool_size"))
767  session->setFilePoolSize(it.value().toInt());
768  // Checking Memory Usage
769  if (hasKey("checking_memory_use"))
770  session->setCheckingMemUsage(it.value().toInt());
771  // Disk write cache
772  if (hasKey("disk_cache"))
773  session->setDiskCacheSize(it.value().toInt());
774  if (hasKey("disk_cache_ttl"))
775  session->setDiskCacheTTL(it.value().toInt());
776  // Enable OS cache
777  if (hasKey("enable_os_cache"))
778  session->setUseOSCache(it.value().toBool());
779  // Coalesce reads & writes
780  if (hasKey("enable_coalesce_read_write"))
781  session->setCoalesceReadWriteEnabled(it.value().toBool());
782  // Piece extent affinity
783  if (hasKey("enable_piece_extent_affinity"))
784  session->setPieceExtentAffinity(it.value().toBool());
785  // Suggest mode
786  if (hasKey("enable_upload_suggestions"))
787  session->setSuggestMode(it.value().toBool());
788  // Send buffer watermark
789  if (hasKey("send_buffer_watermark"))
790  session->setSendBufferWatermark(it.value().toInt());
791  if (hasKey("send_buffer_low_watermark"))
792  session->setSendBufferLowWatermark(it.value().toInt());
793  if (hasKey("send_buffer_watermark_factor"))
794  session->setSendBufferWatermarkFactor(it.value().toInt());
795  // Outgoing connections per second
796  if (hasKey("connection_speed"))
797  session->setConnectionSpeed(it.value().toInt());
798  // Socket listen backlog size
799  if (hasKey("socket_backlog_size"))
800  session->setSocketBacklogSize(it.value().toInt());
801  // Outgoing ports
802  if (hasKey("outgoing_ports_min"))
803  session->setOutgoingPortsMin(it.value().toInt());
804  if (hasKey("outgoing_ports_max"))
805  session->setOutgoingPortsMax(it.value().toInt());
806  // UPnP lease duration
807  if (hasKey("upnp_lease_duration"))
808  session->setUPnPLeaseDuration(it.value().toInt());
809  // Type of service
810  if (hasKey("peer_tos"))
811  session->setPeerToS(it.value().toInt());
812  // uTP-TCP mixed mode
813  if (hasKey("utp_tcp_mixed_mode"))
814  session->setUtpMixedMode(static_cast<BitTorrent::MixedModeAlgorithm>(it.value().toInt()));
815  // Support internationalized domain name (IDN)
816  if (hasKey("idn_support_enabled"))
817  session->setIDNSupportEnabled(it.value().toBool());
818  // Multiple connections per IP
819  if (hasKey("enable_multi_connections_from_same_ip"))
820  session->setMultiConnectionsPerIpEnabled(it.value().toBool());
821  // Validate HTTPS tracker certificate
822  if (hasKey("validate_https_tracker_certificate"))
823  session->setValidateHTTPSTrackerCertificate(it.value().toBool());
824  // SSRF mitigation
825  if (hasKey("ssrf_mitigation"))
826  session->setSSRFMitigationEnabled(it.value().toBool());
827  // Disallow connection to peers on privileged ports
828  if (hasKey("block_peers_on_privileged_ports"))
829  session->setBlockPeersOnPrivilegedPorts(it.value().toBool());
830  // Embedded tracker
831  if (hasKey("embedded_tracker_port"))
832  pref->setTrackerPort(it.value().toInt());
833  if (hasKey("enable_embedded_tracker"))
834  session->setTrackerEnabled(it.value().toBool());
835  // Choking algorithm
836  if (hasKey("upload_slots_behavior"))
837  session->setChokingAlgorithm(static_cast<BitTorrent::ChokingAlgorithm>(it.value().toInt()));
838  // Seed choking algorithm
839  if (hasKey("upload_choking_algorithm"))
840  session->setSeedChokingAlgorithm(static_cast<BitTorrent::SeedChokingAlgorithm>(it.value().toInt()));
841  // Announce
842  if (hasKey("announce_to_all_trackers"))
843  session->setAnnounceToAllTrackers(it.value().toBool());
844  if (hasKey("announce_to_all_tiers"))
845  session->setAnnounceToAllTiers(it.value().toBool());
846  if (hasKey("announce_ip"))
847  {
848  const QHostAddress announceAddr {it.value().toString().trimmed()};
849  session->setAnnounceIP(announceAddr.isNull() ? QString {} : announceAddr.toString());
850  }
851  if (hasKey("max_concurrent_http_announces"))
852  session->setMaxConcurrentHTTPAnnounces(it.value().toInt());
853  if (hasKey("stop_tracker_timeout"))
854  session->setStopTrackerTimeout(it.value().toInt());
855  // Peer Turnover
856  if (hasKey("peer_turnover"))
857  session->setPeerTurnover(it.value().toInt());
858  if (hasKey("peer_turnover_cutoff"))
859  session->setPeerTurnoverCutoff(it.value().toInt());
860  if (hasKey("peer_turnover_interval"))
861  session->setPeerTurnoverInterval(it.value().toInt());
862 
863  // Save preferences
864  pref->apply();
865 }
866 
868 {
870 }
871 
873 {
874  QJsonArray ifaceList;
875  for (const QNetworkInterface &iface : asConst(QNetworkInterface::allInterfaces()))
876  {
877  if (!iface.addressEntries().isEmpty())
878  {
879  ifaceList.append(QJsonObject
880  {
881  {"name", iface.humanReadableName()},
882  {"value", iface.name()}
883  });
884  }
885  }
886 
887  setResult(ifaceList);
888 }
889 
891 {
892  requireParams({"iface"});
893 
894  const QString ifaceName = params().value("iface");
895  QJsonArray addressList;
896 
897  const auto appendAddress = [&addressList](const QHostAddress &addr)
898  {
899  if (addr.protocol() == QAbstractSocket::IPv6Protocol)
900  addressList.append(Utils::Net::canonicalIPv6Addr(addr).toString());
901  else
902  addressList.append(addr.toString());
903  };
904 
905  if (ifaceName.isEmpty())
906  {
907  for (const QHostAddress &addr : asConst(QNetworkInterface::allAddresses()))
908  appendAddress(addr);
909  }
910  else
911  {
912  const QNetworkInterface iface = QNetworkInterface::interfaceFromName(ifaceName);
913  for (const QNetworkAddressEntry &entry : asConst(iface.addressEntries()))
914  appendAddress(entry.ip());
915  }
916 
917  setResult(addressList);
918 }
void requireParams(const QVector< QString > &requiredParams) const
const StringMap & params() const
const DataMap & data() const
void setResult(const QString &result)
void defaultSavePathAction()
void networkInterfaceAddressListAction()
void buildInfoAction()
void versionAction()
void webapiVersionAction()
void preferencesAction()
void shutdownAction()
void networkInterfaceListAction()
void setPreferencesAction()
static Session * instance()
Definition: session.cpp:997
QString networkInterfaceAddress() const
Definition: session.cpp:2823
static PortForwarder * instance()
virtual void setEnabled(bool enabled)=0
virtual bool isEnabled() const =0
static ProxyConfigurationManager * instance()
QString getMailNotificationSMTPUsername() const
QString getWebUICustomHTTPHeaders() const
QString getMailNotificationSMTPPassword() const
bool resolvePeerCountries() const
QString getAutoRunProgram() const
static Preferences * instance()
int getWebUIMaxAuthFailCount() const
QString getWebUiRootFolder() const
QString getWebUIHttpsCertificatePath() const
int getTrackerPort() const
std::chrono::seconds getWebUIBanDuration() const
QString getMailNotificationEmail() const
bool isWebUiLocalAuthEnabled() const
QString getWebUiAddress() const
bool getMailNotificationSMTPAuth() const
bool isWebUiSecureCookieEnabled() const
QString getDynDNSUsername() const
QString getMailNotificationSender() const
bool getMailNotificationSMTPSSL() const
QString getDynDNSPassword() const
bool isWebUIHostHeaderValidationEnabled() const
QTime getSchedulerStartTime() const
bool useUPnPForWebUIPort() const
bool isAltWebUiEnabled() const
bool isWebUiAuthSubnetWhitelistEnabled() const
QString getWebUITrustedReverseProxiesList() const
bool recheckTorrentsOnCompletion() const
QTime getSchedulerEndTime() const
bool isWebUICustomHTTPHeadersEnabled() const
bool isWebUiClickjackingProtectionEnabled() const
DNS::Service getDynDNSService() const
bool isDynDNSEnabled() const
QString getLocale() const
quint16 getWebUiPort() const
bool isWebUiCSRFProtectionEnabled() const
bool isWebUIReverseProxySupportEnabled() const
QString getWebUiUsername() const
Scheduler::Days getSchedulerDays() const
QString getServerDomains() const
QString getMailNotificationSMTP() const
int getWebUISessionTimeout() const
QVector< Utils::Net::Subnet > getWebUiAuthSubnetWhitelist() const
bool isMailNotificationEnabled() const
bool isWebUiHttpsEnabled() const
bool isAutoRunEnabled() const
QString getDynDomainName() const
QString getWebUIHttpsKeyPath() const
void setDownloadRepacks(bool enabled)
bool isProcessingEnabled() const
void setSmartEpisodeFilters(const QStringList &filters)
static AutoDownloader * instance()
QStringList smartEpisodeFilters() const
void setProcessingEnabled(bool enabled)
int refreshInterval() const
bool isProcessingEnabled() const
static Session * instance()
int maxArticlesPerFeed() const
void setRefreshInterval(int refreshInterval)
void setMaxArticlesPerFeed(int n)
void setProcessingEnabled(bool enabled)
static AutoDeleteMode autoDeleteMode()
static void setAutoDeleteMode(AutoDeleteMode mode)
void removeWatchedFolder(const QString &path)
QHash< QString, WatchedFolderOptions > folders() const
static TorrentFilesWatcher * instance()
static QString makeCleanPath(const QString &path)
void setWatchedFolder(const QString &path, const WatchedFolderOptions &options)
constexpr std::add_const_t< T > & asConst(T &t) noexcept
Definition: global.h:42
Service
Definition: preferences.h:68
QString toNativePath(const QString &path)
Definition: fs.cpp:64
QString libtorrentVersionString()
Definition: misc.cpp:487
QString opensslVersionString()
Definition: misc.cpp:494
QString boostVersionString()
Definition: misc.cpp:477
QString zlibVersionString()
Definition: misc.cpp:504
QString subnetToString(const Subnet &subnet)
Definition: net.cpp:95
QHostAddress canonicalIPv6Addr(const QHostAddress &addr)
Definition: net.cpp:100
QPair< QHostAddress, int > Subnet
Definition: net.h:40
QByteArray generate(const QString &password)
Definition: password.cpp:68
QString fromEnum(const T &value)
Definition: string.h:67
T toEnum(const QString &serializedValue, const T &defaultValue)
Definition: string.h:77
MaxRatioAction
Definition: session.h:72
BitTorrent::AddTorrentParams addTorrentParams
const Utils::Version< int, 3, 2 > API_VERSION