Skip to content
73 changes: 20 additions & 53 deletions src/csync/csync_exclude.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* SPDX-License-Identifier: LGPL-2.1-or-later
*/

#include "config_csync.h"

Check failure on line 10 in src/csync/csync_exclude.cpp

View workflow job for this annotation

GitHub Actions / build

src/csync/csync_exclude.cpp:10:10 [clang-diagnostic-error]

'config_csync.h' file not found
#include <qglobal.h>

#ifndef _GNU_SOURCE
Expand All @@ -21,7 +21,6 @@

#include "common/utility.h"
#include "common/filesystembase.h"
#include "../version.h"

#include <QString>
#include <QFileInfo>
Expand Down Expand Up @@ -220,7 +219,6 @@

ExcludedFiles::ExcludedFiles(const QString &localPath)
: _localPath(localPath)
, _clientVersion(MIRALL_VERSION_MAJOR, MIRALL_VERSION_MINOR, MIRALL_VERSION_PATCH)
{
Q_ASSERT(_localPath.endsWith(QStringLiteral("/")));
// Windows used to use PathMatchSpec which allows *foo to match abc/deffoo.
Expand Down Expand Up @@ -283,22 +281,14 @@
prepare();
}

void ExcludedFiles::setClientVersion(ExcludedFiles::Version version)
{
_clientVersion = version;
}

void ExcludedFiles::loadExcludeFilePatterns(const QString &basePath, QFile &file)
{
QStringList patterns;
while (!file.atEnd()) {
QByteArray line = file.readLine().trimmed();
if (line.startsWith("#!version")) {
if (!versionDirectiveKeepNextLine(line))
file.readLine();
}
if (line.isEmpty() || line.startsWith('#'))
if (line.isEmpty() || line.startsWith('#')) {
continue;
}
const auto patternStr = QString::fromUtf8(line);
if (QStringView{patternStr}.trimmed() == QLatin1StringView("*")) {
continue;
Expand All @@ -309,7 +299,7 @@
_allExcludes[basePath].append(patterns);

// nothing to prepare if the user decided to not exclude anything
if (!_allExcludes.value(basePath).isEmpty()){
if (!_allExcludes.value(basePath).isEmpty()) {
prepare(basePath);
}
}
Expand Down Expand Up @@ -360,32 +350,6 @@
return success;
}

bool ExcludedFiles::versionDirectiveKeepNextLine(const QByteArray &directive) const
{
if (!directive.startsWith("#!version"))
return true;
QByteArrayList args = directive.split(' ');
if (args.size() != 3)
return true;
QByteArray op = args[1];
QByteArrayList argVersions = args[2].split('.');
if (argVersions.size() != 3)
return true;

auto argVersion = std::make_tuple(argVersions[0].toInt(), argVersions[1].toInt(), argVersions[2].toInt());
if (op == "<=")
return _clientVersion <= argVersion;
if (op == "<")
return _clientVersion < argVersion;
if (op == ">")
return _clientVersion > argVersion;
if (op == ">=")
return _clientVersion >= argVersion;
if (op == "==")
return _clientVersion == argVersion;
return true;
}

bool ExcludedFiles::isExcluded(
const QString &filePath,
const QString &basePath,
Expand Down Expand Up @@ -470,8 +434,9 @@
continue;
}

if (!m.hasMatch())
return CSYNC_NOT_EXCLUDED;
if (!m.hasMatch()) {
continue;
}
if (m.capturedStart(QStringLiteral("exclude")) != -1) {
return CSYNC_FILE_EXCLUDE_LIST;
} else if (m.capturedStart(QStringLiteral("excluderemove")) != -1) {
Expand All @@ -494,12 +459,13 @@
continue;
}

if (m.hasMatch()) {
if (m.capturedStart(QStringLiteral("exclude")) != -1) {
return CSYNC_FILE_EXCLUDE_LIST;
} else if (m.capturedStart(QStringLiteral("excluderemove")) != -1) {
return CSYNC_FILE_EXCLUDE_AND_REMOVE;
}
if (!m.hasMatch()) {
continue;
}
if (m.capturedStart(QStringLiteral("exclude")) != -1) {
return CSYNC_FILE_EXCLUDE_LIST;
} else if (m.capturedStart(QStringLiteral("excluderemove")) != -1) {
return CSYNC_FILE_EXCLUDE_AND_REMOVE;
}
}
return CSYNC_NOT_EXCLUDED;
Expand Down Expand Up @@ -533,12 +499,13 @@
continue;
}

if (m.hasMatch()) {
if (m.capturedStart(QStringLiteral("exclude")) != -1) {
return CSYNC_FILE_EXCLUDE_LIST;
} else if (m.capturedStart(QStringLiteral("excluderemove")) != -1) {
return CSYNC_FILE_EXCLUDE_AND_REMOVE;
}
if (!m.hasMatch()) {
continue;
}
if (m.capturedStart(QStringLiteral("exclude")) != -1) {
return CSYNC_FILE_EXCLUDE_LIST;
} else if (m.capturedStart(QStringLiteral("excluderemove")) != -1) {
return CSYNC_FILE_EXCLUDE_AND_REMOVE;
}
}

Expand Down
30 changes: 0 additions & 30 deletions src/csync/csync_exclude.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ class OCSYNC_EXPORT ExcludedFiles : public QObject
{
Q_OBJECT
public:
using Version = std::tuple<int, int, int>;

explicit ExcludedFiles(const QString &localPath = QStringLiteral("/"));
~ExcludedFiles() override;

Expand Down Expand Up @@ -110,11 +108,6 @@ class OCSYNC_EXPORT ExcludedFiles : public QObject
*/
void setWildcardsMatchSlash(bool onoff);

/**
* Sets the client version, only used for testing.
*/
void setClientVersion(Version version);

/**
* @brief Check if the given path should be excluded in a traversal situation.
*
Expand Down Expand Up @@ -148,23 +141,6 @@ public slots:
void loadExcludeFilePatterns(const QString &basePath, QFile &file);

private:
/**
* Returns true if the version directive indicates the next line
* should be skipped.
*
* A version directive has the form "#!version <op> <version>"
* where <op> can be <, <=, ==, >, >= and <version> can be any version
* like 2.5.0.
*
* Example:
*
* #!version < 2.5.0
* myexclude
*
* Would enable the "myexclude" pattern only for versions before 2.5.0.
*/
[[nodiscard]] bool versionDirectiveKeepNextLine(const QByteArray &directive) const;

/**
* @brief Match the exclude pattern against the full path.
*
Expand Down Expand Up @@ -257,12 +233,6 @@ public slots:
*/
bool _wildcardsMatchSlash = false;

/**
* The client version. Used to evaluate version-dependent excludes,
* see versionDirectiveKeepNextLine().
*/
Version _clientVersion;

friend class TestExcludedFiles;
};

Expand Down
24 changes: 4 additions & 20 deletions src/gui/accountsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
#include "filesystem.h"
#include "encryptfolderjob.h"
#include "syncresult.h"
#include "ignorelisttablewidget.h"
#include "ignorelisteditor.h"
#include "wizard/owncloudwizard.h"
#include "networksettings.h"
#include "ui_mnemonicdialog.h"
Expand Down Expand Up @@ -551,26 +551,10 @@ void AccountSettings::openIgnoredFilesDialog(const QString & absFolderPath)
Q_ASSERT(QFileInfo(absFolderPath).isAbsolute());

const QString ignoreFile{absFolderPath + ".sync-exclude.lst"};
const auto layout = new QVBoxLayout();
const auto ignoreListWidget = new IgnoreListTableWidget(this);
ignoreListWidget->readIgnoreFile(ignoreFile);
layout->addWidget(ignoreListWidget);

const auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
layout->addWidget(buttonBox);

const auto dialog = new QDialog();
dialog->setLayout(layout);

connect(buttonBox, &QDialogButtonBox::clicked, [=](QAbstractButton * button) {
if (buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) {
ignoreListWidget->slotWriteIgnoreFile(ignoreFile);
}
dialog->close();
});
connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::close);

dialog->open();
auto ignoreListEditor = new IgnoreListEditor(ignoreFile, this);
ignoreListEditor->setAttribute(Qt::WA_DeleteOnClose);
ignoreListEditor->open();
}

void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index, const QPoint& pos)
Expand Down
111 changes: 72 additions & 39 deletions src/gui/ignorelisteditor.cpp
Original file line number Diff line number Diff line change
@@ -1,86 +1,119 @@
/*
* SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2014 ownCloud GmbH
* SPDX-License-Identifier: GPL-2.0-or-later
*/

#include "configfile.h"

Check failure on line 7 in src/gui/ignorelisteditor.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/ignorelisteditor.cpp:7:10 [clang-diagnostic-error]

'configfile.h' file not found

#include "folderman.h"
#include "generalsettings.h"
#include "ignorelisteditor.h"
#include "ignorelisttablewidget.h"
#include "ui_ignorelisteditor.h"

#include <QFile>
#include <QDir>
#include <QFile>
#include <QInputDialog>
#include <QListWidget>
#include <QListWidgetItem>
#include <QMessageBox>
#include <QInputDialog>
#include <QPushButton>

namespace OCC {

IgnoreListEditor::IgnoreListEditor(QWidget *parent)
: QDialog(parent)
, ui(new Ui::IgnoreListEditor)
: QDialog{parent}
, ui{new Ui::IgnoreListEditor}
, _ignoreListType{IgnoreListType::Global}
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
ui->setupUi(this);

ConfigFile cfgFile;
//FIXME This is not true. The entries are hardcoded below in setupTableReadOnlyItems
readOnlyTooltip = tr("This entry is provided by the system at \"%1\" "
"and cannot be modified in this view.")
.arg(QDir::toNativeSeparators(cfgFile.excludeFile(ConfigFile::SystemScope)));

setupTableReadOnlyItems();
const auto userConfig = cfgFile.excludeFile(ConfigFile::Scope::UserScope);
ui->ignoreTableWidget->readIgnoreFile(userConfig);

connect(this, &QDialog::accepted, [=, this]() {
ui->ignoreTableWidget->slotWriteIgnoreFile(userConfig);
/* handle the hidden file checkbox */

/* the ignoreHiddenFiles flag is a folder specific setting, but for now, it is
* handled globally. Save it to every folder that is defined.
* TODO this can now be fixed, simply attach this IgnoreListEditor to top-level account
* settings
*/
FolderMan::instance()->setIgnoreHiddenFiles(ignoreHiddenFiles());
});
connect(ui->buttonBox, &QDialogButtonBox::clicked,
this, &IgnoreListEditor::slotRestoreDefaults);
_ignoreFile = cfgFile.excludeFile(ConfigFile::Scope::UserScope);
setupUi();
}

ui->syncHiddenFilesCheckBox->setChecked(!FolderMan::instance()->ignoreHiddenFiles());
IgnoreListEditor::IgnoreListEditor(const QString &ignoreFile, QWidget *parent)

Check warning on line 35 in src/gui/ignorelisteditor.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/ignorelisteditor.cpp:35:1 [cppcoreguidelines-pro-type-member-init]

constructor does not initialize these fields: , ui, _ignoreFile, _ignoreListType
: QDialog{parent}
, ui{new Ui::IgnoreListEditor}
, _ignoreFile{ignoreFile}
, _ignoreListType{IgnoreListType::Folder}
{
setupUi();
ui->groupboxGlobalIgnoreSettings->hide();
}

IgnoreListEditor::~IgnoreListEditor()
{
delete ui;
}

void IgnoreListEditor::setupTableReadOnlyItems()
bool IgnoreListEditor::ignoreHiddenFiles() const

Check warning on line 50 in src/gui/ignorelisteditor.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/ignorelisteditor.cpp:50:24 [modernize-use-trailing-return-type]

use a trailing return type for this function
{
ui->ignoreTableWidget->addPattern(".csync_journal.db*", /*deletable=*/false, /*readonly=*/true);
ui->ignoreTableWidget->addPattern("._sync_*.db*", /*deletable=*/false, /*readonly=*/true);
ui->ignoreTableWidget->addPattern(".sync_*.db*", /*deletable=*/false, /*readonly=*/true);
return !ui->syncHiddenFilesCheckBox->isChecked();
}

bool IgnoreListEditor::ignoreHiddenFiles()
void IgnoreListEditor::slotSaveIgnoreList()
{
return !ui->syncHiddenFilesCheckBox->isChecked();
// TODO: this will tell the file provider extension a different set of files to globally ignore
// when called from the local editor -- not good!
ui->ignoreTableWidget->slotWriteIgnoreFile(_ignoreFile);

if (_ignoreListType != Global) {
return;
}

/* handle the hidden file checkbox for the global ignore list editor */

/* the ignoreHiddenFiles flag is a folder specific setting, but for now, it is
* handled globally. Save it to every folder that is defined.
* TODO this can now be fixed, simply attach this IgnoreListEditor to top-level account
* settings
*/
FolderMan::instance()->setIgnoreHiddenFiles(ignoreHiddenFiles());
}

void IgnoreListEditor::slotRestoreDefaults(QAbstractButton *button)
{
if(ui->buttonBox->buttonRole(button) != QDialogButtonBox::ResetRole)
if(ui->buttonBox->buttonRole(button) != QDialogButtonBox::ResetRole) {
return;
}

ui->ignoreTableWidget->slotRemoveAllItems();

ConfigFile cfgFile;
setupTableReadOnlyItems();
ui->ignoreTableWidget->readIgnoreFile(cfgFile.excludeFile(ConfigFile::SystemScope), false);

if (_ignoreListType == Global) {
ConfigFile cfgFile;

Check warning on line 86 in src/gui/ignorelisteditor.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/ignorelisteditor.cpp:86:20 [cppcoreguidelines-init-variables]

variable 'cfgFile' is not initialized
ui->ignoreTableWidget->readIgnoreFile(cfgFile.excludeFile(ConfigFile::SystemScope), false);
return;
}

ui->ignoreTableWidget->readIgnoreFile(_ignoreFile);
}

void IgnoreListEditor::setupUi()
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
ui->setupUi(this);

setupTableReadOnlyItems();
ui->ignoreTableWidget->readIgnoreFile(_ignoreFile);

connect(this, &QDialog::accepted, this, &IgnoreListEditor::slotSaveIgnoreList);
connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &IgnoreListEditor::slotRestoreDefaults);

ui->syncHiddenFilesCheckBox->setChecked(!FolderMan::instance()->ignoreHiddenFiles());
}

void IgnoreListEditor::setupTableReadOnlyItems()
{
if (_ignoreListType != Global) {
return;
}

ui->ignoreTableWidget->addPattern(".csync_journal.db*", /*deletable=*/false, /*readonly=*/true);
ui->ignoreTableWidget->addPattern("._sync_*.db*", /*deletable=*/false, /*readonly=*/true);
ui->ignoreTableWidget->addPattern(".sync_*.db*", /*deletable=*/false, /*readonly=*/true);
}

} // namespace OCC
Loading
Loading