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 | SPDX-FileCopyrightText: 2000-2009 Waldo Bastian <bastian@kde.org> |
6 | SPDX-FileCopyrightText: 2007 Thiago Macieira <thiago@kde.org> |
7 | SPDX-FileCopyrightText: 2013 Dawit Alemayehu <adawit@kde.org> |
8 | |
9 | SPDX-License-Identifier: LGPL-2.0-or-later |
10 | */ |
11 | |
12 | #ifndef KIO_JOB_P_H |
13 | #define KIO_JOB_P_H |
14 | |
15 | #include "commands_p.h" |
16 | #include "global.h" |
17 | #include "jobtracker.h" |
18 | #include "kiocoredebug.h" |
19 | #include "simplejob.h" |
20 | #include "transferjob.h" |
21 | #include "worker_p.h" |
22 | #include <KJobTrackerInterface> |
23 | #include <QDataStream> |
24 | #include <QPointer> |
25 | #include <QUrl> |
26 | #include <kio/jobuidelegateextension.h> |
27 | #include <kio/jobuidelegatefactory.h> |
28 | |
29 | /* clang-format off */ |
30 | #define KIO_ARGS \ |
31 | QByteArray packedArgs; \ |
32 | QDataStream stream(&packedArgs, QIODevice::WriteOnly); \ |
33 | stream |
34 | /* clang-format on */ |
35 | |
36 | namespace KIO |
37 | { |
38 | static constexpr filesize_t invalidFilesize = static_cast<KIO::filesize_t>(-1); |
39 | |
40 | // Exported for KIOWidgets jobs |
41 | class KIOCORE_EXPORT JobPrivate |
42 | { |
43 | public: |
44 | JobPrivate() |
45 | : m_parentJob(nullptr) |
46 | , m_extraFlags(0) |
47 | , m_uiDelegateExtension(KIO::defaultJobUiDelegateExtension()) |
48 | , m_privilegeExecutionEnabled(false) |
49 | { |
50 | } |
51 | |
52 | virtual ~JobPrivate(); |
53 | |
54 | /** |
55 | * Some extra storage space for jobs that don't have their own |
56 | * private d pointer. |
57 | */ |
58 | enum { |
59 | EF_TransferJobAsync = (1 << 0), |
60 | EF_TransferJobNeedData = (1 << 1), |
61 | EF_TransferJobDataSent = (1 << 2), |
62 | EF_ListJobUnrestricted = (1 << 3), |
63 | EF_KillCalled = (1 << 4), |
64 | }; |
65 | |
66 | enum FileOperationType { |
67 | ChangeAttr, // chmod(), chown(), setModificationTime() |
68 | Copy, |
69 | Delete, |
70 | MkDir, |
71 | Move, |
72 | Rename, |
73 | Symlink, |
74 | Transfer, // put() and get() |
75 | Other, // if other file operation set message, title inside the job. |
76 | }; |
77 | |
78 | // Maybe we could use the QObject parent/child mechanism instead |
79 | // (requires a new ctor, and moving the ctor code to some init()). |
80 | Job *m_parentJob; |
81 | int ; |
82 | MetaData m_incomingMetaData; |
83 | MetaData m_internalMetaData; |
84 | MetaData m_outgoingMetaData; |
85 | JobUiDelegateExtension *m_uiDelegateExtension; |
86 | Job *q_ptr; |
87 | // For privilege operation |
88 | bool m_privilegeExecutionEnabled; |
89 | QString m_title, m_message; |
90 | FileOperationType m_operationType; |
91 | |
92 | QByteArray privilegeOperationData(); |
93 | void slotSpeed(KJob *job, unsigned long speed); |
94 | |
95 | static void emitMoving(KIO::Job *, const QUrl &src, const QUrl &dest); |
96 | static void emitRenaming(KIO::Job *, const QUrl &src, const QUrl &dest); |
97 | static void emitCopying(KIO::Job *, const QUrl &src, const QUrl &dest); |
98 | static void emitCreatingDir(KIO::Job *, const QUrl &dir); |
99 | static void emitDeleting(KIO::Job *, const QUrl &url); |
100 | static void emitStating(KIO::Job *, const QUrl &url); |
101 | static void emitTransferring(KIO::Job *, const QUrl &url); |
102 | static void emitMounting(KIO::Job *, const QString &dev, const QString &point); |
103 | static void emitUnmounting(KIO::Job *, const QString &point); |
104 | |
105 | Q_DECLARE_PUBLIC(Job) |
106 | }; |
107 | |
108 | class SimpleJobPrivate : public JobPrivate |
109 | { |
110 | public: |
111 | /** |
112 | * Creates a new simple job. |
113 | * @param url the url of the job |
114 | * @param command the command of the job |
115 | * @param packedArgs the arguments |
116 | */ |
117 | SimpleJobPrivate(const QUrl &url, int command, const QByteArray &packedArgs) |
118 | : m_worker(nullptr) |
119 | , m_packedArgs(packedArgs) |
120 | , m_url(url) |
121 | , m_command(command) |
122 | , m_schedSerial(0) |
123 | , m_redirectionHandlingEnabled(true) |
124 | { |
125 | } |
126 | |
127 | QPointer<Worker> m_worker; |
128 | QByteArray m_packedArgs; |
129 | QUrl m_url; |
130 | int m_command; |
131 | |
132 | // for use in KIO::Scheduler |
133 | // |
134 | // There are two kinds of protocol: |
135 | // (1) The protocol of the url |
136 | // (2) The actual protocol that the KIO worker uses. |
137 | // |
138 | // These two often match, but not necessarily. Most notably, they don't |
139 | // match when doing ftp via a proxy. |
140 | // In that case (1) is ftp, but (2) is http. |
141 | // |
142 | // JobData::protocol stores (2) while Job::url().protocol() returns (1). |
143 | // The ProtocolInfoDict is indexed with (2). |
144 | // |
145 | // We schedule workers based on (2) but tell the worker about (1) via |
146 | // Worker::setProtocol(). |
147 | QString m_protocol; |
148 | QStringList m_proxyList; |
149 | int m_schedSerial; |
150 | bool m_redirectionHandlingEnabled; |
151 | |
152 | void simpleJobInit(); |
153 | |
154 | /** |
155 | * Called on a worker's connected signal. |
156 | * @see connected() |
157 | */ |
158 | void slotConnected(); |
159 | /** |
160 | * Forward signal from the worker. |
161 | * @param data_size the processed size in bytes |
162 | * @see processedSize() |
163 | */ |
164 | void slotProcessedSize(KIO::filesize_t data_size); |
165 | /** |
166 | * Forward signal from the worker. |
167 | * @param speed the speed in bytes/s |
168 | * @see speed() |
169 | */ |
170 | void slotSpeed(unsigned long speed); |
171 | /** |
172 | * Forward signal from the worker. |
173 | * Can also be called by the parent job, when it knows the size. |
174 | * @param data_size the total size |
175 | */ |
176 | void slotTotalSize(KIO::filesize_t data_size); |
177 | |
178 | /** |
179 | * Called on a worker's info message. |
180 | * @param s the info message |
181 | * @see infoMessage() |
182 | */ |
183 | void _k_slotWorkerInfoMessage(const QString &s); |
184 | |
185 | /** |
186 | * Called when privilegeOperationRequested() is emitted by worker. |
187 | */ |
188 | void slotPrivilegeOperationRequested(); |
189 | |
190 | /** |
191 | * @internal |
192 | * Called by the scheduler when a worker gets to |
193 | * work on this job. |
194 | **/ |
195 | virtual void start(KIO::Worker *worker); |
196 | |
197 | /** |
198 | * @internal |
199 | * Called to detach a worker from a job. |
200 | **/ |
201 | void workerDone(); |
202 | |
203 | /** |
204 | * Called by subclasses to restart the job after a redirection was signalled. |
205 | * The m_redirectionURL data member can appear in several subclasses, so we have it |
206 | * passed in. The regular URL will be set to the redirection URL which is then cleared. |
207 | */ |
208 | void restartAfterRedirection(QUrl *redirectionUrl); |
209 | |
210 | Q_DECLARE_PUBLIC(SimpleJob) |
211 | |
212 | static inline SimpleJobPrivate *get(KIO::SimpleJob *job) |
213 | { |
214 | return job->d_func(); |
215 | } |
216 | static inline SimpleJob *newJobNoUi(const QUrl &url, int command, const QByteArray &packedArgs) |
217 | { |
218 | SimpleJob *job = new SimpleJob(*new SimpleJobPrivate(url, command, packedArgs)); |
219 | return job; |
220 | } |
221 | static inline SimpleJob *newJob(const QUrl &url, int command, const QByteArray &packedArgs, JobFlags flags = HideProgressInfo) |
222 | { |
223 | SimpleJob *job = new SimpleJob(*new SimpleJobPrivate(url, command, packedArgs)); |
224 | job->setUiDelegate(KIO::createDefaultJobUiDelegate()); |
225 | if (!(flags & HideProgressInfo)) { |
226 | KIO::getJobTracker()->registerJob(job); |
227 | } |
228 | if (!(flags & NoPrivilegeExecution)) { |
229 | job->d_func()->m_privilegeExecutionEnabled = true; |
230 | // Only delete, rename and symlink operation accept JobFlags. |
231 | FileOperationType opType; |
232 | switch (command) { |
233 | case CMD_DEL: |
234 | opType = Delete; |
235 | break; |
236 | case CMD_RENAME: |
237 | opType = Rename; |
238 | break; |
239 | case CMD_SYMLINK: |
240 | opType = Symlink; |
241 | break; |
242 | default: |
243 | return job; |
244 | } |
245 | job->d_func()->m_operationType = opType; |
246 | } |
247 | return job; |
248 | } |
249 | }; |
250 | |
251 | class TransferJobPrivate : public SimpleJobPrivate |
252 | { |
253 | public: |
254 | inline TransferJobPrivate(const QUrl &url, int command, const QByteArray &packedArgs, const QByteArray &_staticData) |
255 | : SimpleJobPrivate(url, command, packedArgs) |
256 | , m_internalSuspended(false) |
257 | , m_errorPage(false) |
258 | , staticData(_staticData) |
259 | , m_isMimetypeEmitted(false) |
260 | , m_closedBeforeStart(false) |
261 | { |
262 | } |
263 | |
264 | inline TransferJobPrivate(const QUrl &url, int command, const QByteArray &packedArgs, QIODevice *ioDevice) |
265 | : SimpleJobPrivate(url, command, packedArgs) |
266 | , m_internalSuspended(false) |
267 | , m_errorPage(false) |
268 | , m_isMimetypeEmitted(false) |
269 | , m_closedBeforeStart(false) |
270 | , m_outgoingDataSource(QPointer<QIODevice>(ioDevice)) |
271 | { |
272 | } |
273 | |
274 | bool m_internalSuspended; |
275 | bool m_errorPage; |
276 | QByteArray staticData; |
277 | QUrl m_redirectionURL; |
278 | QList<QUrl> m_redirectionList; |
279 | QString m_mimetype; |
280 | bool m_isMimetypeEmitted; |
281 | bool m_closedBeforeStart; |
282 | QPointer<QIODevice> m_outgoingDataSource; |
283 | QMetaObject::Connection m_readChannelFinishedConnection; |
284 | |
285 | /** |
286 | * Flow control. Suspend data processing from the worker. |
287 | */ |
288 | void internalSuspend(); |
289 | /** |
290 | * Flow control. Resume data processing from the worker. |
291 | */ |
292 | void internalResume(); |
293 | /** |
294 | * @internal |
295 | * Called by the scheduler when a worker gets to |
296 | * work on this job. |
297 | * @param worker the worker that works on the job |
298 | */ |
299 | void start(KIO::Worker *worker) override; |
300 | /** |
301 | * @internal |
302 | * Called when the KIO worker needs the data to send the server. This slot |
303 | * is invoked when the data is to be sent is read from a QIODevice rather |
304 | * instead of a QByteArray buffer. |
305 | */ |
306 | virtual void slotDataReqFromDevice(); |
307 | void slotIODeviceClosed(); |
308 | void slotIODeviceClosedBeforeStart(); |
309 | void slotPostRedirection(); |
310 | |
311 | Q_DECLARE_PUBLIC(TransferJob) |
312 | static inline TransferJob *newJob(const QUrl &url, int command, const QByteArray &packedArgs, const QByteArray &_staticData, JobFlags flags) |
313 | { |
314 | TransferJob *job = new TransferJob(*new TransferJobPrivate(url, command, packedArgs, _staticData)); |
315 | job->setUiDelegate(KIO::createDefaultJobUiDelegate()); |
316 | if (!(flags & HideProgressInfo)) { |
317 | job->setFinishedNotificationHidden(); |
318 | KIO::getJobTracker()->registerJob(job); |
319 | } |
320 | if (!(flags & NoPrivilegeExecution)) { |
321 | job->d_func()->m_privilegeExecutionEnabled = true; |
322 | job->d_func()->m_operationType = Transfer; |
323 | } |
324 | return job; |
325 | } |
326 | |
327 | static inline TransferJob *newJob(const QUrl &url, int command, const QByteArray &packedArgs, QIODevice *ioDevice, JobFlags flags) |
328 | { |
329 | TransferJob *job = new TransferJob(*new TransferJobPrivate(url, command, packedArgs, ioDevice)); |
330 | job->setUiDelegate(KIO::createDefaultJobUiDelegate()); |
331 | if (!(flags & HideProgressInfo)) { |
332 | job->setFinishedNotificationHidden(); |
333 | KIO::getJobTracker()->registerJob(job); |
334 | } |
335 | if (!(flags & NoPrivilegeExecution)) { |
336 | job->d_func()->m_privilegeExecutionEnabled = true; |
337 | job->d_func()->m_operationType = Transfer; |
338 | } |
339 | return job; |
340 | } |
341 | }; |
342 | |
343 | class DirectCopyJobPrivate; |
344 | /** |
345 | * @internal |
346 | * Used for direct copy from or to the local filesystem (i.e.\ WorkerBase::copy()) |
347 | */ |
348 | class DirectCopyJob : public SimpleJob |
349 | { |
350 | Q_OBJECT |
351 | |
352 | public: |
353 | DirectCopyJob(const QUrl &url, const QByteArray &packedArgs); |
354 | ~DirectCopyJob() override; |
355 | |
356 | public Q_SLOTS: |
357 | void slotCanResume(KIO::filesize_t offset); |
358 | |
359 | Q_SIGNALS: |
360 | /** |
361 | * @internal |
362 | * Emitted if the job found an existing partial file |
363 | * and supports resuming. Used by FileCopyJob. |
364 | */ |
365 | void canResume(KIO::Job *job, KIO::filesize_t offset); |
366 | |
367 | private: |
368 | Q_DECLARE_PRIVATE(DirectCopyJob) |
369 | }; |
370 | } |
371 | |
372 | #endif |
373 | |