File indexing completed on 2023-09-24 04:08:37
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 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 84) 0026 // 0027 // Internal functions: 0028 // 0029 KProtocolInfoPrivate::KProtocolInfoPrivate(const QString &path) 0030 { 0031 KConfig sconfig(path, KConfig::SimpleConfig); 0032 KConfigGroup config(&sconfig, "Protocol"); 0033 0034 m_name = config.readEntry("protocol"); 0035 m_exec = config.readPathEntry("exec", QString()); 0036 m_isSourceProtocol = config.readEntry("source", true); 0037 m_supportsPermissions = config.readEntry("permissions", true); 0038 m_isHelperProtocol = config.readEntry("helper", false); 0039 m_supportsReading = config.readEntry("reading", false); 0040 m_supportsWriting = config.readEntry("writing", false); 0041 m_supportsMakeDir = config.readEntry("makedir", false); 0042 m_supportsDeleting = config.readEntry("deleting", false); 0043 m_supportsLinking = config.readEntry("linking", false); 0044 m_supportsMoving = config.readEntry("moving", false); 0045 m_supportsOpening = config.readEntry("opening", false); 0046 m_supportsTruncating = config.readEntry("truncating", false); 0047 m_canCopyFromFile = config.readEntry("copyFromFile", false); 0048 m_canCopyToFile = config.readEntry("copyToFile", false); 0049 m_canRenameFromFile = config.readEntry("renameFromFile", false); 0050 m_canRenameToFile = config.readEntry("renameToFile", false); 0051 m_canDeleteRecursive = config.readEntry("deleteRecursive", false); 0052 const QString fnu = config.readEntry("fileNameUsedForCopying", "FromURL"); 0053 m_fileNameUsedForCopying = KProtocolInfo::FromUrl; 0054 if (fnu == QLatin1String("Name")) { 0055 m_fileNameUsedForCopying = KProtocolInfo::Name; 0056 } else if (fnu == QLatin1String("DisplayName")) { 0057 m_fileNameUsedForCopying = KProtocolInfo::DisplayName; 0058 } 0059 0060 m_listing = config.readEntry("listing", QStringList()); 0061 // Many .protocol files say "Listing=false" when they really mean "Listing=" (i.e. unsupported) 0062 if (m_listing.count() == 1 && m_listing.first() == QLatin1String("false")) { 0063 m_listing.clear(); 0064 } 0065 m_supportsListing = (m_listing.count() > 0); 0066 m_defaultMimetype = config.readEntry("defaultMimetype"); 0067 m_determineMimetypeFromExtension = config.readEntry("determineMimetypeFromExtension", true); 0068 m_archiveMimeTypes = config.readEntry("archiveMimetype", QStringList()); 0069 m_icon = config.readEntry("Icon"); 0070 m_config = config.readEntry("config", m_name); 0071 m_maxWorkers = config.readEntry("maxInstances", 1); 0072 m_maxWorkersPerHost = config.readEntry("maxInstancesPerHost", 0); 0073 0074 QString tmp = config.readEntry("input"); 0075 if (tmp == QLatin1String("filesystem")) { 0076 m_inputType = KProtocolInfo::T_FILESYSTEM; 0077 } else if (tmp == QLatin1String("stream")) { 0078 m_inputType = KProtocolInfo::T_STREAM; 0079 } else { 0080 m_inputType = KProtocolInfo::T_NONE; 0081 } 0082 0083 tmp = config.readEntry("output"); 0084 if (tmp == QLatin1String("filesystem")) { 0085 m_outputType = KProtocolInfo::T_FILESYSTEM; 0086 } else if (tmp == QLatin1String("stream")) { 0087 m_outputType = KProtocolInfo::T_STREAM; 0088 } else { 0089 m_outputType = KProtocolInfo::T_NONE; 0090 } 0091 0092 m_docPath = config.readPathEntry("X-DocPath", QString()); 0093 if (m_docPath.isEmpty()) { 0094 m_docPath = config.readPathEntry("DocPath", QString()); 0095 } 0096 m_protClass = config.readEntry("Class").toLower(); 0097 if (!m_protClass.startsWith(QLatin1Char(':'))) { 0098 m_protClass.prepend(QLatin1Char(':')); 0099 } 0100 0101 const QStringList extraNames = config.readEntry("ExtraNames", QStringList()); 0102 const QStringList extraTypes = config.readEntry("ExtraTypes", QStringList()); 0103 auto it = extraNames.cbegin(); 0104 auto typeit = extraTypes.cbegin(); 0105 for (; it != extraNames.cend() && typeit != extraTypes.cend(); ++it, ++typeit) { 0106 QVariant::Type type = QVariant::nameToType((*typeit).toLatin1().constData()); 0107 // currently QVariant::Type and ExtraField::Type use the same subset of values, so we can just cast. 0108 m_extraFields.append(KProtocolInfo::ExtraField(*it, static_cast<KProtocolInfo::ExtraField::Type>(type))); 0109 } 0110 0111 m_showPreviews = config.readEntry("ShowPreviews", m_protClass == QLatin1String(":local")); 0112 0113 m_capabilities = config.readEntry("Capabilities", QStringList()); 0114 0115 m_slaveHandlesNotify = config.readEntry("slaveHandlesNotify", QStringList()); 0116 0117 m_proxyProtocol = config.readEntry("ProxiedBy"); 0118 } 0119 #endif 0120 0121 KProtocolInfoPrivate::KProtocolInfoPrivate(const QString &name, const QString &exec, const QJsonObject &json) 0122 : m_name(name) 0123 , m_exec(exec) 0124 { 0125 // source has fallback true if not set 0126 m_isSourceProtocol = json.value(QStringLiteral("source")).toBool(true); 0127 // true if not set for backwards compatibility 0128 m_supportsPermissions = json.value(QStringLiteral("permissions")).toBool(true); 0129 0130 // other bools are fine with default false by toBool 0131 m_isHelperProtocol = json.value(QStringLiteral("helper")).toBool(); 0132 m_supportsReading = json.value(QStringLiteral("reading")).toBool(); 0133 m_supportsWriting = json.value(QStringLiteral("writing")).toBool(); 0134 m_supportsMakeDir = json.value(QStringLiteral("makedir")).toBool(); 0135 m_supportsDeleting = json.value(QStringLiteral("deleting")).toBool(); 0136 m_supportsLinking = json.value(QStringLiteral("linking")).toBool(); 0137 m_supportsMoving = json.value(QStringLiteral("moving")).toBool(); 0138 m_supportsOpening = json.value(QStringLiteral("opening")).toBool(); 0139 m_supportsTruncating = json.value(QStringLiteral("truncating")).toBool(); 0140 m_canCopyFromFile = json.value(QStringLiteral("copyFromFile")).toBool(); 0141 m_canCopyToFile = json.value(QStringLiteral("copyToFile")).toBool(); 0142 m_canRenameFromFile = json.value(QStringLiteral("renameFromFile")).toBool(); 0143 m_canRenameToFile = json.value(QStringLiteral("renameToFile")).toBool(); 0144 m_canDeleteRecursive = json.value(QStringLiteral("deleteRecursive")).toBool(); 0145 0146 // default is "FromURL" 0147 const QString fnu = json.value(QStringLiteral("fileNameUsedForCopying")).toString(); 0148 m_fileNameUsedForCopying = KProtocolInfo::FromUrl; 0149 if (fnu == QLatin1String("Name")) { 0150 m_fileNameUsedForCopying = KProtocolInfo::Name; 0151 } else if (fnu == QLatin1String("DisplayName")) { 0152 m_fileNameUsedForCopying = KProtocolInfo::DisplayName; 0153 } 0154 0155 m_listing = json.value(QStringLiteral("listing")).toVariant().toStringList(); 0156 // Many .protocol files say "Listing=false" when they really mean "Listing=" (i.e. unsupported) 0157 if (m_listing.count() == 1 && m_listing.first() == QLatin1String("false")) { 0158 m_listing.clear(); 0159 } 0160 m_supportsListing = (m_listing.count() > 0); 0161 0162 m_defaultMimetype = json.value(QStringLiteral("defaultMimetype")).toString(); 0163 0164 // determineMimetypeFromExtension has fallback true if not set 0165 m_determineMimetypeFromExtension = json.value(QStringLiteral("determineMimetypeFromExtension")).toBool(true); 0166 0167 m_archiveMimeTypes = json.value(QStringLiteral("archiveMimetype")).toVariant().toStringList(); 0168 0169 m_icon = json.value(QStringLiteral("Icon")).toString(); 0170 0171 // config has fallback to name if not set 0172 m_config = json.value(QStringLiteral("config")).toString(m_name); 0173 0174 // max workers has fallback to 1 if not set 0175 m_maxWorkers = json.value(QStringLiteral("maxInstances")).toInt(1); 0176 0177 m_maxWorkersPerHost = json.value(QStringLiteral("maxInstancesPerHost")).toInt(); 0178 0179 QString tmp = json.value(QStringLiteral("input")).toString(); 0180 if (tmp == QLatin1String("filesystem")) { 0181 m_inputType = KProtocolInfo::T_FILESYSTEM; 0182 } else if (tmp == QLatin1String("stream")) { 0183 m_inputType = KProtocolInfo::T_STREAM; 0184 } else { 0185 m_inputType = KProtocolInfo::T_NONE; 0186 } 0187 0188 tmp = json.value(QStringLiteral("output")).toString(); 0189 if (tmp == QLatin1String("filesystem")) { 0190 m_outputType = KProtocolInfo::T_FILESYSTEM; 0191 } else if (tmp == QLatin1String("stream")) { 0192 m_outputType = KProtocolInfo::T_STREAM; 0193 } else { 0194 m_outputType = KProtocolInfo::T_NONE; 0195 } 0196 0197 m_docPath = json.value(QStringLiteral("X-DocPath")).toString(); 0198 if (m_docPath.isEmpty()) { 0199 m_docPath = json.value(QStringLiteral("DocPath")).toString(); 0200 } 0201 0202 m_protClass = json.value(QStringLiteral("Class")).toString().toLower(); 0203 if (!m_protClass.startsWith(QLatin1Char(':'))) { 0204 m_protClass.prepend(QLatin1Char(':')); 0205 } 0206 0207 // ExtraNames is a translated value, use the KCoreAddons helper to read it 0208 const QStringList extraNames = KJsonUtils::readTranslatedValue(json, QStringLiteral("ExtraNames")).toVariant().toStringList(); 0209 const QStringList extraTypes = json.value(QStringLiteral("ExtraTypes")).toVariant().toStringList(); 0210 if (extraNames.size() == extraTypes.size()) { 0211 auto func = [](const QString &name, const QString &type) { 0212 QVariant::Type variantType = QVariant::nameToType(type.toLatin1().constData()); 0213 // currently QVariant::Type and ExtraField::Type use the same subset of values, so we can just cast. 0214 return KProtocolInfo::ExtraField(name, static_cast<KProtocolInfo::ExtraField::Type>(variantType)); 0215 }; 0216 0217 std::transform(extraNames.cbegin(), extraNames.cend(), extraTypes.cbegin(), std::back_inserter(m_extraFields), func); 0218 } else { 0219 qCWarning(KIO_CORE) << "Malformed JSON protocol file for protocol:" << name 0220 << ", number of the ExtraNames fields should match the number of ExtraTypes fields"; 0221 } 0222 0223 // fallback based on class 0224 m_showPreviews = json.value(QStringLiteral("ShowPreviews")).toBool(m_protClass == QLatin1String(":local")); 0225 0226 m_capabilities = json.value(QStringLiteral("Capabilities")).toVariant().toStringList(); 0227 0228 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 101) 0229 m_slaveHandlesNotify = json.value(QStringLiteral("slaveHandlesNotify")).toVariant().toStringList(); 0230 #endif 0231 0232 m_proxyProtocol = json.value(QStringLiteral("ProxiedBy")).toString(); 0233 } 0234 0235 // 0236 // Static functions: 0237 // 0238 0239 QStringList KProtocolInfo::protocols() 0240 { 0241 return KProtocolInfoFactory::self()->protocols(); 0242 } 0243 0244 bool KProtocolInfo::isFilterProtocol(const QString &_protocol) 0245 { 0246 // We call the findProtocol directly (not via KProtocolManager) to bypass any proxy settings. 0247 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); 0248 if (!prot) { 0249 return false; 0250 } 0251 0252 return !prot->m_isSourceProtocol; 0253 } 0254 0255 QString KProtocolInfo::icon(const QString &_protocol) 0256 { 0257 // We call the findProtocol directly (not via KProtocolManager) to bypass any proxy settings. 0258 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); 0259 if (!prot) { 0260 if (auto service = KApplicationTrader::preferredService(QLatin1String("x-scheme-handler/") + _protocol)) { 0261 return service->icon(); 0262 } else { 0263 return QString(); 0264 } 0265 } 0266 0267 return prot->m_icon; 0268 } 0269 0270 QString KProtocolInfo::config(const QString &_protocol) 0271 { 0272 // We call the findProtocol directly (not via KProtocolManager) to bypass any proxy settings. 0273 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); 0274 if (!prot) { 0275 return QString(); 0276 } 0277 0278 return QStringLiteral("kio_%1rc").arg(prot->m_config); 0279 } 0280 0281 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 101) 0282 int KProtocolInfo::maxSlaves(const QString &_protocol) 0283 { 0284 return maxWorkers(_protocol); 0285 } 0286 #endif 0287 0288 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 101) 0289 int KProtocolInfo::maxSlavesPerHost(const QString &_protocol) 0290 { 0291 return maxWorkersPerHost(_protocol); 0292 } 0293 #endif 0294 0295 int KProtocolInfo::maxWorkers(const QString &_protocol) 0296 { 0297 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); 0298 if (!prot) { 0299 return 1; 0300 } 0301 0302 return prot->m_maxWorkers; 0303 } 0304 0305 int KProtocolInfo::maxWorkersPerHost(const QString &_protocol) 0306 { 0307 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); 0308 if (!prot) { 0309 return 0; 0310 } 0311 0312 return prot->m_maxWorkersPerHost; 0313 } 0314 0315 bool KProtocolInfo::determineMimetypeFromExtension(const QString &_protocol) 0316 { 0317 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); 0318 if (!prot) { 0319 return true; 0320 } 0321 0322 return prot->m_determineMimetypeFromExtension; 0323 } 0324 0325 QString KProtocolInfo::exec(const QString &protocol) 0326 { 0327 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(protocol); 0328 if (!prot) { 0329 return QString(); 0330 } 0331 return prot->m_exec; 0332 } 0333 0334 KProtocolInfo::ExtraFieldList KProtocolInfo::extraFields(const QUrl &url) 0335 { 0336 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(url.scheme()); 0337 if (!prot) { 0338 return ExtraFieldList(); 0339 } 0340 0341 return prot->m_extraFields; 0342 } 0343 0344 QString KProtocolInfo::defaultMimetype(const QString &_protocol) 0345 { 0346 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); 0347 if (!prot) { 0348 return QString(); 0349 } 0350 0351 return prot->m_defaultMimetype; 0352 } 0353 0354 QString KProtocolInfo::docPath(const QString &_protocol) 0355 { 0356 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); 0357 if (!prot) { 0358 return QString(); 0359 } 0360 0361 return prot->m_docPath; 0362 } 0363 0364 QString KProtocolInfo::protocolClass(const QString &_protocol) 0365 { 0366 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); 0367 if (!prot) { 0368 return QString(); 0369 } 0370 0371 return prot->m_protClass; 0372 } 0373 0374 bool KProtocolInfo::showFilePreview(const QString &_protocol) 0375 { 0376 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); 0377 const bool defaultSetting = prot ? prot->m_showPreviews : false; 0378 0379 KConfigGroup group(KSharedConfig::openConfig(), "PreviewSettings"); 0380 return group.readEntry(_protocol, defaultSetting); 0381 } 0382 0383 QStringList KProtocolInfo::capabilities(const QString &_protocol) 0384 { 0385 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); 0386 if (!prot) { 0387 return QStringList(); 0388 } 0389 0390 return prot->m_capabilities; 0391 } 0392 0393 QStringList KProtocolInfo::archiveMimetypes(const QString &protocol) 0394 { 0395 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(protocol); 0396 if (!prot) { 0397 return QStringList(); 0398 } 0399 0400 return prot->m_archiveMimeTypes; 0401 } 0402 0403 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 101) 0404 QStringList KProtocolInfo::slaveHandlesNotify(const QString &_protocol) 0405 { 0406 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); 0407 if (!prot) { 0408 return QStringList(); 0409 } 0410 0411 return prot->m_slaveHandlesNotify; 0412 } 0413 #endif 0414 0415 QString KProtocolInfo::proxiedBy(const QString &_protocol) 0416 { 0417 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(_protocol); 0418 if (!prot) { 0419 return QString(); 0420 } 0421 0422 return prot->m_proxyProtocol; 0423 } 0424 0425 bool KProtocolInfo::isFilterProtocol(const QUrl &url) 0426 { 0427 return isFilterProtocol(url.scheme()); 0428 } 0429 0430 bool KProtocolInfo::isHelperProtocol(const QUrl &url) 0431 { 0432 return isHelperProtocol(url.scheme()); 0433 } 0434 0435 bool KProtocolInfo::isHelperProtocol(const QString &protocol) 0436 { 0437 // We call the findProtocol directly (not via KProtocolManager) to bypass any proxy settings. 0438 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(protocol); 0439 if (prot) { 0440 return prot->m_isHelperProtocol; 0441 } 0442 return false; 0443 } 0444 0445 bool KProtocolInfo::isKnownProtocol(const QUrl &url) 0446 { 0447 return isKnownProtocol(url.scheme()); 0448 } 0449 0450 bool KProtocolInfo::isKnownProtocol(const QString &protocol) 0451 { 0452 // We call the findProtocol (const QString&) to bypass any proxy settings. 0453 KProtocolInfoPrivate *prot = KProtocolInfoFactory::self()->findProtocol(protocol); 0454 return prot; 0455 }