/* This file is part of the KDE libraries SPDX-FileCopyrightText: 1999 Torben Weis SPDX-FileCopyrightText: 2003 Waldo Bastian SPDX-FileCopyrightText: 2012 David Faure SPDX-FileCopyrightText: 2022 Harald Sitter SPDX-License-Identifier: LGPL-2.0-only */ #include "kprotocolinfo.h" #include "kprotocolinfo_p.h" #include "kprotocolinfofactory_p.h" #include "kiocoredebug.h" #include #include #include #include #include #include #include KProtocolInfoPrivate::KProtocolInfoPrivate(const QString &name, const QString &exec, const QJsonObject &json) : m_name(name) , m_exec(exec) { // source has fallback true if not set m_isSourceProtocol = json.value(QStringLiteral("source")).toBool(true); // true if not set for backwards compatibility m_supportsPermissions = json.value(QStringLiteral("permissions")).toBool(true); // other bools are fine with default false by toBool m_isHelperProtocol = json.value(QStringLiteral("helper")).toBool(); m_supportsReading = json.value(QStringLiteral("reading")).toBool(); m_supportsWriting = json.value(QStringLiteral("writing")).toBool(); m_supportsMakeDir = json.value(QStringLiteral("makedir")).toBool(); m_supportsDeleting = json.value(QStringLiteral("deleting")).toBool(); m_supportsLinking = json.value(QStringLiteral("linking")).toBool(); m_supportsMoving = json.value(QStringLiteral("moving")).toBool(); m_supportsOpening = json.value(QStringLiteral("opening")).toBool(); m_supportsTruncating = json.value(QStringLiteral("truncating")).toBool(); m_canCopyFromFile = json.value(QStringLiteral("copyFromFile")).toBool(); m_canCopyToFile = json.value(QStringLiteral("copyToFile")).toBool(); m_canRenameFromFile = json.value(QStringLiteral("renameFromFile")).toBool(); m_canRenameToFile = json.value(QStringLiteral("renameToFile")).toBool(); m_canDeleteRecursive = json.value(QStringLiteral("deleteRecursive")).toBool(); // default is "FromURL" const QString fnu = json.value(QStringLiteral("fileNameUsedForCopying")).toString(); m_fileNameUsedForCopying = KProtocolInfo::FromUrl; if (fnu == QLatin1String("Name")) { m_fileNameUsedForCopying = KProtocolInfo::Name; } else if (fnu == QLatin1String("DisplayName")) { m_fileNameUsedForCopying = KProtocolInfo::DisplayName; } m_listing = json.value(QStringLiteral("listing")).toVariant().toStringList(); // Many .protocol files say "Listing=false" when they really mean "Listing=" (i.e. unsupported) if (m_listing.count() == 1 && m_listing.first() == QLatin1String("false")) { m_listing.clear(); } m_supportsListing = (m_listing.count() > 0); m_defaultMimetype = json.value(QStringLiteral("defaultMimetype")).toString(); // determineMimetypeFromExtension has fallback true if not set m_determineMimetypeFromExtension = json.value(QStringLiteral("determineMimetypeFromExtension")).toBool(true); m_archiveMimeTypes = json.value(QStringLiteral("archiveMimetype")).toVariant().toStringList(); m_icon = json.value(QStringLiteral("Icon")).toString(); // config has fallback to name if not set m_config = json.value(QStringLiteral("config")).toString(m_name); // max workers has fallback to 1 if not set m_maxWorkers = json.value(QStringLiteral("maxInstances")).toInt(1); m_maxWorkersPerHost = json.value(QStringLiteral("maxInstancesPerHost")).toInt(); QString tmp = json.value(QStringLiteral("input")).toString(); if (tmp == QLatin1String("filesystem")) { m_inputType = KProtocolInfo::T_FILESYSTEM; } else if (tmp == QLatin1String("stream")) { m_inputType = KProtocolInfo::T_STREAM; } else { m_inputType = KProtocolInfo::T_NONE; } tmp = json.value(QStringLiteral("output")).toString(); if (tmp == QLatin1String("filesystem")) { m_outputType = KProtocolInfo::T_FILESYSTEM; } else if (tmp == QLatin1String("stream")) { m_outputType = KProtocolInfo::T_STREAM; } else { m_outputType = KProtocolInfo::T_NONE; } m_docPath = json.value(QStringLiteral("X-DocPath")).toString(); if (m_docPath.isEmpty()) { m_docPath = json.value(QStringLiteral("DocPath")).toString(); } m_protClass = json.value(QStringLiteral("Class")).toString().toLower(); if (!m_protClass.startsWith(QLatin1Char(':'))) { m_protClass.prepend(QLatin1Char(':')); } // ExtraNames is a translated value, use the KCoreAddons helper to read it const QStringList extraNames = KJsonUtils::readTranslatedValue(json, QStringLiteral("ExtraNames")).toVariant().toStringList(); const QStringList extraTypes = json.value(QStringLiteral("ExtraTypes")).toVariant().toStringList(); if (extraNames.size() == extraTypes.size()) { auto func = [](const QString &name, const QString &type) { const int metaType = QMetaType::fromName(type.toLatin1().constData()).id(); // currently QMetaType::Type and ExtraField::Type use the same subset of values, so we can just cast. return KProtocolInfo::ExtraField(name, static_cast(metaType)); }; std::transform(extraNames.cbegin(), extraNames.cend(), extraTypes.cbegin(), std::back_inserter(m_extraFields), func); } else { qCWarning(KIO_CORE) << "Malformed JSON protocol file for protocol:" << name << ", number of the ExtraNames fields should match the number of ExtraTypes fields"; } // fallback based on class m_showPreviews = json.value(QStringLiteral("ShowPreviews")).toBool(m_protClass == QLatin1String(":local")); m_capabilities = json.value(QStringLiteral("Capabilities")).toVariant().toStringList(); m_proxyProtocol = json.value(QStringLiteral("ProxiedBy")).toString(); } // // Static functions: // QStringList KProtocolInfo::protocols() { return KProtocolInfoFactory::self()->protocols(); } bool KProtocolInfo::isFilterProtocol(const QString &_protocol) { // We call the findProtocol directly (not via KProtocolManager) to bypass any proxy settings. KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); if (!prot) { return false; } return !prot->m_isSourceProtocol; } QString KProtocolInfo::icon(const QString &_protocol) { // We call the findProtocol directly (not via KProtocolManager) to bypass any proxy settings. KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); if (!prot) { if (auto service = KApplicationTrader::preferredService(QLatin1String("x-scheme-handler/") + _protocol)) { return service->icon(); } else { return QString(); } } return prot->m_icon; } QString KProtocolInfo::config(const QString &_protocol) { // We call the findProtocol directly (not via KProtocolManager) to bypass any proxy settings. KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); if (!prot) { return QString(); } return QStringLiteral("kio_%1rc").arg(prot->m_config); } int KProtocolInfo::maxWorkers(const QString &_protocol) { KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); if (!prot) { return 1; } return prot->m_maxWorkers; } int KProtocolInfo::maxWorkersPerHost(const QString &_protocol) { KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); if (!prot) { return 0; } return prot->m_maxWorkersPerHost; } bool KProtocolInfo::determineMimetypeFromExtension(const QString &_protocol) { KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); if (!prot) { return true; } return prot->m_determineMimetypeFromExtension; } QString KProtocolInfo::exec(const QString &protocol) { KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(protocol); if (!prot) { return QString(); } return prot->m_exec; } KProtocolInfo::ExtraFieldList KProtocolInfo::extraFields(const QUrl &url) { KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(url.scheme()); if (!prot) { return ExtraFieldList(); } return prot->m_extraFields; } QString KProtocolInfo::defaultMimetype(const QString &_protocol) { KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); if (!prot) { return QString(); } return prot->m_defaultMimetype; } QString KProtocolInfo::docPath(const QString &_protocol) { KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); if (!prot) { return QString(); } return prot->m_docPath; } QString KProtocolInfo::protocolClass(const QString &_protocol) { KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); if (!prot) { return QString(); } return prot->m_protClass; } bool KProtocolInfo::showFilePreview(const QString &_protocol) { KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); const bool defaultSetting = prot ? prot->m_showPreviews : false; KConfigGroup group(KSharedConfig::openConfig(), QStringLiteral("PreviewSettings")); return group.readEntry(_protocol, defaultSetting); } QStringList KProtocolInfo::capabilities(const QString &_protocol) { KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); if (!prot) { return QStringList(); } return prot->m_capabilities; } QStringList KProtocolInfo::archiveMimetypes(const QString &protocol) { KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(protocol); if (!prot) { return QStringList(); } return prot->m_archiveMimeTypes; } #if KIOCORE_BUILD_DEPRECATED_SINCE(6, 4) QString KProtocolInfo::proxiedBy(const QString &_protocol) { KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); if (!prot) { return QString(); } return prot->m_proxyProtocol; } #endif bool KProtocolInfo::isFilterProtocol(const QUrl &url) { return isFilterProtocol(url.scheme()); } bool KProtocolInfo::isHelperProtocol(const QUrl &url) { return isHelperProtocol(url.scheme()); } bool KProtocolInfo::isHelperProtocol(const QString &protocol) { // We call the findProtocol directly (not via KProtocolManager) to bypass any proxy settings. KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(protocol); if (prot) { return prot->m_isHelperProtocol; } return false; } bool KProtocolInfo::isKnownProtocol(const QUrl &url) { return isKnownProtocol(url.scheme()); } bool KProtocolInfo::isKnownProtocol(const QString &protocol, bool updateCacheIfNotfound) { // We call the findProtocol (const QString&) to bypass any proxy settings. KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(protocol, updateCacheIfNotfound); return prot; }