File indexing completed on 2024-04-14 03:52:53
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"