mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-24 22:15:57 +03:00
Merge pull request #5141 from nextcloud/bugfix/upgradeFromOldClients
fix migration from old settings configuration files
This commit is contained in:
commit
c03e6cca61
3 changed files with 154 additions and 86 deletions
|
@ -13,19 +13,21 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "accountmanager.h"
|
#include "accountmanager.h"
|
||||||
#include "configfile.h"
|
|
||||||
#include "sslerrordialog.h"
|
#include "sslerrordialog.h"
|
||||||
#include "proxyauthhandler.h"
|
#include "proxyauthhandler.h"
|
||||||
#include "common/asserts.h"
|
#include "common/asserts.h"
|
||||||
#include <theme.h>
|
#include "creds/credentialsfactory.h"
|
||||||
#include <creds/credentialsfactory.h>
|
#include "creds/abstractcredentials.h"
|
||||||
#include <creds/abstractcredentials.h>
|
#include "libsync/clientsideencryption.h"
|
||||||
#include <cookiejar.h>
|
#include "libsync/configfile.h"
|
||||||
|
#include "libsync/cookiejar.h"
|
||||||
|
#include "libsync/theme.h"
|
||||||
|
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include "clientsideencryption.h"
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr auto urlC = "url";
|
constexpr auto urlC = "url";
|
||||||
|
@ -49,7 +51,7 @@ constexpr auto httpAuthPrefix = "http_";
|
||||||
constexpr auto webflowAuthPrefix = "webflow_";
|
constexpr auto webflowAuthPrefix = "webflow_";
|
||||||
|
|
||||||
constexpr auto legacyRelativeConfigLocationC = "/ownCloud/owncloud.cfg";
|
constexpr auto legacyRelativeConfigLocationC = "/ownCloud/owncloud.cfg";
|
||||||
constexpr auto legacyOcSettingsC = "ownCloud";
|
constexpr auto legacyCfgFileNameC = "owncloud.cfg";
|
||||||
|
|
||||||
// The maximum versions that this client can read
|
// The maximum versions that this client can read
|
||||||
constexpr auto maxAccountsVersion = 2;
|
constexpr auto maxAccountsVersion = 2;
|
||||||
|
@ -148,47 +150,81 @@ bool AccountManager::restoreFromLegacySettings()
|
||||||
// if the settings file could not be opened, the childKeys list is empty
|
// if the settings file could not be opened, the childKeys list is empty
|
||||||
// then try to load settings from a very old place
|
// then try to load settings from a very old place
|
||||||
if (settings->childKeys().isEmpty()) {
|
if (settings->childKeys().isEmpty()) {
|
||||||
// Now try to open the original ownCloud settings to see if they exist.
|
// Legacy settings used QDesktopServices to get the location for the config folder in 2.4 and before
|
||||||
auto oCCfgFile = QDir::fromNativeSeparators(settings->fileName());
|
const auto legacy2_4CfgSettingsLocation = QString(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/data"));
|
||||||
// replace the last two segments with ownCloud/owncloud.cfg
|
const auto legacy2_4CfgFileParentFolder = legacy2_4CfgSettingsLocation.left(legacy2_4CfgSettingsLocation.lastIndexOf('/'));
|
||||||
oCCfgFile = oCCfgFile.left(oCCfgFile.lastIndexOf('/'));
|
|
||||||
oCCfgFile = oCCfgFile.left(oCCfgFile.lastIndexOf('/'));
|
|
||||||
oCCfgFile += QLatin1String(legacyRelativeConfigLocationC);
|
|
||||||
|
|
||||||
qCInfo(lcAccountManager) << "Migrate: checking old config " << oCCfgFile;
|
// 2.5+ (rest of 2.x series)
|
||||||
|
const auto legacy2_5CfgSettingsLocation = QStandardPaths::writableLocation(Utility::isWindows() ? QStandardPaths::AppDataLocation : QStandardPaths::AppConfigLocation);
|
||||||
|
const auto legacy2_5CfgFileParentFolder = legacy2_5CfgSettingsLocation.left(legacy2_5CfgSettingsLocation.lastIndexOf('/'));
|
||||||
|
|
||||||
QFileInfo fi(oCCfgFile);
|
// Now try the locations we use today
|
||||||
if (fi.isReadable()) {
|
const auto fullLegacyCfgFile = QDir::fromNativeSeparators(settings->fileName());
|
||||||
std::unique_ptr<QSettings> oCSettings(new QSettings(oCCfgFile, QSettings::IniFormat));
|
const auto legacyCfgFileParentFolder = fullLegacyCfgFile.left(fullLegacyCfgFile.lastIndexOf('/'));
|
||||||
oCSettings->beginGroup(QLatin1String(legacyOcSettingsC));
|
const auto legacyCfgFileGrandParentFolder = legacyCfgFileParentFolder.left(legacyCfgFileParentFolder.lastIndexOf('/'));
|
||||||
|
|
||||||
// Check the theme url to see if it is the same url that the oC config was for
|
const auto legacyCfgFileNamePath = QString(QStringLiteral("/") + legacyCfgFileNameC);
|
||||||
auto overrideUrl = Theme::instance()->overrideServerUrl();
|
const auto legacyCfgFileRelativePath = QString(legacyRelativeConfigLocationC);
|
||||||
if (!overrideUrl.isEmpty()) {
|
|
||||||
if (overrideUrl.endsWith('/')) {
|
const auto legacyLocations = QVector<QString>{legacy2_4CfgFileParentFolder + legacyCfgFileRelativePath,
|
||||||
overrideUrl.chop(1);
|
legacy2_5CfgFileParentFolder + legacyCfgFileRelativePath,
|
||||||
}
|
legacyCfgFileParentFolder + legacyCfgFileNamePath,
|
||||||
auto oCUrl = oCSettings->value(QLatin1String(urlC)).toString();
|
legacyCfgFileGrandParentFolder + legacyCfgFileRelativePath};
|
||||||
if (oCUrl.endsWith('/')) {
|
|
||||||
oCUrl.chop(1);
|
for (const auto &configFile : legacyLocations) {
|
||||||
|
if (const QFileInfo configFileInfo(configFile);
|
||||||
|
configFileInfo.exists() && configFileInfo.isReadable()) {
|
||||||
|
|
||||||
|
qCInfo(lcAccountManager) << "Migrate: checking old config " << configFile;
|
||||||
|
|
||||||
|
auto oCSettings = std::make_unique<QSettings>(configFile, QSettings::IniFormat);
|
||||||
|
if (oCSettings->status() != QSettings::Status::NoError) {
|
||||||
|
qCInfo(lcAccountManager) << "Error reading legacy configuration file" << oCSettings->status();
|
||||||
}
|
}
|
||||||
|
|
||||||
// in case the urls are equal reset the settings object to read from
|
// Check the theme url to see if it is the same url that the oC config was for
|
||||||
// the ownCloud settings object
|
auto overrideUrl = Theme::instance()->overrideServerUrl();
|
||||||
qCInfo(lcAccountManager) << "Migrate oC config if " << oCUrl << " == " << overrideUrl << ":"
|
qCInfo(lcAccountManager) << "Migrate: overrideUrl" << overrideUrl;
|
||||||
<< (oCUrl == overrideUrl ? "Yes" : "No");
|
if (!overrideUrl.isEmpty()) {
|
||||||
if (oCUrl == overrideUrl) {
|
if (overrideUrl.endsWith('/')) {
|
||||||
|
overrideUrl.chop(1);
|
||||||
|
}
|
||||||
|
auto oCUrl = oCSettings->value(QLatin1String(urlC)).toString();
|
||||||
|
if (oCUrl.endsWith('/')) {
|
||||||
|
oCUrl.chop(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// in case the urls are equal reset the settings object to read from
|
||||||
|
// the ownCloud settings object
|
||||||
|
qCInfo(lcAccountManager) << "Migrate oC config if " << oCUrl << " == " << overrideUrl << ":"
|
||||||
|
<< (oCUrl == overrideUrl ? "Yes" : "No");
|
||||||
|
if (oCUrl == overrideUrl) {
|
||||||
|
qCInfo(lcAccountManager) << "Copy settings" << oCSettings->allKeys().join(", ");
|
||||||
|
settings = std::move(oCSettings);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qCInfo(lcAccountManager) << "Copy settings" << oCSettings->allKeys().join(", ");
|
||||||
settings = std::move(oCSettings);
|
settings = std::move(oCSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
qCInfo(lcAccountManager) << "Migrate: could not read old config " << configFile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to load the single account.
|
// Try to load the single account.
|
||||||
if (!settings->childKeys().isEmpty()) {
|
if (!settings->childKeys().isEmpty()) {
|
||||||
if (const auto acc = loadAccountHelper(*settings)) {
|
settings->beginGroup(accountsC);
|
||||||
addAccount(acc);
|
const auto childGroups = settings->childGroups();
|
||||||
return true;
|
for (const auto &accountId : childGroups) {
|
||||||
|
settings->beginGroup(accountId);
|
||||||
|
if (const auto acc = loadAccountHelper(*settings)) {
|
||||||
|
addAccount(acc);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
namespace {
|
namespace {
|
||||||
#ifndef VERSION_C
|
#ifndef VERSION_C
|
||||||
#define VERSION_C
|
#define VERSION_C
|
||||||
constexpr auto versionC= "version";
|
constexpr auto versionC = "version";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
|
@ -39,12 +39,11 @@
|
||||||
#include <QNetworkProxy>
|
#include <QNetworkProxy>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
#ifndef VERSION_C
|
constexpr auto settingsAccountsC = "Accounts";
|
||||||
#define VERSION_C
|
constexpr auto settingsFoldersC = "Folders";
|
||||||
constexpr auto versionC= "version";
|
constexpr auto settingsVersionC = "version";
|
||||||
#endif
|
constexpr auto maxFoldersVersion = 1;
|
||||||
}
|
}
|
||||||
static const int maxFoldersVersion = 1;
|
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
|
@ -323,7 +322,7 @@ void FolderMan::setupFoldersHelper(QSettings &settings, AccountStatePtr account,
|
||||||
f->switchToVirtualFiles();
|
f->switchToVirtualFiles();
|
||||||
}
|
}
|
||||||
// Migrate the old "usePlaceholders" setting to the root folder pin state
|
// Migrate the old "usePlaceholders" setting to the root folder pin state
|
||||||
if (settings.value(QLatin1String(versionC), 1).toInt() == 1
|
if (settings.value(QLatin1String(settingsVersionC), 1).toInt() == 1
|
||||||
&& settings.value(QLatin1String("usePlaceholders"), false).toBool()) {
|
&& settings.value(QLatin1String("usePlaceholders"), false).toBool()) {
|
||||||
qCInfo(lcFolderMan) << "Migrate: From usePlaceholders to PinState::OnlineOnly";
|
qCInfo(lcFolderMan) << "Migrate: From usePlaceholders to PinState::OnlineOnly";
|
||||||
f->setRootPinState(PinState::OnlineOnly);
|
f->setRootPinState(PinState::OnlineOnly);
|
||||||
|
@ -347,7 +346,7 @@ int FolderMan::setupFoldersMigration()
|
||||||
{
|
{
|
||||||
ConfigFile cfg;
|
ConfigFile cfg;
|
||||||
QDir storageDir(cfg.configPath());
|
QDir storageDir(cfg.configPath());
|
||||||
_folderConfigPath = cfg.configPath() + QLatin1String("folders");
|
_folderConfigPath = cfg.configPath();
|
||||||
|
|
||||||
qCInfo(lcFolderMan) << "Setup folders from " << _folderConfigPath << "(migration)";
|
qCInfo(lcFolderMan) << "Setup folders from " << _folderConfigPath << "(migration)";
|
||||||
|
|
||||||
|
@ -378,11 +377,11 @@ void FolderMan::backwardMigrationSettingsKeys(QStringList *deleteKeys, QStringLi
|
||||||
|
|
||||||
auto processSubgroup = [&](const QString &name) {
|
auto processSubgroup = [&](const QString &name) {
|
||||||
settings->beginGroup(name);
|
settings->beginGroup(name);
|
||||||
const int foldersVersion = settings->value(QLatin1String(versionC), 1).toInt();
|
const int foldersVersion = settings->value(QLatin1String(settingsVersionC), 1).toInt();
|
||||||
if (foldersVersion <= maxFoldersVersion) {
|
if (foldersVersion <= maxFoldersVersion) {
|
||||||
foreach (const auto &folderAlias, settings->childGroups()) {
|
foreach (const auto &folderAlias, settings->childGroups()) {
|
||||||
settings->beginGroup(folderAlias);
|
settings->beginGroup(folderAlias);
|
||||||
const int folderVersion = settings->value(QLatin1String(versionC), 1).toInt();
|
const int folderVersion = settings->value(QLatin1String(settingsVersionC), 1).toInt();
|
||||||
if (folderVersion > FolderDefinition::maxSettingsVersion()) {
|
if (folderVersion > FolderDefinition::maxSettingsVersion()) {
|
||||||
ignoreKeys->append(settings->group());
|
ignoreKeys->append(settings->group());
|
||||||
}
|
}
|
||||||
|
@ -508,29 +507,10 @@ Folder *FolderMan::setupFolderFromOldConfigFile(const QString &file, AccountStat
|
||||||
|
|
||||||
// Check if the filename is equal to the group setting. If not, use the group
|
// Check if the filename is equal to the group setting. If not, use the group
|
||||||
// name as an alias.
|
// name as an alias.
|
||||||
QStringList groups = settings.childGroups();
|
const auto groups = settings.childGroups();
|
||||||
|
if (groups.isEmpty()) {
|
||||||
if (!groups.contains(escapedAlias) && groups.count() > 0) {
|
qCWarning(lcFolderMan) << "empty file:" << cfgFile.filePath();
|
||||||
escapedAlias = groups.first();
|
return folder;
|
||||||
}
|
|
||||||
|
|
||||||
settings.beginGroup(escapedAlias); // read the group with the same name as the file which is the folder alias
|
|
||||||
|
|
||||||
QString path = settings.value(QLatin1String("localPath")).toString();
|
|
||||||
QString backend = settings.value(QLatin1String("backend")).toString();
|
|
||||||
QString targetPath = settings.value(QLatin1String("targetPath")).toString();
|
|
||||||
bool paused = settings.value(QLatin1String("paused"), false).toBool();
|
|
||||||
// QString connection = settings.value( QLatin1String("connection") ).toString();
|
|
||||||
QString alias = unescapeAlias(escapedAlias);
|
|
||||||
|
|
||||||
if (backend.isEmpty() || backend != QLatin1String("owncloud")) {
|
|
||||||
qCWarning(lcFolderMan) << "obsolete configuration of type" << backend;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// cut off the leading slash, oCUrl always has a trailing.
|
|
||||||
if (targetPath.startsWith(QLatin1Char('/'))) {
|
|
||||||
targetPath.remove(0, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!accountState) {
|
if (!accountState) {
|
||||||
|
@ -538,28 +518,80 @@ Folder *FolderMan::setupFolderFromOldConfigFile(const QString &file, AccountStat
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderDefinition folderDefinition;
|
settings.beginGroup(settingsAccountsC);
|
||||||
folderDefinition.alias = alias;
|
const auto rootChildGroups = settings.childGroups();
|
||||||
folderDefinition.localPath = path;
|
for (const auto &accountId : rootChildGroups) {
|
||||||
folderDefinition.targetPath = targetPath;
|
qCDebug(lcFolderMan) << "try to migrate accountId:" << accountId;
|
||||||
folderDefinition.paused = paused;
|
settings.beginGroup(accountId);
|
||||||
folderDefinition.ignoreHiddenFiles = ignoreHiddenFiles();
|
settings.beginGroup(settingsFoldersC);
|
||||||
|
|
||||||
folder = addFolderInternal(folderDefinition, accountState, std::make_unique<VfsOff>());
|
if (settings.childGroups().isEmpty()) {
|
||||||
if (folder) {
|
continue;
|
||||||
QStringList blackList = settings.value(QLatin1String("blackList")).toStringList();
|
|
||||||
if (!blackList.empty()) {
|
|
||||||
//migrate settings
|
|
||||||
folder->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, blackList);
|
|
||||||
settings.remove(QLatin1String("blackList"));
|
|
||||||
// FIXME: If you remove this codepath, you need to provide another way to do
|
|
||||||
// this via theme.h or the normal FolderMan::setupFolders
|
|
||||||
}
|
}
|
||||||
|
|
||||||
folder->saveToSettings();
|
const auto childGroups = settings.childGroups();
|
||||||
|
for (const auto &alias : childGroups) {
|
||||||
|
settings.beginGroup(alias);
|
||||||
|
qCDebug(lcFolderMan) << "try to migrate folder alias:" << alias;
|
||||||
|
|
||||||
|
const auto path = settings.value(QLatin1String("localPath")).toString();
|
||||||
|
const auto targetPath = settings.value(QLatin1String("targetPath")).toString();
|
||||||
|
const auto journalPath = settings.value(QLatin1String("journalPath")).toString();
|
||||||
|
const auto paused = settings.value(QLatin1String("paused"), false).toBool();
|
||||||
|
const auto ignoreHiddenFiles = settings.value(QLatin1String("ignoreHiddenFiles"), false).toBool();
|
||||||
|
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
qCDebug(lcFolderMan) << "localPath is empty";
|
||||||
|
settings.endGroup();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetPath.isEmpty()) {
|
||||||
|
qCDebug(lcFolderMan) << "targetPath is empty";
|
||||||
|
settings.endGroup();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (journalPath.isEmpty()) {
|
||||||
|
qCDebug(lcFolderMan) << "journalPath is empty";
|
||||||
|
settings.endGroup();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
FolderDefinition folderDefinition;
|
||||||
|
folderDefinition.alias = alias;
|
||||||
|
folderDefinition.localPath = path;
|
||||||
|
folderDefinition.targetPath = targetPath;
|
||||||
|
folderDefinition.journalPath = journalPath;
|
||||||
|
folderDefinition.paused = paused;
|
||||||
|
folderDefinition.ignoreHiddenFiles = ignoreHiddenFiles;
|
||||||
|
|
||||||
|
folder = addFolderInternal(folderDefinition, accountState, std::make_unique<VfsOff>());
|
||||||
|
if (folder) {
|
||||||
|
const auto blackList = settings.value(QLatin1String("blackList")).toStringList();
|
||||||
|
if (!blackList.empty()) {
|
||||||
|
//migrate settings
|
||||||
|
folder->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, blackList);
|
||||||
|
settings.remove(QLatin1String("blackList"));
|
||||||
|
// FIXME: If you remove this codepath, you need to provide another way to do
|
||||||
|
// this via theme.h or the normal FolderMan::setupFolders
|
||||||
|
}
|
||||||
|
|
||||||
|
folder->saveToSettings();
|
||||||
|
}
|
||||||
|
qCInfo(lcFolderMan) << "Migrated!" << folder;
|
||||||
|
settings.sync();
|
||||||
|
|
||||||
|
if (folder) {
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.endGroup();
|
||||||
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
qCInfo(lcFolderMan) << "Migrated!" << folder;
|
|
||||||
settings.sync();
|
|
||||||
return folder;
|
return folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue