Sync translations from Transifex and run lupdate
[qBittorrent.git] / src / app / upgrade.cpp
blob01d3ddef83b3c92285ac4e9fdbdaed5daadc24fb
1 /*
2 * Bittorrent Client using Qt and libtorrent.
3 * Copyright (C) 2019 Mike Tzou (Chocobo1)
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * In addition, as a special exception, the copyright holders give permission to
20 * link this program with the OpenSSL project's "OpenSSL" library (or with
21 * modified versions of it that use the same license as the "OpenSSL" library),
22 * and distribute the linked executables. You must obey the GNU General Public
23 * License in all respects for all of the code used other than "OpenSSL". If you
24 * modify file(s), you may extend this exception to your version of the file(s),
25 * but you are not obligated to do so. If you do not wish to do so, delete this
26 * exception statement from your version.
29 #include "upgrade.h"
31 #include <QtGlobal>
32 #include <QMetaEnum>
34 #include "base/bittorrent/torrentcontentlayout.h"
35 #include "base/global.h"
36 #include "base/logger.h"
37 #include "base/net/proxyconfigurationmanager.h"
38 #include "base/preferences.h"
39 #include "base/profile.h"
40 #include "base/settingsstorage.h"
41 #include "base/settingvalue.h"
42 #include "base/utils/io.h"
43 #include "base/utils/string.h"
45 namespace
47 const int MIGRATION_VERSION = 5;
48 const QString MIGRATION_VERSION_KEY = u"Meta/MigrationVersion"_qs;
50 void exportWebUIHttpsFiles()
52 const auto migrate = [](const QString &oldKey, const QString &newKey, const Path &savePath)
54 SettingsStorage *settingsStorage {SettingsStorage::instance()};
55 const auto oldData {settingsStorage->loadValue<QByteArray>(oldKey)};
56 const auto newData {settingsStorage->loadValue<QString>(newKey)};
57 const QString errorMsgFormat {QObject::tr("Migrate preferences failed: WebUI https, file: \"%1\", error: \"%2\"")};
59 if (!newData.isEmpty() || oldData.isEmpty())
60 return;
62 const nonstd::expected<void, QString> result = Utils::IO::saveToFile(savePath, oldData);
63 if (!result)
65 LogMsg(errorMsgFormat.arg(savePath.toString(), result.error()) , Log::WARNING);
66 return;
69 settingsStorage->storeValue(newKey, savePath);
70 settingsStorage->removeValue(oldKey);
72 LogMsg(QObject::tr("Migrated preferences: WebUI https, exported data to file: \"%1\"").arg(savePath.toString())
73 , Log::INFO);
76 const Path configPath = specialFolderLocation(SpecialFolder::Config);
77 migrate(u"Preferences/WebUI/HTTPS/Certificate"_qs
78 , u"Preferences/WebUI/HTTPS/CertificatePath"_qs
79 , (configPath / Path(u"WebUICertificate.crt"_qs)));
80 migrate(u"Preferences/WebUI/HTTPS/Key"_qs
81 , u"Preferences/WebUI/HTTPS/KeyPath"_qs
82 , (configPath / Path(u"WebUIPrivateKey.pem"_qs)));
85 void upgradeTorrentContentLayout()
87 const QString oldKey = u"BitTorrent/Session/CreateTorrentSubfolder"_qs;
88 const QString newKey = u"BitTorrent/Session/TorrentContentLayout"_qs;
90 SettingsStorage *settingsStorage {SettingsStorage::instance()};
91 const auto oldData {settingsStorage->loadValue<QVariant>(oldKey)};
92 const auto newData {settingsStorage->loadValue<QString>(newKey)};
94 if (!newData.isEmpty() || !oldData.isValid())
95 return;
97 const bool createSubfolder = oldData.toBool();
98 const BitTorrent::TorrentContentLayout torrentContentLayout =
99 (createSubfolder ? BitTorrent::TorrentContentLayout::Original : BitTorrent::TorrentContentLayout::NoSubfolder);
101 settingsStorage->storeValue(newKey, Utils::String::fromEnum(torrentContentLayout));
102 settingsStorage->removeValue(oldKey);
105 void upgradeListenPortSettings()
107 const auto oldKey = u"BitTorrent/Session/UseRandomPort"_qs;
108 const auto newKey = u"Preferences/Connection/PortRangeMin"_qs;
109 auto *settingsStorage = SettingsStorage::instance();
111 if (settingsStorage->hasKey(oldKey))
113 if (settingsStorage->loadValue<bool>(oldKey))
114 settingsStorage->storeValue(newKey, 0);
116 settingsStorage->removeValue(oldKey);
120 void upgradeSchedulerDaysSettings()
122 auto *settingsStorage = SettingsStorage::instance();
123 const auto key = u"Preferences/Scheduler/days"_qs;
124 const auto value = settingsStorage->loadValue<QString>(key);
126 bool ok = false;
127 const auto number = value.toInt(&ok);
129 if (ok)
131 switch (number)
133 case 0:
134 settingsStorage->storeValue(key, Scheduler::Days::EveryDay);
135 break;
136 case 1:
137 settingsStorage->storeValue(key, Scheduler::Days::Weekday);
138 break;
139 case 2:
140 settingsStorage->storeValue(key, Scheduler::Days::Weekend);
141 break;
142 case 3:
143 settingsStorage->storeValue(key, Scheduler::Days::Monday);
144 break;
145 case 4:
146 settingsStorage->storeValue(key, Scheduler::Days::Tuesday);
147 break;
148 case 5:
149 settingsStorage->storeValue(key, Scheduler::Days::Wednesday);
150 break;
151 case 6:
152 settingsStorage->storeValue(key, Scheduler::Days::Thursday);
153 break;
154 case 7:
155 settingsStorage->storeValue(key, Scheduler::Days::Friday);
156 break;
157 case 8:
158 settingsStorage->storeValue(key, Scheduler::Days::Saturday);
159 break;
160 case 9:
161 settingsStorage->storeValue(key, Scheduler::Days::Sunday);
162 break;
163 default:
164 LogMsg(QObject::tr("Invalid value found in configuration file, reverting it to default. Key: \"%1\". Invalid value: \"%2\".")
165 .arg(key, QString::number(number)), Log::WARNING);
166 settingsStorage->removeValue(key);
167 break;
172 void upgradeDNSServiceSettings()
174 auto *settingsStorage = SettingsStorage::instance();
175 const auto key = u"Preferences/DynDNS/Service"_qs;
176 const auto value = settingsStorage->loadValue<QString>(key);
178 bool ok = false;
179 const auto number = value.toInt(&ok);
181 if (ok)
183 switch (number)
185 case -1:
186 settingsStorage->storeValue(key, DNS::Service::None);
187 break;
188 case 0:
189 settingsStorage->storeValue(key, DNS::Service::DynDNS);
190 break;
191 case 1:
192 settingsStorage->storeValue(key, DNS::Service::NoIP);
193 break;
194 default:
195 LogMsg(QObject::tr("Invalid value found in configuration file, reverting it to default. Key: \"%1\". Invalid value: \"%2\".")
196 .arg(key, QString::number(number)), Log::WARNING);
197 settingsStorage->removeValue(key);
198 break;
203 void upgradeTrayIconStyleSettings()
205 auto *settingsStorage = SettingsStorage::instance();
206 const auto key = u"Preferences/Advanced/TrayIconStyle"_qs;
207 const auto value = settingsStorage->loadValue<QString>(key);
209 bool ok = false;
210 const auto number = value.toInt(&ok);
212 if (ok)
214 switch (number)
216 case 0:
217 settingsStorage->storeValue(key, TrayIcon::Style::Normal);
218 break;
219 case 1:
220 settingsStorage->storeValue(key, TrayIcon::Style::MonoDark);
221 break;
222 case 2:
223 settingsStorage->storeValue(key, TrayIcon::Style::MonoLight);
224 break;
225 default:
226 LogMsg(QObject::tr("Invalid value found in configuration file, reverting it to default. Key: \"%1\". Invalid value: \"%2\".")
227 .arg(key, QString::number(number)), Log::WARNING);
228 settingsStorage->removeValue(key);
229 break;
234 void migrateSettingKeys()
236 struct KeyMapping
238 QString newKey;
239 QString oldKey;
242 const KeyMapping mappings[] =
244 {u"AddNewTorrentDialog/Enabled"_qs, u"Preferences/Downloads/NewAdditionDialog"_qs},
245 {u"AddNewTorrentDialog/Expanded"_qs, u"AddNewTorrentDialog/expanded"_qs},
246 {u"AddNewTorrentDialog/Position"_qs, u"AddNewTorrentDialog/y"_qs},
247 {u"AddNewTorrentDialog/SavePathHistory"_qs, u"TorrentAdditionDlg/save_path_history"_qs},
248 {u"AddNewTorrentDialog/TopLevel"_qs, u"Preferences/Downloads/NewAdditionDialogFront"_qs},
249 {u"AddNewTorrentDialog/TreeHeaderState"_qs, u"AddNewTorrentDialog/qt5/treeHeaderState"_qs},
250 {u"AddNewTorrentDialog/Width"_qs, u"AddNewTorrentDialog/width"_qs},
251 {u"BitTorrent/Session/AddExtensionToIncompleteFiles"_qs, u"Preferences/Downloads/UseIncompleteExtension"_qs},
252 {u"BitTorrent/Session/AdditionalTrackers"_qs, u"Preferences/Bittorrent/TrackersList"_qs},
253 {u"BitTorrent/Session/AddTorrentPaused"_qs, u"Preferences/Downloads/StartInPause"_qs},
254 {u"BitTorrent/Session/AddTrackersEnabled"_qs, u"Preferences/Bittorrent/AddTrackers"_qs},
255 {u"BitTorrent/Session/AlternativeGlobalDLSpeedLimit"_qs, u"Preferences/Connection/GlobalDLLimitAlt"_qs},
256 {u"BitTorrent/Session/AlternativeGlobalUPSpeedLimit"_qs, u"Preferences/Connection/GlobalUPLimitAlt"_qs},
257 {u"BitTorrent/Session/AnnounceIP"_qs, u"Preferences/Connection/InetAddress"_qs},
258 {u"BitTorrent/Session/AnnounceToAllTrackers"_qs, u"Preferences/Advanced/AnnounceToAllTrackers"_qs},
259 {u"BitTorrent/Session/AnonymousModeEnabled"_qs, u"Preferences/Advanced/AnonymousMode"_qs},
260 {u"BitTorrent/Session/BandwidthSchedulerEnabled"_qs, u"Preferences/Scheduler/Enabled"_qs},
261 {u"BitTorrent/Session/DefaultSavePath"_qs, u"Preferences/Downloads/SavePath"_qs},
262 {u"BitTorrent/Session/DHTEnabled"_qs, u"Preferences/Bittorrent/DHT"_qs},
263 {u"BitTorrent/Session/DiskCacheSize"_qs, u"Preferences/Downloads/DiskWriteCacheSize"_qs},
264 {u"BitTorrent/Session/DiskCacheTTL"_qs, u"Preferences/Downloads/DiskWriteCacheTTL"_qs},
265 {u"BitTorrent/Session/Encryption"_qs, u"Preferences/Bittorrent/Encryption"_qs},
266 {u"BitTorrent/Session/FinishedTorrentExportDirectory"_qs, u"Preferences/Downloads/FinishedTorrentExportDir"_qs},
267 {u"BitTorrent/Session/ForceProxy"_qs, u"Preferences/Connection/ProxyForce"_qs},
268 {u"BitTorrent/Session/GlobalDLSpeedLimit"_qs, u"Preferences/Connection/GlobalDLLimit"_qs},
269 {u"BitTorrent/Session/GlobalMaxRatio"_qs, u"Preferences/Bittorrent/MaxRatio"_qs},
270 {u"BitTorrent/Session/GlobalUPSpeedLimit"_qs, u"Preferences/Connection/GlobalUPLimit"_qs},
271 {u"BitTorrent/Session/IgnoreLimitsOnLAN"_qs, u"Preferences/Advanced/IgnoreLimitsLAN"_qs},
272 {u"BitTorrent/Session/IgnoreSlowTorrentsForQueueing"_qs, u"Preferences/Queueing/IgnoreSlowTorrents"_qs},
273 {u"BitTorrent/Session/IncludeOverheadInLimits"_qs, u"Preferences/Advanced/IncludeOverhead"_qs},
274 {u"BitTorrent/Session/Interface"_qs, u"Preferences/Connection/Interface"_qs},
275 {u"BitTorrent/Session/InterfaceAddress"_qs, u"Preferences/Connection/InterfaceAddress"_qs},
276 {u"BitTorrent/Session/InterfaceName"_qs, u"Preferences/Connection/InterfaceName"_qs},
277 {u"BitTorrent/Session/IPFilter"_qs, u"Preferences/IPFilter/File"_qs},
278 {u"BitTorrent/Session/IPFilteringEnabled"_qs, u"Preferences/IPFilter/Enabled"_qs},
279 {u"BitTorrent/Session/LSDEnabled"_qs, u"Preferences/Bittorrent/LSD"_qs},
280 {u"BitTorrent/Session/MaxActiveDownloads"_qs, u"Preferences/Queueing/MaxActiveDownloads"_qs},
281 {u"BitTorrent/Session/MaxActiveTorrents"_qs, u"Preferences/Queueing/MaxActiveTorrents"_qs},
282 {u"BitTorrent/Session/MaxActiveUploads"_qs, u"Preferences/Queueing/MaxActiveUploads"_qs},
283 {u"BitTorrent/Session/MaxConnections"_qs, u"Preferences/Bittorrent/MaxConnecs"_qs},
284 {u"BitTorrent/Session/MaxConnectionsPerTorrent"_qs, u"Preferences/Bittorrent/MaxConnecsPerTorrent"_qs},
285 {u"BitTorrent/Session/MaxHalfOpenConnections"_qs, u"Preferences/Connection/MaxHalfOpenConnec"_qs},
286 {u"BitTorrent/Session/MaxRatioAction"_qs, u"Preferences/Bittorrent/MaxRatioAction"_qs},
287 {u"BitTorrent/Session/MaxUploads"_qs, u"Preferences/Bittorrent/MaxUploads"_qs},
288 {u"BitTorrent/Session/MaxUploadsPerTorrent"_qs, u"Preferences/Bittorrent/MaxUploadsPerTorrent"_qs},
289 {u"BitTorrent/Session/OutgoingPortsMax"_qs, u"Preferences/Advanced/OutgoingPortsMax"_qs},
290 {u"BitTorrent/Session/OutgoingPortsMin"_qs, u"Preferences/Advanced/OutgoingPortsMin"_qs},
291 {u"BitTorrent/Session/PeXEnabled"_qs, u"Preferences/Bittorrent/PeX"_qs},
292 {u"BitTorrent/Session/Port"_qs, u"Preferences/Connection/PortRangeMin"_qs},
293 {u"BitTorrent/Session/Preallocation"_qs, u"Preferences/Downloads/PreAllocation"_qs},
294 {u"BitTorrent/Session/ProxyPeerConnections"_qs, u"Preferences/Connection/ProxyPeerConnections"_qs},
295 {u"BitTorrent/Session/QueueingSystemEnabled"_qs, u"Preferences/Queueing/QueueingEnabled"_qs},
296 {u"BitTorrent/Session/RefreshInterval"_qs, u"Preferences/General/RefreshInterval"_qs},
297 {u"BitTorrent/Session/SaveResumeDataInterval"_qs, u"Preferences/Downloads/SaveResumeDataInterval"_qs},
298 {u"BitTorrent/Session/SuperSeedingEnabled"_qs, u"Preferences/Advanced/SuperSeeding"_qs},
299 {u"BitTorrent/Session/TempPath"_qs, u"Preferences/Downloads/TempPath"_qs},
300 {u"BitTorrent/Session/TempPathEnabled"_qs, u"Preferences/Downloads/TempPathEnabled"_qs},
301 {u"BitTorrent/Session/TorrentExportDirectory"_qs, u"Preferences/Downloads/TorrentExportDir"_qs},
302 {u"BitTorrent/Session/TrackerFilteringEnabled"_qs, u"Preferences/IPFilter/FilterTracker"_qs},
303 {u"BitTorrent/Session/UseAlternativeGlobalSpeedLimit"_qs, u"Preferences/Connection/alt_speeds_on"_qs},
304 {u"BitTorrent/Session/UseOSCache"_qs, u"Preferences/Advanced/osCache"_qs},
305 {u"BitTorrent/Session/UseRandomPort"_qs, u"Preferences/General/UseRandomPort"_qs},
306 {u"BitTorrent/Session/uTPEnabled"_qs, u"Preferences/Bittorrent/uTP"_qs},
307 {u"BitTorrent/Session/uTPRateLimited"_qs, u"Preferences/Bittorrent/uTP_rate_limited"_qs},
308 {u"BitTorrent/TrackerEnabled"_qs, u"Preferences/Advanced/trackerEnabled"_qs},
309 {u"Network/PortForwardingEnabled"_qs, u"Preferences/Connection/UPnP"_qs},
310 {u"Network/Proxy/Authentication"_qs, u"Preferences/Connection/Proxy/Authentication"_qs},
311 {u"Network/Proxy/IP"_qs, u"Preferences/Connection/Proxy/IP"_qs},
312 {u"Network/Proxy/OnlyForTorrents"_qs, u"Preferences/Connection/ProxyOnlyForTorrents"_qs},
313 {u"Network/Proxy/Password"_qs, u"Preferences/Connection/Proxy/Password"_qs},
314 {u"Network/Proxy/Port"_qs, u"Preferences/Connection/Proxy/Port"_qs},
315 {u"Network/Proxy/Type"_qs, u"Preferences/Connection/ProxyType"_qs},
316 {u"Network/Proxy/Username"_qs, u"Preferences/Connection/Proxy/Username"_qs},
317 {u"State/BannedIPs"_qs, u"Preferences/IPFilter/BannedIPs"_qs}
320 auto *settingsStorage = SettingsStorage::instance();
321 for (const KeyMapping &mapping : mappings)
323 if (settingsStorage->hasKey(mapping.oldKey))
325 const auto value = settingsStorage->loadValue<QVariant>(mapping.oldKey);
326 settingsStorage->storeValue(mapping.newKey, value);
327 // TODO: Remove oldKey after ~v4.4.3 and bump migration version
332 void migrateProxySettingsEnum()
334 auto *settingsStorage = SettingsStorage::instance();
335 const auto key = u"Network/Proxy/Type"_qs;
336 const auto value = settingsStorage->loadValue<QString>(key);
338 bool ok = false;
339 const auto number = value.toInt(&ok);
341 if (ok)
343 switch (number)
345 case 0:
346 settingsStorage->storeValue(key, Net::ProxyType::None);
347 break;
348 case 1:
349 settingsStorage->storeValue(key, Net::ProxyType::HTTP);
350 break;
351 case 2:
352 settingsStorage->storeValue(key, Net::ProxyType::SOCKS5);
353 break;
354 case 3:
355 settingsStorage->storeValue(key, Net::ProxyType::HTTP_PW);
356 break;
357 case 4:
358 settingsStorage->storeValue(key, Net::ProxyType::SOCKS5_PW);
359 break;
360 case 5:
361 settingsStorage->storeValue(key, Net::ProxyType::SOCKS4);
362 break;
363 default:
364 LogMsg(QObject::tr("Invalid value found in configuration file, reverting it to default. Key: \"%1\". Invalid value: \"%2\".")
365 .arg(key, QString::number(number)), Log::WARNING);
366 settingsStorage->removeValue(key);
367 break;
372 #ifdef Q_OS_WIN
373 void migrateMemoryPrioritySettings()
375 auto *settingsStorage = SettingsStorage::instance();
376 const QString oldKey = u"BitTorrent/OSMemoryPriority"_qs;
377 const QString newKey = u"Application/ProcessMemoryPriority"_qs;
379 if (settingsStorage->hasKey(oldKey))
381 const auto value = settingsStorage->loadValue<QVariant>(oldKey);
382 settingsStorage->storeValue(newKey, value);
385 #endif
387 void migrateStartupWindowState()
389 auto *settingsStorage = SettingsStorage::instance();
390 if (settingsStorage->hasKey(u"Preferences/General/StartMinimized"_qs))
392 const auto startMinimized = settingsStorage->loadValue<bool>(u"Preferences/General/StartMinimized"_qs);
393 const auto minimizeToTray = settingsStorage->loadValue<bool>(u"Preferences/General/MinimizeToTray"_qs);
394 const QString windowState = startMinimized ? (minimizeToTray ? u"Hidden"_qs : u"Minimized"_qs) : u"Normal"_qs;
395 settingsStorage->storeValue(u"GUI/StartUpWindowState"_qs, windowState);
399 void migrateChineseLocale()
401 auto *settingsStorage = SettingsStorage::instance();
402 const auto key = u"Preferences/General/Locale"_qs;
403 if (settingsStorage->hasKey(key))
405 const auto locale = settingsStorage->loadValue<QString>(key);
406 if (locale.compare(u"zh"_qs, Qt::CaseInsensitive) == 0)
407 settingsStorage->storeValue(key, u"zh_CN"_qs);
412 bool upgrade()
414 CachedSettingValue<int> version {MIGRATION_VERSION_KEY, 0};
416 if (version != MIGRATION_VERSION)
418 if (version < 1)
420 exportWebUIHttpsFiles();
421 upgradeTorrentContentLayout();
422 upgradeListenPortSettings();
423 upgradeSchedulerDaysSettings();
424 upgradeDNSServiceSettings();
425 upgradeTrayIconStyleSettings();
428 if (version < 2)
429 migrateSettingKeys();
431 if (version < 3)
432 migrateProxySettingsEnum();
434 #ifdef Q_OS_WIN
435 if (version < 4)
436 migrateMemoryPrioritySettings();
437 #endif
439 if (version < 5)
441 migrateStartupWindowState();
442 migrateChineseLocale();
445 version = MIGRATION_VERSION;
448 return true;
451 void setCurrentMigrationVersion()
453 SettingsStorage::instance()->storeValue(MIGRATION_VERSION_KEY, MIGRATION_VERSION);
456 void handleChangedDefaults(const DefaultPreferencesMode mode)
458 struct DefaultValue
460 QString name;
461 QVariant legacy;
462 QVariant current;
465 const DefaultValue changedDefaults[] =
467 {u"BitTorrent/Session/QueueingSystemEnabled"_qs, true, false}
470 auto *settingsStorage = SettingsStorage::instance();
471 for (const DefaultValue &value : changedDefaults)
473 if (!settingsStorage->hasKey(value.name))
475 settingsStorage->storeValue(value.name
476 , (mode == DefaultPreferencesMode::Legacy ? value.legacy : value.current));