diff options
author | Hannah von Reth <hannah.vonreth@owncloud.com> | 2019-12-06 18:52:12 +0300 |
---|---|---|
committer | Hannah von Reth <hannah.vonreth@owncloud.com> | 2019-12-06 18:52:12 +0300 |
commit | ac1102070f737fb37f006c737d25a6279fa6a823 (patch) | |
tree | dbd687a54f35395656195ea75ae589ff07fe726b /src | |
parent | 3461c0668e190cec8a3dff5f5bbd56afdea531cb (diff) | |
parent | 86c1a666600ee6f83b4c56a77f2a7cc09f281c81 (diff) |
Merge branch '2.6'
Diffstat (limited to 'src')
-rw-r--r-- | src/gui/accountsettings.cpp | 10 | ||||
-rw-r--r-- | src/gui/activityitemdelegate.cpp | 2 | ||||
-rw-r--r-- | src/gui/activitylistmodel.cpp | 2 | ||||
-rw-r--r-- | src/gui/application.cpp | 23 | ||||
-rw-r--r-- | src/gui/application.h | 2 | ||||
-rw-r--r-- | src/gui/networksettings.cpp | 22 | ||||
-rw-r--r-- | src/gui/networksettings.h | 2 | ||||
-rw-r--r-- | src/gui/networksettings.ui | 25 | ||||
-rw-r--r-- | src/gui/owncloudgui.cpp | 17 | ||||
-rw-r--r-- | src/gui/settingsdialog.cpp | 64 | ||||
-rw-r--r-- | src/gui/settingsdialogcommon.cpp | 28 | ||||
-rw-r--r-- | src/gui/socketapi.cpp | 4 | ||||
-rw-r--r-- | src/libsync/accessmanager.cpp | 12 | ||||
-rw-r--r-- | src/libsync/account.cpp | 10 | ||||
-rw-r--r-- | src/libsync/capabilities.cpp | 12 | ||||
-rw-r--r-- | src/libsync/capabilities.h | 4 | ||||
-rw-r--r-- | src/libsync/discovery.cpp | 29 | ||||
-rw-r--r-- | src/libsync/syncengine.cpp | 2 | ||||
-rw-r--r-- | src/libsync/syncfileitem.h | 2 |
19 files changed, 181 insertions, 91 deletions
diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp index 52de0dfa1..baec02e6b 100644 --- a/src/gui/accountsettings.cpp +++ b/src/gui/accountsettings.cpp @@ -363,6 +363,16 @@ void AccountSettings::slotFolderListClicked(const QModelIndex &indx) { if (indx.data(FolderStatusDelegate::AddButton).toBool()) { // "Add Folder Sync Connection" + QTreeView *tv = ui->_folderList; + auto pos = tv->mapFromGlobal(QCursor::pos()); + QStyleOptionViewItem opt; + opt.initFrom(tv); + auto btnRect = tv->visualRect(indx); + auto btnSize = tv->itemDelegate(indx)->sizeHint(opt, indx); + auto actual = QStyle::visualRect(opt.direction, btnRect, QRect(btnRect.topLeft(), btnSize)); + if (!actual.contains(pos)) + return; + if (indx.flags() & Qt::ItemIsEnabled) { slotAddFolder(); } else { diff --git a/src/gui/activityitemdelegate.cpp b/src/gui/activityitemdelegate.cpp index ae2a17e60..01b5fe1b8 100644 --- a/src/gui/activityitemdelegate.cpp +++ b/src/gui/activityitemdelegate.cpp @@ -104,7 +104,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem & int textTopOffset = qRound((iconHeight - fm.height()) / 2.0); // time rect QRect timeBox; - int timeBoxWidth = fm.boundingRect(QLatin1String("4 hour(s) ago on longlongdomain.org")).width(); // FIXME. + int timeBoxWidth = fm.boundingRect(QLatin1String("4 hour(s) ago on longlongdomain.org (username)")).width(); // FIXME. timeBox.setTop(actionIconRect.top() + textTopOffset); timeBox.setLeft(option.rect.right() - timeBoxWidth - margin); timeBox.setWidth(timeBoxWidth); diff --git a/src/gui/activitylistmodel.cpp b/src/gui/activitylistmodel.cpp index 33e57690d..906cebe2a 100644 --- a/src/gui/activitylistmodel.cpp +++ b/src/gui/activitylistmodel.cpp @@ -71,6 +71,8 @@ QVariant ActivityListModel::data(const QModelIndex &index, int role) const return QIcon(QLatin1String(":/client/resources/account.png")); break; case Qt::ToolTipRole: + return tr("%1 %2 on %3").arg(a._subject, Utility::timeAgoInWords(a._dateTime), a._accName); + break; case ActivityItemDelegate::ActionTextRole: return a._subject; break; diff --git a/src/gui/application.cpp b/src/gui/application.cpp index 213780c88..1b94417c6 100644 --- a/src/gui/application.cpp +++ b/src/gui/application.cpp @@ -68,6 +68,8 @@ namespace { static const char optionsC[] = "Options:\n" " -h --help : show this help screen.\n" + " -s --showsettings : show the settings dialog while starting.\n" + " -q --quit : quit the running instance\n" " --logwindow : open a window to show log output.\n" " --logfile <filename> : write log output to file <filename>.\n" " --logfile - : write log output to stdout.\n" @@ -187,7 +189,6 @@ Application::Application(int &argc, char **argv) setOrganizationDomain(QLatin1String(APPLICATION_REV_DOMAIN)); setApplicationName(_theme->appName()); setWindowIcon(_theme->applicationIcon()); - setAttribute(Qt::AA_UseHighDpiPixmaps, true); if (!ConfigFile().exists()) { // Migrate from version <= 2.4 @@ -235,6 +236,11 @@ Application::Application(int &argc, char **argv) if (_helpOnly || _versionOnly) return; + if (_quitInstance) { + QTimer::singleShot(0, qApp, &QApplication::quit); + return; + } + if (isRunning()) return; @@ -311,6 +317,9 @@ Application::Application(int &argc, char **argv) if (_showLogWindow) { _gui->slotToggleLogBrowser(); // _showLogWindow is set in parseOptions. } + if (_showSettings) { + _gui->slotShowSettings(); + } FolderMan::instance()->setupFolders(); _proxy.setupQtProxyFromConfig(); // folders have to be defined first, than we set up the Qt proxy. @@ -515,11 +524,19 @@ void Application::slotParseMessage(const QString &msg, QObject *) const int lengthOfMsgPrefix = 17; QStringList options = msg.mid(lengthOfMsgPrefix).split(QLatin1Char('|')); _showLogWindow = false; + _showSettings = false; parseOptions(options); setupLogging(); if (_showLogWindow) { _gui->slotToggleLogBrowser(); // _showLogWindow is set in parseOptions. } + if (_showSettings) { + _gui->slotShowSettings(); + } + if (_quitInstance) { + qApp->quit(); + } + } else if (msg.startsWith(QLatin1String("MSG_SHOWSETTINGS"))) { qCInfo(lcApplication) << "Running for" << _startedAt.elapsed() / 1000.0 << "sec"; if (_startedAt.elapsed() < 10 * 1000) { @@ -544,6 +561,10 @@ void Application::parseOptions(const QStringList &options) if (option == QLatin1String("--help") || option == QLatin1String("-h")) { setHelp(); break; + } else if (option == QLatin1String("--showsettings") || option == QLatin1String("-s")) { + _showSettings = true; + } else if (option == QLatin1String("--quit") || option == QLatin1String("-q")) { + _quitInstance = true; } else if (option == QLatin1String("--logwindow") || option == QLatin1String("-l")) { _showLogWindow = true; } else if (option == QLatin1String("--logfile")) { diff --git a/src/gui/application.h b/src/gui/application.h index 72667ad49..9dc1a92d0 100644 --- a/src/gui/application.h +++ b/src/gui/application.h @@ -122,6 +122,8 @@ private: // options from command line: bool _showLogWindow; + bool _showSettings = false; + bool _quitInstance = false; QString _logFile; QString _logDir; std::chrono::hours _logExpire; diff --git a/src/gui/networksettings.cpp b/src/gui/networksettings.cpp index d2436396d..2c9aa3c48 100644 --- a/src/gui/networksettings.cpp +++ b/src/gui/networksettings.cpp @@ -55,6 +55,8 @@ NetworkSettings::NetworkSettings(QWidget *parent) _ui->manualSettings, &QWidget::setEnabled); connect(_ui->manualProxyRadioButton, &QAbstractButton::toggled, _ui->typeComboBox, &QWidget::setEnabled); + connect(_ui->manualProxyRadioButton, &QAbstractButton::toggled, + this, &NetworkSettings::checkAccountLocalhost); loadProxySettings(); loadBWLimitSettings(); @@ -80,6 +82,7 @@ NetworkSettings::NetworkSettings(QWidget *parent) // Warn about empty proxy host connect(_ui->hostLineEdit, &QLineEdit::textChanged, this, &NetworkSettings::checkEmptyProxyHost); checkEmptyProxyHost(); + checkAccountLocalhost(); } NetworkSettings::~NetworkSettings() @@ -229,8 +232,27 @@ void NetworkSettings::showEvent(QShowEvent *event) checkEmptyProxyHost(); saveProxySettings(); } + checkAccountLocalhost(); QWidget::showEvent(event); } + +void NetworkSettings::checkAccountLocalhost() +{ + bool visible = false; + if (_ui->manualProxyRadioButton->isChecked()) { + // Check if at least one account is using localhost, because Qt proxy settings have no + // effect for localhost (#7169) + for (const auto &account : AccountManager::instance()->accounts()) { + const auto host = account->account()->url().host(); + // Some typical url for localhost + if (host == "localhost" || host.startsWith("127.") || host == "[::1]") + visible = true; + } + } + _ui->labelLocalhost->setVisible(visible); +} + + } // namespace OCC diff --git a/src/gui/networksettings.h b/src/gui/networksettings.h index 8d35b14dc..cc0d7a562 100644 --- a/src/gui/networksettings.h +++ b/src/gui/networksettings.h @@ -44,6 +44,8 @@ private slots: /// Red marking of host field if empty and enabled void checkEmptyProxyHost(); + void checkAccountLocalhost(); + protected: void showEvent(QShowEvent *event) override; diff --git a/src/gui/networksettings.ui b/src/gui/networksettings.ui index 60c5ae9c2..476079832 100644 --- a/src/gui/networksettings.ui +++ b/src/gui/networksettings.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>542</width> - <height>396</height> + <width>623</width> + <height>581</height> </rect> </property> <property name="windowTitle"> @@ -23,6 +23,13 @@ <string>Proxy Settings</string> </property> <layout class="QGridLayout" name="gridLayout"> + <item row="2" column="1"> + <widget class="QComboBox" name="typeComboBox"> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </item> <item row="0" column="0"> <widget class="QRadioButton" name="noProxyRadioButton"> <property name="text"> @@ -56,13 +63,6 @@ </attribute> </widget> </item> - <item row="2" column="1"> - <widget class="QComboBox" name="typeComboBox"> - <property name="enabled"> - <bool>false</bool> - </property> - </widget> - </item> <item row="3" column="0" colspan="2"> <widget class="QWidget" name="manualSettings" native="true"> <property name="enabled"> @@ -170,6 +170,13 @@ </layout> </widget> </item> + <item> + <widget class="QLabel" name="labelLocalhost"> + <property name="text"> + <string>Note: proxy settings have no effects for accounts on localhost</string> + </property> + </widget> + </item> </layout> </widget> </item> diff --git a/src/gui/owncloudgui.cpp b/src/gui/owncloudgui.cpp index 05f0cb879..1a834ad3c 100644 --- a/src/gui/owncloudgui.cpp +++ b/src/gui/owncloudgui.cpp @@ -1118,10 +1118,7 @@ void ownCloudGui::slotShowShareDialog(const QString &sharePath, const QString &l // // The correct value will be found with a propfind from ShareDialog. // (we want to show the dialog directly, not wait for the propfind first) - SharePermissions maxSharingPermissions = - SharePermissionRead - | SharePermissionUpdate | SharePermissionCreate | SharePermissionDelete - | SharePermissionShare; + SharePermissions maxSharingPermissions = static_cast<SharePermissions>(accountState->account()->capabilities().defaultPermissions()); if (!resharingAllowed) { maxSharingPermissions = SharePermission(0); } @@ -1170,9 +1167,15 @@ void ownCloudGui::slotAbout() msgBox->setInformativeText("<qt>"+about+"</qt>"); msgBox->setStandardButtons(QMessageBox::Ok); QIcon appIcon = Theme::instance()->applicationIcon(); - // Assume icon is always small enough to fit an about dialog? - qDebug() << appIcon.availableSizes().last(); - QPixmap iconPixmap = appIcon.pixmap(appIcon.availableSizes().last()); + const auto sizes = appIcon.availableSizes(); + QSize size; + for (auto it = sizes.crbegin(); it != sizes.crend(); ++it) { + if (it->width() > 600) + continue; + size = *it; + break; + } + QPixmap iconPixmap = appIcon.pixmap(size); iconPixmap.setDevicePixelRatio(2); msgBox->setIconPixmap(iconPixmap); msgBox->show(); diff --git a/src/gui/settingsdialog.cpp b/src/gui/settingsdialog.cpp index a444a4a25..963e885d4 100644 --- a/src/gui/settingsdialog.cpp +++ b/src/gui/settingsdialog.cpp @@ -41,22 +41,48 @@ #include <QWidgetAction> #include <QPainter> #include <QPainterPath> +#include <QMessageBox> namespace { -const char TOOLBAR_CSS[] = - "QToolBar { background: %1; margin: 0; padding: 0; border: none; border-bottom: 1px solid %2; spacing: 0; } " - "QToolBar QToolButton { background: %1; border: none; border-bottom: 1px solid %2; margin: 0; padding: 5px; } " - "QToolBar QToolBarExtension { padding:0; } " - "QToolBar QToolButton:checked { background: %3; color: %4; }"; +const QString TOOLBAR_CSS() +{ + return QStringLiteral("QToolBar { background: %1; margin: 0; padding: 0; border: none; border-bottom: 1px solid %2; spacing: 0; } " + "QToolBar QToolButton { background: %1; border: none; border-bottom: 1px solid %2; margin: 0; padding: 5px; } " + "QToolBar QToolBarExtension { padding:0; } " + "QToolBar QToolButton:checked { background: %3; color: %4; }"); +} + +const float buttonSizeRatio = 1.618f; // golden ratio + -static const float buttonSizeRatio = 1.618; // golden ratio +/** display name with two lines that is displayed in the settings + * If width is bigger than 0, the string will be ellided so it does not exceed that width + */ +QString shortDisplayNameForSettings(OCC::Account *account, int width) +{ + QString user = account->davDisplayName(); + if (user.isEmpty()) { + user = account->credentials()->user(); + } + QString host = account->url().host(); + int port = account->url().port(); + if (port > 0 && port != 80 && port != 443) { + host.append(QLatin1Char(':')); + host.append(QString::number(port)); + } + if (width > 0) { + QFont f; + QFontMetrics fm(f); + host = fm.elidedText(host, Qt::ElideMiddle, width); + user = fm.elidedText(user, Qt::ElideRight, width); + } + return QStringLiteral("%1\n%2").arg(user, host); +} } namespace OCC { -#include "settingsdialogcommon.cpp" - SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent) : QDialog(parent) , _ui(new Ui::SettingsDialog) @@ -107,6 +133,22 @@ SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent) NetworkSettings *networkSettings = new NetworkSettings; _ui->stack->addWidget(networkSettings); + QWidget *spacer = new QWidget(); + spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + _toolBar->addWidget(spacer); + + QAction *quitAction = createColorAwareAction(QLatin1String(":/client/resources/quit.png"), tr("Quit %1").arg(qApp->applicationName())); + quitAction->setCheckable(false); + connect(quitAction, &QAction::triggered, this, [this] { + const auto reply = QMessageBox::question(this, tr("Quit %1").arg(qApp->applicationName()), + tr("Are you sure you want to quit %1?").arg(qApp->applicationName()), + QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::Yes) { + qApp->quit(); + } + }); + _toolBar->addAction(quitAction); + _actionGroupWidgets.insert(_activityAction, _activitySettings); _actionGroupWidgets.insert(generalAction, generalSettings); _actionGroupWidgets.insert(networkAction, networkSettings); @@ -228,7 +270,7 @@ void SettingsDialog::accountAdded(AccountState *s) if (!brandingSingleAccount) { accountAction->setToolTip(s->account()->displayName()); - accountAction->setIconText(SettingsDialogCommon::shortDisplayNameForSettings(s->account().data(), height * buttonSizeRatio)); + accountAction->setIconText(shortDisplayNameForSettings(s->account().data(), height * buttonSizeRatio)); } _toolBar->insertAction(_toolBar->actions().at(0), accountAction); auto accountSettings = new AccountSettings(s, this); @@ -278,7 +320,7 @@ void SettingsDialog::slotAccountDisplayNameChanged() QString displayName = account->displayName(); action->setText(displayName); auto height = _toolBar->sizeHint().height(); - action->setIconText(SettingsDialogCommon::shortDisplayNameForSettings(account, height * buttonSizeRatio)); + action->setIconText(shortDisplayNameForSettings(account, height * buttonSizeRatio)); } } } @@ -323,7 +365,7 @@ void SettingsDialog::customizeStyle() QString highlightTextColor(palette().highlightedText().color().name()); QString dark(palette().dark().color().name()); QString background(palette().base().color().name()); - _toolBar->setStyleSheet(QString::fromLatin1(TOOLBAR_CSS).arg(background, dark, highlightColor, highlightTextColor)); + _toolBar->setStyleSheet(TOOLBAR_CSS().arg(background, dark, highlightColor, highlightTextColor)); Q_FOREACH (QAction *a, _actionGroup->actions()) { QIcon icon = createColorAwareIcon(a->property("iconPath").toString()); diff --git a/src/gui/settingsdialogcommon.cpp b/src/gui/settingsdialogcommon.cpp deleted file mode 100644 index de6f820c8..000000000 --- a/src/gui/settingsdialogcommon.cpp +++ /dev/null @@ -1,28 +0,0 @@ -namespace SettingsDialogCommon -{ - -/** display name with two lines that is displayed in the settings - * If width is bigger than 0, the string will be ellided so it does not exceed that width - */ -QString shortDisplayNameForSettings(Account* account, int width) -{ - QString user = account->davDisplayName(); - if (user.isEmpty()) { - user = account->credentials()->user(); - } - QString host = account->url().host(); - int port = account->url().port(); - if (port > 0 && port != 80 && port != 443) { - host.append(QLatin1Char(':')); - host.append(QString::number(port)); - } - if (width > 0) { - QFont f; - QFontMetrics fm(f); - host = fm.elidedText(host, Qt::ElideMiddle, width); - user = fm.elidedText(user, Qt::ElideRight, width); - } - return user + QLatin1String("\n") + host; -} - -}
\ No newline at end of file diff --git a/src/gui/socketapi.cpp b/src/gui/socketapi.cpp index 5fb27aac4..9d02f8eea 100644 --- a/src/gui/socketapi.cpp +++ b/src/gui/socketapi.cpp @@ -1003,8 +1003,8 @@ void SocketApi::command_GET_MENU_ITEMS(const QString &argument, OCC::SocketListe QFileInfo fileInfo(fileData.localPath); auto parentDir = fileData.parentFolder(); auto parentRecord = parentDir.journalRecord(); - bool canAddToDir = - (fileInfo.isFile() && !parentRecord._remotePerm.hasPermission(RemotePermissions::CanAddFile)) + bool canAddToDir = parentRecord._remotePerm.isNull() + || (fileInfo.isFile() && !parentRecord._remotePerm.hasPermission(RemotePermissions::CanAddFile)) || (fileInfo.isDir() && !parentRecord._remotePerm.hasPermission(RemotePermissions::CanAddSubDirectories)); bool canChangeFile = !isOnTheServer diff --git a/src/libsync/accessmanager.cpp b/src/libsync/accessmanager.cpp index 212d0edeb..3e6435fda 100644 --- a/src/libsync/accessmanager.cpp +++ b/src/libsync/accessmanager.cpp @@ -95,16 +95,10 @@ QNetworkReply *AccessManager::createRequest(QNetworkAccessManager::Operation op, newRequest.setRawHeader("X-Request-ID", requestId); if (newRequest.url().scheme() == "https") { // Not for "http": QTBUG-61397 - // Qt 5.12.4 fixed QTBUG-73947 - http2 should be usable after that - bool http2Allowed = QLibraryInfo::version() >= QVersionNumber(5, 12, 4); + // http2 seems to cause issues, as with our recommended server setup we don't support http2, disable it by default for now + static const bool http2EnabledEnv = qEnvironmentVariableIntValue("OWNCLOUD_HTTP2_ENABLED") == 1; - static auto http2EnabledEnv = qgetenv("OWNCLOUD_HTTP2_ENABLED"); - if (http2EnabledEnv == "1") - http2Allowed = true; - if (http2EnabledEnv == "0") - http2Allowed = false; - - newRequest.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, http2Allowed); + newRequest.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, http2EnabledEnv); } return QNetworkAccessManager::createRequest(op, newRequest, outgoingData); diff --git a/src/libsync/account.cpp b/src/libsync/account.cpp index 80ace0280..6286e2188 100644 --- a/src/libsync/account.cpp +++ b/src/libsync/account.cpp @@ -110,12 +110,16 @@ void Account::setAvatar(const QImage &img) QString Account::displayName() const { - QString dn = QString("%1@%2").arg(davUser(), _url.host()); + QString user = davDisplayName(); + if (user.isEmpty()) + user = davUser(); + QString host = _url.host(); int port = url().port(); if (port > 0 && port != 80 && port != 443) { - dn.append(QLatin1Char(':')); - dn.append(QString::number(port)); + host.append(QLatin1Char(':')); + host.append(QString::number(port)); } + QString dn = QString("%1 (%2)").arg(host, user); return dn; } diff --git a/src/libsync/capabilities.cpp b/src/libsync/capabilities.cpp index 7a68af71c..5043171ec 100644 --- a/src/libsync/capabilities.cpp +++ b/src/libsync/capabilities.cpp @@ -17,6 +17,13 @@ #include <QVariantMap> #include <QDebug> +namespace { + QString FileSharingKey() + { + return QStringLiteral("files_sharing"); + } +} + namespace OCC { @@ -85,6 +92,11 @@ bool Capabilities::shareResharing() const return _capabilities["files_sharing"].toMap()["resharing"].toBool(); } +int Capabilities::defaultPermissions() const +{ + return _capabilities.value(FileSharingKey()).toMap().value("default_permissions", 1).toInt(); +} + bool Capabilities::notificationsAvailable() const { // We require the OCS style API in 9.x, can't deal with the REST one only found in 8.2 diff --git a/src/libsync/capabilities.h b/src/libsync/capabilities.h index b49008f52..e39ac43a1 100644 --- a/src/libsync/capabilities.h +++ b/src/libsync/capabilities.h @@ -43,6 +43,10 @@ public: bool sharePublicLinkEnforceExpireDate() const; bool sharePublicLinkMultiple() const; bool shareResharing() const; + + // TODO: return SharePermission + int defaultPermissions() const; + bool chunkingNg() const; QString zsyncSupportedVersion() const; diff --git a/src/libsync/discovery.cpp b/src/libsync/discovery.cpp index 539451f14..b9c77c80d 100644 --- a/src/libsync/discovery.cpp +++ b/src/libsync/discovery.cpp @@ -1161,6 +1161,7 @@ void ProcessDirectoryJob::processBlacklisted(const PathTuple &path, const OCC::L item->_file = path._target; item->_originalFile = path._original; item->_inode = localEntry.inode; + item->_isSelectiveSync = true; if (dbEntry.isValid() && ((dbEntry._modtime == localEntry.modtime && dbEntry._fileSize == localEntry.size) || (localEntry.isDirectory && dbEntry.isDirectory()))) { item->_instruction = CSYNC_INSTRUCTION_REMOVE; item->_direction = SyncFileItem::Down; @@ -1409,34 +1410,24 @@ DiscoverySingleDirectoryJob *ProcessDirectoryJob::startAsyncServerQuery() if (_localQueryDone) this->process(); } else { - auto fatalError = [&] { - emit _discoveryData->fatalError(tr("Server replied with an error while reading directory '%1' : %2") - .arg(_currentFolder._server, results.error().message)); - }; - auto ignoreOrFatal = [&] { - if (_dirItem) { - _dirItem->_instruction = CSYNC_INSTRUCTION_IGNORE; - _dirItem->_errorString = results.error().message; - emit this->finished(); - } else { - // Fatal for the root job since it has no SyncFileItem - fatalError(); - } - }; - auto code = results.error().code; qCWarning(lcDisco) << "Server error in directory" << _currentFolder._server << code; - if (code == 403 || code == 404 || code == 500 || code == 503) { + if (_dirItem && code >= 403) { + // In case of an HTTP error, we ignore that directory // 403 Forbidden can be sent by the server if the file firewall is active. // A file or directory should be ignored and sync must continue. See #3490 // The server usually replies with the custom "503 Storage not available" // if some path is temporarily unavailable. But in some cases a standard 503 // is returned too. Thus we can't distinguish the two and will treat any // 503 as request to ignore the folder. See #3113 #2884. - // Similarly, the server might also return 404 or 500 in case of bugs. #7199 - ignoreOrFatal(); + // Similarly, the server might also return 404 or 50x in case of bugs. #7199 #7586 + _dirItem->_instruction = CSYNC_INSTRUCTION_IGNORE; + _dirItem->_errorString = results.error().message; + emit this->finished(); } else { - fatalError(); + // Fatal for the root job since it has no SyncFileItem, or for the network errors + emit _discoveryData->fatalError(tr("Server replied with an error while reading directory '%1' : %2") + .arg(_currentFolder._server, results.error().message)); } } }); diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp index d26ff6d71..130238266 100644 --- a/src/libsync/syncengine.cpp +++ b/src/libsync/syncengine.cpp @@ -375,7 +375,7 @@ void OCC::SyncEngine::slotItemDiscovered(const OCC::SyncFileItemPtr &item) item->_status = SyncFileItem::Conflict; } return; - } else if (item->_instruction == CSYNC_INSTRUCTION_REMOVE) { + } else if (item->_instruction == CSYNC_INSTRUCTION_REMOVE && !item->_isSelectiveSync) { _hasRemoveFile = true; } else if (item->_instruction == CSYNC_INSTRUCTION_RENAME) { _hasNoneFiles = true; // If a file (or every file) has been renamed, it means not al files where deleted diff --git a/src/libsync/syncfileitem.h b/src/libsync/syncfileitem.h index 667341be3..f6740c5c8 100644 --- a/src/libsync/syncfileitem.h +++ b/src/libsync/syncfileitem.h @@ -105,6 +105,7 @@ public: , _errorMayBeBlacklisted(false) , _status(NoStatus) , _isRestoration(false) + , _isSelectiveSync(false) , _httpErrorCode(0) , _affectedItems(1) , _instruction(CSYNC_INSTRUCTION_NONE) @@ -241,6 +242,7 @@ public: // Variables useful to report to the user Status _status BITFIELD(4); bool _isRestoration BITFIELD(1); // The original operation was forbidden, and this is a restoration + bool _isSelectiveSync BITFIELD(1); // The file is removed or ignored because it is in the selective sync list quint16 _httpErrorCode; RemotePermissions _remotePerm; QString _errorString; // Contains a string only in case of error |