});
if (foundFolder != folderMap.cend()) {
- emit (*foundFolder)->syncEngine().addErrorToGui(SyncFileItem::SoftError, message, informativeText);
+ emit (*foundFolder)->syncEngine().addErrorToGui(SyncFileItem::SoftError, message, informativeText, OCC::ErrorCategory::GenericError);
}
}
_fileLog->start(path());
if (!reloadExcludes()) {
- slotSyncError(tr("Could not read system exclude file"));
+ slotSyncError(tr("Could not read system exclude file"), ErrorCategory::GenericError);
QMetaObject::invokeMethod(this, "slotSyncFinished", Qt::QueuedConnection, Q_ARG(bool, false));
return;
}
}
}
-void Folder::slotAddErrorToGui(SyncFileItem::Status status, const QString &errorMessage, const QString &subject)
+void Folder::slotAddErrorToGui(SyncFileItem::Status status, const QString &errorMessage, const QString &subject, ErrorCategory category)
{
- emit ProgressDispatcher::instance()->addErrorToGui(alias(), status, errorMessage, subject);
+ emit ProgressDispatcher::instance()->addErrorToGui(alias(), status, errorMessage, subject, category);
}
void Folder::slotSyncStarted()
}
// a item is completed: count the errors and forward to the ProgressDispatcher
-void Folder::slotItemCompleted(const SyncFileItemPtr &item)
+void Folder::slotItemCompleted(const SyncFileItemPtr &item, ErrorCategory errorCategory)
{
if (item->_instruction == CSYNC_INSTRUCTION_NONE || item->_instruction == CSYNC_INSTRUCTION_UPDATE_METADATA) {
// We only care about the updates that deserve to be shown in the UI
_syncResult.processCompletedItem(item);
_fileLog->logItem(*item);
- emit ProgressDispatcher::instance()->itemCompleted(alias(), item);
+ emit ProgressDispatcher::instance()->itemCompleted(alias(), item, errorCategory);
}
void Folder::slotNewBigFolderDiscovered(const QString &newF, bool isExternal)
/** Adds a error message that's not tied to a specific item.
*/
- void slotSyncError(const QString &message, OCC::ErrorCategory category = OCC::ErrorCategory::Normal);
+ void slotSyncError(const QString &message, OCC::ErrorCategory category);
- void slotAddErrorToGui(OCC::SyncFileItem::Status status, const QString &errorMessage, const QString &subject = {});
+ void slotAddErrorToGui(OCC::SyncFileItem::Status status, const QString &errorMessage, const QString &subject, OCC::ErrorCategory category);
void slotTransmissionProgress(const OCC::ProgressInfo &pi);
- void slotItemCompleted(const OCC::SyncFileItemPtr &);
+ void slotItemCompleted(const OCC::SyncFileItemPtr &, OCC::ErrorCategory errorCategory);
void slotRunEtagJob();
void etagRetrieved(const QByteArray &, const QDateTime &tp);
setHasSyncConflicts(conflictsFound);
}
-void ActivityListModel::addErrorToActivityList(const Activity &activity)
+void ActivityListModel::addErrorToActivityList(const Activity &activity, const ErrorType type)
{
- qCInfo(lcActivity) << "Error successfully added to the notification list: " << activity._message << activity._subject << activity._syncResultStatus << activity._syncFileItemStatus;
+ qCInfo(lcActivity) << "Error successfully added to the notification list: " << type << activity._message << activity._subject << activity._syncResultStatus << activity._syncFileItemStatus;
addEntriesToActivityList({activity});
_notificationErrorsLists.prepend(activity);
}
};
Q_ENUM(DataRole)
+ enum class ErrorType {
+ SyncError,
+ NetworkError,
+ };
+ Q_ENUM(ErrorType)
+
explicit ActivityListModel(QObject *parent = nullptr);
explicit ActivityListModel(AccountState *accountState,
void slotTriggerDismiss(const int activityIndex);
void addNotificationToActivityList(const OCC::Activity &activity);
- void addErrorToActivityList(const OCC::Activity &activity);
+ void addErrorToActivityList(const OCC::Activity &activity, const ErrorType type);
void addIgnoredFileToList(const OCC::Activity &newActivity);
void addSyncFileItemToActivityList(const OCC::Activity &activity);
void removeActivityFromActivityList(int row);
activity._links.append(link);
}
+ auto errorType = ActivityListModel::ErrorType::SyncError;
// add 'other errors' to activity list
- _activityModel->addErrorToActivityList(activity);
+ switch (category) {
+ case ErrorCategory::GenericError:
+ errorType = ActivityListModel::ErrorType::SyncError;
+ break;
+ case ErrorCategory::InsufficientRemoteStorage:
+ errorType = ActivityListModel::ErrorType::SyncError;
+ break;
+ case ErrorCategory::NetworkError:
+ errorType = ActivityListModel::ErrorType::NetworkError;
+ break;
+ case ErrorCategory::NoError:
+ break;
+ }
+
+ _activityModel->addErrorToActivityList(activity, errorType);
}
}
-void User::slotAddErrorToGui(const QString &folderAlias, SyncFileItem::Status status, const QString &errorMessage, const QString &subject)
+void User::slotAddErrorToGui(const QString &folderAlias, const SyncFileItem::Status status, const QString &errorMessage, const QString &subject, const ErrorCategory category)
{
const auto folderInstance = FolderMan::instance()->folder(folderAlias);
if (!folderInstance) {
activity._id = -static_cast<int>(qHash(activity._subject + activity._message));
// add 'other errors' to activity list
- _activityModel->addErrorToActivityList(activity);
+ auto errorType = ActivityListModel::ErrorType::SyncError;
+ switch (category)
+ {
+ case ErrorCategory::GenericError:
+ errorType = ActivityListModel::ErrorType::SyncError;
+ break;
+ case ErrorCategory::InsufficientRemoteStorage:
+ errorType = ActivityListModel::ErrorType::SyncError;
+ break;
+ case ErrorCategory::NetworkError:
+ errorType = ActivityListModel::ErrorType::NetworkError;
+ break;
+ case ErrorCategory::NoError:
+ errorType = {};
+ break;
+ }
+
+ _activityModel->addErrorToActivityList(activity, errorType);
showDesktopNotification(activity);
activity._links = {buttonActivityLink};
}
- _activityModel->addErrorToActivityList(activity);
+ _activityModel->addErrorToActivityList(activity, ActivityListModel::ErrorType::SyncError);
}
}
}
void slotItemCompleted(const QString &folder, const OCC::SyncFileItemPtr &item);
void slotProgressInfo(const QString &folder, const OCC::ProgressInfo &progress);
void slotAddError(const QString &folderAlias, const QString &message, OCC::ErrorCategory category);
- void slotAddErrorToGui(const QString &folderAlias, OCC::SyncFileItem::Status status, const QString &errorMessage, const QString &subject = {});
+ void slotAddErrorToGui(const QString &folderAlias, const OCC::SyncFileItem::Status status, const QString &errorMessage, const QString &subject, const ErrorCategory category);
void slotNotificationRequestFinished(int statusCode);
void slotNotifyNetworkError(QNetworkReply *reply);
void slotEndNotificationRequest(int replyCode);
// Check if the specific file can be accessed
if (propagator()->hasCaseClashAccessibilityProblem(fileToUpload._file)) {
- done(item, SyncFileItem::NormalError, tr("File %1 cannot be uploaded because another file with the same name, differing only in case, exists").arg(QDir::toNativeSeparators(item->_file)));
+ done(item, SyncFileItem::NormalError, tr("File %1 cannot be uploaded because another file with the same name, differing only in case, exists").arg(QDir::toNativeSeparators(item->_file)), ErrorCategory::GenericError);
return;
}
const auto renameSuccess = QFile::rename(originalFilePathAbsolute, newFilePathAbsolute);
if (!renameSuccess) {
- done(item, SyncFileItem::NormalError, "File contains trailing spaces and couldn't be renamed");
+ done(item, SyncFileItem::NormalError, "File contains trailing spaces and couldn't be renamed", ErrorCategory::GenericError);
return;
}
item->_modtime = FileSystem::getModTime(newFilePathAbsolute);
if (item->_modtime <= 0) {
_pendingChecksumFiles.remove(item->_file);
- slotOnErrorStartFolderUnlock(item, SyncFileItem::NormalError, tr("File %1 has invalid modified time. Do not upload to the server.").arg(QDir::toNativeSeparators(item->_file)));
+ slotOnErrorStartFolderUnlock(item, SyncFileItem::NormalError, tr("File %1 has invalid modified time. Do not upload to the server.").arg(QDir::toNativeSeparators(item->_file)), ErrorCategory::GenericError);
checkPropagationIsDone();
return;
}
if (!FileSystem::fileExists(fullFilePath)) {
_pendingChecksumFiles.remove(item->_file);
- slotOnErrorStartFolderUnlock(item, SyncFileItem::SoftError, tr("File Removed (start upload) %1").arg(fullFilePath));
+ slotOnErrorStartFolderUnlock(item, SyncFileItem::SoftError, tr("File Removed (start upload) %1").arg(fullFilePath), ErrorCategory::GenericError);
checkPropagationIsDone();
return;
}
item->_modtime = FileSystem::getModTime(originalFilePath);
if (item->_modtime <= 0) {
_pendingChecksumFiles.remove(item->_file);
- slotOnErrorStartFolderUnlock(item, SyncFileItem::NormalError, tr("File %1 has invalid modification time. Do not upload to the server.").arg(QDir::toNativeSeparators(item->_file)));
+ slotOnErrorStartFolderUnlock(item, SyncFileItem::NormalError, tr("File %1 has invalid modification time. Do not upload to the server.").arg(QDir::toNativeSeparators(item->_file)), ErrorCategory::GenericError);
checkPropagationIsDone();
return;
}
<< "prevModtime" << prevModtime
<< "Curr" << item->_modtime;
- slotOnErrorStartFolderUnlock(item, SyncFileItem::SoftError, tr("Local file changed during syncing. It will be resumed."));
+ slotOnErrorStartFolderUnlock(item, SyncFileItem::SoftError, tr("Local file changed during syncing. It will be resumed."), ErrorCategory::GenericError);
checkPropagationIsDone();
return;
}
if (fileIsStillChanging(*item)) {
propagator()->_anotherSyncNeeded = true;
_pendingChecksumFiles.remove(item->_file);
- slotOnErrorStartFolderUnlock(item, SyncFileItem::SoftError, tr("Local file changed during sync."));
+ slotOnErrorStartFolderUnlock(item, SyncFileItem::SoftError, tr("Local file changed during sync."), ErrorCategory::GenericError);
checkPropagationIsDone();
return;
}
}
void BulkPropagatorJob::slotOnErrorStartFolderUnlock(SyncFileItemPtr item,
- SyncFileItem::Status status,
- const QString &errorString)
+ const SyncFileItem::Status status,
+ const QString &errorString,
+ const ErrorCategory errorCategory)
{
- qCInfo(lcBulkPropagatorJob()) << status << errorString;
- done(item, status, errorString);
+ qCInfo(lcBulkPropagatorJob()) << status << errorString << errorCategory;
+ done(item, status, errorString, errorCategory);
}
void BulkPropagatorJob::slotPutFinishedOneFile(const BulkUploadItem &singleFile,
// Update the database entry
const auto result = propagator()->updateMetadata(*oneFile._item);
if (!result) {
- done(oneFile._item, SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()));
+ done(oneFile._item, SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()), ErrorCategory::GenericError);
return;
} else if (*result == Vfs::ConvertToPlaceholderResult::Locked) {
- done(oneFile._item, SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(oneFile._item->_file));
+ done(oneFile._item, SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(oneFile._item->_file), ErrorCategory::GenericError);
return;
}
finalizeOneFile(singleFile);
}
- done(singleFile._item, singleFile._item->_status, {});
+ done(singleFile._item, singleFile._item->_status, {}, ErrorCategory::GenericError);
singleFileIt = _filesToUpload.erase(singleFileIt);
}
}
void BulkPropagatorJob::done(SyncFileItemPtr item,
- SyncFileItem::Status status,
- const QString &errorString)
+ const SyncFileItem::Status status,
+ const QString &errorString,
+ const ErrorCategory category)
{
item->_status = status;
item->_errorString = errorString;
handleJobDoneErrors(item, status);
- emit propagator()->itemCompleted(item);
+ emit propagator()->itemCompleted(item, category);
}
QMap<QByteArray, QByteArray> BulkPropagatorJob::headers(SyncFileItemPtr item) const
const QString &error)
{
abort(AbortType::Synchronous);
- done(item, status, error);
+ done(item, status, error, ErrorCategory::GenericError);
}
void BulkPropagatorJob::checkResettingErrors(SyncFileItemPtr item) const
// invoked on internal error to unlock a folder and faile
void slotOnErrorStartFolderUnlock(OCC::SyncFileItemPtr item,
- OCC::SyncFileItem::Status status,
- const QString &errorString);
+ const OCC::SyncFileItem::Status status,
+ const QString &errorString,
+ const OCC::ErrorCategory errorCategory);
void slotPutFinished();
const QJsonObject &fullReplyObject);
void done(SyncFileItemPtr item,
- SyncFileItem::Status status,
- const QString &errorString);
+ const SyncFileItem::Status status,
+ const QString &errorString,
+ const ErrorCategory category);
/** Bases headers that need to be sent on the PUT, or in the MOVE for chunking-ng */
[[nodiscard]] QMap<QByteArray, QByteArray> headers(SyncFileItemPtr item) const;
#include "common/syncjournaldb.h"
#include "filesystem.h"
#include "syncfileitem.h"
+#include "progressdispatcher.h"
#include <QDebug>
#include <algorithm>
#include <QEventLoop>
// Not locally, not on the server. The entry is stale!
qCInfo(lcDisco) << "Stale DB entry";
if (!_discoveryData->_statedb->deleteFileRecord(path._original, true)) {
- emit _discoveryData->fatalError(tr("Error while deleting file record %1 from the database").arg(path._original));
+ emit _discoveryData->fatalError(tr("Error while deleting file record %1 from the database").arg(path._original), ErrorCategory::GenericError);
qCWarning(lcDisco) << "Failed to delete a file record from the local DB" << path._original;
}
return;
if (isFolderPinStateOnlineOnly && folderPinState.isValid()) {
qCInfo(lcDisco) << "*folderPinState:" << *folderPinState;
}
- emit _discoveryData->addErrorToGui(SyncFileItem::SoftError, tr("Conflict when uploading a folder. It's going to get cleared!"), path._local);
+ emit _discoveryData->addErrorToGui(SyncFileItem::SoftError, tr("Conflict when uploading a folder. It's going to get cleared!"), path._local, ErrorCategory::GenericError);
} else {
qCInfo(lcDisco) << "Wiping virtual file without db entry for" << path._local;
- emit _discoveryData->addErrorToGui(SyncFileItem::SoftError, tr("Conflict when uploading a file. It's going to get removed!"), path._local);
+ emit _discoveryData->addErrorToGui(SyncFileItem::SoftError, tr("Conflict when uploading a file. It's going to get removed!"), path._local, ErrorCategory::GenericError);
}
item->_instruction = CSYNC_INSTRUCTION_REMOVE;
item->_direction = SyncFileItem::Down;
void ProcessDirectoryJob::dbError()
{
- emit _discoveryData->fatalError(tr("Error while reading the database"));
+ emit _discoveryData->fatalError(tr("Error while reading the database"), ErrorCategory::GenericError);
}
void ProcessDirectoryJob::addVirtualFileSuffix(QString &str) const
} else {
// 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));
+ .arg(_currentFolder._server, results.error().message), ErrorCategory::NetworkError);
}
}
});
if (_serverJob)
_serverJob->abort();
- emit _discoveryData->fatalError(msg);
+ emit _discoveryData->fatalError(msg, ErrorCategory::NetworkError);
});
connect(localJob, &DiscoverySingleLocalDirectoryJob::finishedNonFatalError, this, [this](const QString &msg) {
emit this->finished();
} else {
// Fatal for the root job since it has no SyncFileItem
- emit _discoveryData->fatalError(msg);
+ emit _discoveryData->fatalError(msg, ErrorCategory::GenericError);
}
});
#include "discoveryphase.h"
#include "discovery.h"
#include "helpers.h"
+#include "progressdispatcher.h"
#include "account.h"
#include "clientsideencryptionjobs.h"
qCWarning(lcDiscovery) << "(*it)->_type" << (*it)->_type;
qCWarning(lcDiscovery) << "(*it)->_isRestoration " << (*it)->_isRestoration;
Q_ASSERT(false);
- emit addErrorToGui(SyncFileItem::Status::FatalError, tr("Error while canceling deletion of a file"), originalPath);
- emit fatalError(tr("Error while canceling deletion of %1").arg(originalPath));
+ emit addErrorToGui(SyncFileItem::Status::FatalError, tr("Error while canceling deletion of a file"), originalPath, ErrorCategory::GenericError);
+ emit fatalError(tr("Error while canceling deletion of %1").arg(originalPath), ErrorCategory::GenericError);
}
(*it)->_instruction = CSYNC_INSTRUCTION_NONE;
result = true;
class SyncJournalDb;
class ProcessDirectoryJob;
+enum class ErrorCategory;
+
/**
* Represent all the meta-data about a file in the server
*/
QStringList _listExclusiveFiles;
signals:
- void fatalError(const QString &errorString);
+ void fatalError(const QString &errorString, const OCC::ErrorCategory errorCategory);
void itemDiscovered(const OCC::SyncFileItemPtr &item);
void finished();
*/
void silentlyExcluded(const QString &folderPath);
- void addErrorToGui(SyncFileItem::Status status, const QString &errorMessage, const QString &subject);
+ void addErrorToGui(const SyncFileItem::Status status, const QString &errorMessage, const QString &subject, const OCC::ErrorCategory category);
};
/// Implementation of DiscoveryPhase::adjustRenamedPath
}
}
-void PropagateItemJob::done(SyncFileItem::Status statusArg, const QString &errorString)
+void PropagateItemJob::done(const SyncFileItem::Status statusArg, const QString &errorString, const ErrorCategory category)
{
// Duplicate calls to done() are a logic error
ENFORCE(_state != Finished);
qCWarning(lcPropagator) << "Could not complete propagation of" << _item->destination() << "by" << this << "with status" << _item->_status << "and error:" << _item->_errorString;
else
qCInfo(lcPropagator) << "Completed propagation of" << _item->destination() << "by" << this << "with status" << _item->_status;
- emit propagator()->itemCompleted(_item);
+ emit propagator()->itemCompleted(_item, category);
emit finished(_item->_status);
if (_item->_status == SyncFileItem::FatalError) {
if (status == SyncFileItem::Success || status == SyncFileItem::Conflict
|| status == SyncFileItem::Restoration) {
- done(SyncFileItem::SoftError, msg);
+ done(SyncFileItem::SoftError, msg, ErrorCategory::GenericError);
} else {
- done(status, tr("A file or folder was removed from a read only share, but restoring failed: %1").arg(msg));
+ done(status, tr("A file or folder was removed from a read only share, but restoring failed: %1").arg(msg), ErrorCategory::GenericError);
}
}
item->_instruction = CSyncEnums::CSYNC_INSTRUCTION_ERROR;
item->_errorString = tr("Error with the metadata. Getting unexpected metadata format.");
item->_status = SyncFileItem::NormalError;
- emit itemCompleted(item);
+ emit itemCompleted(item, OCC::ErrorCategory::GenericError);
} else {
directoryPropagationJob->appendJob(new UpdateFileDropMetadataJob(this, item->_file));
item->_instruction = CSYNC_INSTRUCTION_NONE;
return qobject_cast<OwncloudPropagator *>(parent());
}
+ErrorCategory PropagatorJob::errorCategoryFromNetworkError(const QNetworkReply::NetworkError error)
+{
+ auto result = ErrorCategory::NoError;
+ switch (error)
+ {
+ case QNetworkReply::NoError:
+ result = ErrorCategory::NoError;
+ break;
+ case QNetworkReply::TemporaryNetworkFailureError:
+ case QNetworkReply::RemoteHostClosedError:
+ result = ErrorCategory::NetworkError;
+ break;
+ case QNetworkReply::ConnectionRefusedError:
+ case QNetworkReply::HostNotFoundError:
+ case QNetworkReply::TimeoutError:
+ case QNetworkReply::OperationCanceledError:
+ case QNetworkReply::SslHandshakeFailedError:
+ case QNetworkReply::NetworkSessionFailedError:
+ case QNetworkReply::BackgroundRequestNotAllowedError:
+ case QNetworkReply::TooManyRedirectsError:
+ case QNetworkReply::InsecureRedirectError:
+ case QNetworkReply::UnknownNetworkError:
+ case QNetworkReply::ProxyConnectionRefusedError:
+ case QNetworkReply::ProxyConnectionClosedError:
+ case QNetworkReply::ProxyNotFoundError:
+ case QNetworkReply::ProxyTimeoutError:
+ case QNetworkReply::ProxyAuthenticationRequiredError:
+ case QNetworkReply::UnknownProxyError:
+ case QNetworkReply::ContentAccessDenied:
+ case QNetworkReply::ContentOperationNotPermittedError:
+ case QNetworkReply::ContentNotFoundError:
+ case QNetworkReply::AuthenticationRequiredError:
+ case QNetworkReply::ContentReSendError:
+ case QNetworkReply::ContentConflictError:
+ case QNetworkReply::ContentGoneError:
+ case QNetworkReply::UnknownContentError:
+ case QNetworkReply::ProtocolUnknownError:
+ case QNetworkReply::ProtocolInvalidOperationError:
+ case QNetworkReply::ProtocolFailure:
+ case QNetworkReply::InternalServerError:
+ case QNetworkReply::OperationNotImplementedError:
+ case QNetworkReply::ServiceUnavailableError:
+ case QNetworkReply::UnknownServerError:
+ result = ErrorCategory::GenericError;
+ break;
+ }
+
+ return result;
+}
+
// ================================================================================
PropagatorJob::JobParallelism PropagatorCompositeJob::parallelism() const
auto *job = qobject_cast<PollJob *>(sender());
ASSERT(job);
if (job->_item->_status == SyncFileItem::FatalError) {
- emit aborted(job->_item->_errorString);
+ emit aborted(job->_item->_errorString, ErrorCategory::GenericError);
deleteLater();
return;
} else if (job->_item->_status != SyncFileItem::Success) {
qCWarning(lcCleanupPolls) << "database error";
job->_item->_status = SyncFileItem::FatalError;
job->_item->_errorString = tr("Error writing metadata to the database");
- emit aborted(job->_item->_errorString);
+ emit aborted(job->_item->_errorString, ErrorCategory::GenericError);
deleteLater();
return;
}
void PropagateIgnoreJob::start()
{
- SyncFileItem::Status status = _item->_status;
+ auto status = _item->_status;
if (status == SyncFileItem::NoStatus) {
if (_item->_instruction == CSYNC_INSTRUCTION_ERROR) {
status = SyncFileItem::NormalError;
_item->_file = conflictRecord.initialBasePath;
}
}
- done(status, _item->_errorString);
+ done(status, _item->_errorString, ErrorCategory::NoError);
}
}
#include <QPointer>
#include <QIODevice>
#include <QMutex>
+#include <QNetworkReply>
#include "csync.h"
#include "syncfileitem.h"
#include "bandwidthmanager.h"
#include "accountfwd.h"
#include "syncoptions.h"
+#include "progressdispatcher.h"
#include <deque>
protected:
[[nodiscard]] OwncloudPropagator *propagator() const;
+ static ErrorCategory errorCategoryFromNetworkError(const QNetworkReply::NetworkError error);
+
/** If this job gets added to a composite job, this will point to the parent.
*
* For the PropagateDirectory::_firstJob it will point to
{
Q_OBJECT
protected:
- virtual void done(SyncFileItem::Status status, const QString &errorString = QString());
+ virtual void done(const SyncFileItem::Status status, const QString &errorString, const ErrorCategory category);
/*
* set a custom restore job message that is used if the restore job succeeded.
signals:
void newItem(const OCC::SyncFileItemPtr &);
- void itemCompleted(const OCC::SyncFileItemPtr &);
+ void itemCompleted(const SyncFileItemPtr &item, OCC::ErrorCategory category);
void progress(const OCC::SyncFileItem &, qint64 bytes);
void finished(bool success);
void start();
signals:
void finished();
- void aborted(const QString &error);
+ void aborted(const QString &error, const ErrorCategory errorCategory);
private slots:
void slotPollFinished();
};
* in IssuesWidget.
*/
enum class ErrorCategory {
- Normal,
+ NoError,
+ GenericError,
+ NetworkError,
InsufficientRemoteStorage,
};
Q_ENUM_NS(OCC::ErrorCategory)
/**
* @brief: the item was completed by a job
*/
- void itemCompleted(const QString &folder, const OCC::SyncFileItemPtr &item);
+ void itemCompleted(const QString &folder, const OCC::SyncFileItemPtr &item, const OCC::ErrorCategory category);
/**
* @brief A new folder-wide sync error was seen.
* @param[out] full error message
* @param[out] subject (optional)
*/
- void addErrorToGui(const QString &folder, OCC::SyncFileItem::Status status, const QString &errorMessage, const QString &subject);
+ void addErrorToGui(const QString &folder, const OCC::SyncFileItem::Status status, const QString &errorMessage, const QString &subject, const OCC::ErrorCategory category);
/**
* @brief Emitted for a folder when a sync is done, listing all pending conflicts
SyncJournalFileRecord parentRec;
if (!propagator()->_journal->getFileRecord(parentPath, &parentRec)) {
qCWarning(lcPropagateDownload) << "could not get file from local DB" << parentPath;
- done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(parentPath));
+ done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(parentPath), ErrorCategory::GenericError);
return;
}
});
connect(_downloadEncryptedHelper, &PropagateDownloadEncrypted::failed, [this] {
done(SyncFileItem::NormalError,
- tr("File %1 cannot be downloaded because encryption information is missing.").arg(QDir::toNativeSeparators(_item->_file)));
+ tr("File %1 cannot be downloaded because encryption information is missing.").arg(QDir::toNativeSeparators(_item->_file)), ErrorCategory::GenericError);
});
_downloadEncryptedHelper->start();
}
QString fsPath = propagator()->fullLocalPath(_item->_file);
if (!FileSystem::verifyFileUnchanged(fsPath, _item->_previousSize, _item->_previousModtime)) {
propagator()->_anotherSyncNeeded = true;
- done(SyncFileItem::SoftError, tr("File has changed since discovery"));
+ done(SyncFileItem::SoftError, tr("File has changed since discovery"), ErrorCategory::GenericError);
return;
}
qCDebug(lcPropagateDownload) << "dehydrating file" << _item->_file;
auto r = vfs->dehydratePlaceholder(*_item);
if (!r) {
- done(SyncFileItem::NormalError, r.error());
+ done(SyncFileItem::NormalError, r.error(), ErrorCategory::GenericError);
return;
}
if (!propagator()->_journal->deleteFileRecord(_item->_originalFile)) {
qCWarning(lcPropagateDownload) << "could not delete file from local DB" << _item->_originalFile;
- done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(_item->_originalFile));
+ done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(_item->_originalFile), ErrorCategory::GenericError);
return;
}
qCDebug(lcPropagateDownload) << "creating virtual file" << _item->_file;
// do a klaas' case clash check.
if (propagator()->localFileNameClash(_item->_file)) {
- done(SyncFileItem::FileNameClash, tr("File %1 can not be downloaded because of a local file name clash!").arg(QDir::toNativeSeparators(_item->_file)));
+ done(SyncFileItem::FileNameClash, tr("File %1 can not be downloaded because of a local file name clash!").arg(QDir::toNativeSeparators(_item->_file)), ErrorCategory::GenericError);
return;
}
auto r = vfs->createPlaceholder(*_item);
if (!r) {
- done(SyncFileItem::NormalError, r.error());
+ done(SyncFileItem::NormalError, r.error(), ErrorCategory::GenericError);
return;
}
updateMetadata(false);
FileSystem::setFileReadOnly(_tmpFile.fileName(), false);
if (!_tmpFile.open(QIODevice::Append | QIODevice::Unbuffered)) {
qCWarning(lcPropagateDownload) << "could not open temporary file" << _tmpFile.fileName();
- done(SyncFileItem::NormalError, _tmpFile.errorString());
+ done(SyncFileItem::NormalError, _tmpFile.errorString(), ErrorCategory::GenericError);
return;
}
// Hide temporary after creation
// tab: instead we'll generate a general "disk space low" message and show
// these detail errors only in the error view.
done(SyncFileItem::DetailError,
- tr("The download would reduce free local disk space below the limit"));
+ tr("The download would reduce free local disk space below the limit"), ErrorCategory::GenericError);
emit propagator()->insufficientLocalStorage();
} else if (diskSpaceResult == OwncloudPropagator::DiskSpaceCritical) {
done(SyncFileItem::FatalError,
- tr("Free space on disk is less than %1").arg(Utility::octetsToString(criticalFreeSpaceLimit())));
+ tr("Free space on disk is less than %1").arg(Utility::octetsToString(criticalFreeSpaceLimit())), ErrorCategory::GenericError);
}
// Remove the temporary, if empty.
&propagator()->_anotherSyncNeeded, errorBody);
}
- done(status, errorString);
+ done(status, errorString, errorCategoryFromNetworkError(err));
return;
}
// This happened when trying to resume a file. The Content-Range header was files, Content-Length was == 0
qCDebug(lcPropagateDownload) << bodySize << _item->_size << _tmpFile.size() << job->resumeStart();
FileSystem::remove(_tmpFile.fileName());
- done(SyncFileItem::SoftError, QLatin1String("Broken webserver returning empty content length for non-empty file on resume"));
+ done(SyncFileItem::SoftError, QLatin1String("Broken webserver returning empty content length for non-empty file on resume"), ErrorCategory::GenericError);
return;
}
if (bodySize > 0 && bodySize != _tmpFile.size() - job->resumeStart()) {
qCDebug(lcPropagateDownload) << bodySize << _tmpFile.size() << job->resumeStart();
propagator()->_anotherSyncNeeded = true;
- done(SyncFileItem::SoftError, tr("The file could not be downloaded completely."));
+ done(SyncFileItem::SoftError, tr("The file could not be downloaded completely."), ErrorCategory::GenericError);
return;
}
FileSystem::remove(_tmpFile.fileName());
done(SyncFileItem::NormalError,
tr("The downloaded file is empty, but the server said it should have been %1.")
- .arg(Utility::octetsToString(_item->_size)));
+ .arg(Utility::octetsToString(_item->_size)), ErrorCategory::GenericError);
return;
}
{
FileSystem::remove(_tmpFile.fileName());
propagator()->_anotherSyncNeeded = true;
- done(SyncFileItem::SoftError, errMsg); // tr("The file downloaded with a broken checksum, will be redownloaded."));
+ done(SyncFileItem::SoftError, errMsg, ErrorCategory::GenericError); // tr("The file downloaded with a broken checksum, will be redownloaded."));
}
void PropagateDownloadFile::deleteExistingFolder()
QString error;
if (!propagator()->createConflict(_item, _associatedComposite, &error)) {
- done(SyncFileItem::NormalError, error);
+ done(SyncFileItem::NormalError, error, ErrorCategory::GenericError);
}
}
if (_downloadEncryptedHelper->decryptFile(_tmpFile)) {
downloadFinished();
} else {
- done(SyncFileItem::NormalError, _downloadEncryptedHelper->errorString());
+ done(SyncFileItem::NormalError, _downloadEncryptedHelper->errorString(), ErrorCategory::GenericError);
}
} else {
downloadFinished();
if (_item->_modtime <= 0) {
FileSystem::remove(_tmpFile.fileName());
- done(SyncFileItem::NormalError, tr("File %1 has invalid modified time reported by server. Do not save it.").arg(QDir::toNativeSeparators(_item->_file)));
+ done(SyncFileItem::NormalError, tr("File %1 has invalid modified time reported by server. Do not save it.").arg(QDir::toNativeSeparators(_item->_file)), ErrorCategory::GenericError);
return;
}
Q_ASSERT(_item->_modtime > 0);
_item->_modtime = FileSystem::getModTime(_tmpFile.fileName());
if (_item->_modtime <= 0) {
FileSystem::remove(_tmpFile.fileName());
- done(SyncFileItem::NormalError, tr("File %1 has invalid modified time reported by server. Do not save it.").arg(QDir::toNativeSeparators(_item->_file)));
+ done(SyncFileItem::NormalError, tr("File %1 has invalid modified time reported by server. Do not save it.").arg(QDir::toNativeSeparators(_item->_file)), ErrorCategory::GenericError);
return;
}
Q_ASSERT(_item->_modtime > 0);
// Make the file a hydrated placeholder if possible
const auto result = propagator()->syncOptions()._vfs->convertToPlaceholder(_tmpFile.fileName(), *_item, filename);
if (!result) {
- done(SyncFileItem::NormalError, result.error());
+ done(SyncFileItem::NormalError, result.error(), ErrorCategory::GenericError);
return;
}
}
qCInfo(lcPropagateDownload) << "downloading case clashed file" << _item->_file;
const auto caseClashConflictResult = propagator()->createCaseClashConflict(_item, _tmpFile.fileName());
if (caseClashConflictResult) {
- done(SyncFileItem::SoftError, *caseClashConflictResult);
+ done(SyncFileItem::SoftError, *caseClashConflictResult, ErrorCategory::GenericError);
} else {
- done(SyncFileItem::FileNameClash, tr("File %1 downloaded but it resulted in a local file name clash!").arg(QDir::toNativeSeparators(_item->_file)));
+ done(SyncFileItem::FileNameClash, tr("File %1 downloaded but it resulted in a local file name clash!").arg(QDir::toNativeSeparators(_item->_file)), ErrorCategory::GenericError);
}
return;
} else {
QString error;
if (!propagator()->createConflict(_item, _associatedComposite, &error)) {
- done(SyncFileItem::SoftError, error);
+ done(SyncFileItem::SoftError, error, ErrorCategory::GenericError);
} else {
previousFileExists = false;
}
const time_t expectedMtime = _item->_previousModtime;
if (!FileSystem::verifyFileUnchanged(filename, expectedSize, expectedMtime)) {
propagator()->_anotherSyncNeeded = true;
- done(SyncFileItem::SoftError, tr("File has changed since discovery"));
+ done(SyncFileItem::SoftError, tr("File has changed since discovery"), ErrorCategory::GenericError);
return;
}
}
propagator()->_anotherSyncNeeded = true;
}
- done(SyncFileItem::SoftError, error);
+ done(SyncFileItem::SoftError, error, ErrorCategory::GenericError);
return;
}
if (!propagator()->_journal->deleteFileRecord(virtualFile)) {
qCWarning(lcPropagateDownload) << "could not delete file from local DB" << virtualFile;
- done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(virtualFile));
+ done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(virtualFile), ErrorCategory::GenericError);
return;
}
const QString fn = propagator()->fullLocalPath(_item->_file);
const auto result = propagator()->updateMetadata(*_item);
if (!result) {
- done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()));
+ done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()), ErrorCategory::GenericError);
return;
} else if (*result == Vfs::ConvertToPlaceholderResult::Locked) {
- done(SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(_item->_file));
+ done(SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(_item->_file), ErrorCategory::GenericError);
return;
}
propagator()->_journal->commit("download file start2");
- done(isConflict ? SyncFileItem::Conflict : SyncFileItem::Success);
+ done(isConflict ? SyncFileItem::Conflict : SyncFileItem::Success, {}, ErrorCategory::NoError);
// handle the special recall file
if (!_item->_remotePerm.hasPermission(RemotePermissions::IsShared)
if (_deleteEncryptedHelper->networkError() != QNetworkReply::NoError && _deleteEncryptedHelper->networkError() != QNetworkReply::ContentNotFoundError) {
status = classifyError(_deleteEncryptedHelper->networkError(), _item->_httpErrorCode, &propagator()->_anotherSyncNeeded);
}
- done(status, _deleteEncryptedHelper->errorString());
+ done(status, _deleteEncryptedHelper->errorString(), ErrorCategory::GenericError);
} else {
- done(SyncFileItem::Success);
+ done(SyncFileItem::Success, {}, ErrorCategory::NoError);
}
});
_deleteEncryptedHelper->start();
if (err != QNetworkReply::NoError && err != QNetworkReply::ContentNotFoundError) {
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
&propagator()->_anotherSyncNeeded);
- done(status, _job->errorString());
+
+ done(status, _job->errorString(), errorCategoryFromNetworkError(err));
return;
}
done(SyncFileItem::NormalError,
tr("Wrong HTTP code returned by server. Expected 204, but received \"%1 %2\".")
.arg(_item->_httpErrorCode)
- .arg(_job->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString()));
+ .arg(_job->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString()), ErrorCategory::GenericError);
return;
}
if (!propagator()->_journal->deleteFileRecord(_item->_originalFile, _item->isDirectory())) {
qCWarning(lcPropagateRemoteDelete) << "could not delete file from local DB" << _item->_originalFile;
- done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(_item->_originalFile));
+ done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(_item->_originalFile), ErrorCategory::GenericError);
return;
}
propagator()->_journal->commit("Remote Remove");
- done(SyncFileItem::Success);
+ done(SyncFileItem::Success, {}, ErrorCategory::NoError);
}
}
} else if (err != QNetworkReply::NoError) {
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
&propagator()->_anotherSyncNeeded);
- done(status, _item->_errorString);
+ done(status, _item->_errorString, errorCategoryFromNetworkError(err));
return;
} else if (_item->_httpErrorCode != 201) {
// Normally we expect "201 Created"
done(SyncFileItem::NormalError,
tr("Wrong HTTP code returned by server. Expected 201, but received \"%1 %2\".")
.arg(_item->_httpErrorCode)
- .arg(jobHttpReasonPhraseString));
+ .arg(jobHttpReasonPhraseString), ErrorCategory::GenericError);
return;
}
job->start();
}
});
- connect(propfindJob, &PropfindJob::finishedWithError, this, [this]{
- // ignore the PROPFIND error
+ connect(propfindJob, &PropfindJob::finishedWithError, this, [this] (QNetworkReply *reply) {
+ const auto err = reply ? reply->error() : QNetworkReply::NetworkError::UnknownNetworkError;
propagator()->_activeJobList.removeOne(this);
- done(SyncFileItem::NormalError);
+ done(SyncFileItem::NormalError, {}, errorCategoryFromNetworkError(err));
});
propfindJob->start();
}
const auto targetFile = propagator()->fullLocalPath(_item->_renameTarget);
QString renameError;
if (!FileSystem::rename(existingFile, targetFile, &renameError)) {
- done(SyncFileItem::NormalError, renameError);
+ done(SyncFileItem::NormalError, renameError, ErrorCategory::GenericError);
return;
}
emit propagator()->touchedFile(existingFile);
SyncJournalFileRecord parentRec;
bool ok = propagator()->_journal->getFileRecord(parentPath, &parentRec);
if (!ok) {
- done(SyncFileItem::NormalError);
+ done(SyncFileItem::NormalError, {}, ErrorCategory::GenericError);
return;
}
// save the file id already so we can detect rename or remove
const auto result = propagator()->updateMetadata(itemCopy);
if (!result) {
- done(SyncFileItem::FatalError, tr("Error writing metadata to the database: %1").arg(result.error()));
+ done(SyncFileItem::FatalError, tr("Error writing metadata to the database: %1").arg(result.error()), ErrorCategory::GenericError);
return;
} else if (*result == Vfs::ConvertToPlaceholderResult::Locked) {
- done(SyncFileItem::FatalError, tr("The file %1 is currently in use").arg(_item->_file));
+ done(SyncFileItem::FatalError, tr("The file %1 is currently in use").arg(_item->_file), ErrorCategory::GenericError);
return;
}
- done(SyncFileItem::Success);
+ done(SyncFileItem::Success, {}, ErrorCategory::NoError);
}
}
SyncJournalFileRecord parentRec;
bool ok = propagator()->_journal->getFileRecord(parentPath, &parentRec);
if (!ok) {
- done(SyncFileItem::NormalError);
+ done(SyncFileItem::NormalError, {}, ErrorCategory::GenericError);
return;
}
QString error;
if (!FileSystem::uncheckedRenameReplace(localTargetAlt, localTarget, &error)) {
done(SyncFileItem::NormalError, tr("Could not rename %1 to %2, error: %3")
- .arg(folderTargetAlt, folderTarget, error));
+ .arg(folderTargetAlt, folderTarget, error), ErrorCategory::GenericError);
return;
}
qCInfo(lcPropagateRemoteMove) << "Suffix vfs required local rename of"
<< "Could not MOVE file" << filePathOriginal << " to" << filePath
<< " with error:" << _job->errorString() << " and successfully restored it.";
}
- done(status, _job->errorString());
+ done(status, _job->errorString(), ErrorCategory::GenericError);
return;
}
done(SyncFileItem::NormalError,
tr("Wrong HTTP code returned by server. Expected 201, but received \"%1 %2\".")
.arg(_item->_httpErrorCode)
- .arg(_job->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString()));
+ .arg(_job->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString()), ErrorCategory::GenericError);
return;
}
SyncJournalFileRecord oldRecord;
if (!propagator()->_journal->getFileRecord(_item->_originalFile, &oldRecord)) {
qCWarning(lcPropagateRemoteMove) << "could not get file from local DB" << _item->_originalFile;
- done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(_item->_originalFile));
+ done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(_item->_originalFile), ErrorCategory::GenericError);
return;
}
auto &vfs = propagator()->syncOptions()._vfs;
// Delete old db data.
if (!propagator()->_journal->deleteFileRecord(_item->_originalFile)) {
qCWarning(lcPropagateRemoteMove) << "could not delete file from local DB" << _item->_originalFile;
- done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(_item->_originalFile));
+ done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(_item->_originalFile), ErrorCategory::GenericError);
return;
}
if (!vfs->setPinState(_item->_originalFile, PinState::Inherited)) {
if (!QFileInfo::exists(targetFile)) {
propagator()->_journal->commit("Remote Rename");
- done(SyncFileItem::Success);
+ done(SyncFileItem::Success, {}, ErrorCategory::NoError);
return;
}
const auto result = propagator()->updateMetadata(newItem);
if (!result) {
- done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()));
+ done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()), ErrorCategory::GenericError);
return;
} else if (*result == Vfs::ConvertToPlaceholderResult::Locked) {
- done(SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(newItem._file));
+ done(SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(newItem._file), ErrorCategory::GenericError);
return;
}
if (pinState && *pinState != PinState::Inherited
&& !vfs->setPinState(newItem._renameTarget, *pinState)) {
- done(SyncFileItem::NormalError, tr("Error setting pin state"));
+ done(SyncFileItem::NormalError, tr("Error setting pin state"), ErrorCategory::GenericError);
return;
}
if (_item->isDirectory()) {
propagator()->_renamedDirectories.insert(_item->_file, _item->_renameTarget);
if (!adjustSelectiveSync(propagator()->_journal, _item->_file, _item->_renameTarget)) {
- done(SyncFileItem::FatalError, tr("Error writing metadata to the database"));
+ done(SyncFileItem::FatalError, tr("Error writing metadata to the database"), ErrorCategory::GenericError);
return;
}
}
propagator()->_journal->commit("Remote Rename");
- done(SyncFileItem::Success);
+ done(SyncFileItem::Success, {}, ErrorCategory::NoError);
}
bool PropagateRemoteMove::adjustSelectiveSync(SyncJournalDb *journal, const QString &from_, const QString &to_)
finalize();
}
-void PropagateUploadFileCommon::done(SyncFileItem::Status status, const QString &errorString)
+void PropagateUploadFileCommon::done(SyncFileItem::Status status, const QString &errorString, const ErrorCategory category)
{
_finished = true;
- PropagateItemJob::done(status, errorString);
+ PropagateItemJob::done(status, errorString, category);
}
void PropagateUploadFileCommon::checkResettingErrors()
void slotPollFinished();
protected:
- void done(SyncFileItem::Status status, const QString &errorString = QString()) override;
+ void done(SyncFileItem::Status status, const QString &errorString = QString(), const ErrorCategory category = ErrorCategory::NoError) override;
/**
* Aborts all running network jobs, except for the ones that mayAbortJob
qCInfo(lcPropagateLocalRemove) << "Going to delete:" << filename;
if (propagator()->localFileNameClash(_item->_file)) {
- done(SyncFileItem::FileNameClash, tr("Could not remove %1 because of a local file name clash").arg(QDir::toNativeSeparators(filename)));
+ done(SyncFileItem::FileNameClash, tr("Could not remove %1 because of a local file name clash").arg(QDir::toNativeSeparators(filename)), ErrorCategory::GenericError);
return;
}
if (_moveToTrash) {
if ((QDir(filename).exists() || FileSystem::fileExists(filename))
&& !FileSystem::moveToTrash(filename, &removeError)) {
- done(SyncFileItem::NormalError, removeError);
+ done(SyncFileItem::NormalError, removeError, ErrorCategory::GenericError);
return;
}
} else {
if (_item->isDirectory()) {
if (QDir(filename).exists() && !removeRecursively(QString())) {
- done(SyncFileItem::NormalError, _error);
+ done(SyncFileItem::NormalError, _error, ErrorCategory::GenericError);
return;
}
} else {
if (FileSystem::fileExists(filename)
&& !FileSystem::remove(filename, &removeError)) {
- done(SyncFileItem::NormalError, removeError);
+ done(SyncFileItem::NormalError, removeError, ErrorCategory::GenericError);
return;
}
}
propagator()->reportProgress(*_item, 0);
if (!propagator()->_journal->deleteFileRecord(_item->_originalFile, _item->isDirectory())) {
qCWarning(lcPropagateLocalRename) << "could not delete file from local DB" << _item->_originalFile;
- done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(_item->_originalFile));
+ done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(_item->_originalFile), ErrorCategory::GenericError);
return;
}
propagator()->_journal->commit("Local remove");
- done(SyncFileItem::Success);
+ done(SyncFileItem::Success, {}, ErrorCategory::NoError);
}
void PropagateLocalMkdir::start()
if (!FileSystem::remove(newDirStr, &removeError)) {
done(SyncFileItem::NormalError,
tr("could not delete file %1, error: %2")
- .arg(newDirStr, removeError));
+ .arg(newDirStr, removeError), ErrorCategory::GenericError);
return;
}
} else if (_item->_instruction == CSYNC_INSTRUCTION_CONFLICT) {
QString error;
if (!propagator()->createConflict(_item, _associatedComposite, &error)) {
- done(SyncFileItem::SoftError, error);
+ done(SyncFileItem::SoftError, error, ErrorCategory::GenericError);
return;
}
}
if (Utility::fsCasePreserving() && propagator()->localFileNameClash(_item->_file)) {
qCWarning(lcPropagateLocalMkdir) << "New folder to create locally already exists with different case:" << _item->_file;
- done(SyncFileItem::FileNameClash, tr("Folder %1 cannot be created because of a local file or folder name clash!").arg(newDirStr));
+ done(SyncFileItem::FileNameClash, tr("Folder %1 cannot be created because of a local file or folder name clash!").arg(newDirStr), ErrorCategory::GenericError);
return;
}
emit propagator()->touchedFile(newDirStr);
QDir localDir(propagator()->localPath());
if (!localDir.mkpath(_item->_file)) {
- done(SyncFileItem::NormalError, tr("Could not create folder %1").arg(newDirStr));
+ done(SyncFileItem::NormalError, tr("Could not create folder %1").arg(newDirStr), ErrorCategory::GenericError);
return;
}
newItem._etag = "_invalid_";
const auto result = propagator()->updateMetadata(newItem);
if (!result) {
- done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()));
+ done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()), ErrorCategory::GenericError);
return;
} else if (*result == Vfs::ConvertToPlaceholderResult::Locked) {
- done(SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(newItem._file));
+ done(SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(newItem._file), ErrorCategory::GenericError);
return;
}
propagator()->_journal->commit("localMkdir");
auto resultStatus = _item->_instruction == CSYNC_INSTRUCTION_CONFLICT
? SyncFileItem::Conflict
: SyncFileItem::Success;
- done(resultStatus);
+ done(resultStatus, {}, ErrorCategory::NoError);
}
PropagateLocalRename::PropagateLocalRename(OwncloudPropagator *propagator, const SyncFileItemPtr &item)
qCInfo(lcPropagateLocalRename) << "renaming a case clashed file" << _item->_file << _item->_renameTarget;
const auto caseClashConflictResult = propagator()->createCaseClashConflict(_item, existingFile);
if (caseClashConflictResult) {
- done(SyncFileItem::SoftError, *caseClashConflictResult);
+ done(SyncFileItem::SoftError, *caseClashConflictResult, ErrorCategory::GenericError);
} else {
- done(SyncFileItem::FileNameClash, tr("File %1 downloaded but it resulted in a local file name clash!").arg(QDir::toNativeSeparators(_item->_file)));
+ done(SyncFileItem::FileNameClash, tr("File %1 downloaded but it resulted in a local file name clash!").arg(QDir::toNativeSeparators(_item->_file)), ErrorCategory::GenericError);
}
return;
}
emit propagator()->touchedFile(existingFile);
emit propagator()->touchedFile(targetFile);
if (QString renameError; !FileSystem::rename(existingFile, targetFile, &renameError)) {
- done(SyncFileItem::NormalError, renameError);
+ done(SyncFileItem::NormalError, renameError, ErrorCategory::GenericError);
return;
}
}
SyncJournalFileRecord oldRecord;
if (!propagator()->_journal->getFileRecord(fileAlreadyMoved ? previousNameInDb : _item->_originalFile, &oldRecord)) {
qCWarning(lcPropagateLocalRename) << "could not get file from local DB" << _item->_originalFile;
- done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(_item->_originalFile));
+ done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(_item->_originalFile), ErrorCategory::GenericError);
return;
}
if (fileAlreadyMoved && !deleteOldDbRecord(previousNameInDb)) {
return;
} else if (!deleteOldDbRecord(_item->_originalFile)) {
+ qCWarning(lcPropagateLocalRename) << "could not delete file from local DB" << _item->_originalFile;
return;
}
if (!vfs->setPinState(_item->_renameTarget, pinState)) {
qCWarning(lcPropagateLocalRename) << "Could not set pin state of" << _item->_renameTarget << "to old value" << pinState;
- done(SyncFileItem::NormalError, tr("Error setting pin state"));
+ done(SyncFileItem::NormalError, tr("Error setting pin state"), ErrorCategory::GenericError);
return;
}
}
const auto result = propagator()->updateMetadata(newItem);
if (!result) {
- done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()));
+ done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()), ErrorCategory::GenericError);
return;
} else if (*result == Vfs::ConvertToPlaceholderResult::Locked) {
- done(SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(newItem._file));
+ done(SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(newItem._file), ErrorCategory::GenericError);
return;
}
} else {
SyncJournalFileRecord oldRecord;
if (!propagator()->_journal->getFileRecord(oldFileName, &oldRecord)) {
qCWarning(lcPropagateLocalRename) << "could not get file from local DB" << oldFileName;
- done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(oldFileNameString));
+ done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(oldFileNameString), OCC::ErrorCategory::GenericError);
return;
}
if (!propagator()->_journal->deleteFileRecord(oldFileName)) {
qCWarning(lcPropagateLocalRename) << "could not delete file from local DB" << oldFileName;
- done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(oldFileNameString));
+ done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(oldFileNameString), OCC::ErrorCategory::GenericError);
return;
}
newItem->_file = newFileNameString;
const auto result = propagator()->updateMetadata(*newItem);
if (!result) {
- done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()));
+ done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()), OCC::ErrorCategory::GenericError);
return;
}
});
if (!dbQueryResult) {
- done(SyncFileItem::FatalError, tr("Failed to propagate directory rename in hierarchy"));
+ done(SyncFileItem::FatalError, tr("Failed to propagate directory rename in hierarchy"), OCC::ErrorCategory::GenericError);
return;
}
propagator()->_renamedDirectories.insert(oldFile, _item->_renameTarget);
if (!PropagateRemoteMove::adjustSelectiveSync(propagator()->_journal, oldFile, _item->_renameTarget)) {
- done(SyncFileItem::FatalError, tr("Failed to rename file"));
+ done(SyncFileItem::FatalError, tr("Failed to rename file"), ErrorCategory::GenericError);
return;
}
}
+ if (pinState != PinState::Inherited && !vfs->setPinState(_item->_renameTarget, pinState)) {
+ done(SyncFileItem::NormalError, tr("Error setting pin state"), ErrorCategory::GenericError);
+ return;
+ }
propagator()->_journal->commit("localRename");
- done(SyncFileItem::Success);
+ done(SyncFileItem::Success, {}, ErrorCategory::NoError);
}
bool PropagateLocalRename::deleteOldDbRecord(const QString &fileName)
{
if (SyncJournalFileRecord oldRecord; !propagator()->_journal->getFileRecord(fileName, &oldRecord)) {
qCWarning(lcPropagateLocalRename) << "could not get file from local DB" << fileName;
- done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(fileName));
+ done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(fileName), OCC::ErrorCategory::GenericError);
return false;
}
if (!propagator()->_journal->deleteFileRecord(fileName)) {
qCWarning(lcPropagateLocalRename) << "could not delete file from local DB" << fileName;
- done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(fileName));
+ done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(fileName), OCC::ErrorCategory::GenericError);
return false;
}
item->_status = SyncFileItem::Status::NormalError;
item->_instruction = CSYNC_INSTRUCTION_ERROR;
item->_errorString = tr("Could not update file: %1").arg(result.error());
- emit itemCompleted(item);
+ emit itemCompleted(item, ErrorCategory::GenericError);
return;
}
}
item->_status = SyncFileItem::Status::NormalError;
item->_instruction = CSYNC_INSTRUCTION_ERROR;
item->_errorString = tr("Could not update virtual file metadata: %1").arg(r.error());
- emit itemCompleted(item);
+ emit itemCompleted(item, ErrorCategory::GenericError);
return;
}
} else {
if (!FileSystem::setModTime(filePath, item->_modtime)) {
item->_instruction = CSYNC_INSTRUCTION_ERROR;
item->_errorString = tr("Could not update file metadata: %1").arg(filePath);
- emit itemCompleted(item);
+ emit itemCompleted(item, ErrorCategory::GenericError);
return;
}
}
}
// This might have changed the shared flag, so we must notify SyncFileStatusTracker for example
- emit itemCompleted(item);
+ emit itemCompleted(item, ErrorCategory::NoError);
} else {
// Update only outdated data from the disk.
if (!QDir(_localPath).exists()) {
_anotherSyncNeeded = DelayedFollowUp;
// No _tr, it should only occur in non-mirall
- Q_EMIT syncError(QStringLiteral("Unable to find local sync folder."));
+ Q_EMIT syncError(QStringLiteral("Unable to find local sync folder."), ErrorCategory::GenericError);
finalize(false);
return;
}
"Placeholders are postfixed with file sizes using Utility::octetsToString()")
.arg(
Utility::octetsToString(freeBytes),
- Utility::octetsToString(minFree)));
+ Utility::octetsToString(minFree)), ErrorCategory::GenericError);
finalize(false);
return;
} else {
// This creates the DB if it does not exist yet.
if (!_journal->open()) {
qCWarning(lcEngine) << "No way to create a sync journal!";
- Q_EMIT syncError(tr("Unable to open or create the local sync database. Make sure you have write access in the sync folder."));
+ Q_EMIT syncError(tr("Unable to open or create the local sync database. Make sure you have write access in the sync folder."), ErrorCategory::GenericError);
finalize(false);
return;
// database creation error!
_lastLocalDiscoveryStyle = _localDiscoveryStyle;
if (_syncOptions._vfs->mode() == Vfs::WithSuffix && _syncOptions._vfs->fileSuffix().isEmpty()) {
- Q_EMIT syncError(tr("Using virtual files with suffix, but suffix is not set"));
+ Q_EMIT syncError(tr("Using virtual files with suffix, but suffix is not set"), ErrorCategory::GenericError);
finalize(false);
return;
}
qCInfo(lcEngine) << (usingSelectiveSync ? "Using Selective Sync" : "NOT Using Selective Sync");
} else {
qCWarning(lcEngine) << "Could not retrieve selective sync list from DB";
- Q_EMIT syncError(tr("Unable to read the blacklist from the local database"));
+ Q_EMIT syncError(tr("Unable to read the blacklist from the local database"), ErrorCategory::GenericError);
finalize(false);
return;
}
_discoveryPhase->setSelectiveSyncWhiteList(_journal->getSelectiveSyncList(SyncJournalDb::SelectiveSyncWhiteList, &ok));
if (!ok) {
qCWarning(lcEngine) << "Unable to read selective sync list, aborting.";
- Q_EMIT syncError(tr("Unable to read from the sync journal."));
+ Q_EMIT syncError(tr("Unable to read from the sync journal."), ErrorCategory::GenericError);
finalize(false);
return;
}
connect(_discoveryPhase.data(), &DiscoveryPhase::itemDiscovered, this, &SyncEngine::slotItemDiscovered);
connect(_discoveryPhase.data(), &DiscoveryPhase::newBigFolder, this, &SyncEngine::newBigFolder);
- connect(_discoveryPhase.data(), &DiscoveryPhase::fatalError, this, [this](const QString &errorString) {
- Q_EMIT syncError(errorString);
+ connect(_discoveryPhase.data(), &DiscoveryPhase::fatalError, this, [this](const QString &errorString, ErrorCategory errorCategory) {
+ Q_EMIT syncError(errorString, errorCategory);
finalize(false);
});
connect(_discoveryPhase.data(), &DiscoveryPhase::finished, this, &SyncEngine::slotDiscoveryFinished);
// Sanity check
if (!_journal->open()) {
qCWarning(lcEngine) << "Bailing out, DB failure";
- Q_EMIT syncError(tr("Cannot open the sync journal"));
+ Q_EMIT syncError(tr("Cannot open the sync journal"), ErrorCategory::GenericError);
finalize(false);
return;
} else {
finish();
}
-void SyncEngine::slotCleanPollsJobAborted(const QString &error)
+void SyncEngine::slotCleanPollsJobAborted(const QString &error, const ErrorCategory errorCategory)
{
- syncError(error);
+ syncError(error, errorCategory);
finalize(false);
}
}
}
-void SyncEngine::slotItemCompleted(const SyncFileItemPtr &item)
+void SyncEngine::slotItemCompleted(const SyncFileItemPtr &item, const ErrorCategory category)
{
_progressInfo->setProgressComplete(*item);
emit transmissionProgress(*_progressInfo);
- emit itemCompleted(item);
+ emit itemCompleted(item, category);
}
void SyncEngine::slotPropagationFinished(bool success)
return;
_uniqueErrors.insert(message);
- emit syncError(message, ErrorCategory::Normal);
+ emit syncError(message, ErrorCategory::GenericError);
}
void SyncEngine::slotInsufficientLocalStorage()
void aboutToPropagate(OCC::SyncFileItemVector &);
// after each item completed by a job (successful or not)
- void itemCompleted(const OCC::SyncFileItemPtr &);
+ void itemCompleted(const OCC::SyncFileItemPtr &item, const OCC::ErrorCategory category);
void transmissionProgress(const OCC::ProgressInfo &progress);
void itemDiscovered(const OCC::SyncFileItemPtr &);
/// We've produced a new sync error of a type.
- void syncError(const QString &message, OCC::ErrorCategory category = OCC::ErrorCategory::Normal);
+ void syncError(const QString &message, const OCC::ErrorCategory category);
- void addErrorToGui(OCC::SyncFileItem::Status status, const QString &errorMessage, const QString &subject);
+ void addErrorToGui(const OCC::SyncFileItem::Status status, const QString &errorMessage, const QString &subject, const OCC::ErrorCategory category);
void finished(bool success);
void started();
*/
void slotNewItem(const OCC::SyncFileItemPtr &item);
- void slotItemCompleted(const OCC::SyncFileItemPtr &item);
+ void slotItemCompleted(const OCC::SyncFileItemPtr &item, const OCC::ErrorCategory category);
void slotDiscoveryFinished();
void slotPropagationFinished(bool success);
void slotProgress(const OCC::SyncFileItem &item, qint64 curent);
- void slotCleanPollsJobAborted(const QString &error);
+ void slotCleanPollsJobAborted(const QString &error, const OCC::ErrorCategory category);
/** Records that a file was touched by a job. */
void slotAddTouchedFile(const QString &fn);
QVERIFY(index.isValid());
}
+ void testActivityAdd(void(OCC::ActivityListModel::*addingMethod)(const OCC::Activity&, OCC::ActivityListModel::ErrorType), OCC::Activity &activity, OCC::ActivityListModel::ErrorType type) {
+ const auto model = testingALM();
+ QCOMPARE(model->rowCount(), 0);
+
+ (model.data()->*addingMethod)(activity, type);
+ QCOMPARE(model->rowCount(), 1);
+
+ const auto index = model->index(0, 0);
+ QVERIFY(index.isValid());
+ }
+
private slots:
void initTestCase()
{
};
void testAddError() {
- testActivityAdd(&TestingALM::addErrorToActivityList, testSyncResultErrorActivity);
+ testActivityAdd(&TestingALM::addErrorToActivityList, testSyncResultErrorActivity, OCC::ActivityListModel::ErrorType::SyncError);
};
void testAddIgnoredFile() {
model->addSyncFileItemToActivityList(testSyncFileItemActivity);
QCOMPARE(model->rowCount(), 51);
- model->addErrorToActivityList(testSyncResultErrorActivity);
+ model->addErrorToActivityList(testSyncResultErrorActivity, OCC::ActivityListModel::ErrorType::SyncError);
QCOMPARE(model->rowCount(), 52);
model->addIgnoredFileToList(testFileIgnoredActivity);