1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2000 Stephan Kulow <coolo@kde.org>
4 SPDX-FileCopyrightText: 2000-2009 David Faure <faure@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "statjob.h"
10
11#include "job_p.h"
12#include "scheduler.h"
13#include "worker_p.h"
14#include <KProtocolInfo>
15#include <QTimer>
16#include <kurlauthorized.h>
17
18using namespace KIO;
19
20class KIO::StatJobPrivate : public SimpleJobPrivate
21{
22public:
23 inline StatJobPrivate(const QUrl &url, int command, const QByteArray &packedArgs)
24 : SimpleJobPrivate(url, command, packedArgs)
25 , m_bSource(true)
26 , m_details(KIO::StatDefaultDetails)
27 {
28 }
29
30 UDSEntry m_statResult;
31 QUrl m_redirectionURL;
32 bool m_bSource;
33 KIO::StatDetails m_details;
34 void slotStatEntry(const KIO::UDSEntry &entry);
35 void slotRedirection(const QUrl &url);
36
37 /**
38 * @internal
39 * Called by the scheduler when a @p worker gets to
40 * work on this job.
41 * @param worker the worker that starts working on this job
42 */
43 void start(Worker *worker) override;
44
45 Q_DECLARE_PUBLIC(StatJob)
46
47 static inline StatJob *newJob(const QUrl &url, int command, const QByteArray &packedArgs, JobFlags flags)
48 {
49 StatJob *job = new StatJob(*new StatJobPrivate(url, command, packedArgs));
50 job->setUiDelegate(KIO::createDefaultJobUiDelegate());
51 if (!(flags & HideProgressInfo)) {
52 job->setFinishedNotificationHidden();
53 KIO::getJobTracker()->registerJob(job);
54 emitStating(job, url);
55 }
56 return job;
57 }
58};
59
60StatJob::StatJob(StatJobPrivate &dd)
61 : SimpleJob(dd)
62{
63 setTotalAmount(unit: Items, amount: 1);
64}
65
66StatJob::~StatJob()
67{
68}
69
70void StatJob::setSide(StatSide side)
71{
72 d_func()->m_bSource = side == SourceSide;
73}
74
75void StatJob::setDetails(KIO::StatDetails details)
76{
77 d_func()->m_details = details;
78}
79
80const UDSEntry &StatJob::statResult() const
81{
82 return d_func()->m_statResult;
83}
84
85QUrl StatJob::mostLocalUrl() const
86{
87 const QUrl _url = url();
88
89 if (_url.isLocalFile()) {
90 return _url;
91 }
92
93 const UDSEntry &udsEntry = d_func()->m_statResult;
94 const QString path = udsEntry.stringValue(field: KIO::UDSEntry::UDS_LOCAL_PATH);
95
96 if (path.isEmpty()) { // Return url as-is
97 return _url;
98 }
99
100 const QString protoClass = KProtocolInfo::protocolClass(protocol: _url.scheme());
101 if (protoClass != QLatin1String(":local")) { // UDS_LOCAL_PATH was set but wrong Class
102 qCWarning(KIO_CORE) << "The protocol Class of the url that was being stat'ed" << _url << ", is" << protoClass
103 << ", however UDS_LOCAL_PATH was set; if you use UDS_LOCAL_PATH, the protocolClass"
104 " should be :local, see KProtocolInfo API docs for more details.";
105 return _url;
106 }
107
108 return QUrl::fromLocalFile(localfile: path);
109}
110
111void StatJobPrivate::start(Worker *worker)
112{
113 Q_Q(StatJob);
114 m_outgoingMetaData.insert(QStringLiteral("statSide"), value: m_bSource ? QStringLiteral("source") : QStringLiteral("dest"));
115 m_outgoingMetaData.insert(QStringLiteral("details"), value: QString::number(m_details));
116
117 q->connect(sender: worker, signal: &KIO::WorkerInterface::statEntry, context: q, slot: [this](const KIO::UDSEntry &entry) {
118 slotStatEntry(entry);
119 });
120 q->connect(sender: worker, signal: &KIO::WorkerInterface::redirection, context: q, slot: [this](const QUrl &url) {
121 slotRedirection(url);
122 });
123
124 SimpleJobPrivate::start(worker);
125}
126
127void StatJobPrivate::slotStatEntry(const KIO::UDSEntry &entry)
128{
129 // qCDebug(KIO_CORE);
130 m_statResult = entry;
131}
132
133// Worker got a redirection request
134void StatJobPrivate::slotRedirection(const QUrl &url)
135{
136 Q_Q(StatJob);
137 // qCDebug(KIO_CORE) << m_url << "->" << url;
138 if (!KUrlAuthorized::authorizeUrlAction(QStringLiteral("redirect"), baseUrl: m_url, destUrl: url)) {
139 qCWarning(KIO_CORE) << "Redirection from" << m_url << "to" << url << "REJECTED!";
140 q->setError(ERR_ACCESS_DENIED);
141 q->setErrorText(url.toDisplayString());
142 return;
143 }
144 m_redirectionURL = url; // We'll remember that when the job finishes
145 // Tell the user that we haven't finished yet
146 Q_EMIT q->redirection(job: q, url: m_redirectionURL);
147}
148
149void StatJob::slotFinished()
150{
151 Q_D(StatJob);
152
153 if (!d->m_redirectionURL.isEmpty() && d->m_redirectionURL.isValid()) {
154 // qCDebug(KIO_CORE) << "StatJob: Redirection to " << m_redirectionURL;
155 if (queryMetaData(QStringLiteral("permanent-redirect")) == QLatin1String("true")) {
156 Q_EMIT permanentRedirection(job: this, fromUrl: d->m_url, toUrl: d->m_redirectionURL);
157 }
158
159 if (d->m_redirectionHandlingEnabled) {
160 d->m_packedArgs.truncate(pos: 0);
161 QDataStream stream(&d->m_packedArgs, QIODevice::WriteOnly);
162 stream << d->m_redirectionURL;
163
164 d->restartAfterRedirection(redirectionUrl: &d->m_redirectionURL);
165 return;
166 }
167 }
168
169 // Return worker to the scheduler
170 SimpleJob::slotFinished();
171}
172
173static bool isUrlValid(const QUrl &url)
174{
175 if (!url.isValid()) {
176 qCWarning(KIO_CORE) << "Invalid url:" << url << ", cancelling job.";
177 return false;
178 }
179
180 if (url.isLocalFile()) {
181 qCWarning(KIO_CORE) << "Url" << url << "already represents a local file, cancelling job.";
182 return false;
183 }
184
185 if (KProtocolInfo::protocolClass(protocol: url.scheme()) != QLatin1String(":local")) {
186 qCWarning(KIO_CORE) << "Protocol Class of url" << url << ", isn't ':local', cancelling job.";
187 return false;
188 }
189
190 return true;
191}
192
193StatJob *KIO::mostLocalUrl(const QUrl &url, JobFlags flags)
194{
195 StatJob *job = stat(url, side: StatJob::SourceSide, details: KIO::StatDefaultDetails, flags);
196 if (!isUrlValid(url)) {
197 QTimer::singleShot(interval: 0, receiver: job, slot: &StatJob::slotFinished);
198 Scheduler::cancelJob(job); // deletes the worker if not 0
199 }
200 return job;
201}
202
203StatJob *KIO::stat(const QUrl &url, JobFlags flags)
204{
205 // Assume SourceSide. Gets are more common than puts.
206 return stat(url, side: StatJob::SourceSide, details: KIO::StatDefaultDetails, flags);
207}
208
209StatJob *KIO::stat(const QUrl &url, KIO::StatJob::StatSide side, KIO::StatDetails details, JobFlags flags)
210{
211 // qCDebug(KIO_CORE) << "stat" << url;
212 KIO_ARGS << url;
213 StatJob *job = StatJobPrivate::newJob(url, command: CMD_STAT, packedArgs, flags);
214 job->setSide(side);
215 job->setDetails(details);
216 return job;
217}
218
219#include "moc_statjob.cpp"
220

source code of kio/src/core/statjob.cpp