File indexing completed on 2024-07-14 03:53:50

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 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #include "job.h"
0011 #include "job_p.h"
0012 
0013 #include <time.h>
0014 
0015 #include <KLocalizedString>
0016 #include <KStringHandler>
0017 
0018 #include "worker_p.h"
0019 #include <kio/jobuidelegateextension.h>
0020 
0021 using namespace KIO;
0022 
0023 Job::Job()
0024     : KCompositeJob(nullptr)
0025     , d_ptr(new JobPrivate)
0026 {
0027     d_ptr->q_ptr = this;
0028     setCapabilities(KJob::Killable | KJob::Suspendable);
0029 }
0030 
0031 Job::Job(JobPrivate &dd)
0032     : KCompositeJob(nullptr)
0033     , d_ptr(&dd)
0034 {
0035     d_ptr->q_ptr = this;
0036     setCapabilities(KJob::Killable | KJob::Suspendable);
0037 }
0038 
0039 Job::~Job()
0040 {
0041     delete d_ptr;
0042 }
0043 
0044 JobUiDelegateExtension *Job::uiDelegateExtension() const
0045 {
0046     Q_D(const Job);
0047     return d->m_uiDelegateExtension;
0048 }
0049 
0050 void Job::setUiDelegateExtension(JobUiDelegateExtension *extension)
0051 {
0052     Q_D(Job);
0053     d->m_uiDelegateExtension = extension;
0054 }
0055 
0056 bool Job::addSubjob(KJob *jobBase)
0057 {
0058     // qDebug() << "addSubjob(" << jobBase << ") this=" << this;
0059 
0060     bool ok = KCompositeJob::addSubjob(jobBase);
0061     KIO::Job *job = qobject_cast<KIO::Job *>(jobBase);
0062     if (ok && job) {
0063         // Copy metadata into subjob (e.g. window-id, user-timestamp etc.)
0064         Q_D(Job);
0065         job->mergeMetaData(d->m_outgoingMetaData);
0066 
0067         // Forward information from that subjob.
0068         connect(job, &KJob::speed, this, [this](KJob *job, ulong speed) {
0069             Q_UNUSED(job);
0070             emitSpeed(speed);
0071         });
0072         job->setProperty("widget", property("widget")); // see KJobWidgets
0073         job->setProperty("window", property("window")); // see KJobWidgets
0074         job->setProperty("userTimestamp", property("userTimestamp")); // see KJobWidgets
0075         job->setUiDelegateExtension(d->m_uiDelegateExtension);
0076     }
0077     return ok;
0078 }
0079 
0080 bool Job::removeSubjob(KJob *jobBase)
0081 {
0082     // qDebug() << "removeSubjob(" << jobBase << ") this=" << this << "subjobs=" << subjobs().count();
0083     return KCompositeJob::removeSubjob(jobBase);
0084 }
0085 
0086 static QString url_description_string(const QUrl &url)
0087 {
0088     return url.scheme() == QLatin1String("data") ? QStringLiteral("data:[...]") : KStringHandler::csqueeze(url.toDisplayString(QUrl::PreferLocalFile), 100);
0089 }
0090 
0091 KIO::JobPrivate::~JobPrivate()
0092 {
0093 }
0094 
0095 void JobPrivate::emitMoving(KIO::Job *job, const QUrl &src, const QUrl &dest)
0096 {
0097     static const QString s_title = i18nc("@title job", "Moving");
0098     static const QString s_source = i18nc("The source of a file operation", "Source");
0099     static const QString s_destination = i18nc("The destination of a file operation", "Destination");
0100     Q_EMIT job->description(job, s_title, qMakePair(s_source, url_description_string(src)), qMakePair(s_destination, url_description_string(dest)));
0101 }
0102 
0103 void JobPrivate::emitRenaming(KIO::Job *job, const QUrl &src, const QUrl &dest)
0104 {
0105     static const QString s_title = i18nc("@title job", "Renaming");
0106     static const QString s_source = i18nc("The source of a file operation", "Source");
0107     static const QString s_destination = i18nc("The destination of a file operation", "Destination");
0108     Q_EMIT job->description(job, s_title, {s_source, url_description_string(src)}, {s_destination, url_description_string(dest)});
0109 }
0110 
0111 void JobPrivate::emitCopying(KIO::Job *job, const QUrl &src, const QUrl &dest)
0112 {
0113     static const QString s_title = i18nc("@title job", "Copying");
0114     static const QString s_source = i18nc("The source of a file operation", "Source");
0115     static const QString s_destination = i18nc("The destination of a file operation", "Destination");
0116     Q_EMIT job->description(job, s_title, qMakePair(s_source, url_description_string(src)), qMakePair(s_destination, url_description_string(dest)));
0117 }
0118 
0119 void JobPrivate::emitCreatingDir(KIO::Job *job, const QUrl &dir)
0120 {
0121     static const QString s_title = i18nc("@title job", "Creating directory");
0122     static const QString s_directory = i18n("Directory");
0123     Q_EMIT job->description(job, s_title, qMakePair(s_directory, url_description_string(dir)));
0124 }
0125 
0126 void JobPrivate::emitDeleting(KIO::Job *job, const QUrl &url)
0127 {
0128     static const QString s_title = i18nc("@title job", "Deleting");
0129     static const QString s_file = i18n("File");
0130     Q_EMIT job->description(job, s_title, qMakePair(s_file, url_description_string(url)));
0131 }
0132 
0133 void JobPrivate::emitStating(KIO::Job *job, const QUrl &url)
0134 {
0135     static const QString s_title = i18nc("@title job", "Examining");
0136     static const QString s_file = i18n("File");
0137     Q_EMIT job->description(job, s_title, qMakePair(s_file, url_description_string(url)));
0138 }
0139 
0140 void JobPrivate::emitTransferring(KIO::Job *job, const QUrl &url)
0141 {
0142     static const QString s_title = i18nc("@title job", "Transferring");
0143     static const QString s_source = i18nc("The source of a file operation", "Source");
0144     Q_EMIT job->description(job, s_title, qMakePair(s_source, url_description_string(url)));
0145 }
0146 
0147 void JobPrivate::emitMounting(KIO::Job *job, const QString &dev, const QString &point)
0148 {
0149     Q_EMIT job->description(job, i18nc("@title job", "Mounting"), qMakePair(i18n("Device"), dev), qMakePair(i18n("Mountpoint"), point));
0150 }
0151 
0152 void JobPrivate::emitUnmounting(KIO::Job *job, const QString &point)
0153 {
0154     Q_EMIT job->description(job, i18nc("@title job", "Unmounting"), qMakePair(i18n("Mountpoint"), point));
0155 }
0156 
0157 bool Job::doKill()
0158 {
0159     // kill all subjobs, without triggering their result slot
0160     for (KJob *job : subjobs()) {
0161         job->kill(KJob::Quietly);
0162     }
0163     clearSubjobs();
0164 
0165     return true;
0166 }
0167 
0168 bool Job::doSuspend()
0169 {
0170     for (KJob *job : subjobs()) {
0171         if (!job->suspend()) {
0172             return false;
0173         }
0174     }
0175 
0176     return true;
0177 }
0178 
0179 bool Job::doResume()
0180 {
0181     for (KJob *job : subjobs()) {
0182         if (!job->resume()) {
0183             return false;
0184         }
0185     }
0186 
0187     return true;
0188 }
0189 
0190 // Job::errorString is implemented in job_error.cpp
0191 
0192 void Job::setParentJob(Job *job)
0193 {
0194     Q_D(Job);
0195     Q_ASSERT(d->m_parentJob == nullptr);
0196     Q_ASSERT(job);
0197     d->m_parentJob = job;
0198 }
0199 
0200 Job *Job::parentJob() const
0201 {
0202     return d_func()->m_parentJob;
0203 }
0204 
0205 MetaData Job::metaData() const
0206 {
0207     return d_func()->m_incomingMetaData;
0208 }
0209 
0210 QString Job::queryMetaData(const QString &key)
0211 {
0212     return d_func()->m_incomingMetaData.value(key, QString());
0213 }
0214 
0215 void Job::setMetaData(const KIO::MetaData &_metaData)
0216 {
0217     Q_D(Job);
0218     d->m_outgoingMetaData = _metaData;
0219 }
0220 
0221 void Job::addMetaData(const QString &key, const QString &value)
0222 {
0223     d_func()->m_outgoingMetaData.insert(key, value);
0224 }
0225 
0226 void Job::addMetaData(const QMap<QString, QString> &values)
0227 {
0228     Q_D(Job);
0229     for (auto it = values.cbegin(); it != values.cend(); ++it) {
0230         d->m_outgoingMetaData.insert(it.key(), it.value());
0231     }
0232 }
0233 
0234 void Job::mergeMetaData(const QMap<QString, QString> &values)
0235 {
0236     Q_D(Job);
0237     for (auto it = values.cbegin(); it != values.cend(); ++it) {
0238         // there's probably a faster way
0239         if (!d->m_outgoingMetaData.contains(it.key())) {
0240             d->m_outgoingMetaData.insert(it.key(), it.value());
0241         }
0242     }
0243 }
0244 
0245 MetaData Job::outgoingMetaData() const
0246 {
0247     return d_func()->m_outgoingMetaData;
0248 }
0249 
0250 QByteArray JobPrivate::privilegeOperationData()
0251 {
0252     PrivilegeOperationStatus status = OperationNotAllowed;
0253 
0254     if (m_parentJob) {
0255         QByteArray jobData = m_parentJob->d_func()->privilegeOperationData();
0256         // Copy meta-data from parent job
0257         m_incomingMetaData.insert(QStringLiteral("TestData"), m_parentJob->queryMetaData(QStringLiteral("TestData")));
0258         return jobData;
0259     } else {
0260         if (m_privilegeExecutionEnabled) {
0261             status = OperationAllowed;
0262             switch (m_operationType) {
0263             case ChangeAttr:
0264                 m_title = i18n("Change Attribute");
0265                 m_message = i18n(
0266                     "Root privileges are required to change file attributes. "
0267                     "Do you want to continue?");
0268                 break;
0269             case Copy:
0270                 m_title = i18n("Copy Files");
0271                 m_message = i18n(
0272                     "Root privileges are required to complete the copy operation. "
0273                     "Do you want to continue?");
0274                 break;
0275             case Delete:
0276                 m_title = i18n("Delete Files");
0277                 m_message = i18n(
0278                     "Root privileges are required to complete the delete operation. "
0279                     "However, doing so may damage your system. Do you want to continue?");
0280                 break;
0281             case MkDir:
0282                 m_title = i18n("Create Folder");
0283                 m_message = i18n(
0284                     "Root privileges are required to create this folder. "
0285                     "Do you want to continue?");
0286                 break;
0287             case Move:
0288                 m_title = i18n("Move Items");
0289                 m_message = i18n(
0290                     "Root privileges are required to complete the move operation. "
0291                     "Do you want to continue?");
0292                 break;
0293             case Rename:
0294                 m_title = i18n("Rename");
0295                 m_message = i18n(
0296                     "Root privileges are required to complete renaming. "
0297                     "Do you want to continue?");
0298                 break;
0299             case Symlink:
0300                 m_title = i18n("Create Symlink");
0301                 m_message = i18n(
0302                     "Root privileges are required to create a symlink. "
0303                     "Do you want to continue?");
0304                 break;
0305             case Transfer:
0306                 m_title = i18n("Transfer data");
0307                 m_message = i18n(
0308                     "Root privileges are required to complete transferring data. "
0309                     "Do you want to continue?");
0310                 Q_FALLTHROUGH();
0311             default:
0312                 break;
0313             }
0314 
0315             if (m_outgoingMetaData.value(QStringLiteral("UnitTesting")) == QLatin1String("true")) {
0316                 // Set meta-data for the top-level job
0317                 m_incomingMetaData.insert(QStringLiteral("TestData"), QStringLiteral("PrivilegeOperationAllowed"));
0318             }
0319         }
0320     }
0321 
0322     QByteArray parentJobData;
0323     QDataStream ds(&parentJobData, QIODevice::WriteOnly);
0324     ds << status << m_title << m_message;
0325     return parentJobData;
0326 }
0327 
0328 //////////////////////////
0329 
0330 class KIO::DirectCopyJobPrivate : public KIO::SimpleJobPrivate
0331 {
0332 public:
0333     DirectCopyJobPrivate(const QUrl &url, int command, const QByteArray &packedArgs)
0334         : SimpleJobPrivate(url, command, packedArgs)
0335     {
0336     }
0337 
0338     /**
0339      * @internal
0340      * Called by the scheduler when a @p worker gets to
0341      * work on this job.
0342      * @param worker the worker that starts working on this job
0343      */
0344     void start(Worker *worker) override;
0345 
0346     Q_DECLARE_PUBLIC(DirectCopyJob)
0347 };
0348 
0349 DirectCopyJob::DirectCopyJob(const QUrl &url, const QByteArray &packedArgs)
0350     : SimpleJob(*new DirectCopyJobPrivate(url, CMD_COPY, packedArgs))
0351 {
0352     setUiDelegate(KIO::createDefaultJobUiDelegate());
0353 }
0354 
0355 DirectCopyJob::~DirectCopyJob()
0356 {
0357 }
0358 
0359 void DirectCopyJobPrivate::start(Worker *worker)
0360 {
0361     Q_Q(DirectCopyJob);
0362     q->connect(worker, &WorkerInterface::canResume, q, &DirectCopyJob::slotCanResume);
0363     SimpleJobPrivate::start(worker);
0364 }
0365 
0366 void DirectCopyJob::slotCanResume(KIO::filesize_t offset)
0367 {
0368     Q_EMIT canResume(this, offset);
0369 }
0370 
0371 //////////////////////////
0372 
0373 SimpleJob *KIO::file_delete(const QUrl &src, JobFlags flags)
0374 {
0375     KIO_ARGS << src << qint8(true); // isFile
0376     SimpleJob *job = SimpleJobPrivate::newJob(src, CMD_DEL, packedArgs, flags);
0377     if (job->uiDelegateExtension()) {
0378         job->uiDelegateExtension()->createClipboardUpdater(job, JobUiDelegateExtension::RemoveContent);
0379     }
0380     return job;
0381 }
0382 
0383 //////////
0384 ////
0385 
0386 #include "moc_job_base.cpp"
0387 #include "moc_job_p.cpp"