File indexing completed on 2024-07-21 03:41:07

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 1999 Torben Weis <weis@kde.org>
0004     SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org>
0005     SPDX-FileCopyrightText: 2012 David Faure <faure@kde.org>
0006     SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
0007 
0008     SPDX-License-Identifier: LGPL-2.0-only
0009 */
0010 
0011 #include "kprotocolinfo.h"
0012 #include "kprotocolinfo_p.h"
0013 #include "kprotocolinfofactory_p.h"
0014 
0015 #include "kiocoredebug.h"
0016 
0017 #include <KApplicationTrader>
0018 #include <KConfig>
0019 #include <KConfigGroup>
0020 #include <KJsonUtils>
0021 #include <KPluginMetaData>
0022 #include <KSharedConfig>
0023 #include <QUrl>
0024 
0025 KProtocolInfoPrivate::KProtocolInfoPrivate(const QString &name, const QString &exec, const QJsonObject &json)
0026     : m_name(name)
0027     , m_exec(exec)
0028 {
0029     // source has fallback true if not set
0030     m_isSourceProtocol = json.value(QStringLiteral("source")).toBool(true);
0031     // true if not set for backwards compatibility
0032     m_supportsPermissions = json.value(QStringLiteral("permissions")).toBool(true);
0033 
0034     // other bools are fine with default false by toBool
0035     m_isHelperProtocol = json.value(QStringLiteral("helper")).toBool();
0036     m_supportsReading = json.value(QStringLiteral("reading")).toBool();
0037     m_supportsWriting = json.value(QStringLiteral("writing")).toBool();
0038     m_supportsMakeDir = json.value(QStringLiteral("makedir")).toBool();
0039     m_supportsDeleting = json.value(QStringLiteral("deleting")).toBool();
0040     m_supportsLinking = json.value(QStringLiteral("linking")).toBool();
0041     m_supportsMoving = json.value(QStringLiteral("moving")).toBool();
0042     m_supportsOpening = json.value(QStringLiteral("opening")).toBool();
0043     m_supportsTruncating = json.value(QStringLiteral("truncating")).toBool();
0044     m_canCopyFromFile = json.value(QStringLiteral("copyFromFile")).toBool();
0045     m_canCopyToFile = json.value(QStringLiteral("copyToFile")).toBool();
0046     m_canRenameFromFile = json.value(QStringLiteral("renameFromFile")).toBool();
0047     m_canRenameToFile = json.value(QStringLiteral("renameToFile")).toBool();
0048     m_canDeleteRecursive = json.value(QStringLiteral("deleteRecursive")).toBool();
0049 
0050     // default is "FromURL"
0051     const QString fnu = json.value(QStringLiteral("fileNameUsedForCopying")).toString();
0052     m_fileNameUsedForCopying = KProtocolInfo::FromUrl;
0053     if (fnu == QLatin1String("Name")) {
0054         m_fileNameUsedForCopying = KProtocolInfo::Name;
0055     } else if (fnu == QLatin1String("DisplayName")) {
0056         m_fileNameUsedForCopying = KProtocolInfo::DisplayName;
0057     }
0058 
0059     m_listing = json.value(QStringLiteral("listing")).toVariant().toStringList();
0060     // Many .protocol files say "Listing=false" when they really mean "Listing=" (i.e. unsupported)
0061     if (m_listing.count() == 1 && m_listing.first() == QLatin1String("false")) {
0062         m_listing.clear();
0063     }
0064     m_supportsListing = (m_listing.count() > 0);
0065 
0066     m_defaultMimetype = json.value(QStringLiteral("defaultMimetype")).toString();
0067 
0068     // determineMimetypeFromExtension has fallback true if not set
0069     m_determineMimetypeFromExtension = json.value(QStringLiteral("determineMimetypeFromExtension")).toBool(true);
0070 
0071     m_archiveMimeTypes = json.value(QStringLiteral("archiveMimetype")).toVariant().toStringList();
0072 
0073     m_icon = json.value(QStringLiteral("Icon")).toString();
0074 
0075     // config has fallback to name if not set
0076     m_config = json.value(QStringLiteral("config")).toString(m_name);
0077 
0078     // max workers has fallback to 1 if not set
0079     m_maxWorkers = json.value(QStringLiteral("maxInstances")).toInt(1);
0080 
0081     m_maxWorkersPerHost = json.value(QStringLiteral("maxInstancesPerHost")).toInt();
0082 
0083     QString tmp = json.value(QStringLiteral("input")).toString();
0084     if (tmp == QLatin1String("filesystem")) {
0085         m_inputType = KProtocolInfo::T_FILESYSTEM;
0086     } else if (tmp == QLatin1String("stream")) {
0087         m_inputType = KProtocolInfo::T_STREAM;
0088     } else {
0089         m_inputType = KProtocolInfo::T_NONE;
0090     }
0091 
0092     tmp = json.value(QStringLiteral("output")).toString();
0093     if (tmp == QLatin1String("filesystem")) {
0094         m_outputType = KProtocolInfo::T_FILESYSTEM;
0095     } else if (tmp == QLatin1String("stream")) {
0096         m_outputType = KProtocolInfo::T_STREAM;
0097     } else {
0098         m_outputType = KProtocolInfo::T_NONE;
0099     }
0100 
0101     m_docPath = json.value(QStringLiteral("X-DocPath")).toString();
0102     if (m_docPath.isEmpty()) {
0103         m_docPath = json.value(QStringLiteral("DocPath")).toString();
0104     }
0105 
0106     m_protClass = json.value(QStringLiteral("Class")).toString().toLower();
0107     if (!m_protClass.startsWith(QLatin1Char(':'))) {
0108         m_protClass.prepend(QLatin1Char(':'));
0109     }
0110 
0111     // ExtraNames is a translated value, use the KCoreAddons helper to read it
0112     const QStringList extraNames = KJsonUtils::readTranslatedValue(json, QStringLiteral("ExtraNames")).toVariant().toStringList();
0113     const QStringList extraTypes = json.value(QStringLiteral("ExtraTypes")).toVariant().toStringList();
0114     if (extraNames.size() == extraTypes.size()) {
0115         auto func = [](const QString &name, const QString &type) {
0116             const int metaType = QMetaType::fromName(type.toLatin1().constData()).id();
0117             // currently QMetaType::Type and ExtraField::Type use the same subset of values, so we can just cast.
0118             return KProtocolInfo::ExtraField(name, static_cast<KProtocolInfo::ExtraField::Type>(metaType));
0119         };
0120 
0121         std::transform(extraNames.cbegin(), extraNames.cend(), extraTypes.cbegin(), std::back_inserter(m_extraFields), func);
0122     } else {
0123         qCWarning(KIO_CORE) << "Malformed JSON protocol file for protocol:" << name
0124                             << ", number of the ExtraNames fields should match the number of ExtraTypes fields";
0125     }
0126 
0127     // fallback based on class
0128     m_showPreviews = json.value(QStringLiteral("ShowPreviews")).toBool(m_protClass == QLatin1String(":local"));
0129 
0130     m_capabilities = json.value(QStringLiteral("Capabilities")).toVariant().toStringList();
0131 
0132     m_proxyProtocol = json.value(QStringLiteral("ProxiedBy")).toString();
0133 }
0134 
0135 //
0136 // Static functions:
0137 //
0138 
0139 QStringList KProtocolInfo::protocols()
0140 {
0141     return KProtocolInfoFactory::self()->protocols();
0142 }
0143 
0144 bool KProtocolInfo::isFilterProtocol(const QString &_protocol)
0145 {
0146     // We call the findProtocol directly (not via KProtocolManager) to bypass any proxy settings.
0147     KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
0148     if (!prot) {
0149         return false;
0150     }
0151 
0152     return !prot->m_isSourceProtocol;
0153 }
0154 
0155 QString KProtocolInfo::icon(const QString &_protocol)
0156 {
0157     // We call the findProtocol directly (not via KProtocolManager) to bypass any proxy settings.
0158     KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
0159     if (!prot) {
0160         if (auto service = KApplicationTrader::preferredService(QLatin1String("x-scheme-handler/") + _protocol)) {
0161             return service->icon();
0162         } else {
0163             return QString();
0164         }
0165     }
0166 
0167     return prot->m_icon;
0168 }
0169 
0170 QString KProtocolInfo::config(const QString &_protocol)
0171 {
0172     // We call the findProtocol directly (not via KProtocolManager) to bypass any proxy settings.
0173     KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
0174     if (!prot) {
0175         return QString();
0176     }
0177 
0178     return QStringLiteral("kio_%1rc").arg(prot->m_config);
0179 }
0180 
0181 int KProtocolInfo::maxWorkers(const QString &_protocol)
0182 {
0183     KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
0184     if (!prot) {
0185         return 1;
0186     }
0187 
0188     return prot->m_maxWorkers;
0189 }
0190 
0191 int KProtocolInfo::maxWorkersPerHost(const QString &_protocol)
0192 {
0193     KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
0194     if (!prot) {
0195         return 0;
0196     }
0197 
0198     return prot->m_maxWorkersPerHost;
0199 }
0200 
0201 bool KProtocolInfo::determineMimetypeFromExtension(const QString &_protocol)
0202 {
0203     KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
0204     if (!prot) {
0205         return true;
0206     }
0207 
0208     return prot->m_determineMimetypeFromExtension;
0209 }
0210 
0211 QString KProtocolInfo::exec(const QString &protocol)
0212 {
0213     KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(protocol);
0214     if (!prot) {
0215         return QString();
0216     }
0217     return prot->m_exec;
0218 }
0219 
0220 KProtocolInfo::ExtraFieldList KProtocolInfo::extraFields(const QUrl &url)
0221 {
0222     KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(url.scheme());
0223     if (!prot) {
0224         return ExtraFieldList();
0225     }
0226 
0227     return prot->m_extraFields;
0228 }
0229 
0230 QString KProtocolInfo::defaultMimetype(const QString &_protocol)
0231 {
0232     KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
0233     if (!prot) {
0234         return QString();
0235     }
0236 
0237     return prot->m_defaultMimetype;
0238 }
0239 
0240 QString KProtocolInfo::docPath(const QString &_protocol)
0241 {
0242     KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
0243     if (!prot) {
0244         return QString();
0245     }
0246 
0247     return prot->m_docPath;
0248 }
0249 
0250 QString KProtocolInfo::protocolClass(const QString &_protocol)
0251 {
0252     KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
0253     if (!prot) {
0254         return QString();
0255     }
0256 
0257     return prot->m_protClass;
0258 }
0259 
0260 bool KProtocolInfo::showFilePreview(const QString &_protocol)
0261 {
0262     KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
0263     const bool defaultSetting = prot ? prot->m_showPreviews : false;
0264 
0265     KConfigGroup group(KSharedConfig::openConfig(), QStringLiteral("PreviewSettings"));
0266     return group.readEntry(_protocol, defaultSetting);
0267 }
0268 
0269 QStringList KProtocolInfo::capabilities(const QString &_protocol)
0270 {
0271     KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
0272     if (!prot) {
0273         return QStringList();
0274     }
0275 
0276     return prot->m_capabilities;
0277 }
0278 
0279 QStringList KProtocolInfo::archiveMimetypes(const QString &protocol)
0280 {
0281     KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(protocol);
0282     if (!prot) {
0283         return QStringList();
0284     }
0285 
0286     return prot->m_archiveMimeTypes;
0287 }
0288 
0289 QString KProtocolInfo::proxiedBy(const QString &_protocol)
0290 {
0291     KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
0292     if (!prot) {
0293         return QString();
0294     }
0295 
0296     return prot->m_proxyProtocol;
0297 }
0298 
0299 bool KProtocolInfo::isFilterProtocol(const QUrl &url)
0300 {
0301     return isFilterProtocol(url.scheme());
0302 }
0303 
0304 bool KProtocolInfo::isHelperProtocol(const QUrl &url)
0305 {
0306     return isHelperProtocol(url.scheme());
0307 }
0308 
0309 bool KProtocolInfo::isHelperProtocol(const QString &protocol)
0310 {
0311     // We call the findProtocol directly (not via KProtocolManager) to bypass any proxy settings.
0312     KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(protocol);
0313     if (prot) {
0314         return prot->m_isHelperProtocol;
0315     }
0316     return false;
0317 }
0318 
0319 bool KProtocolInfo::isKnownProtocol(const QUrl &url)
0320 {
0321     return isKnownProtocol(url.scheme());
0322 }
0323 
0324 bool KProtocolInfo::isKnownProtocol(const QString &protocol, bool updateCacheIfNotfound)
0325 {
0326     // We call the findProtocol (const QString&) to bypass any proxy settings.
0327     KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(protocol, updateCacheIfNotfound);
0328     return prot;
0329 }