File indexing completed on 2024-12-01 03:40:38

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 "jobtracker.h"
0018 #include "kiocoredebug.h"
0019 #include "simplejob.h"
0020 #include "transferjob.h"
0021 #include "worker_p.h"
0022 #include <KJobTrackerInterface>
0023 #include <QDataStream>
0024 #include <QPointer>
0025 #include <QUrl>
0026 #include <kio/jobuidelegateextension.h>
0027 #include <kio/jobuidelegatefactory.h>
0028 
0029 /* clang-format off */
0030 #define KIO_ARGS \
0031     QByteArray packedArgs; \
0032     QDataStream stream(&packedArgs, QIODevice::WriteOnly); \
0033     stream
0034 /* clang-format on */
0035 
0036 namespace KIO
0037 {
0038 static constexpr filesize_t invalidFilesize = static_cast<KIO::filesize_t>(-1);
0039 
0040 // Exported for KIOWidgets jobs
0041 class KIOCORE_EXPORT JobPrivate
0042 {
0043 public:
0044     JobPrivate()
0045         : m_parentJob(nullptr)
0046         , m_extraFlags(0)
0047         , m_uiDelegateExtension(KIO::defaultJobUiDelegateExtension())
0048         , m_privilegeExecutionEnabled(false)
0049     {
0050     }
0051 
0052     virtual ~JobPrivate();
0053 
0054     /**
0055      * Some extra storage space for jobs that don't have their own
0056      * private d pointer.
0057      */
0058     enum {
0059         EF_TransferJobAsync = (1 << 0),
0060         EF_TransferJobNeedData = (1 << 1),
0061         EF_TransferJobDataSent = (1 << 2),
0062         EF_ListJobUnrestricted = (1 << 3),
0063         EF_KillCalled = (1 << 4),
0064     };
0065 
0066     enum FileOperationType {
0067         ChangeAttr, // chmod(), chown(), setModificationTime()
0068         Copy,
0069         Delete,
0070         MkDir,
0071         Move,
0072         Rename,
0073         Symlink,
0074         Transfer, // put() and get()
0075         Other, // if other file operation set message, title inside the job.
0076     };
0077 
0078     // Maybe we could use the QObject parent/child mechanism instead
0079     // (requires a new ctor, and moving the ctor code to some init()).
0080     Job *m_parentJob;
0081     int m_extraFlags;
0082     MetaData m_incomingMetaData;
0083     MetaData m_internalMetaData;
0084     MetaData m_outgoingMetaData;
0085     JobUiDelegateExtension *m_uiDelegateExtension;
0086     Job *q_ptr;
0087     // For privilege operation
0088     bool m_privilegeExecutionEnabled;
0089     QString m_title, m_message;
0090     FileOperationType m_operationType;
0091 
0092     QByteArray privilegeOperationData();
0093     void slotSpeed(KJob *job, unsigned long speed);
0094 
0095     static void emitMoving(KIO::Job *, const QUrl &src, const QUrl &dest);
0096     static void emitRenaming(KIO::Job *, const QUrl &src, const QUrl &dest);
0097     static void emitCopying(KIO::Job *, const QUrl &src, const QUrl &dest);
0098     static void emitCreatingDir(KIO::Job *, const QUrl &dir);
0099     static void emitDeleting(KIO::Job *, const QUrl &url);
0100     static void emitStating(KIO::Job *, const QUrl &url);
0101     static void emitTransferring(KIO::Job *, const QUrl &url);
0102     static void emitMounting(KIO::Job *, const QString &dev, const QString &point);
0103     static void emitUnmounting(KIO::Job *, const QString &point);
0104 
0105     Q_DECLARE_PUBLIC(Job)
0106 };
0107 
0108 class SimpleJobPrivate : public JobPrivate
0109 {
0110 public:
0111     /**
0112      * Creates a new simple job.
0113      * @param url the url of the job
0114      * @param command the command of the job
0115      * @param packedArgs the arguments
0116      */
0117     SimpleJobPrivate(const QUrl &url, int command, const QByteArray &packedArgs)
0118         : m_worker(nullptr)
0119         , m_packedArgs(packedArgs)
0120         , m_url(url)
0121         , m_command(command)
0122         , m_schedSerial(0)
0123         , m_redirectionHandlingEnabled(true)
0124     {
0125     }
0126 
0127     QPointer<Worker> m_worker;
0128     QByteArray m_packedArgs;
0129     QUrl m_url;
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     // Worker::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 worker's connected signal.
0156      * @see connected()
0157      */
0158     void slotConnected();
0159     /**
0160      * Forward signal from the worker.
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 worker.
0167      * @param speed the speed in bytes/s
0168      * @see speed()
0169      */
0170     void slotSpeed(unsigned long speed);
0171     /**
0172      * Forward signal from the worker.
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 worker's info message.
0180      * @param s the info message
0181      * @see infoMessage()
0182      */
0183     void _k_slotWorkerInfoMessage(const QString &s);
0184 
0185     /**
0186      * Called when privilegeOperationRequested() is emitted by worker.
0187      */
0188     void slotPrivilegeOperationRequested();
0189 
0190     /**
0191      * @internal
0192      * Called by the scheduler when a worker gets to
0193      * work on this job.
0194      **/
0195     virtual void start(KIO::Worker *worker);
0196 
0197     /**
0198      * @internal
0199      * Called to detach a worker from a job.
0200      **/
0201     void workerDone();
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     {
0262     }
0263 
0264     inline TransferJobPrivate(const QUrl &url, int command, const QByteArray &packedArgs, QIODevice *ioDevice)
0265         : SimpleJobPrivate(url, command, packedArgs)
0266         , m_internalSuspended(false)
0267         , m_errorPage(false)
0268         , m_isMimetypeEmitted(false)
0269         , m_closedBeforeStart(false)
0270         , m_outgoingDataSource(QPointer<QIODevice>(ioDevice))
0271     {
0272     }
0273 
0274     bool m_internalSuspended;
0275     bool m_errorPage;
0276     QByteArray staticData;
0277     QUrl m_redirectionURL;
0278     QList<QUrl> m_redirectionList;
0279     QString m_mimetype;
0280     bool m_isMimetypeEmitted;
0281     bool m_closedBeforeStart;
0282     QPointer<QIODevice> m_outgoingDataSource;
0283     QMetaObject::Connection m_readChannelFinishedConnection;
0284 
0285     /**
0286      * Flow control. Suspend data processing from the worker.
0287      */
0288     void internalSuspend();
0289     /**
0290      * Flow control. Resume data processing from the worker.
0291      */
0292     void internalResume();
0293     /**
0294      * @internal
0295      * Called by the scheduler when a worker gets to
0296      * work on this job.
0297      * @param worker the worker that works on the job
0298      */
0299     void start(KIO::Worker *worker) override;
0300     /**
0301      * @internal
0302      * Called when the KIO worker needs the data to send the server. This slot
0303      * is invoked when the data is to be sent is read from a QIODevice rather
0304      * instead of a QByteArray buffer.
0305      */
0306     virtual void slotDataReqFromDevice();
0307     void slotIODeviceClosed();
0308     void slotIODeviceClosedBeforeStart();
0309     void slotPostRedirection();
0310 
0311     Q_DECLARE_PUBLIC(TransferJob)
0312     static inline TransferJob *newJob(const QUrl &url, int command, const QByteArray &packedArgs, const QByteArray &_staticData, JobFlags flags)
0313     {
0314         TransferJob *job = new TransferJob(*new TransferJobPrivate(url, command, packedArgs, _staticData));
0315         job->setUiDelegate(KIO::createDefaultJobUiDelegate());
0316         if (!(flags & HideProgressInfo)) {
0317             job->setFinishedNotificationHidden();
0318             KIO::getJobTracker()->registerJob(job);
0319         }
0320         if (!(flags & NoPrivilegeExecution)) {
0321             job->d_func()->m_privilegeExecutionEnabled = true;
0322             job->d_func()->m_operationType = Transfer;
0323         }
0324         return job;
0325     }
0326 
0327     static inline TransferJob *newJob(const QUrl &url, int command, const QByteArray &packedArgs, QIODevice *ioDevice, JobFlags flags)
0328     {
0329         TransferJob *job = new TransferJob(*new TransferJobPrivate(url, command, packedArgs, ioDevice));
0330         job->setUiDelegate(KIO::createDefaultJobUiDelegate());
0331         if (!(flags & HideProgressInfo)) {
0332             job->setFinishedNotificationHidden();
0333             KIO::getJobTracker()->registerJob(job);
0334         }
0335         if (!(flags & NoPrivilegeExecution)) {
0336             job->d_func()->m_privilegeExecutionEnabled = true;
0337             job->d_func()->m_operationType = Transfer;
0338         }
0339         return job;
0340     }
0341 };
0342 
0343 class DirectCopyJobPrivate;
0344 /**
0345  * @internal
0346  * Used for direct copy from or to the local filesystem (i.e.\ WorkerBase::copy())
0347  */
0348 class DirectCopyJob : public SimpleJob
0349 {
0350     Q_OBJECT
0351 
0352 public:
0353     DirectCopyJob(const QUrl &url, const QByteArray &packedArgs);
0354     ~DirectCopyJob() override;
0355 
0356 public Q_SLOTS:
0357     void slotCanResume(KIO::filesize_t offset);
0358 
0359 Q_SIGNALS:
0360     /**
0361      * @internal
0362      * Emitted if the job found an existing partial file
0363      * and supports resuming. Used by FileCopyJob.
0364      */
0365     void canResume(KIO::Job *job, KIO::filesize_t offset);
0366 
0367 private:
0368     Q_DECLARE_PRIVATE(DirectCopyJob)
0369 };
0370 }
0371 
0372 #endif