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