571575df28
When receiving two files with the same name, the first file might not be saved to disk already when we have to decide the name for the second if we do it too early. BUG: 470078
152 lines
4.6 KiB
C++
152 lines
4.6 KiB
C++
/*
|
|
* SPDX-FileCopyrightText: 2013 Albert Vaca <albertvaka@gmail.com>
|
|
* SPDX-FileCopyrightText: 2015 Aleix Pol i Gonzalez <aleixpol@kde.org>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
*/
|
|
|
|
#include "filetransferjob.h"
|
|
#include "daemon.h"
|
|
#include <core_debug.h>
|
|
|
|
#include <QDebug>
|
|
#include <QFileInfo>
|
|
#include <qalgorithms.h>
|
|
#include <QNetworkAccessManager>
|
|
|
|
#include <KLocalizedString>
|
|
#include <KFileUtils>
|
|
|
|
FileTransferJob::FileTransferJob(const NetworkPacket *np, const QUrl &destination)
|
|
: KJob()
|
|
, m_origin(np->payload())
|
|
, m_reply(nullptr)
|
|
, m_from(QStringLiteral("KDE Connect"))
|
|
, m_destination(destination)
|
|
, m_speedBytes(0)
|
|
, m_written(0)
|
|
, m_size(np->payloadSize())
|
|
, m_np(np)
|
|
, m_autoRename(false)
|
|
{
|
|
Q_ASSERT(m_origin);
|
|
// Disabled this assert: QBluetoothSocket doesn't report "->isReadable() == true" until it's connected
|
|
// Q_ASSERT(m_origin->isReadable());
|
|
if (m_destination.scheme().isEmpty()) {
|
|
qCWarning(KDECONNECT_CORE) << "Destination QUrl" << m_destination << "lacks a scheme. Setting its scheme to 'file'.";
|
|
m_destination.setScheme(QStringLiteral("file"));
|
|
}
|
|
|
|
setCapabilities(Killable);
|
|
qCDebug(KDECONNECT_CORE) << "FileTransferJob Downloading payload to" << destination << "size:" << m_size;
|
|
}
|
|
|
|
void FileTransferJob::start()
|
|
{
|
|
QMetaObject::invokeMethod(this, "doStart", Qt::QueuedConnection);
|
|
// qCDebug(KDECONNECT_CORE) << "FileTransferJob start";
|
|
}
|
|
|
|
void FileTransferJob::doStart()
|
|
{
|
|
if (m_destination.isLocalFile() && QFile::exists(m_destination.toLocalFile())) {
|
|
if (m_autoRename) {
|
|
QFileInfo fileInfo(m_destination.toLocalFile());
|
|
QString path = fileInfo.path();
|
|
QString fileName = fileInfo.fileName();
|
|
m_destination.setPath(path + QStringLiteral("/") + KFileUtils::suggestName(QUrl(path), fileName), QUrl::DecodedMode);
|
|
} else {
|
|
setError(2);
|
|
setErrorText(i18n("Filename already present"));
|
|
emitResult();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (m_origin->bytesAvailable())
|
|
startTransfer();
|
|
connect(m_origin.data(), &QIODevice::readyRead, this, &FileTransferJob::startTransfer);
|
|
}
|
|
|
|
void FileTransferJob::startTransfer()
|
|
{
|
|
// Don't put each ready read
|
|
if (m_reply)
|
|
return;
|
|
|
|
setProcessedAmount(Bytes, 0);
|
|
|
|
QNetworkRequest req(m_destination);
|
|
if (m_size >= 0) {
|
|
setTotalAmount(Bytes, m_size);
|
|
req.setHeader(QNetworkRequest::ContentLengthHeader, m_size);
|
|
}
|
|
m_reply = Daemon::instance()->networkAccessManager()->put(req, m_origin.data());
|
|
|
|
connect(m_reply, &QNetworkReply::uploadProgress, this, [this](qint64 bytesSent, qint64 /*bytesTotal*/) {
|
|
if (!m_timer.isValid())
|
|
m_timer.start();
|
|
setProcessedAmount(Bytes, bytesSent);
|
|
|
|
const auto elapsed = m_timer.elapsed();
|
|
if (elapsed > 0) {
|
|
emitSpeed((1000 * bytesSent) / elapsed);
|
|
}
|
|
|
|
m_written = bytesSent;
|
|
});
|
|
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
|
connect(m_reply, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), this, &FileTransferJob::transferFailed);
|
|
#else
|
|
connect(m_reply, &QNetworkReply::errorOccurred, this, &FileTransferJob::transferFailed);
|
|
#endif
|
|
connect(m_reply, &QNetworkReply::finished, this, &FileTransferJob::transferFinished);
|
|
}
|
|
|
|
void FileTransferJob::transferFailed(QNetworkReply::NetworkError error)
|
|
{
|
|
qCDebug(KDECONNECT_CORE) << "Couldn't transfer the file successfully" << error << m_reply->errorString();
|
|
setError(error);
|
|
setErrorText(i18n("Received incomplete file: %1", m_reply->errorString()));
|
|
emitResult();
|
|
|
|
m_reply->close();
|
|
}
|
|
|
|
void FileTransferJob::transferFinished()
|
|
{
|
|
// TODO: MD5-check the file
|
|
if (m_size == m_written) {
|
|
qCDebug(KDECONNECT_CORE) << "Finished transfer" << m_destination;
|
|
emitResult();
|
|
} else {
|
|
qCDebug(KDECONNECT_CORE) << "Received incomplete file (" << m_written << "/" << m_size << "bytes ), deleting";
|
|
|
|
deleteDestinationFile();
|
|
|
|
setError(3);
|
|
setErrorText(i18n("Received incomplete file from: %1", m_from));
|
|
emitResult();
|
|
}
|
|
}
|
|
|
|
void FileTransferJob::deleteDestinationFile()
|
|
{
|
|
if (m_destination.isLocalFile() && QFile::exists(m_destination.toLocalFile())) {
|
|
QFile::remove(m_destination.toLocalFile());
|
|
}
|
|
}
|
|
|
|
bool FileTransferJob::doKill()
|
|
{
|
|
if (m_reply) {
|
|
m_reply->close();
|
|
}
|
|
if (m_origin) {
|
|
m_origin->close();
|
|
}
|
|
|
|
deleteDestinationFile();
|
|
|
|
return true;
|
|
}
|