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 | * \a url the url of the job |
114 | * \a command the command of the job |
115 | * \a 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 | int m_schedSerial; |
149 | bool m_redirectionHandlingEnabled; |
150 | |
151 | void simpleJobInit(); |
152 | |
153 | /*! |
154 | * Called on a worker's connected signal. |
155 | * \sa connected() |
156 | */ |
157 | void slotConnected(); |
158 | /*! |
159 | * Forward signal from the worker. |
160 | * \a data_size the processed size in bytes |
161 | * \sa processedSize() |
162 | */ |
163 | void slotProcessedSize(KIO::filesize_t data_size); |
164 | /*! |
165 | * Forward signal from the worker. |
166 | * \a speed the speed in bytes/s |
167 | * \sa speed() |
168 | */ |
169 | void slotSpeed(unsigned long speed); |
170 | /*! |
171 | * Forward signal from the worker. |
172 | * Can also be called by the parent job, when it knows the size. |
173 | * \a data_size the total size |
174 | */ |
175 | void slotTotalSize(KIO::filesize_t data_size); |
176 | |
177 | /*! |
178 | * Called on a worker's info message. |
179 | * \a s the info message |
180 | * \sa infoMessage() |
181 | */ |
182 | void _k_slotWorkerInfoMessage(const QString &s); |
183 | |
184 | /*! |
185 | * Called when privilegeOperationRequested() is emitted by worker. |
186 | */ |
187 | void slotPrivilegeOperationRequested(); |
188 | |
189 | /*! |
190 | * \internal |
191 | * Called by the scheduler when a worker gets to |
192 | * work on this job. |
193 | **/ |
194 | virtual void start(KIO::Worker *worker); |
195 | |
196 | /*! |
197 | * \internal |
198 | * Called to detach a worker from a job. |
199 | **/ |
200 | void workerDone(); |
201 | |
202 | /*! |
203 | * Called by subclasses to restart the job after a redirection was signalled. |
204 | * The m_redirectionURL data member can appear in several subclasses, so we have it |
205 | * passed in. The regular URL will be set to the redirection URL which is then cleared. |
206 | */ |
207 | void restartAfterRedirection(QUrl *redirectionUrl); |
208 | |
209 | Q_DECLARE_PUBLIC(SimpleJob) |
210 | |
211 | static inline SimpleJobPrivate *get(KIO::SimpleJob *job) |
212 | { |
213 | return job->d_func(); |
214 | } |
215 | static inline SimpleJob *newJobNoUi(const QUrl &url, int command, const QByteArray &packedArgs) |
216 | { |
217 | SimpleJob *job = new SimpleJob(*new SimpleJobPrivate(url, command, packedArgs)); |
218 | return job; |
219 | } |
220 | static inline SimpleJob *newJob(const QUrl &url, int command, const QByteArray &packedArgs, JobFlags flags = HideProgressInfo) |
221 | { |
222 | SimpleJob *job = new SimpleJob(*new SimpleJobPrivate(url, command, packedArgs)); |
223 | job->setUiDelegate(KIO::createDefaultJobUiDelegate()); |
224 | if (!(flags & HideProgressInfo)) { |
225 | KIO::getJobTracker()->registerJob(job); |
226 | } |
227 | if (!(flags & NoPrivilegeExecution)) { |
228 | job->d_func()->m_privilegeExecutionEnabled = true; |
229 | // Only delete, rename and symlink operation accept JobFlags. |
230 | FileOperationType opType; |
231 | switch (command) { |
232 | case CMD_DEL: |
233 | opType = Delete; |
234 | break; |
235 | case CMD_RENAME: |
236 | opType = Rename; |
237 | break; |
238 | case CMD_SYMLINK: |
239 | opType = Symlink; |
240 | break; |
241 | default: |
242 | return job; |
243 | } |
244 | job->d_func()->m_operationType = opType; |
245 | } |
246 | return job; |
247 | } |
248 | }; |
249 | |
250 | class TransferJobPrivate : public SimpleJobPrivate |
251 | { |
252 | public: |
253 | inline TransferJobPrivate(const QUrl &url, int command, const QByteArray &packedArgs, const QByteArray &_staticData) |
254 | : SimpleJobPrivate(url, command, packedArgs) |
255 | , m_internalSuspended(false) |
256 | , staticData(_staticData) |
257 | , m_isMimetypeEmitted(false) |
258 | , m_closedBeforeStart(false) |
259 | { |
260 | } |
261 | |
262 | inline TransferJobPrivate(const QUrl &url, int command, const QByteArray &packedArgs, QIODevice *ioDevice) |
263 | : SimpleJobPrivate(url, command, packedArgs) |
264 | , m_internalSuspended(false) |
265 | , m_isMimetypeEmitted(false) |
266 | , m_closedBeforeStart(false) |
267 | , m_outgoingDataSource(QPointer<QIODevice>(ioDevice)) |
268 | { |
269 | } |
270 | |
271 | bool m_internalSuspended; |
272 | QByteArray staticData; |
273 | QUrl m_redirectionURL; |
274 | QList<QUrl> m_redirectionList; |
275 | QString m_mimetype; |
276 | bool m_isMimetypeEmitted; |
277 | bool m_closedBeforeStart; |
278 | QPointer<QIODevice> m_outgoingDataSource; |
279 | QMetaObject::Connection m_readChannelFinishedConnection; |
280 | |
281 | /*! |
282 | * Flow control. Suspend data processing from the worker. |
283 | */ |
284 | void internalSuspend(); |
285 | /*! |
286 | * Flow control. Resume data processing from the worker. |
287 | */ |
288 | void internalResume(); |
289 | /*! |
290 | * \internal |
291 | * Called by the scheduler when a worker gets to |
292 | * work on this job. |
293 | * \a worker the worker that works on the job |
294 | */ |
295 | void start(KIO::Worker *worker) override; |
296 | /*! |
297 | * \internal |
298 | * Called when the KIO worker needs the data to send the server. This slot |
299 | * is invoked when the data is to be sent is read from a QIODevice rather |
300 | * instead of a QByteArray buffer. |
301 | */ |
302 | virtual void slotDataReqFromDevice(); |
303 | void slotIODeviceClosed(); |
304 | void slotIODeviceClosedBeforeStart(); |
305 | void slotPostRedirection(); |
306 | |
307 | Q_DECLARE_PUBLIC(TransferJob) |
308 | static inline TransferJob *newJob(const QUrl &url, int command, const QByteArray &packedArgs, const QByteArray &_staticData, JobFlags flags) |
309 | { |
310 | TransferJob *job = new TransferJob(*new TransferJobPrivate(url, command, packedArgs, _staticData)); |
311 | job->setUiDelegate(KIO::createDefaultJobUiDelegate()); |
312 | if (!(flags & HideProgressInfo)) { |
313 | job->setFinishedNotificationHidden(); |
314 | KIO::getJobTracker()->registerJob(job); |
315 | } |
316 | if (!(flags & NoPrivilegeExecution)) { |
317 | job->d_func()->m_privilegeExecutionEnabled = true; |
318 | job->d_func()->m_operationType = Transfer; |
319 | } |
320 | return job; |
321 | } |
322 | |
323 | static inline TransferJob *newJob(const QUrl &url, int command, const QByteArray &packedArgs, QIODevice *ioDevice, JobFlags flags) |
324 | { |
325 | TransferJob *job = new TransferJob(*new TransferJobPrivate(url, command, packedArgs, ioDevice)); |
326 | job->setUiDelegate(KIO::createDefaultJobUiDelegate()); |
327 | if (!(flags & HideProgressInfo)) { |
328 | job->setFinishedNotificationHidden(); |
329 | KIO::getJobTracker()->registerJob(job); |
330 | } |
331 | if (!(flags & NoPrivilegeExecution)) { |
332 | job->d_func()->m_privilegeExecutionEnabled = true; |
333 | job->d_func()->m_operationType = Transfer; |
334 | } |
335 | return job; |
336 | } |
337 | }; |
338 | |
339 | class DirectCopyJobPrivate; |
340 | /*! |
341 | * \internal |
342 | * Used for direct copy from or to the local filesystem (i.e.\ WorkerBase::copy()) |
343 | */ |
344 | class DirectCopyJob : public SimpleJob |
345 | { |
346 | Q_OBJECT |
347 | |
348 | public: |
349 | DirectCopyJob(const QUrl &url, const QByteArray &packedArgs); |
350 | ~DirectCopyJob() override; |
351 | |
352 | public Q_SLOTS: |
353 | void slotCanResume(KIO::filesize_t offset); |
354 | |
355 | Q_SIGNALS: |
356 | /*! |
357 | * \internal |
358 | * Emitted if the job found an existing partial file |
359 | * and supports resuming. Used by FileCopyJob. |
360 | */ |
361 | void canResume(KIO::Job *job, KIO::filesize_t offset); |
362 | |
363 | private: |
364 | Q_DECLARE_PRIVATE(DirectCopyJob) |
365 | }; |
366 | } |
367 | |
368 | #endif |
369 | |