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 | |
18 | using namespace KIO; |
19 | |
20 | class KIO::StatJobPrivate : public SimpleJobPrivate |
21 | { |
22 | public: |
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 | |
60 | StatJob::StatJob(StatJobPrivate &dd) |
61 | : SimpleJob(dd) |
62 | { |
63 | setTotalAmount(unit: Items, amount: 1); |
64 | } |
65 | |
66 | StatJob::~StatJob() |
67 | { |
68 | } |
69 | |
70 | void StatJob::setSide(StatSide side) |
71 | { |
72 | d_func()->m_bSource = side == SourceSide; |
73 | } |
74 | |
75 | void StatJob::setDetails(KIO::StatDetails details) |
76 | { |
77 | d_func()->m_details = details; |
78 | } |
79 | |
80 | const UDSEntry &StatJob::statResult() const |
81 | { |
82 | return d_func()->m_statResult; |
83 | } |
84 | |
85 | QUrl 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 | |
111 | void 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 | |
127 | void StatJobPrivate::slotStatEntry(const KIO::UDSEntry &entry) |
128 | { |
129 | // qCDebug(KIO_CORE); |
130 | m_statResult = entry; |
131 | } |
132 | |
133 | // Worker got a redirection request |
134 | void 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 | |
149 | void 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 | |
173 | static 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 | |
193 | StatJob *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 | |
203 | StatJob *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 | |
209 | StatJob *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 | |