namespace OCC {
-InvalidFilenameDialog::InvalidFilenameDialog(AccountPtr account, Folder *folder, QString filePath, QWidget *parent)
+InvalidFilenameDialog::InvalidFilenameDialog(AccountPtr account, Folder *folder, QString filePath, FileLocation fileLocation, QWidget *parent)
: QDialog(parent)
, _ui(new Ui::InvalidFilenameDialog)
, _account(account)
, _folder(folder)
, _filePath(std::move(filePath))
+ , _fileLocation(fileLocation)
{
Q_ASSERT(_account);
Q_ASSERT(_folder);
connect(_ui->filenameLineEdit, &QLineEdit::textChanged, this,
&InvalidFilenameDialog::onFilenameLineEditTextChanged);
- checkIfAllowedToRename();
+ if (_fileLocation == FileLocation::NewLocalFile) {
+ allowRenaming();
+ _ui->errorLabel->setText({});
+ } else {
+ checkIfAllowedToRename();
+ }
}
InvalidFilenameDialog::~InvalidFilenameDialog() = default;
}
}
- _ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
- _ui->filenameLineEdit->setEnabled(true);
- _ui->filenameLineEdit->selectAll();
-
- const auto filePathFileInfo = QFileInfo(_filePath);
- const auto fileName = filePathFileInfo.fileName();
- processLeadingOrTrailingSpacesError(fileName);
+ allowRenaming();
}
bool InvalidFilenameDialog::processLeadingOrTrailingSpacesError(const QString &fileName)
onCheckIfAllowedToRenameComplete({}, reply);
}
+void InvalidFilenameDialog::allowRenaming()
+{
+ _ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
+ _ui->filenameLineEdit->setEnabled(true);
+ _ui->filenameLineEdit->selectAll();
+
+ const auto filePathFileInfo = QFileInfo(_filePath);
+ const auto fileName = filePathFileInfo.fileName();
+ processLeadingOrTrailingSpacesError(fileName);
+}
+
void InvalidFilenameDialog::useInvalidName()
{
emit acceptedInvalidName(_filePath);
Q_OBJECT
public:
- explicit InvalidFilenameDialog(AccountPtr account, Folder *folder, QString filePath, QWidget *parent = nullptr);
+ enum class FileLocation {
+ Default = 0,
+ NewLocalFile,
+ };
+
+ explicit InvalidFilenameDialog(AccountPtr account, Folder *folder, QString filePath, FileLocation fileLocation = FileLocation::Default, QWidget *parent = nullptr);
~InvalidFilenameDialog() override;
QString _relativeFilePath;
QString _originalFileName;
QString _newFilename;
+ FileLocation _fileLocation = FileLocation::Default;
void onFilenameLineEditTextChanged(const QString &text);
void onMoveJobFinished();
bool processLeadingOrTrailingSpacesError(const QString &fileName);
void onPropfindPermissionSuccess(const QVariantMap &values);
void onPropfindPermissionError(QNetworkReply *reply = nullptr);
+ void allowRenaming();
private slots:
void useInvalidName();
};
|| a._syncFileItemStatus == SyncFileItem::Restoration
|| a._syncFileItemStatus == SyncFileItem::FileLocked
|| a._syncFileItemStatus == SyncFileItem::FileNameInvalid
+ || a._syncFileItemStatus == SyncFileItem::FileNameInvalidOnServer
|| a._syncFileItemStatus == SyncFileItem::FileNameClash) {
colorIconPath.append("state-warning.svg");
return colorIconPath;
return !a._links.isEmpty() &&
a._syncFileItemStatus != SyncFileItem::FileNameClash &&
a._syncFileItemStatus != SyncFileItem::Conflict &&
- a._syncFileItemStatus != SyncFileItem::FileNameInvalid;
+ a._syncFileItemStatus != SyncFileItem::FileNameInvalid &&
+ a._syncFileItemStatus != SyncFileItem::FileNameInvalidOnServer;
case IsCurrentUserFileActivityRole:
return a._isCurrentUserFileActivity;
case ThumbnailRole: {
} else if (activity._syncFileItemStatus == SyncFileItem::FileNameClash) {
triggerCaseClashAction(activity);
return;
- } else if (activity._syncFileItemStatus == SyncFileItem::FileNameInvalid) {
+ } else if (activity._syncFileItemStatus == SyncFileItem::FileNameInvalid
+ || activity._syncFileItemStatus == SyncFileItem::FileNameInvalidOnServer) {
if (!_currentInvalidFilenameDialog.isNull()) {
_currentInvalidFilenameDialog->close();
}
auto folder = FolderMan::instance()->folder(activity._folder);
const auto folderDir = QDir(folder->path());
+ const auto fileLocation = activity._syncFileItemStatus == SyncFileItem::FileNameInvalidOnServer
+ ? InvalidFilenameDialog::FileLocation::NewLocalFile
+ : InvalidFilenameDialog::FileLocation::Default;
+
_currentInvalidFilenameDialog = new InvalidFilenameDialog(_accountState->account(), folder,
- folderDir.filePath(activity._file));
+ folderDir.filePath(activity._file), fileLocation);
connect(_currentInvalidFilenameDialog, &InvalidFilenameDialog::accepted, folder, [folder]() {
folder->scheduleThisFolderSoon();
});
return base;
}
+QString AbstractNetworkJob::errorStringParsingBodyException(const QByteArray &body) const
+{
+ return extractException(body);
+}
+
AbstractNetworkJob::~AbstractNetworkJob()
{
setReply(nullptr);
return exception;
}
+QString extractException(const QByteArray &errorResponse)
+{
+ QXmlStreamReader reader(errorResponse);
+ reader.readNextStartElement();
+ if (reader.name() != QLatin1String("error")) {
+ return {};
+ }
+
+ while (!reader.atEnd() && !reader.hasError()) {
+ reader.readNextStartElement();
+ if (reader.name() == QLatin1String("exception")) {
+ return reader.readElementText();
+ }
+ }
+ return {};
+}
+
QString errorMessage(const QString &baseError, const QByteArray &body)
{
QString msg = baseError;
*/
QString errorStringParsingBody(QByteArray *body = nullptr);
+ /** Like errorString, but also checking the reply body for information.
+ *
+ * Specifically, sometimes xml bodies have extra error information.
+ * This function reads the body of the reply and parses out the
+ * error information, if possible.
+ *
+ * \a body is optinally filled with the reply body.
+ *
+ * Warning: Needs to call reply()->readAll().
+ */
+ [[nodiscard]] QString errorStringParsingBodyException(const QByteArray &body) const;
+
/** Make a new request */
void retry();
*/
QString OWNCLOUDSYNC_EXPORT extractErrorMessage(const QByteArray &errorResponse);
+
+/** Gets the SabreDAV-style exception from an error response.
+ *
+ * This assumes the response is XML with a 'exception' tag that has a
+ * 'exception' tag that contains the data to extract.
+ *
+ * Returns a null string if no message was found.
+ */
+[[nodiscard]] QString OWNCLOUDSYNC_EXPORT extractException(const QByteArray &errorResponse);
+
/** Builds a error message based on the error and the reply body. */
QString OWNCLOUDSYNC_EXPORT errorMessage(const QString &baseError, const QByteArray &body);
case SyncFileItem::FileIgnored:
case SyncFileItem::FileLocked:
case SyncFileItem::FileNameInvalid:
+ case SyncFileItem::FileNameInvalidOnServer:
case SyncFileItem::FileNameClash:
case SyncFileItem::NoStatus:
case SyncFileItem::NormalError:
case SyncFileItem::BlacklistedError:
case SyncFileItem::FileLocked:
case SyncFileItem::FileNameInvalid:
+ case SyncFileItem::FileNameInvalidOnServer:
case SyncFileItem::FileNameClash:
// nothing
break;
|| kind == SyncFileItem::Conflict || kind == SyncFileItem::Restoration
|| kind == SyncFileItem::DetailError || kind == SyncFileItem::BlacklistedError
|| kind == SyncFileItem::FileLocked || kind == SyncFileItem::FileNameInvalid
+ || kind == SyncFileItem::FileNameInvalidOnServer
|| kind == SyncFileItem::FileNameClash;
}
status = SyncFileItem::DetailError;
errorString = tr("Upload of %1 exceeds the quota for the folder").arg(Utility::octetsToString(_fileToUpload._size));
emit propagator()->insufficientRemoteStorage();
+ } else if (_item->_httpErrorCode == 400) {
+ const auto exception = job->errorStringParsingBodyException(replyContent);
+
+ if (exception.endsWith(QStringLiteral("\\InvalidPath"))) {
+ errorString = tr("Unable to upload an item with invalid characters");
+ status = SyncFileItem::FileNameInvalidOnServer;
+ }
}
abortWithError(status, errorString);
*/
FileNameInvalid,
+ /**
+ * The filename contains invalid characters and can not be uploaded to the server
+ */
+ FileNameInvalidOnServer,
+
/**
* There is a file name clash (e.g. attempting to download test.txt when TEST.TXT already exists
* on a platform where the filesystem is case-insensitive
if (!_firstItemError) {
_firstItemError = item;
}
- } else if (item->_status == SyncFileItem::Conflict || item->_status == SyncFileItem::FileNameInvalid || item->_status == SyncFileItem::FileNameClash) {
+ } else if (item->_status == SyncFileItem::Conflict || item->_status == SyncFileItem::FileNameInvalid || item->_status == SyncFileItem::FileNameInvalidOnServer || item->_status == SyncFileItem::FileNameClash) {
if (item->_instruction == CSYNC_INSTRUCTION_CONFLICT) {
_numNewConflictItems++;
if (!_firstNewConflictItem) {