KIO

forwardingworkerbase.cpp
1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2004 Kevin Ottens <ervin@ipsquad.net>
4 SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "forwardingworkerbase.h"
10#include "../utils_p.h"
11
12#include "deletejob.h"
13#include "filecopyjob.h"
14#include "kiocoredebug.h"
15#include "listjob.h"
16#include "mimetypejob.h"
17#include "mkdirjob.h"
18#include "statjob.h"
19#include "transferjob.h"
20
21#include <QEventLoop>
22#include <QMimeDatabase>
23
24namespace KIO
25{
26class ForwardingWorkerBasePrivate
27{
28public:
29 ForwardingWorkerBasePrivate(const QByteArray &protocol, QObject *eventLoopParent, ForwardingWorkerBase *qq)
30 : q(qq)
31 , m_protocol(QString::fromUtf8(protocol))
32 , eventLoop(eventLoopParent)
33 {
34 }
35 ForwardingWorkerBase *const q;
36
37 const QString m_protocol;
38 QUrl m_processedURL;
39 QUrl m_requestedURL;
40
41 bool internalRewriteUrl(const QUrl &url, QUrl &newURL);
42
43 void connectJob(Job *job);
44 void connectSimpleJob(SimpleJob *job);
45 void connectListJob(ListJob *job);
46 void connectTransferJob(TransferJob *job);
47
48 void _k_slotResult(KJob *job);
49 void _k_slotWarning(KJob *job, const QString &msg) const;
50 void _k_slotInfoMessage(KJob *job, const QString &msg) const;
51 void _k_slotTotalSize(KJob *job, qulonglong size) const;
52 void _k_slotProcessedSize(KJob *job, qulonglong size) const;
53 void _k_slotSpeed(KJob *job, unsigned long bytesPerSecond) const;
54
55 // KIO::SimpleJob subclasses
56 void _k_slotRedirection(KIO::Job *job, const QUrl &url);
57
58 // KIO::ListJob
59 void _k_slotEntries(KIO::Job *job, const KIO::UDSEntryList &entries) const;
60
61 // KIO::TransferJob
62 void _k_slotData(KIO::Job *job, const QByteArray &data) const;
63 void _k_slotDataReq(KIO::Job *job, QByteArray &data) const;
64 void _k_slotMimetype(KIO::Job *job, const QString &type) const;
65 void _k_slotCanResume(KIO::Job *job, KIO::filesize_t offset) const;
66
67 [[nodiscard]] WorkerResult loopResult()
68 {
69 eventLoop.exec();
70 return m_pendingResult;
71 }
72
73private:
74 // These are intentionally private to force us to go through [[nodiscard]] helper functions, lest we forget to retrieve the result.
75 QEventLoop eventLoop;
76 WorkerResult m_pendingResult = WorkerResult::pass();
77};
78
79ForwardingWorkerBase::ForwardingWorkerBase(const QByteArray &protocol, const QByteArray &poolSocket, const QByteArray &appSocket)
80 : WorkerBase(protocol, poolSocket, appSocket)
81 , d(new ForwardingWorkerBasePrivate(protocol, this, this))
82{
83}
84
85ForwardingWorkerBase::~ForwardingWorkerBase() = default;
86
87bool ForwardingWorkerBasePrivate::internalRewriteUrl(const QUrl &url, QUrl &newURL)
88{
89 bool result = true;
90
91 if (url.scheme() == m_protocol) {
92 result = q->rewriteUrl(url, newURL);
93 } else {
94 newURL = url;
95 }
96
97 m_processedURL = newURL;
98 m_requestedURL = url;
99 return result;
100}
101
102void ForwardingWorkerBase::adjustUDSEntry(KIO::UDSEntry &entry, UDSEntryCreationMode creationMode) const
103{
104 const bool listing = (creationMode == UDSEntryCreationInListDir);
105 // qDebug() << "listing==" << listing;
106
107 const QString name = entry.stringValue(KIO::UDSEntry::UDS_NAME);
109 QUrl url;
110 const QString urlStr = entry.stringValue(KIO::UDSEntry::UDS_URL);
111 const bool url_found = !urlStr.isEmpty();
112 if (url_found) {
113 url = QUrl(urlStr);
114 QUrl new_url(d->m_requestedURL);
115 if (listing) {
116 new_url.setPath(Utils::concatPaths(new_url.path(), url.fileName()));
117 }
118 // ## Didn't find a way to use an iterator instead of re-doing a key lookup
119 entry.replace(KIO::UDSEntry::UDS_URL, new_url.toString());
120 // qDebug() << "URL =" << url;
121 // qDebug() << "New URL =" << new_url;
122 }
123
124 if (mimetype.isEmpty()) {
125 QUrl new_url(d->m_processedURL);
126 if (url_found && listing) {
127 new_url.setPath(Utils::concatPaths(new_url.path(), url.fileName()));
128 } else if (listing) {
129 new_url.setPath(Utils::concatPaths(new_url.path(), name));
130 }
131
132 QMimeDatabase db;
133 mimetype = db.mimeTypeForUrl(new_url).name();
134
136
137 // qDebug() << "New MIME type = " << mimetype;
138 }
139
140 if (d->m_processedURL.isLocalFile()) {
141 QUrl new_url(d->m_processedURL);
142 if (listing) {
143 new_url.setPath(Utils::concatPaths(new_url.path(), name));
144 }
145
147 }
148}
149
150QUrl ForwardingWorkerBase::processedUrl() const
151{
152 return d->m_processedURL;
153}
154
155QUrl ForwardingWorkerBase::requestedUrl() const
156{
157 return d->m_requestedURL;
158}
159
160WorkerResult ForwardingWorkerBase::get(const QUrl &url)
161{
162 QUrl new_url;
163 if (d->internalRewriteUrl(url, new_url)) {
164 KIO::TransferJob *job = KIO::get(new_url, NoReload, HideProgressInfo);
165 d->connectTransferJob(job);
166
167 return d->loopResult();
168 }
169 return WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
170}
171
172WorkerResult ForwardingWorkerBase::put(const QUrl &url, int permissions, JobFlags flags)
173{
174 QUrl new_url;
175 if (d->internalRewriteUrl(url, new_url)) {
176 KIO::TransferJob *job = KIO::put(new_url, permissions, flags | HideProgressInfo);
177 d->connectTransferJob(job);
178
179 return d->loopResult();
180 }
181 return WorkerResult::fail(KIO::ERR_MALFORMED_URL, url.toDisplayString());
182}
183
184WorkerResult ForwardingWorkerBase::stat(const QUrl &url)
185{
186 QUrl new_url;
187 if (d->internalRewriteUrl(url, new_url)) {
189 d->connectSimpleJob(job);
190
191 return d->loopResult();
192 }
193 return WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
194}
195
196WorkerResult ForwardingWorkerBase::mimetype(const QUrl &url)
197{
198 QUrl new_url;
199 if (d->internalRewriteUrl(url, new_url)) {
201 d->connectTransferJob(job);
202
203 return d->loopResult();
204 }
205 return WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
206}
207
208WorkerResult ForwardingWorkerBase::listDir(const QUrl &url)
209{
210 QUrl new_url;
211 if (d->internalRewriteUrl(url, new_url)) {
213 d->connectListJob(job);
214
215 return d->loopResult();
216 }
217 return WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
218}
219
220WorkerResult ForwardingWorkerBase::mkdir(const QUrl &url, int permissions)
221{
222 QUrl new_url;
223 if (d->internalRewriteUrl(url, new_url)) {
224 KIO::SimpleJob *job = KIO::mkdir(new_url, permissions);
225 d->connectSimpleJob(job);
226
227 return d->loopResult();
228 }
229 return WorkerResult::fail(KIO::ERR_MALFORMED_URL, url.toDisplayString());
230}
231
232WorkerResult ForwardingWorkerBase::rename(const QUrl &src, const QUrl &dest, JobFlags flags)
233{
234 qCDebug(KIO_CORE) << "rename" << src << dest;
235
236 QUrl new_src;
237 QUrl new_dest;
238 if (!d->internalRewriteUrl(src, new_src)) {
239 return WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, src.toDisplayString());
240 }
241 if (d->internalRewriteUrl(dest, new_dest)) {
242 KIO::Job *job = KIO::rename(new_src, new_dest, flags);
243 d->connectJob(job);
244
245 return d->loopResult();
246 }
247 return WorkerResult::fail(KIO::ERR_MALFORMED_URL, dest.toDisplayString());
248}
249
250WorkerResult ForwardingWorkerBase::symlink(const QString &target, const QUrl &dest, JobFlags flags)
251{
252 qCDebug(KIO_CORE) << "symlink" << target << dest;
253
254 QUrl new_dest;
255 if (d->internalRewriteUrl(dest, new_dest)) {
256 KIO::SimpleJob *job = KIO::symlink(target, new_dest, flags | HideProgressInfo);
257 d->connectSimpleJob(job);
258
259 return d->loopResult();
260 }
261 return WorkerResult::fail(KIO::ERR_MALFORMED_URL, dest.toDisplayString());
262}
263
264WorkerResult ForwardingWorkerBase::chmod(const QUrl &url, int permissions)
265{
266 QUrl new_url;
267 if (d->internalRewriteUrl(url, new_url)) {
268 KIO::SimpleJob *job = KIO::chmod(new_url, permissions);
269 d->connectSimpleJob(job);
270
271 return d->loopResult();
272 }
273 return WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
274}
275
276WorkerResult ForwardingWorkerBase::setModificationTime(const QUrl &url, const QDateTime &mtime)
277{
278 QUrl new_url;
279 if (d->internalRewriteUrl(url, new_url)) {
280 KIO::SimpleJob *job = KIO::setModificationTime(new_url, mtime);
281 d->connectSimpleJob(job);
282
283 return d->loopResult();
284 }
285 return WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
286}
287
288WorkerResult ForwardingWorkerBase::copy(const QUrl &src, const QUrl &dest, int permissions, JobFlags flags)
289{
290 qCDebug(KIO_CORE) << "copy" << src << dest;
291
292 QUrl new_src;
293 QUrl new_dest;
294 if (!d->internalRewriteUrl(src, new_src)) {
295 return WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, src.toDisplayString());
296 }
297 if (d->internalRewriteUrl(dest, new_dest)) {
298 KIO::Job *job = KIO::file_copy(new_src, new_dest, permissions, flags | HideProgressInfo);
299 d->connectJob(job);
300
301 return d->loopResult();
302 }
303 return WorkerResult::fail(KIO::ERR_MALFORMED_URL, dest.toDisplayString());
304}
305
306WorkerResult ForwardingWorkerBase::del(const QUrl &url, bool isfile)
307{
308 QUrl new_url;
309 if (d->internalRewriteUrl(url, new_url)) {
310 if (isfile) {
312 d->connectJob(job);
313 } else {
314 KIO::SimpleJob *job = KIO::rmdir(new_url);
315 d->connectSimpleJob(job);
316 }
317
318 return d->loopResult();
319 }
320 return WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
321}
322
323//////////////////////////////////////////////////////////////////////////////
324
325void ForwardingWorkerBasePrivate::connectJob(KIO::Job *job)
326{
327 // We will forward the warning message, no need to let the job
328 // display it itself
329 job->setUiDelegate(nullptr);
330
331 // Forward metadata (e.g. modification time for put())
332 job->setMetaData(q->allMetaData());
333
334 q->connect(job, &KJob::result, q, [this](KJob *job) {
335 _k_slotResult(job);
336 });
337 q->connect(job, &KJob::warning, q, [this](KJob *job, const QString &text) {
338 _k_slotWarning(job, text);
339 });
340 q->connect(job, &KJob::infoMessage, q, [this](KJob *job, const QString &info) {
341 _k_slotInfoMessage(job, info);
342 });
343 q->connect(job, &KJob::totalSize, q, [this](KJob *job, qulonglong size) {
344 _k_slotTotalSize(job, size);
345 });
346 q->connect(job, &KJob::processedSize, q, [this](KJob *job, qulonglong size) {
347 _k_slotProcessedSize(job, size);
348 });
349 q->connect(job, &KJob::speed, q, [this](KJob *job, ulong speed) {
350 _k_slotSpeed(job, speed);
351 });
352}
353
354void ForwardingWorkerBasePrivate::connectSimpleJob(KIO::SimpleJob *job)
355{
356 connectJob(job);
357 if (job->metaObject()->indexOfSignal("redirection(KIO::Job*,QUrl)") > -1) {
358 q->connect(job, SIGNAL(redirection(KIO::Job *, QUrl)), SLOT(_k_slotRedirection(KIO::Job *, QUrl)));
359 }
360}
361
362void ForwardingWorkerBasePrivate::connectListJob(KIO::ListJob *job)
363{
364 connectSimpleJob(job);
365 q->connect(job, &KIO::ListJob::entries, q, [this](KIO::Job *job, const KIO::UDSEntryList &entries) {
366 _k_slotEntries(job, entries);
367 });
368}
369
370void ForwardingWorkerBasePrivate::connectTransferJob(KIO::TransferJob *job)
371{
372 connectSimpleJob(job);
373 q->connect(job, &KIO::TransferJob::data, q, [this](KIO::Job *job, const QByteArray &data) {
374 _k_slotData(job, data);
375 });
376 q->connect(job, &KIO::TransferJob::dataReq, q, [this](KIO::Job *job, QByteArray &data) {
377 _k_slotDataReq(job, data);
378 });
379 q->connect(job, &KIO::TransferJob::mimeTypeFound, q, [this](KIO::Job *job, const QString &mimeType) {
380 _k_slotMimetype(job, mimeType);
381 });
382 q->connect(job, &KIO::TransferJob::canResume, q, [this](KIO::Job *job, KIO::filesize_t offset) {
383 _k_slotCanResume(job, offset);
384 });
385}
386
387//////////////////////////////////////////////////////////////////////////////
388
389void ForwardingWorkerBasePrivate::_k_slotResult(KJob *job)
390{
391 if (job->error() != 0) {
392 m_pendingResult = WorkerResult::fail(job->error(), job->errorText());
393 } else {
394 if (auto stat_job = qobject_cast<KIO::StatJob *>(job)) {
395 KIO::UDSEntry entry = stat_job->statResult();
396 q->adjustUDSEntry(entry, ForwardingWorkerBase::UDSEntryCreationInStat);
397 q->statEntry(entry);
398 }
399 m_pendingResult = WorkerResult::pass();
400 }
401
402 eventLoop.exit();
403}
404
405void ForwardingWorkerBasePrivate::_k_slotWarning(KJob * /*job*/, const QString &msg) const
406{
407 q->warning(msg);
408}
409
410void ForwardingWorkerBasePrivate::_k_slotInfoMessage(KJob * /*job*/, const QString &msg) const
411{
412 q->infoMessage(msg);
413}
414
415void ForwardingWorkerBasePrivate::_k_slotTotalSize(KJob * /*job*/, qulonglong size) const
416{
417 q->totalSize(size);
418}
419
420void ForwardingWorkerBasePrivate::_k_slotProcessedSize(KJob * /*job*/, qulonglong size) const
421{
422 q->processedSize(size);
423}
424
425void ForwardingWorkerBasePrivate::_k_slotSpeed(KJob * /*job*/, unsigned long bytesPerSecond) const
426{
427 q->speed(bytesPerSecond);
428}
429
430void ForwardingWorkerBasePrivate::_k_slotRedirection(KIO::Job *job, const QUrl &url)
431{
432 q->redirection(url);
433
434 // We've been redirected stop everything.
435 job->kill(KJob::Quietly);
436 m_pendingResult = WorkerResult::pass();
437
438 eventLoop.exit();
439}
440
441void ForwardingWorkerBasePrivate::_k_slotEntries(KIO::Job * /*job*/, const KIO::UDSEntryList &entries) const
442{
443 KIO::UDSEntryList final_entries = entries;
444
445 for (auto &entry : final_entries) {
446 q->adjustUDSEntry(entry, ForwardingWorkerBase::UDSEntryCreationInListDir);
447 }
448
449 q->listEntries(final_entries);
450}
451
452void ForwardingWorkerBasePrivate::_k_slotData(KIO::Job * /*job*/, const QByteArray &_data) const
453{
454 q->data(_data);
455}
456
457void ForwardingWorkerBasePrivate::_k_slotDataReq(KIO::Job * /*job*/, QByteArray &data) const
458{
459 q->dataReq();
460 q->readData(data);
461}
462
463void ForwardingWorkerBasePrivate::_k_slotMimetype(KIO::Job * /*job*/, const QString &type) const
464{
465 q->mimeType(type);
466}
467
468void ForwardingWorkerBasePrivate::_k_slotCanResume(KIO::Job * /*job*/, KIO::filesize_t offset) const
469{
470 q->canResume(offset);
471}
472
473} // namespace KIO
474
475#include "moc_forwardingworkerbase.cpp"
A more complex Job to delete files and directories.
Definition deletejob.h:34
The base class for all jobs.
Definition job_base.h:45
void setMetaData(const KIO::MetaData &metaData)
Set meta data to be sent to the worker, replacing existing meta data.
Definition job.cpp:215
A ListJob is allows you to get the get the content of a directory.
Definition listjob.h:28
void entries(KIO::Job *job, const KIO::UDSEntryList &list)
This signal emits the entry found by the job while listing.
A simple job (one url and one command).
Definition simplejob.h:27
The transfer job pumps data into and/or out of a KIO worker.
Definition transferjob.h:26
void mimeTypeFound(KIO::Job *job, const QString &mimeType)
MIME type determined.
void dataReq(KIO::Job *job, QByteArray &data)
Request for data.
void data(KIO::Job *job, const QByteArray &data)
Data from the worker has arrived.
void canResume(KIO::Job *job, KIO::filesize_t offset)
Universal Directory Service.
Definition udsentry.h:78
QString stringValue(uint field) const
Definition udsentry.cpp:365
@ UDS_URL
An alternative URL (If different from the caption).
Definition udsentry.h:251
@ UDS_MIME_TYPE
A MIME type; the KIO worker should set it if it's known.
Definition udsentry.h:253
@ UDS_LOCAL_PATH
A local file path if the KIO worker display files sitting on the local filesystem (but in another hie...
Definition udsentry.h:227
@ UDS_NAME
Filename - as displayed in directory listings etc.
Definition udsentry.h:224
void replace(uint field, const QString &value)
Replace or insert field with string value.
Definition udsentry.cpp:400
The result of a worker call When using the Result type always mark the function Q_REQUIRED_RESULT to ...
Definition workerbase.h:36
static WorkerResult pass()
Constructs a success result.
int error() const
void processedSize(KJob *job, qulonglong size)
void result(KJob *job)
void warning(KJob *job, const QString &message)
void infoMessage(KJob *job, const QString &message)
void totalSize(KJob *job, qulonglong size)
QString errorText() const
bool kill(KJob::KillVerbosity verbosity=KJob::Quietly)
void setUiDelegate(KJobUiDelegate *delegate)
void speed(KJob *job, unsigned long speed)
A namespace for KIO globals.
KIOCORE_EXPORT ChmodJob * chmod(const KFileItemList &lstItems, int permissions, int mask, const QString &newOwner, const QString &newGroup, bool recursive, JobFlags flags=DefaultFlags)
Creates a job that changes permissions/ownership on several files or directories, optionally recursiv...
Definition chmodjob.cpp:288
KIOCORE_EXPORT DeleteJob * del(const QUrl &src, JobFlags flags=DefaultFlags)
Delete a file or directory.
KIOCORE_EXPORT SimpleJob * rmdir(const QUrl &url)
Removes a single directory.
KIOCORE_EXPORT MkdirJob * mkdir(const QUrl &url, int permissions=-1)
Creates a single directory.
Definition mkdirjob.cpp:110
KIOCORE_EXPORT SimpleJob * rename(const QUrl &src, const QUrl &dest, JobFlags flags=DefaultFlags)
Rename a file or directory.
KIOCORE_EXPORT StatJob * stat(const QUrl &url, JobFlags flags=DefaultFlags)
Find all details for one file or directory.
Definition statjob.cpp:203
KIOCORE_EXPORT ListJob * listDir(const QUrl &url, JobFlags flags=DefaultFlags, ListJob::ListFlags listFlags=ListJob::ListFlag::IncludeHidden)
List the contents of url, which is assumed to be a directory.
Definition listjob.cpp:239
KIOCORE_EXPORT TransferJob * get(const QUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
Get (means: read).
KIOCORE_EXPORT SimpleJob * symlink(const QString &target, const QUrl &dest, JobFlags flags=DefaultFlags)
Create or move a symlink.
KIOCORE_EXPORT MimetypeJob * mimetype(const QUrl &url, JobFlags flags=DefaultFlags)
Find MIME type for one file or directory.
KIOCORE_EXPORT SimpleJob * setModificationTime(const QUrl &url, const QDateTime &mtime)
Changes the modification time on a file or directory.
KIOCORE_EXPORT FileCopyJob * file_copy(const QUrl &src, const QUrl &dest, int permissions=-1, JobFlags flags=DefaultFlags)
Copy a single file.
@ HideProgressInfo
Hide progress information dialog, i.e. don't show a GUI.
Definition job_base.h:251
KIOCORE_EXPORT TransferJob * put(const QUrl &url, int permissions, JobFlags flags=DefaultFlags)
Put (means: write)
qulonglong filesize_t
64-bit file size
Definition global.h:35
int exec(ProcessEventsFlags flags)
pointer data()
int indexOfSignal(const char *signal) const const
QMimeType mimeTypeForUrl(const QUrl &url) const const
virtual const QMetaObject * metaObject() const const
bool isEmpty() const const
QString fileName(ComponentFormattingOptions options) const const
QString path(ComponentFormattingOptions options) const const
QString scheme() const const
void setPath(const QString &path, ParsingMode mode)
QString toDisplayString(FormattingOptions options) const const
QString toLocalFile() const const
QString toString(FormattingOptions options) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:51 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.