Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/per account connection settings #6890

Merged
merged 49 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
63f15de
Add connection settings tab to account settings
claucambra Jun 27, 2024
88d2064
Present network settings component within connection settings tab in …
claucambra Jun 27, 2024
ae1b9bd
Add AccountNetworkProxySetting enum to account
claucambra Jun 28, 2024
15bc9a4
Add AccountNetworkTransferLimitSetting enum to account
claucambra Jun 28, 2024
2501cdf
Add network proxy setting property to account
claucambra Jun 28, 2024
73dd000
Add proxy type property to account
claucambra Jun 28, 2024
a4553f5
Add proxy host name property to account
claucambra Jun 28, 2024
8c6a181
Add proxy port property to account
claucambra Jun 28, 2024
daed4c7
Add proxy needs auth property to account
claucambra Jun 28, 2024
c0cd839
Add proxy user property to account
claucambra Jun 28, 2024
56b8fcf
Add proxy password property to account
claucambra Jun 28, 2024
7a9fd72
Add upload limit setting property to account
claucambra Jun 28, 2024
f96fe64
Add download limit setting property to account
claucambra Jun 28, 2024
d06e8b1
Add upload limit property to account
claucambra Jun 28, 2024
35bc728
Add download limit setting property to account
claucambra Jun 28, 2024
3956612
Save and restore account-specific network settings in account maanger
claucambra Jun 28, 2024
03946a8
Take account-specific network configuration into account in proxyauth…
claucambra Jun 28, 2024
dd71436
Add account member to network settings
claucambra Jun 28, 2024
fe031a1
Load in account specific network settings in network settings widget
claucambra Jun 28, 2024
f9d0f43
Adapt network settings loadBwLimitSettings for account-specific settings
claucambra Jun 28, 2024
f9b4c76
Implement saving proxy settings to account in network settings
claucambra Jun 28, 2024
8dabae6
Respect account proxy settings in owncloudsetupwizard server check
claucambra Jun 28, 2024
ac98197
Respect account proxy settings in connectionvalidator
claucambra Jun 28, 2024
8e9e125
When generally setting dirty proxy in folderman only mark dirty those…
claucambra Jun 28, 2024
9dfcd87
Ensure we are resetting account proxy settings when not using proxy i…
claucambra Jun 28, 2024
ab1d02d
Fix account-specific network setting enum values
claucambra Jun 28, 2024
04f335e
Modify network access manager proxy within account when setting proxy…
claucambra Jun 28, 2024
b14b86e
Clean up networksettings saveProxySettings
claucambra Jun 28, 2024
97f31a2
Save bwlimits for account-specific network configuration
claucambra Jun 28, 2024
480828b
Respect account-specific transfer limits in folder
claucambra Jun 28, 2024
9c856d2
Correctly load global proxy setting state on account-specific network…
claucambra Jul 7, 2024
770beba
Store accounts' proxy passwords in keychain
claucambra Jul 7, 2024
e3b002a
Use single-defined constexpr string for proxy password keychain key
claucambra Jul 7, 2024
5db01d4
Ensure keychain chunk jobs in account manager run as intended
claucambra Jul 7, 2024
2803690
KeychainChunk job exec is synchronous, do not bother with signals in …
claucambra Jul 7, 2024
2d0c069
Get intended default values for bw limit settings for account when no…
claucambra Jul 7, 2024
01f8199
Use better keychain chunk job constructors
claucambra Jul 7, 2024
70e7bcf
Simplify proxy password keychain keys
claucambra Jul 7, 2024
a8c5cbc
Add logging on error for proxy password saving
claucambra Jul 7, 2024
68cff89
Ensure per-account network settings are saved on change
claucambra Jul 7, 2024
5c0c2af
Move folder status model initialisation to member init list in Accoun…
claucambra Jul 8, 2024
5b8f9e4
Ensure file provider tab is not shown when file provider module not e…
claucambra Jul 8, 2024
926c3b6
Use an AccountPtr instead of raw pointer in networksettings
claucambra Jul 8, 2024
5bc6388
Add a method to set a specific account's folders' network limits as d…
claucambra Jul 8, 2024
ef59399
Use qtkeychain directly in account manager
claucambra Jul 8, 2024
37c77d8
Use full user id at host with port for proxy password keychain
claucambra Jul 8, 2024
564be17
Remove now unused disguiseTabWidget
claucambra Jul 9, 2024
eeb9cc2
Use application proxy when setting global proxy setting via network s…
claucambra Jul 22, 2024
7dec7b2
Move all proxy configuration procedures into account and out of netwo…
claucambra Jul 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 91 additions & 1 deletion src/gui/accountmanager.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check notice on line 1 in src/gui/accountmanager.cpp

View workflow job for this annotation

GitHub Actions / build

Run clang-format on src/gui/accountmanager.cpp

File src/gui/accountmanager.cpp does not conform to Custom style guidelines. (lines 359, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524)
* Copyright (C) by Olivier Goffart <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
Expand All @@ -16,9 +16,9 @@

#include "sslerrordialog.h"
#include "proxyauthhandler.h"
#include "common/asserts.h"
#include "creds/credentialsfactory.h"
#include "creds/abstractcredentials.h"
#include "creds/keychainchunk.h"
#include "libsync/clientsideencryption.h"
#include "libsync/configfile.h"
#include "libsync/cookiejar.h"
Expand All @@ -29,6 +29,13 @@
#include <QNetworkAccessManager>
#include <QMessageBox>
#include <QPushButton>
#include <type_traits>

#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <qt6keychain/keychain.h>
#else
#include <qt5keychain/keychain.h>
#endif

namespace {
constexpr auto urlC = "url";
Expand All @@ -46,6 +53,16 @@
constexpr auto serverColorC = "serverColor";
constexpr auto serverTextColorC = "serverTextColor";
constexpr auto skipE2eeMetadataChecksumValidationC = "skipE2eeMetadataChecksumValidation";
constexpr auto networkProxySettingC = "networkProxySetting";
constexpr auto networkProxyTypeC = "networkProxyType";
constexpr auto networkProxyHostNameC = "networkProxyHostName";
constexpr auto networkProxyPortC = "networkProxyPort";
constexpr auto networkProxyNeedsAuthC = "networkProxyNeedsAuth";
constexpr auto networkProxyUserC = "networkProxyUser";
constexpr auto networkUploadLimitSettingC = "networkUploadLimitSetting";
constexpr auto networkDownloadLimitSettingC = "networkDownloadLimitSetting";
constexpr auto networkUploadLimitC = "networkUploadLimit";
constexpr auto networkDownloadLimitC = "networkDownloadLimit";
constexpr auto generalC = "General";

constexpr auto dummyAuthTypeC = "dummy";
Expand All @@ -55,6 +72,8 @@
constexpr auto httpAuthPrefix = "http_";
constexpr auto webflowAuthPrefix = "webflow_";

constexpr auto networkProxyPasswordKeychainKeySuffixC = "_proxy_password";

constexpr auto legacyRelativeConfigLocationC = "/ownCloud/owncloud.cfg";
constexpr auto legacyCfgFileNameC = "owncloud.cfg";

Expand Down Expand Up @@ -330,6 +349,42 @@
} else {
settings.setValue(QLatin1String(skipE2eeMetadataChecksumValidationC), acc->_skipE2eeMetadataChecksumValidation);
}
settings.setValue(networkProxySettingC, static_cast<std::underlying_type_t<Account::AccountNetworkProxySetting>>(acc->networkProxySetting()));
settings.setValue(networkProxyTypeC, acc->proxyType());
settings.setValue(networkProxyHostNameC, acc->proxyHostName());
settings.setValue(networkProxyPortC, acc->proxyPort());
settings.setValue(networkProxyNeedsAuthC, acc->proxyNeedsAuth());
settings.setValue(networkProxyUserC, acc->proxyUser());
settings.setValue(networkUploadLimitSettingC, static_cast<std::underlying_type_t<Account::AccountNetworkTransferLimitSetting>>(acc->uploadLimitSetting()));
settings.setValue(networkDownloadLimitSettingC, static_cast<std::underlying_type_t<Account::AccountNetworkTransferLimitSetting>>(acc->downloadLimitSetting()));
settings.setValue(networkUploadLimitC, acc->uploadLimit());
settings.setValue(networkDownloadLimitC, acc->downloadLimit());

const auto proxyPasswordKey = QString(acc->userIdAtHostWithPort() + networkProxyPasswordKeychainKeySuffixC);
if (const auto proxyPassword = acc->proxyPassword(); proxyPassword.isEmpty()) {
const auto job = new QKeychain::DeletePasswordJob(Theme::instance()->appName(), this);
job->setKey(proxyPasswordKey);
connect(job, &QKeychain::Job::finished, this, [](const QKeychain::Job *const incomingJob) {
if (incomingJob->error() == QKeychain::NoError) {
qCInfo(lcAccountManager) << "Deleted proxy password from keychain";
} else {
qCWarning(lcAccountManager) << "Failed to delete proxy password to keychain" << incomingJob->errorString();
}
});
job->start();
} else {
const auto job = new QKeychain::WritePasswordJob(Theme::instance()->appName(), this);
job->setKey(proxyPasswordKey);
job->setBinaryData(proxyPassword.toUtf8());
connect(job, &QKeychain::Job::finished, this, [](const QKeychain::Job *const incomingJob) {
if (incomingJob->error() == QKeychain::NoError) {
qCInfo(lcAccountManager) << "Saved proxy password to keychain";
} else {
qCWarning(lcAccountManager) << "Failed to save proxy password to keychain" << incomingJob->errorString();
}
});
job->start();
}

if (acc->_credentials) {
if (saveCredentials) {
Expand Down Expand Up @@ -451,6 +506,41 @@

acc->setCredentials(CredentialsFactory::create(authType));

acc->setNetworkProxySetting(settings.value(networkProxySettingC).value<Account::AccountNetworkProxySetting>());
acc->setProxyType(settings.value(networkProxyTypeC).value<QNetworkProxy::ProxyType>());
acc->setProxyHostName(settings.value(networkProxyHostNameC).toString());
acc->setProxyPort(settings.value(networkProxyPortC).toInt());
acc->setProxyNeedsAuth(settings.value(networkProxyNeedsAuthC).toBool());
acc->setProxyUser(settings.value(networkProxyUserC).toString());
acc->setUploadLimitSetting(
settings.value(
networkUploadLimitSettingC,
QVariant::fromValue(Account::AccountNetworkTransferLimitSetting::GlobalLimit)
).value<Account::AccountNetworkTransferLimitSetting>());
acc->setDownloadLimitSetting(
settings.value(
networkDownloadLimitSettingC,
QVariant::fromValue(Account::AccountNetworkTransferLimitSetting::GlobalLimit)
).value<Account::AccountNetworkTransferLimitSetting>());
acc->setUploadLimit(settings.value(networkUploadLimitC).toInt());
acc->setDownloadLimit(settings.value(networkDownloadLimitC).toInt());

const auto proxyPasswordKey = QString(acc->userIdAtHostWithPort() + networkProxyPasswordKeychainKeySuffixC);
const auto job = new QKeychain::ReadPasswordJob(Theme::instance()->appName(), this);
job->setKey(proxyPasswordKey);
connect(job, &QKeychain::Job::finished, this, [acc](const QKeychain::Job *const incomingJob) {
const auto incomingReadJob = qobject_cast<const QKeychain::ReadPasswordJob *>(incomingJob);
if (incomingReadJob->error() == QKeychain::NoError) {
qCInfo(lcAccountManager) << "Read proxy password to keychain for" << acc->userIdAtHostWithPort();
const auto passwordData = incomingReadJob->binaryData();
const auto password = QString::fromUtf8(passwordData);
acc->setProxyPassword(password);
} else {
qCWarning(lcAccountManager) << "Failed to read proxy password to keychain" << incomingJob->errorString();
}
});
job->start();

// now the server cert, it is in the general group
settings.beginGroup(QLatin1String(generalC));
const auto certs = QSslCertificate::fromData(settings.value(caCertsKeyC).toByteArray());
Expand Down
27 changes: 14 additions & 13 deletions src/gui/accountsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "syncresult.h"
#include "ignorelisttablewidget.h"
#include "wizard/owncloudwizard.h"
#include "networksettings.h"
#include "ui_mnemonicdialog.h"

#include <cmath>
Expand Down Expand Up @@ -173,12 +174,12 @@ class MouseCursorChanger : public QObject
AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
: QWidget(parent)
, _ui(new Ui::AccountSettings)
, _model(new FolderStatusModel)
, _accountState(accountState)
, _userInfo(accountState, false, true)
{
_ui->setupUi(this);

_model = new FolderStatusModel;
_model->setAccountState(_accountState);
_model->setParent(this);
const auto delegate = new FolderStatusDelegate;
Expand Down Expand Up @@ -206,14 +207,22 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
const auto fpSettingsWidget = fpSettingsController->settingsViewWidget(fpAccountUserIdAtHost, fileProviderTab);
fpSettingsLayout->addWidget(fpSettingsWidget);
fileProviderTab->setLayout(fpSettingsLayout);
} else {
disguiseTabWidget();
}
#else
disguiseTabWidget();
_ui->tabWidget->setCurrentIndex(0);
const auto tabWidget = _ui->tabWidget;
const auto fileProviderTab = _ui->fileProviderTab;
if (const auto fileProviderWidgetTabIndex = tabWidget->indexOf(fileProviderTab); fileProviderWidgetTabIndex >= 0) {
tabWidget->removeTab(fileProviderWidgetTabIndex);
}
tabWidget->setCurrentIndex(0);
#endif

const auto connectionSettingsTab = _ui->connectionSettingsTab;
const auto connectionSettingsLayout = new QVBoxLayout(connectionSettingsTab);
const auto networkSettings = new NetworkSettings(_accountState->account(), connectionSettingsTab);
connectionSettingsLayout->addWidget(networkSettings);
connectionSettingsTab->setLayout(connectionSettingsLayout);

const auto mouseCursorChanger = new MouseCursorChanger(this);
mouseCursorChanger->folderList = _ui->_folderList;
mouseCursorChanger->model = _model;
Expand Down Expand Up @@ -1709,14 +1718,6 @@ void AccountSettings::initializeE2eEncryptionSettingsMessage()
connect(actionEnableE2e, &QAction::triggered, this, &AccountSettings::slotE2eEncryptionGenerateKeys);
}

void AccountSettings::disguiseTabWidget() const
{
// Ensure all elements of the tab widget are hidden.
// Document mode lets the child view take up the whole view.
_ui->tabWidget->setDocumentMode(true);
_ui->tabWidget->tabBar()->hide();
}

} // namespace OCC

#include "accountsettings.moc"
2 changes: 0 additions & 2 deletions src/gui/accountsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,6 @@ private slots:
/// Returns the alias of the selected folder, empty string if none
[[nodiscard]] QString selectedFolderAlias() const;

void disguiseTabWidget() const;

Ui::AccountSettings *_ui;

FolderStatusModel *_model;
Expand Down
10 changes: 9 additions & 1 deletion src/gui/accountsettings.ui
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,11 @@
</item>
<item row="3" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="tabShape">
<enum>QTabWidget::Rounded</enum>
</property>
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="standardSyncTab">
<attribute name="title">
Expand Down Expand Up @@ -308,6 +311,11 @@
<string>Virtual file sync</string>
</attribute>
</widget>
<widget class="QWidget" name="connectionSettingsTab">
<attribute name="title">
<string>Connection settings</string>
</attribute>
</widget>
</widget>
</item>
</layout>
Expand Down
5 changes: 5 additions & 0 deletions src/gui/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,11 @@ Application::Application(int &argc, char **argv)

if (_theme->doNotUseProxy()) {
ConfigFile().setProxyType(QNetworkProxy::NoProxy);
for (const auto &accountState : AccountManager::instance()->accounts()) {
if (accountState && accountState->account()) {
accountState->account()->setNetworkProxySetting(Account::AccountNetworkProxySetting::GlobalProxy);
}
}
}

parseOptions(arguments());
Expand Down
6 changes: 3 additions & 3 deletions src/gui/connectionvalidator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* for more details.
*/

#include <QJsonDocument>

Check failure on line 15 in src/gui/connectionvalidator.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/connectionvalidator.cpp:15:10 [clang-diagnostic-error]

'QJsonDocument' file not found
#include <QJsonObject>
#include <QJsonArray>
#include <QLoggingCategory>
Expand Down Expand Up @@ -57,10 +57,10 @@
_isCheckingServerAndAuth = true;

// Lookup system proxy in a thread https://github.com/owncloud/client/issues/2993
if (ClientProxy::isUsingSystemDefault()) {
if ((ClientProxy::isUsingSystemDefault() && _account->networkProxySetting() == Account::AccountNetworkProxySetting::GlobalProxy)

Check warning on line 60 in src/gui/connectionvalidator.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/connectionvalidator.cpp:60:5 [bugprone-branch-clone]

if with identical then and else branches
|| _account->proxyType() == QNetworkProxy::DefaultProxy) {
qCDebug(lcConnectionValidator) << "Trying to look up system proxy";
ClientProxy::lookupSystemProxyAsync(_account->url(),
this, SLOT(systemProxyLookupDone(QNetworkProxy)));
ClientProxy::lookupSystemProxyAsync(_account->url(), this, SLOT(systemProxyLookupDone(QNetworkProxy)));
} else {
// We want to reset the QNAM proxy so that the global proxy settings are used (via ClientProxy settings)
_account->networkAccessManager()->setProxy(QNetworkProxy(QNetworkProxy::DefaultProxy));
Expand Down
18 changes: 14 additions & 4 deletions src/gui/folder.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check notice on line 1 in src/gui/folder.cpp

View workflow job for this annotation

GitHub Actions / build

Run clang-format on src/gui/folder.cpp

File src/gui/folder.cpp does not conform to Custom style guidelines. (lines 1145, 1146, 1155, 1156)
* Copyright (C) by Duncan Mac-Vicar P. <[email protected]>
* Copyright (C) by Daniel Molkentin <[email protected]>
* Copyright (C) by Klaas Freitag <[email protected]>
Expand All @@ -13,7 +13,7 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "common/syncjournaldb.h"

Check failure on line 16 in src/gui/folder.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/folder.cpp:16:10 [clang-diagnostic-error]

'common/syncjournaldb.h' file not found
#include "config.h"

#include "account.h"
Expand Down Expand Up @@ -47,6 +47,7 @@
#include <QMessageBox>
#include <QPushButton>
#include <QApplication>
#include <type_traits>

namespace {
#ifndef VERSION_C
Expand Down Expand Up @@ -1134,19 +1135,28 @@

void Folder::setDirtyNetworkLimits()
{
const auto account = _accountState->account();
const auto useGlobalDown = account->downloadLimitSetting() == Account::AccountNetworkTransferLimitSetting::GlobalLimit;
const auto useGlobalUp = account->uploadLimitSetting() == Account::AccountNetworkTransferLimitSetting::GlobalLimit;

ConfigFile cfg;

Check warning on line 1142 in src/gui/folder.cpp

View workflow job for this annotation

GitHub Actions / build

src/gui/folder.cpp:1142:16 [cppcoreguidelines-init-variables]

variable 'cfg' is not initialized

int downloadLimit = -75; // 75%
int useDownLimit = cfg.useDownloadLimit();
const auto useDownLimit = useGlobalDown
? cfg.useDownloadLimit()
: static_cast<std::underlying_type_t<Account::AccountNetworkTransferLimitSetting>>(account->downloadLimitSetting());
if (useDownLimit >= 1) {
downloadLimit = cfg.downloadLimit() * 1000;
downloadLimit = useGlobalDown ? cfg.downloadLimit() * 1000 : account->downloadLimit() * 1000;
} else if (useDownLimit == 0) {
downloadLimit = 0;
}

int uploadLimit = -75; // 75%
int useUpLimit = cfg.useUploadLimit();
const auto useUpLimit = useGlobalUp
? cfg.useUploadLimit()
: static_cast<std::underlying_type_t<Account::AccountNetworkTransferLimitSetting>>(account->uploadLimitSetting());
if (useUpLimit >= 1) {
uploadLimit = cfg.uploadLimit() * 1000;
uploadLimit = useGlobalUp ? cfg.uploadLimit() * 1000 : account->uploadLimit() * 1000;
} else if (useUpLimit == 0) {
uploadLimit = 0;
}
Expand Down
26 changes: 19 additions & 7 deletions src/gui/folderman.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check notice on line 1 in src/gui/folderman.cpp

View workflow job for this annotation

GitHub Actions / build

Run clang-format on src/gui/folderman.cpp

File src/gui/folderman.cpp does not conform to Custom style guidelines. (lines 1514, 1515, 1516)
* Copyright (C) by Klaas Freitag <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -1511,13 +1511,14 @@
{
const auto folderMapValues = _folderMap.values();
for (const auto folder : folderMapValues) {
if (folder) {
if (folder->accountState() && folder->accountState()->account()
&& folder->accountState()->account()->networkAccessManager()) {
// Need to do this so we do not use the old determined system proxy
folder->accountState()->account()->networkAccessManager()->setProxy(
QNetworkProxy(QNetworkProxy::DefaultProxy));
}
if (folder
&& folder->accountState()
&& folder->accountState()->account()
&& folder->accountState()->account()->networkAccessManager()
&& folder->accountState()->account()->networkProxySetting() == Account::AccountNetworkProxySetting::GlobalProxy) {
// Need to do this so we do not use the old determined system proxy
const auto proxy = QNetworkProxy(QNetworkProxy::DefaultProxy);
folder->accountState()->account()->networkAccessManager()->setProxy(proxy);
}
}
}
Expand All @@ -1533,6 +1534,17 @@
}
}

void FolderMan::setDirtyNetworkLimits(const AccountPtr &account) const
{
const auto folderMapValues = _folderMap.values();
for (const auto folder : folderMapValues) {
// set only in busy folders. Otherwise they read the config anyway.
if (folder && folder->isBusy() && folder->accountState()->account() == account) {
folder->setDirtyNetworkLimits();
}
}
}

void FolderMan::leaveShare(const QString &localFile)
{
const auto localFileNoTrailingSlash = localFile.endsWith('/') ? localFile.chopped(1) : localFile;
Expand Down
1 change: 1 addition & 0 deletions src/gui/folderman.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#ifndef FOLDERMAN_H
#define FOLDERMAN_H

#include <QByteArray>

Check failure on line 19 in src/gui/folderman.h

View workflow job for this annotation

GitHub Actions / build

src/gui/folderman.h:19:10 [clang-diagnostic-error]

'QByteArray' file not found
#include <QObject>
#include <QQueue>
#include <QList>
Expand Down Expand Up @@ -227,6 +227,7 @@

void setDirtyProxy();
void setDirtyNetworkLimits();
void setDirtyNetworkLimits(const AccountPtr &account) const;

/** removes current user from the share **/
void leaveShare(const QString &localFile);
Expand Down
Loading
Loading