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
36namespace KIO
37{
38static constexpr filesize_t invalidFilesize = static_cast<KIO::filesize_t>(-1);
39
40// Exported for KIOWidgets jobs
41class KIOCORE_EXPORT JobPrivate
42{
43public:
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 m_extraFlags;
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
108class SimpleJobPrivate : public JobPrivate
109{
110public:
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
250class TransferJobPrivate : public SimpleJobPrivate
251{
252public:
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
339class DirectCopyJobPrivate;
340/*!
341 * \internal
342 * Used for direct copy from or to the local filesystem (i.e.\ WorkerBase::copy())
343 */
344class DirectCopyJob : public SimpleJob
345{
346 Q_OBJECT
347
348public:
349 DirectCopyJob(const QUrl &url, const QByteArray &packedArgs);
350 ~DirectCopyJob() override;
351
352public Q_SLOTS:
353 void slotCanResume(KIO::filesize_t offset);
354
355Q_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
363private:
364 Q_DECLARE_PRIVATE(DirectCopyJob)
365};
366}
367
368#endif
369

source code of kio/src/core/job_p.h