File indexing completed on 2024-04-28 11:40:57

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2000 Stephan Kulow <coolo@kde.org>
0004     SPDX-FileCopyrightText: 2000-2009 David Faure <faure@kde.org>
0005     SPDX-FileCopyrightText: 2000-2009 Waldo Bastian <bastian@kde.org>
0006     SPDX-FileCopyrightText: 2007 Thiago Macieira <thiago@kde.org>
0007     SPDX-FileCopyrightText: 2013 Dawit Alemayehu <adawit@kde.org>
0008 
0009     SPDX-License-Identifier: LGPL-2.0-or-later
0010 */
0011 
0012 #ifndef KIO_JOB_P_H
0013 #define KIO_JOB_P_H
0014 
0015 #include "commands_p.h"
0016 #include "global.h"
0017 #include "kiocoredebug.h"
0018 #include "simplejob.h"
0019 #include "slave.h"
0020 #include "transferjob.h"
0021 #include <KJobTrackerInterface>
0022 #include <QDataStream>
0023 #include <QPointer>
0024 #include <QUrl>
0025 #include <kio/jobuidelegateextension.h>
0026 #include <kio/jobuidelegatefactory.h>
0027 
0028 /* clang-format off */
0029 #define KIO_ARGS \
0030     QByteArray packedArgs; \
0031     QDataStream stream(&packedArgs, QIODevice::WriteOnly); \
0032     stream
0033 /* clang-format on */
0034 
0035 namespace KIO
0036 {
0037 static constexpr filesize_t invalidFilesize = static_cast<KIO::filesize_t>(-1);
0038 
0039 // Exported for KIOWidgets jobs
0040 class KIOCORE_EXPORT JobPrivate
0041 {
0042 public:
0043     JobPrivate()
0044         : m_parentJob(nullptr)
0045         , m_extraFlags(0)
0046         , m_uiDelegateExtension(KIO::defaultJobUiDelegateExtension())
0047         , m_privilegeExecutionEnabled(false)
0048     {
0049     }
0050 
0051     virtual ~JobPrivate();
0052 
0053     /**
0054      * Some extra storage space for jobs that don't have their own
0055      * private d pointer.
0056      */
0057     enum {
0058         EF_TransferJobAsync = (1 << 0),
0059         EF_TransferJobNeedData = (1 << 1),
0060         EF_TransferJobDataSent = (1 << 2),
0061         EF_ListJobUnrestricted = (1 << 3),
0062         EF_KillCalled = (1 << 4),
0063     };
0064 
0065     enum FileOperationType {
0066         ChangeAttr, // chmod(), chown(), setModificationTime()
0067         Copy,
0068         Delete,
0069         MkDir,
0070         Move,
0071         Rename,
0072         Symlink,
0073         Transfer, // put() and get()
0074         Other, // if other file operation set message, title inside the job.
0075     };
0076 
0077     // Maybe we could use the QObject parent/child mechanism instead
0078     // (requires a new ctor, and moving the ctor code to some init()).
0079     Job *m_parentJob;
0080     int m_extraFlags;
0081     MetaData m_incomingMetaData;
0082     MetaData m_internalMetaData;
0083     MetaData m_outgoingMetaData;
0084     JobUiDelegateExtension *m_uiDelegateExtension;
0085     Job *q_ptr;
0086     // For privilege operation
0087     bool m_privilegeExecutionEnabled;
0088     QString m_title, m_message;
0089     FileOperationType m_operationType;
0090 
0091     QByteArray privilegeOperationData();
0092     void slotSpeed(KJob *job, unsigned long speed);
0093 
0094     static void emitMoving(KIO::Job *, const QUrl &src, const QUrl &dest);
0095     static void emitRenaming(KIO::Job *, const QUrl &src, const QUrl &dest);
0096     static void emitCopying(KIO::Job *, const QUrl &src, const QUrl &dest);
0097     static void emitCreatingDir(KIO::Job *, const QUrl &dir);
0098     static void emitDeleting(KIO::Job *, const QUrl &url);
0099     static void emitStating(KIO::Job *, const QUrl &url);
0100     static void emitTransferring(KIO::Job *, const QUrl &url);
0101     static void emitMounting(KIO::Job *, const QString &dev, const QString &point);
0102     static void emitUnmounting(KIO::Job *, const QString &point);
0103 
0104     Q_DECLARE_PUBLIC(Job)
0105 };
0106 
0107 class SimpleJobPrivate : public JobPrivate
0108 {
0109 public:
0110     /**
0111      * Creates a new simple job.
0112      * @param url the url of the job
0113      * @param command the command of the job
0114      * @param packedArgs the arguments
0115      */
0116     SimpleJobPrivate(const QUrl &url, int command, const QByteArray &packedArgs)
0117         : m_slave(nullptr)
0118         , m_packedArgs(packedArgs)
0119         , m_url(url)
0120         , m_command(command)
0121         , m_schedSerial(0)
0122         , m_redirectionHandlingEnabled(true)
0123     {
0124     }
0125 
0126     QPointer<Slave> m_slave;
0127     QByteArray m_packedArgs;
0128     QUrl m_url;
0129     QUrl m_subUrl; // TODO KF6 remove
0130     int m_command;
0131 
0132     // for use in KIO::Scheduler
0133     //
0134     // There are two kinds of protocol:
0135     // (1) The protocol of the url
0136     // (2) The actual protocol that the KIO worker uses.
0137     //
0138     // These two often match, but not necessarily. Most notably, they don't
0139     // match when doing ftp via a proxy.
0140     // In that case (1) is ftp, but (2) is http.
0141     //
0142     // JobData::protocol stores (2) while Job::url().protocol() returns (1).
0143     // The ProtocolInfoDict is indexed with (2).
0144     //
0145     // We schedule workers based on (2) but tell the worker about (1) via
0146     // Slave::setProtocol().
0147     QString m_protocol;
0148     QStringList m_proxyList;
0149     int m_schedSerial;
0150     bool m_redirectionHandlingEnabled;
0151 
0152     void simpleJobInit();
0153 
0154     /**
0155      * Called on a slave's connected signal.
0156      * @see connected()
0157      */
0158     void slotConnected();
0159     /**
0160      * Forward signal from the slave.
0161      * @param data_size the processed size in bytes
0162      * @see processedSize()
0163      */
0164     void slotProcessedSize(KIO::filesize_t data_size);
0165     /**
0166      * Forward signal from the slave.
0167      * @param speed the speed in bytes/s
0168      * @see speed()
0169      */
0170     void slotSpeed(unsigned long speed);
0171     /**
0172      * Forward signal from the slave
0173      * Can also be called by the parent job, when it knows the size.
0174      * @param data_size the total size
0175      */
0176     void slotTotalSize(KIO::filesize_t data_size);
0177 
0178     /**
0179      * Called on a slave's info message.
0180      * @param s the info message
0181      * @see infoMessage()
0182      */
0183     void _k_slotSlaveInfoMessage(const QString &s);
0184 
0185     /**
0186      * Called when privilegeOperationRequested() is emitted by slave.
0187      */
0188     void slotPrivilegeOperationRequested();
0189 
0190     /**
0191      * @internal
0192      * Called by the scheduler when a slave gets to
0193      * work on this job.
0194      **/
0195     virtual void start(KIO::Slave *slave);
0196 
0197     /**
0198      * @internal
0199      * Called to detach a slave from a job.
0200      **/
0201     void slaveDone();
0202 
0203     /**
0204      * Called by subclasses to restart the job after a redirection was signalled.
0205      * The m_redirectionURL data member can appear in several subclasses, so we have it
0206      * passed in. The regular URL will be set to the redirection URL which is then cleared.
0207      */
0208     void restartAfterRedirection(QUrl *redirectionUrl);
0209 
0210     Q_DECLARE_PUBLIC(SimpleJob)
0211 
0212     static inline SimpleJobPrivate *get(KIO::SimpleJob *job)
0213     {
0214         return job->d_func();
0215     }
0216     static inline SimpleJob *newJobNoUi(const QUrl &url, int command, const QByteArray &packedArgs)
0217     {
0218         SimpleJob *job = new SimpleJob(*new SimpleJobPrivate(url, command, packedArgs));
0219         return job;
0220     }
0221     static inline SimpleJob *newJob(const QUrl &url, int command, const QByteArray &packedArgs, JobFlags flags = HideProgressInfo)
0222     {
0223         SimpleJob *job = new SimpleJob(*new SimpleJobPrivate(url, command, packedArgs));
0224         job->setUiDelegate(KIO::createDefaultJobUiDelegate());
0225         if (!(flags & HideProgressInfo)) {
0226             KIO::getJobTracker()->registerJob(job);
0227         }
0228         if (!(flags & NoPrivilegeExecution)) {
0229             job->d_func()->m_privilegeExecutionEnabled = true;
0230             // Only delete, rename and symlink operation accept JobFlags.
0231             FileOperationType opType;
0232             switch (command) {
0233             case CMD_DEL:
0234                 opType = Delete;
0235                 break;
0236             case CMD_RENAME:
0237                 opType = Rename;
0238                 break;
0239             case CMD_SYMLINK:
0240                 opType = Symlink;
0241                 break;
0242             default:
0243                 return job;
0244             }
0245             job->d_func()->m_operationType = opType;
0246         }
0247         return job;
0248     }
0249 };
0250 
0251 class TransferJobPrivate : public SimpleJobPrivate
0252 {
0253 public:
0254     inline TransferJobPrivate(const QUrl &url, int command, const QByteArray &packedArgs, const QByteArray &_staticData)
0255         : SimpleJobPrivate(url, command, packedArgs)
0256         , m_internalSuspended(false)
0257         , m_errorPage(false)
0258         , staticData(_staticData)
0259         , m_isMimetypeEmitted(false)
0260         , m_closedBeforeStart(false)
0261         , m_subJob(nullptr)
0262     {
0263     }
0264 
0265     inline TransferJobPrivate(const QUrl &url, int command, const QByteArray &packedArgs, QIODevice *ioDevice)
0266         : SimpleJobPrivate(url, command, packedArgs)
0267         , m_internalSuspended(false)
0268         , m_errorPage(false)
0269         , m_isMimetypeEmitted(false)
0270         , m_closedBeforeStart(false)
0271         , m_subJob(nullptr)
0272         , m_outgoingDataSource(QPointer<QIODevice>(ioDevice))
0273     {
0274     }
0275 
0276     bool m_internalSuspended;
0277     bool m_errorPage;
0278     QByteArray staticData;
0279     QUrl m_redirectionURL;
0280     QList<QUrl> m_redirectionList;
0281     QString m_mimetype;
0282     bool m_isMimetypeEmitted;
0283     bool m_closedBeforeStart;
0284     TransferJob *m_subJob;
0285     QPointer<QIODevice> m_outgoingDataSource;
0286     QMetaObject::Connection m_readChannelFinishedConnection;
0287 
0288     /**
0289      * Flow control. Suspend data processing from the slave.
0290      */
0291     void internalSuspend();
0292     /**
0293      * Flow control. Resume data processing from the slave.
0294      */
0295     void internalResume();
0296     /**
0297      * @internal
0298      * Called by the scheduler when a slave gets to
0299      * work on this job.
0300      * @param slave the slave that works on the job
0301      */
0302     void start(KIO::Slave *slave) override;
0303     /**
0304      * @internal
0305      * Called when the KIO worker needs the data to send the server. This slot
0306      * is invoked when the data is to be sent is read from a QIODevice rather
0307      * instead of a QByteArray buffer.
0308      */
0309     virtual void slotDataReqFromDevice();
0310     void slotIODeviceClosed();
0311     void slotIODeviceClosedBeforeStart();
0312     void slotPostRedirection();
0313     void slotNeedSubUrlData();
0314     void slotSubUrlData(KIO::Job *, const QByteArray &);
0315 
0316     Q_DECLARE_PUBLIC(TransferJob)
0317     static inline TransferJob *newJob(const QUrl &url, int command, const QByteArray &packedArgs, const QByteArray &_staticData, JobFlags flags)
0318     {
0319         TransferJob *job = new TransferJob(*new TransferJobPrivate(url, command, packedArgs, _staticData));
0320         job->setUiDelegate(KIO::createDefaultJobUiDelegate());
0321         if (!(flags & HideProgressInfo)) {
0322             job->setFinishedNotificationHidden();
0323             KIO::getJobTracker()->registerJob(job);
0324         }
0325         if (!(flags & NoPrivilegeExecution)) {
0326             job->d_func()->m_privilegeExecutionEnabled = true;
0327             job->d_func()->m_operationType = Transfer;
0328         }
0329         return job;
0330     }
0331 
0332     static inline TransferJob *newJob(const QUrl &url, int command, const QByteArray &packedArgs, QIODevice *ioDevice, JobFlags flags)
0333     {
0334         TransferJob *job = new TransferJob(*new TransferJobPrivate(url, command, packedArgs, ioDevice));
0335         job->setUiDelegate(KIO::createDefaultJobUiDelegate());
0336         if (!(flags & HideProgressInfo)) {
0337             job->setFinishedNotificationHidden();
0338             KIO::getJobTracker()->registerJob(job);
0339         }
0340         if (!(flags & NoPrivilegeExecution)) {
0341             job->d_func()->m_privilegeExecutionEnabled = true;
0342             job->d_func()->m_operationType = Transfer;
0343         }
0344         return job;
0345     }
0346 };
0347 
0348 class DirectCopyJobPrivate;
0349 /**
0350  * @internal
0351  * Used for direct copy from or to the local filesystem (i.e.\ WorkerBase::copy())
0352  */
0353 class DirectCopyJob : public SimpleJob
0354 {
0355     Q_OBJECT
0356 
0357 public:
0358     DirectCopyJob(const QUrl &url, const QByteArray &packedArgs);
0359     ~DirectCopyJob() override;
0360 
0361 public Q_SLOTS:
0362     void slotCanResume(KIO::filesize_t offset);
0363 
0364 Q_SIGNALS:
0365     /**
0366      * @internal
0367      * Emitted if the job found an existing partial file
0368      * and supports resuming. Used by FileCopyJob.
0369      */
0370     void canResume(KIO::Job *job, KIO::filesize_t offset);
0371 
0372 private:
0373     Q_DECLARE_PRIVATE(DirectCopyJob)
0374 };
0375 }
0376 
0377 #endif