1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1999 Torben Weis <weis@kde.org>
4 SPDX-FileCopyrightText: 2000 Waldo Bastain <bastain@kde.org>
5 SPDX-FileCopyrightText: 2000 Dawit Alemayehu <adawit@kde.org>
6 SPDX-FileCopyrightText: 2008 Jarosław Staniek <staniek@kde.org>
7 SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
8
9 SPDX-License-Identifier: LGPL-2.0-only
10*/
11
12#include "kprotocolmanager.h"
13#include "kprotocolinfo_p.h"
14#include "kprotocolmanager_p.h"
15
16#include "hostinfo.h"
17
18#include <config-kiocore.h>
19
20#include <qplatformdefs.h>
21#include <string.h>
22#ifdef Q_OS_WIN
23#include <qt_windows.h>
24#undef interface // windows.h defines this, breaks QtDBus since it has parameters named interface
25#else
26#include <sys/utsname.h>
27#endif
28
29#include <QCache>
30#include <QCoreApplication>
31#ifndef KIO_ANDROID_STUB
32#include <QDBusInterface>
33#include <QDBusReply>
34#endif
35#include <QHostAddress>
36#include <QHostInfo>
37#include <QLocale>
38#include <QMimeDatabase>
39#include <QRegularExpression>
40#include <QSslSocket>
41#include <QStandardPaths>
42#include <QUrl>
43
44#if !defined(QT_NO_NETWORKPROXY) && (defined(Q_OS_WIN32) || defined(Q_OS_MAC))
45#include <QNetworkProxyFactory>
46#include <QNetworkProxyQuery>
47#endif
48
49#include <KConfigGroup>
50#include <KSharedConfig>
51#include <kio_version.h>
52
53#include <kprotocolinfofactory_p.h>
54
55#include "ioworker_defaults.h"
56#include "workerconfig.h"
57
58/*
59 Domain suffix match. E.g. return true if host is "cuzco.inka.de" and
60 nplist is "inka.de,hadiko.de" or if host is "localhost" and nplist is
61 "localhost".
62*/
63static bool revmatch(const char *host, const char *nplist)
64{
65 if (host == nullptr) {
66 return false;
67 }
68
69 const char *hptr = host + strlen(s: host) - 1;
70 const char *nptr = nplist + strlen(s: nplist) - 1;
71 const char *shptr = hptr;
72
73 while (nptr >= nplist) {
74 if (*hptr != *nptr) {
75 hptr = shptr;
76
77 // Try to find another domain or host in the list
78 while (--nptr >= nplist && *nptr != ',' && *nptr != ' ') {
79 ;
80 }
81
82 // Strip out multiple spaces and commas
83 while (--nptr >= nplist && (*nptr == ',' || *nptr == ' ')) {
84 ;
85 }
86 } else {
87 if (nptr == nplist || nptr[-1] == ',' || nptr[-1] == ' ') {
88 return true;
89 }
90 if (nptr[-1] == '/' && hptr == host) { // "bugs.kde.org" vs "http://bugs.kde.org", the config UI says URLs are ok
91 return true;
92 }
93 if (hptr == host) { // e.g. revmatch("bugs.kde.org","mybugs.kde.org")
94 return false;
95 }
96
97 hptr--;
98 nptr--;
99 }
100 }
101
102 return false;
103}
104
105Q_GLOBAL_STATIC(KProtocolManagerPrivate, kProtocolManagerPrivate)
106
107static void syncOnExit()
108{
109 if (kProtocolManagerPrivate.exists()) {
110 kProtocolManagerPrivate()->sync();
111 }
112}
113
114KProtocolManagerPrivate::KProtocolManagerPrivate()
115{
116 // post routine since KConfig::sync() breaks if called too late
117 qAddPostRoutine(syncOnExit);
118 cachedProxyData.setMaxCost(200); // double the max cost.
119}
120
121KProtocolManagerPrivate::~KProtocolManagerPrivate()
122{
123}
124
125/*
126 * Returns true if url is in the no proxy list.
127 */
128bool KProtocolManagerPrivate::shouldIgnoreProxyFor(const QUrl &url)
129{
130 bool isMatch = false;
131 const ProxyType type = proxyType();
132 const bool useRevProxy = ((type == ManualProxy) && useReverseProxy());
133 const bool useNoProxyList = (type == ManualProxy || type == EnvVarProxy);
134
135 // No proxy only applies to ManualProxy and EnvVarProxy types...
136 if (useNoProxyList && noProxyFor.isEmpty()) {
137 QStringList noProxyForList(readNoProxyFor().split(sep: QLatin1Char(',')));
138 QMutableStringListIterator it(noProxyForList);
139 while (it.hasNext()) {
140 SubnetPair subnet = QHostAddress::parseSubnet(subnet: it.next());
141 if (!subnet.first.isNull()) {
142 noProxySubnets << subnet;
143 it.remove();
144 }
145 }
146 noProxyFor = noProxyForList.join(sep: QLatin1Char(','));
147 }
148
149 if (!noProxyFor.isEmpty()) {
150 QString qhost = url.host().toLower();
151 QByteArray host = qhost.toLatin1();
152 const QString qno_proxy = noProxyFor.trimmed().toLower();
153 const QByteArray no_proxy = qno_proxy.toLatin1();
154 isMatch = revmatch(host: host.constData(), nplist: no_proxy.constData());
155
156 // If no match is found and the request url has a port
157 // number, try the combination of "host:port". This allows
158 // users to enter host:port in the No-proxy-For list.
159 if (!isMatch && url.port() > 0) {
160 qhost += QLatin1Char(':') + QString::number(url.port());
161 host = qhost.toLatin1();
162 isMatch = revmatch(host: host.constData(), nplist: no_proxy.constData());
163 }
164
165 // If the hostname does not contain a dot, check if
166 // <local> is part of noProxy.
167 if (!isMatch && !host.isEmpty() && (strchr(s: host.constData(), c: '.') == nullptr)) {
168 isMatch = revmatch(host: "<local>", nplist: no_proxy.constData());
169 }
170 }
171
172 const QString host(url.host());
173
174 if (!noProxySubnets.isEmpty() && !host.isEmpty()) {
175 QHostAddress address(host);
176 // If request url is not IP address, do a DNS lookup of the hostname.
177 // TODO: Perhaps we should make configurable ?
178 if (address.isNull()) {
179 // qDebug() << "Performing DNS lookup for" << host;
180 QHostInfo info = KIO::HostInfo::lookupHost(hostName: host, timeout: 2000);
181 const QList<QHostAddress> addresses = info.addresses();
182 if (!addresses.isEmpty()) {
183 address = addresses.first();
184 }
185 }
186
187 if (!address.isNull()) {
188 for (const SubnetPair &subnet : std::as_const(t&: noProxySubnets)) {
189 if (address.isInSubnet(subnet)) {
190 isMatch = true;
191 break;
192 }
193 }
194 }
195 }
196
197 return (useRevProxy != isMatch);
198}
199
200void KProtocolManagerPrivate::sync()
201{
202 QMutexLocker lock(&mutex);
203 if (http_config) {
204 http_config->sync();
205 }
206 if (configPtr) {
207 configPtr->sync();
208 }
209}
210
211void KProtocolManager::reparseConfiguration()
212{
213 KProtocolManagerPrivate *d = kProtocolManagerPrivate();
214 QMutexLocker lock(&d->mutex);
215 if (d->http_config) {
216 d->http_config->reparseConfiguration();
217 }
218 if (d->configPtr) {
219 d->configPtr->reparseConfiguration();
220 }
221 d->cachedProxyData.clear();
222 d->noProxyFor.clear();
223 d->modifiers.clear();
224 d->useragent.clear();
225 lock.unlock();
226
227 // Force the slave config to re-read its config...
228 KIO::WorkerConfig::self()->reset();
229}
230
231static KSharedConfig::Ptr config()
232{
233 KProtocolManagerPrivate *d = kProtocolManagerPrivate();
234 Q_ASSERT(!d->mutex.tryLock()); // the caller must have locked the mutex
235 if (!d->configPtr) {
236 d->configPtr = KSharedConfig::openConfig(QStringLiteral("kioslaverc"), mode: KConfig::NoGlobals);
237 }
238 return d->configPtr;
239}
240
241KProtocolManagerPrivate::ProxyType KProtocolManagerPrivate::proxyType()
242{
243 KConfigGroup cg(config(), QStringLiteral("Proxy Settings"));
244 return static_cast<ProxyType>(cg.readEntry(key: "ProxyType", defaultValue: 0));
245}
246
247bool KProtocolManagerPrivate::useReverseProxy()
248{
249 KConfigGroup cg(config(), QStringLiteral("Proxy Settings"));
250 return cg.readEntry(key: "ReversedException", defaultValue: false);
251}
252
253QString KProtocolManagerPrivate::readNoProxyFor()
254{
255 QString noProxy = config()->group(QStringLiteral("Proxy Settings")).readEntry(key: "NoProxyFor");
256 if (proxyType() == EnvVarProxy) {
257 noProxy = QString::fromLocal8Bit(ba: qgetenv(varName: noProxy.toLocal8Bit().constData()));
258 }
259 return noProxy;
260}
261
262QMap<QString, QString> KProtocolManager::entryMap(const QString &group)
263{
264 KProtocolManagerPrivate *d = kProtocolManagerPrivate();
265 QMutexLocker lock(&d->mutex);
266 return config()->entryMap(aGroup: group);
267}
268
269/*=============================== TIMEOUT SETTINGS ==========================*/
270
271int KProtocolManager::readTimeout()
272{
273 KProtocolManagerPrivate *d = kProtocolManagerPrivate();
274 QMutexLocker lock(&d->mutex);
275 KConfigGroup cg(config(), QString());
276 int val = cg.readEntry(key: "ReadTimeout", defaultValue: DEFAULT_READ_TIMEOUT);
277 return qMax(a: MIN_TIMEOUT_VALUE, b: val);
278}
279
280int KProtocolManager::connectTimeout()
281{
282 KProtocolManagerPrivate *d = kProtocolManagerPrivate();
283 QMutexLocker lock(&d->mutex);
284 KConfigGroup cg(config(), QString());
285 int val = cg.readEntry(key: "ConnectTimeout", defaultValue: DEFAULT_CONNECT_TIMEOUT);
286 return qMax(a: MIN_TIMEOUT_VALUE, b: val);
287}
288
289int KProtocolManager::proxyConnectTimeout()
290{
291 KProtocolManagerPrivate *d = kProtocolManagerPrivate();
292 QMutexLocker lock(&d->mutex);
293 KConfigGroup cg(config(), QString());
294 int val = cg.readEntry(key: "ProxyConnectTimeout", defaultValue: DEFAULT_PROXY_CONNECT_TIMEOUT);
295 return qMax(a: MIN_TIMEOUT_VALUE, b: val);
296}
297
298int KProtocolManager::responseTimeout()
299{
300 KProtocolManagerPrivate *d = kProtocolManagerPrivate();
301 QMutexLocker lock(&d->mutex);
302 KConfigGroup cg(config(), QString());
303 int val = cg.readEntry(key: "ResponseTimeout", defaultValue: DEFAULT_RESPONSE_TIMEOUT);
304 return qMax(a: MIN_TIMEOUT_VALUE, b: val);
305}
306
307static QString adjustProtocol(const QString &scheme)
308{
309 if (scheme.compare(other: QLatin1String("webdav"), cs: Qt::CaseInsensitive) == 0) {
310 return QStringLiteral("http");
311 }
312
313 if (scheme.compare(other: QLatin1String("webdavs"), cs: Qt::CaseInsensitive) == 0) {
314 return QStringLiteral("https");
315 }
316
317 return scheme.toLower();
318}
319
320QString KProtocolManagerPrivate::proxyFor(const QString &protocol)
321{
322 const QString key = adjustProtocol(scheme: protocol) + QLatin1String("Proxy");
323 QString proxyStr(config()->group(QStringLiteral("Proxy Settings")).readEntry(key));
324 const int index = proxyStr.lastIndexOf(c: QLatin1Char(' '));
325
326 if (index > -1) {
327 const QStringView portStr = QStringView(proxyStr).right(n: proxyStr.length() - index - 1);
328 const bool isDigits = std::all_of(first: portStr.cbegin(), last: portStr.cend(), pred: [](const QChar c) {
329 return c.isDigit();
330 });
331
332 if (isDigits) {
333 proxyStr = QStringView(proxyStr).left(n: index) + QLatin1Char(':') + portStr;
334 } else {
335 proxyStr.clear();
336 }
337 }
338
339 return proxyStr;
340}
341
342QStringList KProtocolManagerPrivate::getSystemProxyFor(const QUrl &url)
343{
344 QStringList proxies;
345
346#if !defined(QT_NO_NETWORKPROXY) && (defined(Q_OS_WIN32) || defined(Q_OS_MAC))
347 QNetworkProxyQuery query(url);
348 const QList<QNetworkProxy> proxyList = QNetworkProxyFactory::systemProxyForQuery(query);
349 proxies.reserve(proxyList.size());
350 for (const QNetworkProxy &proxy : proxyList) {
351 QUrl url;
352 const QNetworkProxy::ProxyType type = proxy.type();
353 if (type == QNetworkProxy::NoProxy || type == QNetworkProxy::DefaultProxy) {
354 proxies << QLatin1String("DIRECT");
355 continue;
356 }
357
358 if (type == QNetworkProxy::HttpProxy || type == QNetworkProxy::HttpCachingProxy) {
359 url.setScheme(QLatin1String("http"));
360 } else if (type == QNetworkProxy::Socks5Proxy) {
361 url.setScheme(QLatin1String("socks"));
362 } else if (type == QNetworkProxy::FtpCachingProxy) {
363 url.setScheme(QLatin1String("ftp"));
364 }
365
366 url.setHost(proxy.hostName());
367 url.setPort(proxy.port());
368 url.setUserName(proxy.user());
369 proxies << url.url();
370 }
371#else
372 // On Unix/Linux use system environment variables if any are set.
373 QString proxyVar(proxyFor(protocol: url.scheme()));
374 // Check for SOCKS proxy, if not proxy is found for given url.
375 if (!proxyVar.isEmpty()) {
376 const QString proxy(QString::fromLocal8Bit(ba: qgetenv(varName: proxyVar.toLocal8Bit().constData())).trimmed());
377 if (!proxy.isEmpty()) {
378 proxies << proxy;
379 }
380 }
381 // Add the socks proxy as an alternate proxy if it exists,
382 proxyVar = proxyFor(QStringLiteral("socks"));
383 if (!proxyVar.isEmpty()) {
384 QString proxy = QString::fromLocal8Bit(ba: qgetenv(varName: proxyVar.toLocal8Bit().constData())).trimmed();
385 // Make sure the scheme of SOCKS proxy is always set to "socks://".
386 const int index = proxy.indexOf(s: QLatin1String("://"));
387 const int offset = (index == -1) ? 0 : (index + 3);
388 proxy = QLatin1String("socks://") + QStringView(proxy).mid(pos: offset);
389 if (!proxy.isEmpty()) {
390 proxies << proxy;
391 }
392 }
393#endif
394 return proxies;
395}
396
397QStringList KProtocolManagerPrivate::proxiesForUrl(const QUrl &url)
398{
399 QStringList proxyList;
400
401 KProtocolManagerPrivate *d = kProtocolManagerPrivate();
402 QMutexLocker lock(&d->mutex);
403 if (!d->shouldIgnoreProxyFor(url)) {
404 switch (d->proxyType()) {
405 case PACProxy:
406 case WPADProxy: {
407 QUrl u(url);
408 const QString protocol = adjustProtocol(scheme: u.scheme());
409 u.setScheme(protocol);
410
411#ifndef KIO_ANDROID_STUB
412 if (protocol.startsWith(s: QLatin1String("http")) || protocol.startsWith(s: QLatin1String("ftp"))) {
413 QDBusReply<QStringList> reply =
414 QDBusInterface(QStringLiteral("org.kde.kded6"), QStringLiteral("/modules/proxyscout"), QStringLiteral("org.kde.KPAC.ProxyScout"))
415 .call(QStringLiteral("proxiesForUrl"), args: u.toString());
416 proxyList = reply;
417 }
418#endif
419 break;
420 }
421 case EnvVarProxy:
422 proxyList = d->getSystemProxyFor(url);
423 break;
424 case ManualProxy: {
425 QString proxy(d->proxyFor(protocol: url.scheme()));
426 if (!proxy.isEmpty()) {
427 proxyList << proxy;
428 }
429 // Add the socks proxy as an alternate proxy if it exists,
430 proxy = d->proxyFor(QStringLiteral("socks"));
431 if (!proxy.isEmpty()) {
432 // Make sure the scheme of SOCKS proxy is always set to "socks://".
433 const int index = proxy.indexOf(s: QLatin1String("://"));
434 const int offset = (index == -1) ? 0 : (index + 3);
435 proxy = QLatin1String("socks://") + QStringView(proxy).mid(pos: offset);
436 proxyList << proxy;
437 }
438 break;
439 }
440 case NoProxy:
441 break;
442 }
443 }
444
445 if (proxyList.isEmpty()) {
446 proxyList << QStringLiteral("DIRECT");
447 }
448
449 return proxyList;
450}
451
452// Generates proxy cache key from request given url.
453static QString extractProxyCacheKeyFromUrl(const QUrl &u)
454{
455 QString key = u.scheme();
456 key += u.host();
457
458 if (u.port() > 0) {
459 key += QString::number(u.port());
460 }
461 return key;
462}
463
464QString KProtocolManagerPrivate::workerProtocol(const QUrl &url, QStringList &proxyList)
465{
466 proxyList.clear();
467 KProtocolManagerPrivate *d = kProtocolManagerPrivate();
468 QMutexLocker lock(&d->mutex);
469 // Do not perform a proxy lookup for any url classified as a ":local" url or
470 // one that does not have a host component or if proxy is disabled.
471 QString protocol(url.scheme());
472 if (url.host().isEmpty() || KProtocolInfo::protocolClass(protocol) == QLatin1String(":local") || kProtocolManagerPrivate->proxyType() == NoProxy) {
473 return protocol;
474 }
475
476 const QString proxyCacheKey = extractProxyCacheKeyFromUrl(u: url);
477
478 // Look for cached proxy information to avoid more work.
479 if (d->cachedProxyData.contains(key: proxyCacheKey)) {
480 KProxyData *data = d->cachedProxyData.object(key: proxyCacheKey);
481 proxyList = data->proxyList;
482 return data->protocol;
483 }
484 lock.unlock();
485
486 const QStringList proxies = KProtocolManagerPrivate::proxiesForUrl(url);
487 const int count = proxies.count();
488
489 if (count > 0 && !(count == 1 && proxies.first() == QLatin1String("DIRECT"))) {
490 for (const QString &proxy : proxies) {
491 if (proxy == QLatin1String("DIRECT")) {
492 proxyList << proxy;
493 } else {
494 QUrl u(proxy);
495 if (!u.isEmpty() && u.isValid() && !u.scheme().isEmpty()) {
496 proxyList << proxy;
497 }
498 }
499 }
500 }
501
502 // The idea behind worker protocols is not applicable to http
503 // and webdav protocols as well as protocols unknown to KDE.
504 /* clang-format off */
505 if (!proxyList.isEmpty()
506 && !protocol.startsWith(s: QLatin1String("http"))
507 && !protocol.startsWith(s: QLatin1String("webdav"))
508 && KProtocolInfo::isKnownProtocol(protocol)) { /* clang-format on */
509 for (const QString &proxy : std::as_const(t&: proxyList)) {
510 QUrl u(proxy);
511 if (u.isValid() && KProtocolInfo::isKnownProtocol(protocol: u.scheme())) {
512 protocol = u.scheme();
513 break;
514 }
515 }
516 }
517
518 lock.relock();
519 // cache the proxy information...
520 d->cachedProxyData.insert(key: proxyCacheKey, object: new KProxyData(protocol, proxyList));
521 return protocol;
522}
523
524/*================================= USER-AGENT SETTINGS =====================*/
525
526// This is not the OS, but the windowing system, e.g. X11 on Unix/Linux.
527static QString platform()
528{
529#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
530 return QStringLiteral("X11");
531#elif defined(Q_OS_MAC)
532 return QStringLiteral("Macintosh");
533#elif defined(Q_OS_WIN)
534 return QStringLiteral("Windows");
535#else
536 return QStringLiteral("Unknown");
537#endif
538}
539
540QString KProtocolManagerPrivate::defaultUserAgent(const QString &_modifiers)
541{
542 KProtocolManagerPrivate *d = kProtocolManagerPrivate();
543 QMutexLocker lock(&d->mutex);
544 QString modifiers = _modifiers.toLower();
545 if (modifiers.isEmpty()) {
546 modifiers = QStringLiteral("om"); // Show OS, Machine
547 }
548
549 if (d->modifiers == modifiers && !d->useragent.isEmpty()) {
550 return d->useragent;
551 }
552
553 d->modifiers = modifiers;
554
555 QString systemName;
556 QString systemVersion;
557 QString machine;
558 QString supp;
559 const bool sysInfoFound = KProtocolManagerPrivate::getSystemNameVersionAndMachine(systemName, systemVersion, machine);
560
561 supp += platform();
562
563 if (sysInfoFound) {
564 if (modifiers.contains(c: QLatin1Char('o'))) {
565 supp += QLatin1String("; ") + systemName;
566 if (modifiers.contains(c: QLatin1Char('v'))) {
567 supp += QLatin1Char(' ') + systemVersion;
568 }
569
570 if (modifiers.contains(c: QLatin1Char('m'))) {
571 supp += QLatin1Char(' ') + machine;
572 }
573 }
574
575 if (modifiers.contains(c: QLatin1Char('l'))) {
576 supp += QLatin1String("; ") + QLocale::languageToString(language: QLocale().language());
577 }
578 }
579
580 QString appName = QCoreApplication::applicationName();
581 if (appName.isEmpty() || appName.startsWith(s: QLatin1String("kcmshell"), cs: Qt::CaseInsensitive)) {
582 appName = QStringLiteral("KDE");
583 }
584 QString appVersion = QCoreApplication::applicationVersion();
585 if (appVersion.isEmpty()) {
586 appVersion += QLatin1String(KIO_VERSION_STRING);
587 }
588
589 d->useragent = QLatin1String("Mozilla/5.0 (%1) ").arg(args&: supp)
590 + QLatin1String("KIO/%1.%2 ").arg(args: QString::number(KIO_VERSION_MAJOR), args: QString::number(KIO_VERSION_MINOR))
591 + QLatin1String("%1/%2").arg(args&: appName, args&: appVersion);
592
593 // qDebug() << "USERAGENT STRING:" << d->useragent;
594 return d->useragent;
595}
596
597bool KProtocolManagerPrivate::getSystemNameVersionAndMachine(QString &systemName, QString &systemVersion, QString &machine)
598{
599#if defined(Q_OS_WIN)
600 // we do not use unameBuf.sysname information constructed in kdewin32
601 // because we want to get separate name and version
602 systemName = QStringLiteral("Windows");
603 OSVERSIONINFOEX versioninfo;
604 ZeroMemory(&versioninfo, sizeof(OSVERSIONINFOEX));
605 // try calling GetVersionEx using the OSVERSIONINFOEX, if that fails, try using the OSVERSIONINFO
606 versioninfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
607 bool ok = GetVersionEx((OSVERSIONINFO *)&versioninfo);
608 if (!ok) {
609 versioninfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
610 ok = GetVersionEx((OSVERSIONINFO *)&versioninfo);
611 }
612 if (ok) {
613 systemVersion = QString::number(versioninfo.dwMajorVersion);
614 systemVersion += QLatin1Char('.');
615 systemVersion += QString::number(versioninfo.dwMinorVersion);
616 }
617#else
618 struct utsname unameBuf;
619 if (0 != uname(name: &unameBuf)) {
620 return false;
621 }
622 systemName = QString::fromUtf8(utf8: unameBuf.sysname);
623 systemVersion = QString::fromUtf8(utf8: unameBuf.release);
624 machine = QString::fromUtf8(utf8: unameBuf.machine);
625#endif
626 return true;
627}
628
629/*==================================== OTHERS ===============================*/
630
631bool KProtocolManager::markPartial()
632{
633 KProtocolManagerPrivate *d = kProtocolManagerPrivate();
634 QMutexLocker lock(&d->mutex);
635 return config()->group(group: QString()).readEntry(key: "MarkPartial", defaultValue: true);
636}
637
638int KProtocolManager::minimumKeepSize()
639{
640 KProtocolManagerPrivate *d = kProtocolManagerPrivate();
641 QMutexLocker lock(&d->mutex);
642 return config()->group(group: QString()).readEntry(key: "MinimumKeepSize",
643 defaultValue: DEFAULT_MINIMUM_KEEP_SIZE); // 5000 byte
644}
645
646bool KProtocolManager::autoResume()
647{
648 KProtocolManagerPrivate *d = kProtocolManagerPrivate();
649 QMutexLocker lock(&d->mutex);
650 return config()->group(group: QString()).readEntry(key: "AutoResume", defaultValue: false);
651}
652
653/* =========================== PROTOCOL CAPABILITIES ============== */
654
655static KProtocolInfoPrivate *findProtocol(const QUrl &url)
656{
657 if (!url.isValid()) {
658 return nullptr;
659 }
660 QString protocol = url.scheme();
661 if (!KProtocolInfo::proxiedBy(protocol).isEmpty()) {
662 QStringList dummy;
663 protocol = KProtocolManagerPrivate::workerProtocol(url, proxyList&: dummy);
664 }
665
666 return KProtocolInfoFactory::self()->findProtocol(protocol);
667}
668
669KProtocolInfo::Type KProtocolManager::inputType(const QUrl &url)
670{
671 KProtocolInfoPrivate *prot = findProtocol(url);
672 if (!prot) {
673 return KProtocolInfo::T_NONE;
674 }
675
676 return prot->m_inputType;
677}
678
679KProtocolInfo::Type KProtocolManager::outputType(const QUrl &url)
680{
681 KProtocolInfoPrivate *prot = findProtocol(url);
682 if (!prot) {
683 return KProtocolInfo::T_NONE;
684 }
685
686 return prot->m_outputType;
687}
688
689bool KProtocolManager::isSourceProtocol(const QUrl &url)
690{
691 KProtocolInfoPrivate *prot = findProtocol(url);
692 if (!prot) {
693 return false;
694 }
695
696 return prot->m_isSourceProtocol;
697}
698
699bool KProtocolManager::supportsListing(const QUrl &url)
700{
701 KProtocolInfoPrivate *prot = findProtocol(url);
702 if (!prot) {
703 return false;
704 }
705
706 return prot->m_supportsListing;
707}
708
709QStringList KProtocolManager::listing(const QUrl &url)
710{
711 KProtocolInfoPrivate *prot = findProtocol(url);
712 if (!prot) {
713 return QStringList();
714 }
715
716 return prot->m_listing;
717}
718
719bool KProtocolManager::supportsReading(const QUrl &url)
720{
721 KProtocolInfoPrivate *prot = findProtocol(url);
722 if (!prot) {
723 return false;
724 }
725
726 return prot->m_supportsReading;
727}
728
729bool KProtocolManager::supportsWriting(const QUrl &url)
730{
731 KProtocolInfoPrivate *prot = findProtocol(url);
732 if (!prot) {
733 return false;
734 }
735
736 return prot->m_supportsWriting;
737}
738
739bool KProtocolManager::supportsMakeDir(const QUrl &url)
740{
741 KProtocolInfoPrivate *prot = findProtocol(url);
742 if (!prot) {
743 return false;
744 }
745
746 return prot->m_supportsMakeDir;
747}
748
749bool KProtocolManager::supportsDeleting(const QUrl &url)
750{
751 KProtocolInfoPrivate *prot = findProtocol(url);
752 if (!prot) {
753 return false;
754 }
755
756 return prot->m_supportsDeleting;
757}
758
759bool KProtocolManager::supportsLinking(const QUrl &url)
760{
761 KProtocolInfoPrivate *prot = findProtocol(url);
762 if (!prot) {
763 return false;
764 }
765
766 return prot->m_supportsLinking;
767}
768
769bool KProtocolManager::supportsMoving(const QUrl &url)
770{
771 KProtocolInfoPrivate *prot = findProtocol(url);
772 if (!prot) {
773 return false;
774 }
775
776 return prot->m_supportsMoving;
777}
778
779bool KProtocolManager::supportsOpening(const QUrl &url)
780{
781 KProtocolInfoPrivate *prot = findProtocol(url);
782 if (!prot) {
783 return false;
784 }
785
786 return prot->m_supportsOpening;
787}
788
789bool KProtocolManager::supportsTruncating(const QUrl &url)
790{
791 KProtocolInfoPrivate *prot = findProtocol(url);
792 if (!prot) {
793 return false;
794 }
795
796 return prot->m_supportsTruncating;
797}
798
799bool KProtocolManager::canCopyFromFile(const QUrl &url)
800{
801 KProtocolInfoPrivate *prot = findProtocol(url);
802 if (!prot) {
803 return false;
804 }
805
806 return prot->m_canCopyFromFile;
807}
808
809bool KProtocolManager::canCopyToFile(const QUrl &url)
810{
811 KProtocolInfoPrivate *prot = findProtocol(url);
812 if (!prot) {
813 return false;
814 }
815
816 return prot->m_canCopyToFile;
817}
818
819bool KProtocolManager::canRenameFromFile(const QUrl &url)
820{
821 KProtocolInfoPrivate *prot = findProtocol(url);
822 if (!prot) {
823 return false;
824 }
825
826 return prot->m_canRenameFromFile;
827}
828
829bool KProtocolManager::canRenameToFile(const QUrl &url)
830{
831 KProtocolInfoPrivate *prot = findProtocol(url);
832 if (!prot) {
833 return false;
834 }
835
836 return prot->m_canRenameToFile;
837}
838
839bool KProtocolManager::canDeleteRecursive(const QUrl &url)
840{
841 KProtocolInfoPrivate *prot = findProtocol(url);
842 if (!prot) {
843 return false;
844 }
845
846 return prot->m_canDeleteRecursive;
847}
848
849KProtocolInfo::FileNameUsedForCopying KProtocolManager::fileNameUsedForCopying(const QUrl &url)
850{
851 KProtocolInfoPrivate *prot = findProtocol(url);
852 if (!prot) {
853 return KProtocolInfo::FromUrl;
854 }
855
856 return prot->m_fileNameUsedForCopying;
857}
858
859QString KProtocolManager::defaultMimetype(const QUrl &url)
860{
861 KProtocolInfoPrivate *prot = findProtocol(url);
862 if (!prot) {
863 return QString();
864 }
865
866 return prot->m_defaultMimetype;
867}
868
869QString KProtocolManager::protocolForArchiveMimetype(const QString &mimeType)
870{
871 KProtocolManagerPrivate *d = kProtocolManagerPrivate();
872 QMutexLocker lock(&d->mutex);
873 if (d->protocolForArchiveMimetypes.isEmpty()) {
874 const QList<KProtocolInfoPrivate *> allProtocols = KProtocolInfoFactory::self()->allProtocols();
875 for (KProtocolInfoPrivate *allProtocol : allProtocols) {
876 const QStringList archiveMimetypes = allProtocol->m_archiveMimeTypes;
877 for (const QString &mime : archiveMimetypes) {
878 d->protocolForArchiveMimetypes.insert(key: mime, value: allProtocol->m_name);
879 }
880 }
881 }
882 return d->protocolForArchiveMimetypes.value(key: mimeType);
883}
884
885QString KProtocolManager::charsetFor(const QUrl &url)
886{
887 return KIO::WorkerConfig::self()->configData(protocol: url.scheme(), host: url.host(), QStringLiteral("Charset"));
888}
889
890bool KProtocolManager::supportsPermissions(const QUrl &url)
891{
892 KProtocolInfoPrivate *prot = findProtocol(url);
893 if (!prot) {
894 return true;
895 }
896
897 return prot->m_supportsPermissions;
898}
899
900#undef PRIVATE_DATA
901
902#include "moc_kprotocolmanager_p.cpp"
903

source code of kio/src/core/kprotocolmanager.cpp