Skip to content

Commit

Permalink
Merge branch 'master' into qstring-refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
Integral-Tech authored Dec 17, 2024
2 parents cb88186 + f74b3ee commit 560020c
Show file tree
Hide file tree
Showing 109 changed files with 6,930 additions and 5,333 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ else()
set(APPLICATION_REV_DOMAIN_INSTALLER ${APPLICATION_REV_DOMAIN})
endif()

option( APPLICATION_DISPLAY_LEGACY_IMPORT_DIALOG "Display legacy import dialog" ON )

# For usage in XML files we preprocess
string(REPLACE "&" "&" APPLICATION_NAME_XML_ESCAPED "${APPLICATION_NAME}")
string(REPLACE "<" "&lt;" APPLICATION_NAME_XML_ESCAPED "${APPLICATION_NAME_XML_ESCAPED}")
Expand Down
2 changes: 1 addition & 1 deletion VERSION.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ set( MIRALL_VERSION_YEAR 2024 )
set( MIRALL_SOVERSION 0 )

# Minimum supported server version according to https://docs.nextcloud.com/server/latest/admin_manual/release_schedule.html
set(NEXTCLOUD_SERVER_VERSION_MIN_SUPPORTED_MAJOR 16)
set(NEXTCLOUD_SERVER_VERSION_MIN_SUPPORTED_MAJOR 18)
set(NEXTCLOUD_SERVER_VERSION_MIN_SUPPORTED_MINOR 0)
set(NEXTCLOUD_SERVER_VERSION_MIN_SUPPORTED_PATCH 0)

Expand Down
28 changes: 21 additions & 7 deletions admin/osx/mac-crafter/Sources/Utils/Codesign.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ enum CodeSigningError: Error {
}

enum AppBundleSigningError: Error {
case doesNotExist(String)
case couldNotEnumerate(String)
}

Expand All @@ -44,7 +45,9 @@ func isExecutable(_ path: String) throws -> Bool {
throw CodeSigningError.failedToCodeSign("Failed to determine if \(path) is an executable.")
}

let outputData = outPipe.fileHandleForReading.readDataToEndOfFile()
let outputFileHandle = outPipe.fileHandleForReading
let outputData = outputFileHandle.readDataToEndOfFile()
try outputFileHandle.close()
let output = String(data: outputData, encoding: .utf8) ?? ""
return output.contains("Mach-O 64-bit executable")
}
Expand All @@ -64,6 +67,10 @@ func recursivelyCodesign(
skip: [String] = []
) throws {
let fm = FileManager.default
guard fm.fileExists(atPath: path) else {
throw AppBundleSigningError.doesNotExist("Item at \(path) does not exist.")
}

guard let pathEnumerator = fm.enumerator(atPath: path) else {
throw AppBundleSigningError.couldNotEnumerate(
"Failed to enumerate directory at \(path)."
Expand Down Expand Up @@ -118,14 +125,21 @@ func codesignClientAppBundle(
// Multiple components of the app will now have the get-task-allow entitlements.
// We need to strip these out manually.

print("Code-signing Sparkle autoupdater app (without entitlements)...")
let sparkleFrameworkPath = "\(frameworksPath)/Sparkle.framework"
try recursivelyCodesign(path: "\(sparkleFrameworkPath)/Resources/Autoupdate.app",
identity: codeSignIdentity,
options: "--timestamp --force --verbose=4 --options runtime --deep")
if FileManager.default.fileExists(atPath: "\(sparkleFrameworkPath)/Resources/Autoupdate.app") {
print("Code-signing Sparkle autoupdater app (without entitlements)...")

print("Re-codesigning Sparkle library...")
try codesign(identity: codeSignIdentity, path: "\(sparkleFrameworkPath)/Sparkle")
try recursivelyCodesign(
path: "\(sparkleFrameworkPath)/Resources/Autoupdate.app",
identity: codeSignIdentity,
options: "--timestamp --force --verbose=4 --options runtime --deep"
)

print("Re-codesigning Sparkle library...")
try codesign(identity: codeSignIdentity, path: "\(sparkleFrameworkPath)/Sparkle")
} else {
print("Build does not have Sparkle, skipping.")
}

print("Code-signing app extensions (removing get-task-allow entitlements)...")
let fm = FileManager.default
Expand Down
1 change: 1 addition & 0 deletions config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#cmakedefine01 ENFORCE_VIRTUAL_FILES_SYNC_FOLDER
#cmakedefine DO_NOT_USE_PROXY "@DO_NOT_USE_PROXY@"
#cmakedefine ENFORCE_SINGLE_ACCOUNT "@ENFORCE_SINGLE_ACCOUNT@"
#cmakedefine01 APPLICATION_DISPLAY_LEGACY_IMPORT_DIALOG

#cmakedefine ZLIB_FOUND @ZLIB_FOUND@

Expand Down
2 changes: 1 addition & 1 deletion doc/macosvfs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ macOS Virtual Files

.. index:: macosvfs

Introduction
macOS Vitual Files client
============

Virtual file-based synchronisation for Nextcloud desktop users is now
Expand Down
2 changes: 2 additions & 0 deletions shell_integration/windows/NCContextMenu/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ install(TARGETS NCContextMenu
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR}
)

install(FILES $<TARGET_PDB_FILE:NCContextMenu> DESTINATION bin OPTIONAL)
2 changes: 2 additions & 0 deletions shell_integration/windows/NCOverlays/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ install(TARGETS NCOverlays
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR}
)

install(FILES $<TARGET_PDB_FILE:NCOverlays> DESTINATION bin OPTIONAL)
3 changes: 3 additions & 0 deletions src/cmd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,8 @@ if(NOT BUILD_LIBRARIES_ONLY)
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
if (WIN32)
install(FILES $<TARGET_PDB_FILE:nextcloudcmd> DESTINATION bin OPTIONAL)
endif()
endif()
endif()
16 changes: 12 additions & 4 deletions src/common/vfs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include "common/filesystembase.h"

#include <QDir>
#include <QPluginLoader>
#include <QLoggingCategory>

Expand Down Expand Up @@ -65,21 +66,28 @@ Optional<Vfs::Mode> Vfs::modeFromString(const QString &str)
return {};
}

Result<bool, QString> Vfs::checkAvailability(const QString &path)
Result<void, QString> Vfs::checkAvailability(const QString &path, Vfs::Mode mode)
{
const auto mode = bestAvailableVfsMode();
#ifdef Q_OS_WIN
if (mode == Mode::WindowsCfApi) {
const auto fs = FileSystem::fileSystemForPath(path);
const auto info = QFileInfo(path);
if (QDir(info.canonicalFilePath()).isRoot()) {
return tr("The Virtual filesystem feature does not support a drive as sync root");
}
const auto fs = FileSystem::fileSystemForPath(info.absoluteFilePath());
if (fs != QLatin1String("NTFS")) {
return tr("The Virtual filesystem feature requires a NTFS file system, %1 is using %2").arg(path, fs);
}
const auto type = GetDriveTypeW(reinterpret_cast<const wchar_t *>(QDir::toNativeSeparators(info.absoluteFilePath().mid(0, 3)).utf16()));
if (type == DRIVE_REMOTE) {
return tr("The Virtual filesystem feature is not supported on network drives");
}
}
#else
Q_UNUSED(mode)
Q_UNUSED(path)
#endif
return true;
return {};
}

void Vfs::start(const VfsSetupParams &params)
Expand Down
2 changes: 1 addition & 1 deletion src/common/vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ class OCSYNC_EXPORT Vfs : public QObject
static QString modeToString(Mode mode);
static Optional<Mode> modeFromString(const QString &str);

static Result<bool, QString> checkAvailability(const QString &path);
static Result<void, QString> checkAvailability(const QString &path, OCC::Vfs::Mode mode);

enum class AvailabilityError
{
Expand Down
4 changes: 4 additions & 0 deletions src/csync/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,8 @@ else()
)
endif()

if (WIN32)
install(FILES $<TARGET_PDB_FILE:nextcloud_csync> DESTINATION bin OPTIONAL)
endif()

configure_file(config_csync.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_csync.h)
8 changes: 7 additions & 1 deletion src/csync/vio/csync_vio_local_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,13 @@ std::unique_ptr<csync_file_stat_t> csync_vio_local_readdir(csync_vio_handle_t *h
!isDirectory) {
file_stat->type = ItemTypeSkip;
} else if (isDirectory) {
file_stat->type = ItemTypeDirectory;
if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT &&
(handle->ffd.dwReserved0 == IO_REPARSE_TAG_SYMLINK ||
handle->ffd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT)) {
file_stat->type = ItemTypeSoftLink;
} else {
file_stat->type = ItemTypeDirectory;
}
} else {
file_stat->type = ItemTypeFile;
}
Expand Down
3 changes: 3 additions & 0 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,9 @@ install(TARGETS nextcloud
BUNDLE DESTINATION "."
)

if (WIN32)
install(FILES $<TARGET_PDB_FILE:nextcloud> DESTINATION bin OPTIONAL)
endif()

# FIXME: The following lines are dup in src/gui and src/cmd because it needs to be done after both are installed
#FIXME: find a nice solution to make the second if(BUILD_OWNCLOUD_OSX_BUNDLE) unnecessary
Expand Down
29 changes: 20 additions & 9 deletions src/gui/accountmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ constexpr auto networkProxyPasswordKeychainKeySuffixC = "_proxy_password";
constexpr auto legacyRelativeConfigLocationC = "/ownCloud/owncloud.cfg";
constexpr auto legacyCfgFileNameC = "owncloud.cfg";

constexpr auto unbrandedRelativeConfigLocationC = "/Nextcloud/nextcloud.cfg";
constexpr auto unbrandedCfgFileNameC = "nextcloud.cfg";

// The maximum versions that this client can read
constexpr auto maxAccountsVersion = 2;
constexpr auto maxAccountVersion = 1;
Expand Down Expand Up @@ -170,7 +173,8 @@ bool AccountManager::restoreFromLegacySettings()
// try to open the correctly themed settings
auto settings = ConfigFile::settingsWithGroup(Theme::instance()->appName());

auto displayMessageBoxWarning = false;
auto wasLegacyImportDialogDisplayed = false;
const auto displayLegacyImportDialog = Theme::instance()->displayLegacyImportDialog();

// if the settings file could not be opened, the childKeys list is empty
// then try to load settings from a very old place
Expand All @@ -191,10 +195,16 @@ bool AccountManager::restoreFromLegacySettings()
const auto legacyCfgFileNamePath = QString(QStringLiteral("/") + legacyCfgFileNameC);
const auto legacyCfgFileRelativePath = QString(legacyRelativeConfigLocationC);

const auto legacyLocations = QVector<QString>{legacy2_4CfgFileParentFolder + legacyCfgFileRelativePath,
legacy2_5CfgFileParentFolder + legacyCfgFileRelativePath,
legacyCfgFileParentFolder + legacyCfgFileNamePath,
legacyCfgFileGrandParentFolder + legacyCfgFileRelativePath};
auto legacyLocations = QVector<QString>{legacy2_4CfgFileParentFolder + legacyCfgFileRelativePath,
legacy2_5CfgFileParentFolder + legacyCfgFileRelativePath,
legacyCfgFileParentFolder + legacyCfgFileNamePath,
legacyCfgFileGrandParentFolder + legacyCfgFileRelativePath};

if (Theme::instance()->isBranded()) {
const auto unbrandedCfgFileNamePath = QString(QStringLiteral("/") + unbrandedCfgFileNameC);
const auto unbrandedCfgFileRelativePath = QString(unbrandedRelativeConfigLocationC);
legacyLocations.append({legacyCfgFileParentFolder + unbrandedCfgFileNamePath, legacyCfgFileGrandParentFolder + unbrandedCfgFileRelativePath});
}

for (const auto &configFile : legacyLocations) {
auto oCSettings = std::make_unique<QSettings>(configFile, QSettings::IniFormat);
Expand All @@ -206,10 +216,11 @@ bool AccountManager::restoreFromLegacySettings()
oCSettings->beginGroup(QLatin1String(accountsC));
const auto accountsListSize = oCSettings->childGroups().size();
oCSettings->endGroup();
if (const QFileInfo configFileInfo(configFile); configFileInfo.exists() && configFileInfo.isReadable()) {
displayMessageBoxWarning = true;
if (const QFileInfo configFileInfo(configFile);
configFileInfo.exists() && configFileInfo.isReadable()) {
qCInfo(lcAccountManager) << "Migrate: checking old config " << configFile;
if (!forceLegacyImport() && accountsListSize > 0) {
if (!forceLegacyImport() && accountsListSize > 0 && displayLegacyImportDialog) {
wasLegacyImportDialogDisplayed = true;
const auto importQuestion = accountsListSize > 1
? tr("%1 accounts were detected from a legacy desktop client.\n"
"Should the accounts be imported?").arg(QString::number(accountsListSize))
Expand Down Expand Up @@ -282,7 +293,7 @@ bool AccountManager::restoreFromLegacySettings()
return true;
}

if (displayMessageBoxWarning) {
if (wasLegacyImportDialogDisplayed) {
QMessageBox::information(nullptr,
tr("Legacy import"),
tr("Could not import accounts from legacy client configuration."));
Expand Down
7 changes: 5 additions & 2 deletions src/gui/accountsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
const auto fpAccountUserIdAtHost = _accountState->account()->userIdAtHostWithPort();
const auto fpSettingsController = Mac::FileProviderSettingsController::instance();
const auto fpSettingsWidget = fpSettingsController->settingsViewWidget(fpAccountUserIdAtHost, fileProviderTab);
fpSettingsLayout->setContentsMargins(0, 0, 0, 0);
fpSettingsLayout->addWidget(fpSettingsWidget);
fileProviderTab->setLayout(fpSettingsLayout);
}
Expand All @@ -220,6 +221,7 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
const auto connectionSettingsTab = _ui->connectionSettingsTab;
const auto connectionSettingsLayout = new QVBoxLayout(connectionSettingsTab);
const auto networkSettings = new NetworkSettings(_accountState->account(), connectionSettingsTab);
connectionSettingsLayout->setContentsMargins(0, 0, 0, 0);
connectionSettingsLayout->addWidget(networkSettings);
connectionSettingsTab->setLayout(connectionSettingsLayout);

Expand Down Expand Up @@ -708,8 +710,9 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
ac->setDisabled(Theme::instance()->enforceVirtualFilesSyncFolder());
}

if (Theme::instance()->showVirtualFilesOption() && !folder->virtualFilesEnabled() && Vfs::checkAvailability(folder->path())) {
const auto mode = bestAvailableVfsMode();
if (const auto mode = bestAvailableVfsMode();
Theme::instance()->showVirtualFilesOption()
&& !folder->virtualFilesEnabled() && Vfs::checkAvailability(folder->path(), mode)) {
if (mode == Vfs::WindowsCfApi || ConfigFile().showExperimentalOptions()) {
ac = menu->addAction(tr("Enable virtual file support %1 …").arg(mode == Vfs::WindowsCfApi ? QString() : tr("(experimental)")));
// TODO: remove when UX decision is made
Expand Down
40 changes: 24 additions & 16 deletions src/gui/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -484,23 +484,31 @@ void Application::setupAccountsAndFolders()
if (const auto accounts = AccountManager::instance()->accounts();
accountsRestoreResult == AccountManager::AccountsRestoreSuccessFromLegacyVersion
&& !accounts.isEmpty()) {

const auto accountsListSize = accounts.size();
const auto accountsRestoreMessage = accountsListSize > 1
? tr("%1 accounts", "number of accounts imported").arg(QString::number(accountsListSize))
: tr("1 account");
const auto foldersRestoreMessage = foldersListSize > 1
? tr("%1 folders", "number of folders imported").arg(QString::number(foldersListSize))
: tr("1 folder");
const auto messageBox = new QMessageBox(QMessageBox::Information,
tr("Legacy import"),
tr("Imported %1 and %2 from a legacy desktop client.\n%3",
"number of accounts and folders imported. list of users.")
.arg(accountsRestoreMessage,
foldersRestoreMessage,
prettyNamesList(accounts))
);
messageBox->setWindowModality(Qt::NonModal);
messageBox->open();
if (Theme::instance()->displayLegacyImportDialog()) {
const auto accountsRestoreMessage = accountsListSize > 1
? tr("%1 accounts", "number of accounts imported").arg(QString::number(accountsListSize))
: tr("1 account");
const auto foldersRestoreMessage = foldersListSize > 1
? tr("%1 folders", "number of folders imported").arg(QString::number(foldersListSize))
: tr("1 folder");
const auto messageBox = new QMessageBox(QMessageBox::Information,
tr("Legacy import"),
tr("Imported %1 and %2 from a legacy desktop client.\n%3",
"number of accounts and folders imported. list of users.")
.arg(accountsRestoreMessage,
foldersRestoreMessage,
prettyNamesList(accounts))
);
messageBox->setWindowModality(Qt::NonModal);
messageBox->open();
}

qCWarning(lcApplication) << "Migration result AccountManager::AccountsRestoreResult:" << accountsRestoreResult;
qCWarning(lcApplication) << "Folders migrated: " << foldersListSize;
qCWarning(lcApplication) << accountsListSize << "account(s) were migrated:" << prettyNamesList(accounts);

} else {
qCWarning(lcApplication) << "Migration result AccountManager::AccountsRestoreResult: " << accountsRestoreResult;
qCWarning(lcApplication) << "Folders migrated: " << foldersListSize;
Expand Down
12 changes: 7 additions & 5 deletions src/gui/caseclashfilenamedialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,22 +175,24 @@ QString CaseClashFilenameDialog::caseClashConflictFile(const QString &conflictFi
{
const auto filePathFileInfo = QFileInfo(conflictFilePath);
const auto conflictFileName = filePathFileInfo.fileName();
const auto lookingForDirectory = FileSystem::isDir(filePathFileInfo.absoluteFilePath());

QDirIterator it(filePathFileInfo.path(), QDirIterator::Subdirectories);

while(it.hasNext()) {
const auto filePath = it.next();
qCDebug(lcCaseClashConflictFialog) << filePath;

if (FileSystem::isDir(filePath)) {
if (FileSystem::isDir(filePath) && !lookingForDirectory) {
continue;
}

QFileInfo fileInfo(filePath);
const auto currentFileName = fileInfo.fileName();
if (currentFileName.compare(conflictFileName, Qt::CaseInsensitive) == 0 &&
currentFileName != conflictFileName) {
const auto currentFileName = QFileInfo(filePath).fileName();
if (currentFileName.compare(conflictFileName, Qt::CaseInsensitive) != 0) {
continue;
}

if (currentFileName != conflictFileName) {
return filePath;
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/gui/editlocallyjob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,11 +467,11 @@ void EditLocallyJob::processLocalItem()
if (rec.isDirectory() || !_accountState->account()->capabilities().filesLockAvailable()) {
openFile();
} else {
lockFile();
lockFile(rec._etag);
}
}

void EditLocallyJob::lockFile()
void EditLocallyJob::lockFile(const QString &etag)
{
Q_ASSERT(_accountState);
Q_ASSERT(_accountState->account());
Expand Down Expand Up @@ -506,6 +506,7 @@ void EditLocallyJob::lockFile()
_folderForFile->accountState()->account()->setLockFileState(_relPath,
_folderForFile->remotePathTrailingSlash(),
_folderForFile->path(),
etag,
_folderForFile->journalDb(),
SyncFileItem::LockStatus::LockedItem,
SyncFileItem::LockOwnerType::TokenLock);
Expand Down
2 changes: 1 addition & 1 deletion src/gui/editlocallyjob.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ private slots:

void processLocalItem();
void openFile();
void lockFile();
void lockFile(const QString &etag);

void fileAlreadyLocked();
void fileLockSuccess(const OCC::SyncFileItemPtr &item);
Expand Down
Loading

0 comments on commit 560020c

Please sign in to comment.