File indexing completed on 2024-05-05 16:13:10

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2004 Kevin Ottens <ervin@ipsquad.net>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "forwardingslavebase.h"
0009 #include "../utils_p.h"
0010 
0011 #include "deletejob.h"
0012 #include "job.h"
0013 #include "kiocoredebug.h"
0014 #include "mkdirjob.h"
0015 
0016 #include <QMimeDatabase>
0017 
0018 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 101)
0019 
0020 namespace KIO
0021 {
0022 class ForwardingSlaveBasePrivate
0023 {
0024 public:
0025     ForwardingSlaveBasePrivate(QObject *eventLoopParent, ForwardingSlaveBase *qq)
0026         : q(qq)
0027         , eventLoop(eventLoopParent)
0028     {
0029     }
0030     ForwardingSlaveBase *const q;
0031 
0032     QUrl m_processedURL;
0033     QUrl m_requestedURL;
0034     QEventLoop eventLoop;
0035 
0036     bool internalRewriteUrl(const QUrl &url, QUrl &newURL);
0037 
0038     void connectJob(Job *job);
0039     void connectSimpleJob(SimpleJob *job);
0040     void connectListJob(ListJob *job);
0041     void connectTransferJob(TransferJob *job);
0042 
0043     void _k_slotResult(KJob *job);
0044     void _k_slotWarning(KJob *job, const QString &msg);
0045     void _k_slotInfoMessage(KJob *job, const QString &msg);
0046     void _k_slotTotalSize(KJob *job, qulonglong size);
0047     void _k_slotProcessedSize(KJob *job, qulonglong size);
0048     void _k_slotSpeed(KJob *job, unsigned long bytesPerSecond);
0049 
0050     // KIO::SimpleJob subclasses
0051     void _k_slotRedirection(KIO::Job *job, const QUrl &url);
0052 
0053     // KIO::ListJob
0054     void _k_slotEntries(KIO::Job *job, const KIO::UDSEntryList &entries);
0055 
0056     // KIO::TransferJob
0057     void _k_slotData(KIO::Job *job, const QByteArray &data);
0058     void _k_slotDataReq(KIO::Job *job, QByteArray &data);
0059     void _k_slotMimetype(KIO::Job *job, const QString &type);
0060     void _k_slotCanResume(KIO::Job *job, KIO::filesize_t offset);
0061 };
0062 
0063 ForwardingSlaveBase::ForwardingSlaveBase(const QByteArray &protocol, const QByteArray &poolSocket, const QByteArray &appSocket)
0064     : QObject()
0065     , SlaveBase(protocol, poolSocket, appSocket)
0066     , d(new ForwardingSlaveBasePrivate(this, this))
0067 {
0068 }
0069 
0070 ForwardingSlaveBase::~ForwardingSlaveBase() = default;
0071 
0072 bool ForwardingSlaveBasePrivate::internalRewriteUrl(const QUrl &url, QUrl &newURL)
0073 {
0074     bool result = true;
0075 
0076     if (url.scheme() == QLatin1String(q->mProtocol)) {
0077         result = q->rewriteUrl(url, newURL);
0078     } else {
0079         newURL = url;
0080     }
0081 
0082     m_processedURL = newURL;
0083     m_requestedURL = url;
0084     return result;
0085 }
0086 
0087 void ForwardingSlaveBase::prepareUDSEntry(KIO::UDSEntry &entry, bool listing) const
0088 {
0089     // qDebug() << "listing==" << listing;
0090 
0091     const QString name = entry.stringValue(KIO::UDSEntry::UDS_NAME);
0092     QString mimetype = entry.stringValue(KIO::UDSEntry::UDS_MIME_TYPE);
0093     QUrl url;
0094     const QString urlStr = entry.stringValue(KIO::UDSEntry::UDS_URL);
0095     const bool url_found = !urlStr.isEmpty();
0096     if (url_found) {
0097         url = QUrl(urlStr);
0098         QUrl new_url(d->m_requestedURL);
0099         if (listing) {
0100             new_url.setPath(Utils::concatPaths(new_url.path(), url.fileName()));
0101         }
0102         // ## Didn't find a way to use an iterator instead of re-doing a key lookup
0103         entry.replace(KIO::UDSEntry::UDS_URL, new_url.toString());
0104         // qDebug() << "URL =" << url;
0105         // qDebug() << "New URL =" << new_url;
0106     }
0107 
0108     if (mimetype.isEmpty()) {
0109         QUrl new_url(d->m_processedURL);
0110         if (url_found && listing) {
0111             new_url.setPath(Utils::concatPaths(new_url.path(), url.fileName()));
0112         } else if (listing) {
0113             new_url.setPath(Utils::concatPaths(new_url.path(), name));
0114         }
0115 
0116         QMimeDatabase db;
0117         mimetype = db.mimeTypeForUrl(new_url).name();
0118 
0119         entry.replace(KIO::UDSEntry::UDS_MIME_TYPE, mimetype);
0120 
0121         // qDebug() << "New MIME type = " << mimetype;
0122     }
0123 
0124     if (d->m_processedURL.isLocalFile()) {
0125         QUrl new_url(d->m_processedURL);
0126         if (listing) {
0127             new_url.setPath(Utils::concatPaths(new_url.path(), name));
0128         }
0129 
0130         entry.replace(KIO::UDSEntry::UDS_LOCAL_PATH, new_url.toLocalFile());
0131     }
0132 }
0133 
0134 QUrl ForwardingSlaveBase::processedUrl() const
0135 {
0136     return d->m_processedURL;
0137 }
0138 
0139 QUrl ForwardingSlaveBase::requestedUrl() const
0140 {
0141     return d->m_requestedURL;
0142 }
0143 
0144 void ForwardingSlaveBase::get(const QUrl &url)
0145 {
0146     QUrl new_url;
0147     if (d->internalRewriteUrl(url, new_url)) {
0148         KIO::TransferJob *job = KIO::get(new_url, NoReload, HideProgressInfo);
0149         d->connectTransferJob(job);
0150 
0151         d->eventLoop.exec();
0152     } else {
0153         error(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
0154     }
0155 }
0156 
0157 void ForwardingSlaveBase::put(const QUrl &url, int permissions, JobFlags flags)
0158 {
0159     QUrl new_url;
0160     if (d->internalRewriteUrl(url, new_url)) {
0161         KIO::TransferJob *job = KIO::put(new_url, permissions, flags | HideProgressInfo);
0162         d->connectTransferJob(job);
0163 
0164         d->eventLoop.exec();
0165     } else {
0166         error(KIO::ERR_MALFORMED_URL, url.toDisplayString());
0167     }
0168 }
0169 
0170 void ForwardingSlaveBase::stat(const QUrl &url)
0171 {
0172     QUrl new_url;
0173     if (d->internalRewriteUrl(url, new_url)) {
0174         KIO::SimpleJob *job = KIO::stat(new_url, KIO::HideProgressInfo);
0175         d->connectSimpleJob(job);
0176 
0177         d->eventLoop.exec();
0178     } else {
0179         error(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
0180     }
0181 }
0182 
0183 void ForwardingSlaveBase::mimetype(const QUrl &url)
0184 {
0185     QUrl new_url;
0186     if (d->internalRewriteUrl(url, new_url)) {
0187         KIO::TransferJob *job = KIO::mimetype(new_url, KIO::HideProgressInfo);
0188         d->connectTransferJob(job);
0189 
0190         d->eventLoop.exec();
0191     } else {
0192         error(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
0193     }
0194 }
0195 
0196 void ForwardingSlaveBase::listDir(const QUrl &url)
0197 {
0198     QUrl new_url;
0199     if (d->internalRewriteUrl(url, new_url)) {
0200         KIO::ListJob *job = KIO::listDir(new_url, KIO::HideProgressInfo);
0201         d->connectListJob(job);
0202 
0203         d->eventLoop.exec();
0204     } else {
0205         error(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
0206     }
0207 }
0208 
0209 void ForwardingSlaveBase::mkdir(const QUrl &url, int permissions)
0210 {
0211     QUrl new_url;
0212     if (d->internalRewriteUrl(url, new_url)) {
0213         KIO::SimpleJob *job = KIO::mkdir(new_url, permissions);
0214         d->connectSimpleJob(job);
0215 
0216         d->eventLoop.exec();
0217     } else {
0218         error(KIO::ERR_MALFORMED_URL, url.toDisplayString());
0219     }
0220 }
0221 
0222 void ForwardingSlaveBase::rename(const QUrl &src, const QUrl &dest, JobFlags flags)
0223 {
0224     qCDebug(KIO_CORE) << "rename" << src << dest;
0225 
0226     QUrl new_src;
0227     QUrl new_dest;
0228     if (!d->internalRewriteUrl(src, new_src)) {
0229         error(KIO::ERR_DOES_NOT_EXIST, src.toDisplayString());
0230     } else if (d->internalRewriteUrl(dest, new_dest)) {
0231         KIO::Job *job = KIO::rename(new_src, new_dest, flags);
0232         d->connectJob(job);
0233 
0234         d->eventLoop.exec();
0235     } else {
0236         error(KIO::ERR_MALFORMED_URL, dest.toDisplayString());
0237     }
0238 }
0239 
0240 void ForwardingSlaveBase::symlink(const QString &target, const QUrl &dest, JobFlags flags)
0241 {
0242     qCDebug(KIO_CORE) << "symlink" << target << dest;
0243 
0244     QUrl new_dest;
0245     if (d->internalRewriteUrl(dest, new_dest)) {
0246         KIO::SimpleJob *job = KIO::symlink(target, new_dest, flags | HideProgressInfo);
0247         d->connectSimpleJob(job);
0248 
0249         d->eventLoop.exec();
0250     } else {
0251         error(KIO::ERR_MALFORMED_URL, dest.toDisplayString());
0252     }
0253 }
0254 
0255 void ForwardingSlaveBase::chmod(const QUrl &url, int permissions)
0256 {
0257     QUrl new_url;
0258     if (d->internalRewriteUrl(url, new_url)) {
0259         KIO::SimpleJob *job = KIO::chmod(new_url, permissions);
0260         d->connectSimpleJob(job);
0261 
0262         d->eventLoop.exec();
0263     } else {
0264         error(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
0265     }
0266 }
0267 
0268 void ForwardingSlaveBase::setModificationTime(const QUrl &url, const QDateTime &mtime)
0269 {
0270     QUrl new_url;
0271     if (d->internalRewriteUrl(url, new_url)) {
0272         KIO::SimpleJob *job = KIO::setModificationTime(new_url, mtime);
0273         d->connectSimpleJob(job);
0274 
0275         d->eventLoop.exec();
0276     } else {
0277         error(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
0278     }
0279 }
0280 
0281 void ForwardingSlaveBase::copy(const QUrl &src, const QUrl &dest, int permissions, JobFlags flags)
0282 {
0283     qCDebug(KIO_CORE) << "copy" << src << dest;
0284 
0285     QUrl new_src;
0286     QUrl new_dest;
0287     if (!d->internalRewriteUrl(src, new_src)) {
0288         error(KIO::ERR_DOES_NOT_EXIST, src.toDisplayString());
0289     } else if (d->internalRewriteUrl(dest, new_dest)) {
0290         KIO::Job *job = KIO::file_copy(new_src, new_dest, permissions, flags | HideProgressInfo);
0291         d->connectJob(job);
0292 
0293         d->eventLoop.exec();
0294     } else {
0295         error(KIO::ERR_MALFORMED_URL, dest.toDisplayString());
0296     }
0297 }
0298 
0299 void ForwardingSlaveBase::del(const QUrl &url, bool isfile)
0300 {
0301     QUrl new_url;
0302     if (d->internalRewriteUrl(url, new_url)) {
0303         if (isfile) {
0304             KIO::DeleteJob *job = KIO::del(new_url, HideProgressInfo);
0305             d->connectJob(job);
0306         } else {
0307             KIO::SimpleJob *job = KIO::rmdir(new_url);
0308             d->connectSimpleJob(job);
0309         }
0310 
0311         d->eventLoop.exec();
0312     } else {
0313         error(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
0314     }
0315 }
0316 
0317 //////////////////////////////////////////////////////////////////////////////
0318 
0319 void ForwardingSlaveBasePrivate::connectJob(KIO::Job *job)
0320 {
0321     // We will forward the warning message, no need to let the job
0322     // display it itself
0323     job->setUiDelegate(nullptr);
0324 
0325     // Forward metadata (e.g. modification time for put())
0326     job->setMetaData(q->allMetaData());
0327 
0328     q->connect(job, &KJob::result, q, [this](KJob *job) {
0329         _k_slotResult(job);
0330     });
0331     q->connect(job, &KJob::warning, q, [this](KJob *job, const QString &text) {
0332         _k_slotWarning(job, text);
0333     });
0334     q->connect(job, &KJob::infoMessage, q, [this](KJob *job, const QString &info) {
0335         _k_slotInfoMessage(job, info);
0336     });
0337     q->connect(job, &KJob::totalSize, q, [this](KJob *job, qulonglong size) {
0338         _k_slotTotalSize(job, size);
0339     });
0340     q->connect(job, &KJob::processedSize, q, [this](KJob *job, qulonglong size) {
0341         _k_slotProcessedSize(job, size);
0342     });
0343     q->connect(job, &KJob::speed, q, [this](KJob *job, ulong speed) {
0344         _k_slotSpeed(job, speed);
0345     });
0346 }
0347 
0348 void ForwardingSlaveBasePrivate::connectSimpleJob(KIO::SimpleJob *job)
0349 {
0350     connectJob(job);
0351     if (job->metaObject()->indexOfSignal("redirection(KIO::Job*,QUrl)") > -1) {
0352         q->connect(job, SIGNAL(redirection(KIO::Job *, QUrl)), SLOT(_k_slotRedirection(KIO::Job *, QUrl)));
0353     }
0354 }
0355 
0356 void ForwardingSlaveBasePrivate::connectListJob(KIO::ListJob *job)
0357 {
0358     connectSimpleJob(job);
0359     q->connect(job, &KIO::ListJob::entries, q, [this](KIO::Job *job, const KIO::UDSEntryList &entries) {
0360         _k_slotEntries(job, entries);
0361     });
0362 }
0363 
0364 void ForwardingSlaveBasePrivate::connectTransferJob(KIO::TransferJob *job)
0365 {
0366     connectSimpleJob(job);
0367     q->connect(job, &KIO::TransferJob::data, q, [this](KIO::Job *job, const QByteArray &data) {
0368         _k_slotData(job, data);
0369     });
0370     q->connect(job, &KIO::TransferJob::dataReq, q, [this](KIO::Job *job, QByteArray &data) {
0371         _k_slotDataReq(job, data);
0372     });
0373     q->connect(job, &KIO::TransferJob::mimeTypeFound, q, [this](KIO::Job *job, const QString &mimeType) {
0374         _k_slotMimetype(job, mimeType);
0375     });
0376     q->connect(job, &KIO::TransferJob::canResume, q, [this](KIO::Job *job, KIO::filesize_t offset) {
0377         _k_slotCanResume(job, offset);
0378     });
0379 }
0380 
0381 //////////////////////////////////////////////////////////////////////////////
0382 
0383 void ForwardingSlaveBasePrivate::_k_slotResult(KJob *job)
0384 {
0385     if (job->error() != 0) {
0386         q->error(job->error(), job->errorText());
0387     } else {
0388         KIO::StatJob *stat_job = qobject_cast<KIO::StatJob *>(job);
0389         if (stat_job != nullptr) {
0390             KIO::UDSEntry entry = stat_job->statResult();
0391             q->prepareUDSEntry(entry);
0392             q->statEntry(entry);
0393         }
0394         q->finished();
0395     }
0396 
0397     eventLoop.exit();
0398 }
0399 
0400 void ForwardingSlaveBasePrivate::_k_slotWarning(KJob * /*job*/, const QString &msg)
0401 {
0402     q->warning(msg);
0403 }
0404 
0405 void ForwardingSlaveBasePrivate::_k_slotInfoMessage(KJob * /*job*/, const QString &msg)
0406 {
0407     q->infoMessage(msg);
0408 }
0409 
0410 void ForwardingSlaveBasePrivate::_k_slotTotalSize(KJob * /*job*/, qulonglong size)
0411 {
0412     q->totalSize(size);
0413 }
0414 
0415 void ForwardingSlaveBasePrivate::_k_slotProcessedSize(KJob * /*job*/, qulonglong size)
0416 {
0417     q->processedSize(size);
0418 }
0419 
0420 void ForwardingSlaveBasePrivate::_k_slotSpeed(KJob * /*job*/, unsigned long bytesPerSecond)
0421 {
0422     q->speed(bytesPerSecond);
0423 }
0424 
0425 void ForwardingSlaveBasePrivate::_k_slotRedirection(KIO::Job *job, const QUrl &url)
0426 {
0427     q->redirection(url);
0428 
0429     // We've been redirected stop everything.
0430     job->kill(KJob::Quietly);
0431     q->finished();
0432 
0433     eventLoop.exit();
0434 }
0435 
0436 void ForwardingSlaveBasePrivate::_k_slotEntries(KIO::Job * /*job*/, const KIO::UDSEntryList &entries)
0437 {
0438     KIO::UDSEntryList final_entries = entries;
0439 
0440     for (auto &entry : final_entries) {
0441         q->prepareUDSEntry(entry, true);
0442     }
0443 
0444     q->listEntries(final_entries);
0445 }
0446 
0447 void ForwardingSlaveBasePrivate::_k_slotData(KIO::Job * /*job*/, const QByteArray &_data)
0448 {
0449     q->data(_data);
0450 }
0451 
0452 void ForwardingSlaveBasePrivate::_k_slotDataReq(KIO::Job * /*job*/, QByteArray &data)
0453 {
0454     q->dataReq();
0455     q->readData(data);
0456 }
0457 
0458 void ForwardingSlaveBasePrivate::_k_slotMimetype(KIO::Job * /*job*/, const QString &type)
0459 {
0460     q->mimeType(type);
0461 }
0462 
0463 void ForwardingSlaveBasePrivate::_k_slotCanResume(KIO::Job * /*job*/, KIO::filesize_t offset)
0464 {
0465     q->canResume(offset);
0466 }
0467 
0468 }
0469 
0470 #include "moc_forwardingslavebase.cpp"
0471 
0472 #endif