File indexing completed on 2024-04-28 08:49:01
0001 /* 0002 * SPDX-FileCopyrightText: 2013 Albert Vaca <albertvaka@gmail.com> 0003 * SPDX-FileCopyrightText: 2015 Aleix Pol i Gonzalez <aleixpol@kde.org> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "filetransferjob.h" 0009 #include "daemon.h" 0010 #include <core_debug.h> 0011 0012 #include <QDebug> 0013 #include <QFileInfo> 0014 #include <QNetworkAccessManager> 0015 #include <qalgorithms.h> 0016 0017 #include <KFileUtils> 0018 #include <KLocalizedString> 0019 0020 FileTransferJob::FileTransferJob(const NetworkPacket *np, const QUrl &destination) 0021 : KJob() 0022 , m_origin(np->payload()) 0023 , m_reply(nullptr) 0024 , m_from(QStringLiteral("KDE Connect")) 0025 , m_destination(destination) 0026 , m_written(0) 0027 , m_size(np->payloadSize()) 0028 , m_np(np) 0029 , m_autoRename(false) 0030 { 0031 Q_ASSERT(m_origin); 0032 // Disabled this assert: QBluetoothSocket doesn't report "->isReadable() == true" until it's connected 0033 // Q_ASSERT(m_origin->isReadable()); 0034 if (m_destination.scheme().isEmpty()) { 0035 qCWarning(KDECONNECT_CORE) << "Destination QUrl" << m_destination << "lacks a scheme. Setting its scheme to 'file'."; 0036 m_destination.setScheme(QStringLiteral("file")); 0037 } 0038 0039 setCapabilities(Killable); 0040 qCDebug(KDECONNECT_CORE) << "FileTransferJob Downloading payload to" << destination << "size:" << m_size; 0041 } 0042 0043 void FileTransferJob::start() 0044 { 0045 QMetaObject::invokeMethod(this, "doStart", Qt::QueuedConnection); 0046 // qCDebug(KDECONNECT_CORE) << "FileTransferJob start"; 0047 } 0048 0049 void FileTransferJob::doStart() 0050 { 0051 if (m_destination.isLocalFile() && QFile::exists(m_destination.toLocalFile())) { 0052 if (m_autoRename) { 0053 QFileInfo fileInfo(m_destination.toLocalFile()); 0054 QString path = fileInfo.path(); 0055 QString fileName = fileInfo.fileName(); 0056 m_destination.setPath(path + QStringLiteral("/") + KFileUtils::suggestName(QUrl(path), fileName), QUrl::DecodedMode); 0057 } else { 0058 setError(2); 0059 setErrorText(i18n("Filename already present")); 0060 emitResult(); 0061 return; 0062 } 0063 } 0064 0065 if (m_origin->bytesAvailable()) 0066 startTransfer(); 0067 connect(m_origin.data(), &QIODevice::readyRead, this, &FileTransferJob::startTransfer); 0068 } 0069 0070 void FileTransferJob::startTransfer() 0071 { 0072 // Don't put each ready read 0073 if (m_reply) 0074 return; 0075 0076 setProcessedAmount(Bytes, 0); 0077 0078 QNetworkRequest req(m_destination); 0079 if (m_size >= 0) { 0080 setTotalAmount(Bytes, m_size); 0081 req.setHeader(QNetworkRequest::ContentLengthHeader, m_size); 0082 } 0083 m_reply = Daemon::instance()->networkAccessManager()->put(req, m_origin.data()); 0084 0085 connect(m_reply, &QNetworkReply::uploadProgress, this, [this](qint64 bytesSent, qint64 /*bytesTotal*/) { 0086 if (!m_timer.isValid()) 0087 m_timer.start(); 0088 setProcessedAmount(Bytes, bytesSent); 0089 0090 const auto elapsed = m_timer.elapsed(); 0091 if (elapsed > 0) { 0092 emitSpeed((1000 * bytesSent) / elapsed); 0093 } 0094 0095 m_written = bytesSent; 0096 }); 0097 connect(m_reply, &QNetworkReply::errorOccurred, this, &FileTransferJob::transferFailed); 0098 connect(m_reply, &QNetworkReply::finished, this, &FileTransferJob::transferFinished); 0099 } 0100 0101 void FileTransferJob::transferFailed(QNetworkReply::NetworkError error) 0102 { 0103 qCDebug(KDECONNECT_CORE) << "Couldn't transfer the file successfully" << error << m_reply->errorString(); 0104 setError(error); 0105 setErrorText(i18n("Received incomplete file: %1", m_reply->errorString())); 0106 emitResult(); 0107 0108 m_reply->close(); 0109 } 0110 0111 void FileTransferJob::transferFinished() 0112 { 0113 // TODO: MD5-check the file 0114 if (m_size == m_written) { 0115 qCDebug(KDECONNECT_CORE) << "Finished transfer" << m_destination; 0116 emitResult(); 0117 } else { 0118 qCDebug(KDECONNECT_CORE) << "Received incomplete file (" << m_written << "/" << m_size << "bytes ), deleting"; 0119 0120 deleteDestinationFile(); 0121 0122 setError(3); 0123 setErrorText(i18n("Received incomplete file from: %1", m_from)); 0124 emitResult(); 0125 } 0126 } 0127 0128 void FileTransferJob::deleteDestinationFile() 0129 { 0130 if (m_destination.isLocalFile() && QFile::exists(m_destination.toLocalFile())) { 0131 QFile::remove(m_destination.toLocalFile()); 0132 } 0133 } 0134 0135 bool FileTransferJob::doKill() 0136 { 0137 if (m_reply) { 0138 m_reply->close(); 0139 } 0140 if (m_origin) { 0141 m_origin->close(); 0142 } 0143 0144 deleteDestinationFile(); 0145 0146 return true; 0147 } 0148 0149 #include "moc_filetransferjob.cpp"