KIO
kprotocolmanager.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 1999 Torben Weis <weis@kde.org> 00003 Copyright (C) 2000- Waldo Bastain <bastain@kde.org> 00004 Copyright (C) 2000- Dawit Alemayehu <adawit@kde.org> 00005 Copyright (C) 2008 Jarosław Staniek <staniek@kde.org> 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License version 2 as published by the Free Software Foundation. 00010 00011 This library is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 Library General Public License for more details. 00015 00016 You should have received a copy of the GNU Library General Public License 00017 along with this library; see the file COPYING.LIB. If not, write to 00018 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 Boston, MA 02110-1301, USA. 00020 */ 00021 00022 #include "kprotocolmanager.h" 00023 00024 #include "hostinfo_p.h" 00025 00026 #include <string.h> 00027 #include <unistd.h> 00028 #include <sys/utsname.h> 00029 00030 #include <QtCore/QCoreApplication> 00031 #include <QtNetwork/QSslSocket> 00032 #include <QtNetwork/QHostAddress> 00033 #include <QtNetwork/QHostInfo> 00034 #include <QtDBus/QtDBus> 00035 00036 #if !defined(QT_NO_NETWORKPROXY) && (defined (Q_OS_WIN32) || defined(Q_OS_MAC)) 00037 #include <QtNetwork/QNetworkProxyFactory> 00038 #include <QtNetwork/QNetworkProxyQuery> 00039 #endif 00040 00041 #include <kdeversion.h> 00042 #include <kdebug.h> 00043 #include <kglobal.h> 00044 #include <klocale.h> 00045 #include <kconfiggroup.h> 00046 #include <ksharedconfig.h> 00047 #include <kstandarddirs.h> 00048 #include <kurl.h> 00049 #include <kmimetypetrader.h> 00050 #include <kprotocolinfofactory.h> 00051 00052 #include <kio/slaveconfig.h> 00053 #include <kio/ioslave_defaults.h> 00054 #include <kio/http_slave_defaults.h> 00055 00056 #define QL1S(x) QLatin1String(x) 00057 #define QL1C(x) QLatin1Char(x) 00058 00059 typedef QPair<QHostAddress, int> SubnetPair; 00060 00061 /* 00062 Domain suffix match. E.g. return true if host is "cuzco.inka.de" and 00063 nplist is "inka.de,hadiko.de" or if host is "localhost" and nplist is 00064 "localhost". 00065 */ 00066 static bool revmatch(const char *host, const char *nplist) 00067 { 00068 if (host == 0) 00069 return false; 00070 00071 const char *hptr = host + strlen( host ) - 1; 00072 const char *nptr = nplist + strlen( nplist ) - 1; 00073 const char *shptr = hptr; 00074 00075 while ( nptr >= nplist ) 00076 { 00077 if ( *hptr != *nptr ) 00078 { 00079 hptr = shptr; 00080 00081 // Try to find another domain or host in the list 00082 while(--nptr>=nplist && *nptr!=',' && *nptr!=' ') ; 00083 00084 // Strip out multiple spaces and commas 00085 while(--nptr>=nplist && (*nptr==',' || *nptr==' ')) ; 00086 } 00087 else 00088 { 00089 if ( nptr==nplist || nptr[-1]==',' || nptr[-1]==' ') 00090 return true; 00091 if ( nptr[-1]=='/' && hptr == host ) // "bugs.kde.org" vs "http://bugs.kde.org", the config UI says URLs are ok 00092 return true; 00093 if ( hptr == host ) // e.g. revmatch("bugs.kde.org","mybugs.kde.org") 00094 return false; 00095 00096 hptr--; 00097 nptr--; 00098 } 00099 } 00100 00101 return false; 00102 } 00103 00104 class KProtocolManagerPrivate 00105 { 00106 public: 00107 KProtocolManagerPrivate(); 00108 ~KProtocolManagerPrivate(); 00109 bool shouldIgnoreProxyFor(const KUrl& url); 00110 00111 KSharedConfig::Ptr config; 00112 KSharedConfig::Ptr http_config; 00113 KUrl url; 00114 QString protocol; 00115 QStringList proxyList; 00116 QString modifiers; 00117 QString useragent; 00118 QString noProxyFor; 00119 QList<SubnetPair> noProxySubnets; 00120 00121 QMap<QString /*mimetype*/, QString /*protocol*/> protocolForArchiveMimetypes; 00122 }; 00123 00124 K_GLOBAL_STATIC(KProtocolManagerPrivate, kProtocolManagerPrivate) 00125 00126 KProtocolManagerPrivate::KProtocolManagerPrivate() 00127 { 00128 // post routine since KConfig::sync() breaks if called too late 00129 qAddPostRoutine(kProtocolManagerPrivate.destroy); 00130 } 00131 00132 KProtocolManagerPrivate::~KProtocolManagerPrivate() 00133 { 00134 qRemovePostRoutine(kProtocolManagerPrivate.destroy); 00135 } 00136 00137 /* 00138 * Returns true if url is in the no proxy list. 00139 */ 00140 bool KProtocolManagerPrivate::shouldIgnoreProxyFor(const KUrl& url) 00141 { 00142 bool isMatch = false; 00143 const KProtocolManager::ProxyType type = KProtocolManager::proxyType(); 00144 const bool useRevProxy = ((type == KProtocolManager::ManualProxy) && KProtocolManager::useReverseProxy()); 00145 const bool hasNoProxyList = (type == KProtocolManager::ManualProxy || type == KProtocolManager::EnvVarProxy); 00146 00147 // No proxy only applies to ManualProxy and EnvVarProxy types... 00148 if (hasNoProxyList && !noProxyFor.isEmpty()) { 00149 QStringList noProxyForList (KProtocolManager::noProxyFor().split(QL1C(','))); 00150 QMutableStringListIterator it (noProxyForList); 00151 while (it.hasNext()) { 00152 SubnetPair subnet = QHostAddress::parseSubnet(it.next()); 00153 if (!subnet.first.isNull()) { 00154 noProxySubnets << subnet; 00155 it.remove(); 00156 } 00157 } 00158 noProxyFor = noProxyForList.join(QL1S(",")); 00159 } 00160 00161 if (!noProxyFor.isEmpty()) { 00162 QString qhost = url.host().toLower(); 00163 QByteArray host = qhost.toLatin1(); 00164 const QString qno_proxy = noProxyFor.trimmed().toLower(); 00165 const QByteArray no_proxy = qno_proxy.toLatin1(); 00166 isMatch = revmatch(host, no_proxy); 00167 00168 // If no match is found and the request url has a port 00169 // number, try the combination of "host:port". This allows 00170 // users to enter host:port in the No-proxy-For list. 00171 if (!isMatch && url.port() > 0) { 00172 qhost += QL1C(':'); 00173 qhost += QString::number(url.port()); 00174 host = qhost.toLatin1(); 00175 isMatch = revmatch (host, no_proxy); 00176 } 00177 00178 // If the hostname does not contain a dot, check if 00179 // <local> is part of noProxy. 00180 if (!isMatch && !host.isEmpty() && (strchr(host, '.') == NULL)) { 00181 isMatch = revmatch("<local>", no_proxy); 00182 } 00183 } 00184 00185 if (!noProxySubnets.isEmpty()) { 00186 QHostAddress address (url.host()); 00187 if (address.isNull()) { 00188 QHostInfo info = KIO::HostInfo::lookupHost(url.host(), 2000); 00189 address = info.addresses().first(); 00190 } 00191 00192 if (!address.isNull()) { 00193 Q_FOREACH(const SubnetPair& subnet, noProxySubnets) { 00194 if (address.isInSubnet(subnet)) { 00195 isMatch = true; 00196 break; 00197 } 00198 } 00199 } 00200 } 00201 00202 return (useRevProxy != isMatch); 00203 } 00204 00205 00206 #define PRIVATE_DATA \ 00207 KProtocolManagerPrivate *d = kProtocolManagerPrivate 00208 00209 void KProtocolManager::reparseConfiguration() 00210 { 00211 PRIVATE_DATA; 00212 if (d->http_config) { 00213 d->http_config->reparseConfiguration(); 00214 } 00215 if (d->config) { 00216 d->config->reparseConfiguration(); 00217 } 00218 d->protocol.clear(); 00219 d->proxyList.clear(); 00220 d->noProxyFor.clear(); 00221 d->modifiers.clear(); 00222 d->useragent.clear(); 00223 d->url.clear(); 00224 00225 // Force the slave config to re-read its config... 00226 KIO::SlaveConfig::self()->reset (); 00227 } 00228 00229 KSharedConfig::Ptr KProtocolManager::config() 00230 { 00231 PRIVATE_DATA; 00232 if (!d->config) 00233 { 00234 d->config = KSharedConfig::openConfig("kioslaverc", KConfig::NoGlobals); 00235 } 00236 return d->config; 00237 } 00238 00239 static KConfigGroup http_config() 00240 { 00241 PRIVATE_DATA; 00242 if (!d->http_config) { 00243 d->http_config = KSharedConfig::openConfig("kio_httprc", KConfig::NoGlobals); 00244 } 00245 return KConfigGroup(d->http_config, QString()); 00246 } 00247 00248 /*=============================== TIMEOUT SETTINGS ==========================*/ 00249 00250 int KProtocolManager::readTimeout() 00251 { 00252 KConfigGroup cg( config(), QString() ); 00253 int val = cg.readEntry( "ReadTimeout", DEFAULT_READ_TIMEOUT ); 00254 return qMax(MIN_TIMEOUT_VALUE, val); 00255 } 00256 00257 int KProtocolManager::connectTimeout() 00258 { 00259 KConfigGroup cg( config(), QString() ); 00260 int val = cg.readEntry( "ConnectTimeout", DEFAULT_CONNECT_TIMEOUT ); 00261 return qMax(MIN_TIMEOUT_VALUE, val); 00262 } 00263 00264 int KProtocolManager::proxyConnectTimeout() 00265 { 00266 KConfigGroup cg( config(), QString() ); 00267 int val = cg.readEntry( "ProxyConnectTimeout", DEFAULT_PROXY_CONNECT_TIMEOUT ); 00268 return qMax(MIN_TIMEOUT_VALUE, val); 00269 } 00270 00271 int KProtocolManager::responseTimeout() 00272 { 00273 KConfigGroup cg( config(), QString() ); 00274 int val = cg.readEntry( "ResponseTimeout", DEFAULT_RESPONSE_TIMEOUT ); 00275 return qMax(MIN_TIMEOUT_VALUE, val); 00276 } 00277 00278 /*========================== PROXY SETTINGS =================================*/ 00279 00280 bool KProtocolManager::useProxy() 00281 { 00282 return proxyType() != NoProxy; 00283 } 00284 00285 bool KProtocolManager::useReverseProxy() 00286 { 00287 KConfigGroup cg(config(), "Proxy Settings" ); 00288 return cg.readEntry("ReversedException", false); 00289 } 00290 00291 KProtocolManager::ProxyType KProtocolManager::proxyType() 00292 { 00293 KConfigGroup cg(config(), "Proxy Settings" ); 00294 return static_cast<ProxyType>(cg.readEntry( "ProxyType" , 0)); 00295 } 00296 00297 KProtocolManager::ProxyAuthMode KProtocolManager::proxyAuthMode() 00298 { 00299 KConfigGroup cg(config(), "Proxy Settings" ); 00300 return static_cast<ProxyAuthMode>(cg.readEntry( "AuthMode" , 0)); 00301 } 00302 00303 /*========================== CACHING =====================================*/ 00304 00305 bool KProtocolManager::useCache() 00306 { 00307 return http_config().readEntry( "UseCache", true ); 00308 } 00309 00310 KIO::CacheControl KProtocolManager::cacheControl() 00311 { 00312 QString tmp = http_config().readEntry("cache"); 00313 if (tmp.isEmpty()) 00314 return DEFAULT_CACHE_CONTROL; 00315 return KIO::parseCacheControl(tmp); 00316 } 00317 00318 QString KProtocolManager::cacheDir() 00319 { 00320 return http_config().readPathEntry("CacheDir", KGlobal::dirs()->saveLocation("cache","http")); 00321 } 00322 00323 int KProtocolManager::maxCacheAge() 00324 { 00325 return http_config().readEntry( "MaxCacheAge", DEFAULT_MAX_CACHE_AGE ); // 14 days 00326 } 00327 00328 int KProtocolManager::maxCacheSize() 00329 { 00330 return http_config().readEntry( "MaxCacheSize", DEFAULT_MAX_CACHE_SIZE ); // 5 MB 00331 } 00332 00333 QString KProtocolManager::noProxyFor() 00334 { 00335 QString noProxy = config()->group("Proxy Settings").readEntry( "NoProxyFor" ); 00336 if (proxyType() == EnvVarProxy) 00337 noProxy = QString::fromLocal8Bit(qgetenv(noProxy.toLocal8Bit())); 00338 00339 return noProxy; 00340 } 00341 00342 static QString adjustProtocol(const QString& scheme) 00343 { 00344 if (scheme.compare(QL1S("webdav"), Qt::CaseInsensitive) == 0) 00345 return QL1S("http"); 00346 00347 if (scheme.compare(QL1S("webdavs"), Qt::CaseInsensitive) == 0) 00348 return QL1S("https"); 00349 00350 return scheme.toLower(); 00351 } 00352 00353 QString KProtocolManager::proxyFor( const QString& protocol ) 00354 { 00355 const QString key = adjustProtocol(protocol) + QL1S("Proxy"); 00356 QString proxyStr (config()->group("Proxy Settings").readEntry(key)); 00357 const int index = proxyStr.lastIndexOf(QL1C(' ')); 00358 00359 if (index > -1) { 00360 bool ok = false; 00361 const QString portStr(proxyStr.right(proxyStr.length() - index - 1)); 00362 portStr.toInt(&ok); 00363 if (ok) { 00364 proxyStr = proxyStr.left(index) + QL1C(':') + portStr; 00365 } else { 00366 proxyStr.clear(); 00367 } 00368 } 00369 00370 return proxyStr; 00371 } 00372 00373 QString KProtocolManager::proxyForUrl( const KUrl &url ) 00374 { 00375 const QStringList proxies = proxiesForUrl(url); 00376 00377 if (proxies.isEmpty()) 00378 return QString(); 00379 00380 return proxies.first(); 00381 } 00382 00383 static QStringList getSystemProxyFor( const KUrl& url ) 00384 { 00385 QStringList proxies; 00386 00387 #if !defined(QT_NO_NETWORKPROXY) && (defined(Q_OS_WIN32) || defined(Q_OS_MAC)) 00388 QNetworkProxyQuery query ( url ); 00389 const QList<QNetworkProxy> proxyList = QNetworkProxyFactory::systemProxyForQuery(query); 00390 Q_FOREACH(const QNetworkProxy& proxy, proxyList) 00391 { 00392 KUrl url; 00393 const QNetworkProxy::ProxyType type = proxy.type(); 00394 if (type == QNetworkProxy::NoProxy || type == QNetworkProxy::DefaultProxy) 00395 { 00396 proxies << QL1S("DIRECT"); 00397 continue; 00398 } 00399 00400 if (type == QNetworkProxy::HttpProxy || type == QNetworkProxy::HttpCachingProxy) 00401 url.setProtocol(QL1S("http")); 00402 else if (type == QNetworkProxy::Socks5Proxy) 00403 url.setProtocol(QL1S("socks")); 00404 else if (type == QNetworkProxy::FtpCachingProxy) 00405 url.setProtocol(QL1S("ftp")); 00406 00407 url.setHost(proxy.hostName()); 00408 url.setPort(proxy.port()); 00409 url.setUser(proxy.user()); 00410 proxies << url.url(); 00411 } 00412 #else 00413 // On Unix/Linux use system environment variables if any are set. 00414 QString proxyVar (KProtocolManager::proxyFor(url.protocol())); 00415 // Check for SOCKS proxy, if not proxy is found for given url. 00416 if (!proxyVar.isEmpty()) { 00417 QString proxy (QString::fromLocal8Bit(qgetenv(proxyVar.toLocal8Bit())).trimmed()); 00418 if (proxy.isEmpty()) { 00419 proxyVar = KProtocolManager::proxyFor(QL1S("socks")); 00420 proxy = QString::fromLocal8Bit(qgetenv(proxyVar.toLocal8Bit())).trimmed(); 00421 } 00422 proxies << proxy; 00423 } 00424 #endif 00425 return proxies; 00426 } 00427 00428 QStringList KProtocolManager::proxiesForUrl( const KUrl &url ) 00429 { 00430 QStringList proxyList; 00431 00432 PRIVATE_DATA; 00433 if (!d->shouldIgnoreProxyFor(url)) { 00434 switch (proxyType()) 00435 { 00436 case PACProxy: 00437 case WPADProxy: 00438 { 00439 KUrl u (url); 00440 const QString protocol = adjustProtocol(u.protocol()); 00441 u.setProtocol(protocol); 00442 00443 if (KProtocolInfo::protocolClass(protocol) != QL1S(":local")) 00444 { 00445 QDBusReply<QStringList> reply = QDBusInterface(QL1S("org.kde.kded"), 00446 QL1S("/modules/proxyscout"), 00447 QL1S("org.kde.KPAC.ProxyScout")) 00448 .call(QL1S("proxiesForUrl"), u.url()); 00449 proxyList = reply; 00450 } 00451 break; 00452 } 00453 case EnvVarProxy: 00454 proxyList = getSystemProxyFor( url ); 00455 break; 00456 case ManualProxy: 00457 { 00458 QString proxy (proxyFor(url.protocol())); 00459 // Check for SOCKS proxy, if not proxy is found for given url. 00460 if (proxy.isEmpty()) { 00461 proxy = proxyFor(QL1S("socks")); 00462 // Make sure the scheme of SOCKS proxy is always set to "socks://". 00463 if (!proxy.isEmpty()) { 00464 const int index = proxy.indexOf(QL1S("://")); 00465 proxy = QL1S("socks://") + (index == -1 ? proxy : proxy.mid(index+3)); 00466 } 00467 } 00468 proxyList << proxy; 00469 } 00470 break; 00471 case NoProxy: 00472 default: 00473 break; 00474 } 00475 } 00476 00477 if (proxyList.isEmpty()) { 00478 proxyList << QL1S("DIRECT"); 00479 } 00480 00481 return proxyList; 00482 } 00483 00484 void KProtocolManager::badProxy( const QString &proxy ) 00485 { 00486 QDBusInterface( QL1S("org.kde.kded"), QL1S("/modules/proxyscout")) 00487 .asyncCall(QL1S("blackListProxy"), proxy); 00488 } 00489 00490 // For proxy address comparisons, we only need to compare 00491 // protocol, host and port number. Nothing else. 00492 static bool compareProxyUrls(const KUrl& u1, const KUrl& u2) 00493 { 00494 return ((u1.protocol() == u2.protocol()) && 00495 (u1.host() == u2.host()) && 00496 (u1.port() == u2.port())); 00497 } 00498 00499 QString KProtocolManager::slaveProtocol(const KUrl &url, QString &proxy) 00500 { 00501 QStringList proxyList; 00502 const QString protocol = KProtocolManager::slaveProtocol(url, proxyList); 00503 if (!proxyList.isEmpty()) { 00504 proxy = proxyList.first(); 00505 } 00506 return protocol; 00507 } 00508 00509 QString KProtocolManager::slaveProtocol(const KUrl &url, QStringList &proxyList) 00510 { 00511 if (url.hasSubUrl()) // We don't want the suburl's protocol 00512 { 00513 const KUrl::List list = KUrl::split(url); 00514 return slaveProtocol(list.last(), proxyList); 00515 } 00516 00517 PRIVATE_DATA; 00518 if (compareProxyUrls(d->url, url)) 00519 { 00520 proxyList = d->proxyList; 00521 return d->protocol; 00522 } 00523 00524 // Do not perform a proxy lookup for any url classified as a ":local" url or 00525 // one that does not have a host name. 00526 const QString scheme = url.protocol(); 00527 if (KProtocolInfo::protocolClass(scheme) == QL1S(":local") || !url.hasHost()) 00528 { 00529 return scheme; 00530 } 00531 00532 d->url = url; 00533 d->protocol = scheme; 00534 d->proxyList.clear(); 00535 proxyList.clear(); 00536 00537 const QStringList proxies = proxiesForUrl(url); 00538 const int count = proxies.count(); 00539 00540 if (count > 0 && !(count == 1 && proxies.first() == QL1S("DIRECT"))) 00541 { 00542 // The idea behind slave protocols is not applicable to http 00543 // and webdav protocols as well as protocols unknown to KDE. 00544 const bool useRequestScheme = (scheme.startsWith(QL1S("http")) || 00545 scheme.startsWith(QL1S("webdav")) || 00546 !KProtocolInfo::isKnownProtocol(scheme)); 00547 Q_FOREACH(const QString& proxy, proxies) 00548 { 00549 if (proxy == QL1S("DIRECT")) 00550 { 00551 proxyList << proxy; 00552 } 00553 else 00554 { 00555 KUrl u (proxy); 00556 if (!u.isEmpty() && u.isValid() && !u.protocol().isEmpty()) 00557 { 00558 d->protocol = (useRequestScheme ? scheme : u.protocol()); 00559 proxyList << proxy; 00560 // kDebug () << "Slave protocol:" << d->protocol; 00561 } 00562 } 00563 } 00564 } 00565 00566 if (!proxyList.isEmpty()) 00567 { 00568 d->proxyList = proxyList; 00569 } 00570 00571 return d->protocol; 00572 } 00573 00574 /*================================= USER-AGENT SETTINGS =====================*/ 00575 00576 QString KProtocolManager::userAgentForHost( const QString& hostname ) 00577 { 00578 const QString sendUserAgent = KIO::SlaveConfig::self()->configData("http", hostname.toLower(), "SendUserAgent").toLower(); 00579 if (sendUserAgent == QL1S("false")) 00580 return QString(); 00581 00582 const QString useragent = KIO::SlaveConfig::self()->configData("http", hostname.toLower(), "UserAgent"); 00583 00584 // Return the default user-agent if none is specified 00585 // for the requested host. 00586 if (useragent.isEmpty()) 00587 return defaultUserAgent(); 00588 00589 return useragent; 00590 } 00591 00592 QString KProtocolManager::defaultUserAgent( ) 00593 { 00594 const QString modifiers = KIO::SlaveConfig::self()->configData("http", QString(), "UserAgentKeys"); 00595 return defaultUserAgent(modifiers); 00596 } 00597 00598 static QString defaultUserAgentFromPreferredService() 00599 { 00600 QString agentStr; 00601 00602 // Check if the default COMPONENT contains a custom default UA string... 00603 KService::Ptr service = KMimeTypeTrader::self()->preferredService(QL1S("text/html"), 00604 QL1S("KParts/ReadOnlyPart")); 00605 if (service && service->showInKDE()) 00606 agentStr = service->property(QL1S("X-KDE-Default-UserAgent"), 00607 QVariant::String).toString(); 00608 return agentStr; 00609 } 00610 00611 static QString platform() 00612 { 00613 #if defined(Q_WS_X11) 00614 return QL1S("X11"); 00615 #elif defined(Q_WS_MAC) 00616 return QL1S("Macintosh"); 00617 #elif defined(Q_WS_WIN) 00618 return QL1S("Windows"); 00619 #elif defined(Q_WS_S60) 00620 return QL1S("Symbian"); 00621 #endif 00622 } 00623 00624 QString KProtocolManager::defaultUserAgent( const QString &_modifiers ) 00625 { 00626 PRIVATE_DATA; 00627 QString modifiers = _modifiers.toLower(); 00628 if (modifiers.isEmpty()) 00629 modifiers = DEFAULT_USER_AGENT_KEYS; 00630 00631 if (d->modifiers == modifiers && !d->useragent.isEmpty()) 00632 return d->useragent; 00633 00634 d->modifiers = modifiers; 00635 00636 /* 00637 The following code attempts to determine the default user agent string 00638 from the 'X-KDE-UA-DEFAULT-STRING' property of the desktop file 00639 for the preferred service that was configured to handle the 'text/html' 00640 mime type. If the prefered service's desktop file does not specify this 00641 property, the long standing default user agent string will be used. 00642 The following keyword placeholders are automatically converted when the 00643 user agent string is read from the property: 00644 00645 %SECURITY% Expands to"N" when SSL is not supported, otherwise it is ignored. 00646 %OSNAME% Expands to operating system name, e.g. Linux. 00647 %OSVERSION% Expands to operating system version, e.g. 2.6.32 00648 %SYSTYPE% Expands to machine or system type, e.g. i386 00649 %PLATFORM% Expands to windowing system, e.g. X11 on Unix/Linux. 00650 %LANGUAGE% Expands to default language in use, e.g. en-US. 00651 %APPVERSION% Expands to QCoreApplication applicationName()/applicationVerison(), 00652 e.g. Konqueror/4.5.0. If application name and/or application version 00653 number are not set, then "KDE" and the runtime KDE version numbers 00654 are used respectively. 00655 00656 All of the keywords are handled case-insensitively. 00657 */ 00658 00659 QString systemName, systemVersion, machine, supp; 00660 const bool sysInfoFound = getSystemNameVersionAndMachine( systemName, systemVersion, machine ); 00661 QString agentStr = defaultUserAgentFromPreferredService(); 00662 00663 if (agentStr.isEmpty()) 00664 { 00665 supp += platform(); 00666 00667 if (sysInfoFound) 00668 { 00669 if (modifiers.contains('o')) 00670 { 00671 supp += QL1S("; "); 00672 supp += systemName; 00673 if (modifiers.contains('v')) 00674 { 00675 supp += QL1C(' '); 00676 supp += systemVersion; 00677 } 00678 00679 if (modifiers.contains('m')) 00680 { 00681 supp += QL1C(' '); 00682 supp += machine; 00683 } 00684 } 00685 00686 if (modifiers.contains('l')) 00687 { 00688 supp += QL1S("; "); 00689 supp += KGlobal::locale()->language(); 00690 } 00691 } 00692 00693 // Full format: Mozilla/5.0 (Linux 00694 d->useragent = QL1S("Mozilla/5.0 ("); 00695 d->useragent += supp; 00696 d->useragent += QL1S(") KHTML/"); 00697 d->useragent += QString::number(KDE::versionMajor()); 00698 d->useragent += QL1C('.'); 00699 d->useragent += QString::number(KDE::versionMinor()); 00700 d->useragent += QL1C('.'); 00701 d->useragent += QString::number(KDE::versionRelease()); 00702 d->useragent += QL1S(" (like Gecko) Konqueror/"); 00703 d->useragent += QString::number(KDE::versionMajor()); 00704 d->useragent += QL1C('.'); 00705 d->useragent += QString::number(KDE::versionMinor()); 00706 } 00707 else 00708 { 00709 QString appName = QCoreApplication::applicationName(); 00710 if (appName.isEmpty() || appName.startsWith(QL1S("kcmshell"), Qt::CaseInsensitive)) 00711 appName = QL1S ("KDE"); 00712 00713 QString appVersion = QCoreApplication::applicationVersion(); 00714 if (appVersion.isEmpty()) { 00715 appVersion += QString::number(KDE::versionMajor()); 00716 appVersion += QL1C('.'); 00717 appVersion += QString::number(KDE::versionMinor()); 00718 appVersion += QL1C('.'); 00719 appVersion += QString::number(KDE::versionRelease()); 00720 } 00721 00722 appName += QL1C('/'); 00723 appName += appVersion; 00724 00725 agentStr.replace(QL1S("%appversion%"), appName, Qt::CaseInsensitive); 00726 00727 if (!QSslSocket::supportsSsl()) 00728 agentStr.replace(QL1S("%security%"), QL1S("N"), Qt::CaseInsensitive); 00729 else 00730 agentStr.remove(QL1S("%security%"), Qt::CaseInsensitive); 00731 00732 if (sysInfoFound) 00733 { 00734 // Platform (e.g. X11). It is no longer configurable from UI. 00735 agentStr.replace(QL1S("%platform%"), platform(), Qt::CaseInsensitive); 00736 00737 // Operating system (e.g. Linux) 00738 if (modifiers.contains('o')) 00739 { 00740 agentStr.replace(QL1S("%osname%"), systemName, Qt::CaseInsensitive); 00741 00742 // OS version (e.g. 2.6.36) 00743 if (modifiers.contains('v')) 00744 agentStr.replace(QL1S("%osversion%"), systemVersion, Qt::CaseInsensitive); 00745 else 00746 agentStr.remove(QL1S("%osversion%"), Qt::CaseInsensitive); 00747 00748 // Machine type (i686, x86-64, etc.) 00749 if (modifiers.contains('m')) 00750 agentStr.replace(QL1S("%systype%"), machine, Qt::CaseInsensitive); 00751 else 00752 agentStr.remove(QL1S("%systype%"), Qt::CaseInsensitive); 00753 } 00754 else 00755 { 00756 agentStr.remove(QL1S("%osname%"), Qt::CaseInsensitive); 00757 agentStr.remove(QL1S("%osversion%"), Qt::CaseInsensitive); 00758 agentStr.remove(QL1S("%systype%"), Qt::CaseInsensitive); 00759 } 00760 00761 // Language (e.g. en_US) 00762 if (modifiers.contains('l')) 00763 agentStr.replace(QL1S("%language%"), KGlobal::locale()->language(), Qt::CaseInsensitive); 00764 else 00765 agentStr.remove(QL1S("%language%"), Qt::CaseInsensitive); 00766 00767 // Clean up unnecessary separators that could be left over from the 00768 // possible keyword removal above... 00769 agentStr.replace(QRegExp("[(]\\s*[;]\\s*"), QL1S("(")); 00770 agentStr.replace(QRegExp("[;]\\s*[;]\\s*"), QL1S("; ")); 00771 agentStr.replace(QRegExp("\\s*[;]\\s*[)]"), QL1S(")")); 00772 } 00773 else 00774 { 00775 agentStr.remove(QL1S("%osname%")); 00776 agentStr.remove(QL1S("%osversion%")); 00777 agentStr.remove(QL1S("%platform%")); 00778 agentStr.remove(QL1S("%systype%")); 00779 agentStr.remove(QL1S("%language%")); 00780 } 00781 00782 d->useragent = agentStr.simplified(); 00783 } 00784 00785 //kDebug() << "USERAGENT STRING:" << d->useragent; 00786 return d->useragent; 00787 } 00788 00789 QString KProtocolManager::userAgentForApplication( const QString &appName, const QString& appVersion, 00790 const QStringList& extraInfo ) 00791 { 00792 QString systemName, systemVersion, machine, info; 00793 00794 if (getSystemNameVersionAndMachine( systemName, systemVersion, machine )) 00795 { 00796 info += systemName; 00797 info += QL1C('/'); 00798 info += systemVersion; 00799 info += QL1S("; "); 00800 } 00801 00802 info += QL1S("KDE/"); 00803 info += QString::number(KDE::versionMajor()); 00804 info += QL1C('.'); 00805 info += QString::number(KDE::versionMinor()); 00806 info += QL1C('.'); 00807 info += QString::number(KDE::versionRelease()); 00808 00809 if (!machine.isEmpty()) 00810 { 00811 info += QL1S("; "); 00812 info += machine; 00813 } 00814 00815 info += QL1S("; "); 00816 info += extraInfo.join(QL1S("; ")); 00817 00818 return (appName + QL1C('/') + appVersion + QL1S(" (") + info + QL1C(')')); 00819 } 00820 00821 bool KProtocolManager::getSystemNameVersionAndMachine( 00822 QString& systemName, QString& systemVersion, QString& machine ) 00823 { 00824 struct utsname unameBuf; 00825 if ( 0 != uname( &unameBuf ) ) 00826 return false; 00827 #if defined(Q_WS_WIN) && !defined(_WIN32_WCE) 00828 // we do not use unameBuf.sysname information constructed in kdewin32 00829 // because we want to get separate name and version 00830 systemName = QL1S( "Windows" ); 00831 OSVERSIONINFOEX versioninfo; 00832 ZeroMemory(&versioninfo, sizeof(OSVERSIONINFOEX)); 00833 // try calling GetVersionEx using the OSVERSIONINFOEX, if that fails, try using the OSVERSIONINFO 00834 versioninfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); 00835 bool ok = GetVersionEx( (OSVERSIONINFO *) &versioninfo ); 00836 if ( !ok ) { 00837 versioninfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); 00838 ok = GetVersionEx( (OSVERSIONINFO *) &versioninfo ); 00839 } 00840 if ( ok ) { 00841 systemVersion = QString::number(versioninfo.dwMajorVersion); 00842 systemVersion += QL1C('.'); 00843 systemVersion += QString::number(versioninfo.dwMinorVersion); 00844 } 00845 #else 00846 systemName = unameBuf.sysname; 00847 systemVersion = unameBuf.release; 00848 #endif 00849 machine = unameBuf.machine; 00850 return true; 00851 } 00852 00853 QString KProtocolManager::acceptLanguagesHeader() 00854 { 00855 static const QString &english = KGlobal::staticQString("en"); 00856 00857 // User's desktop language preference. 00858 QStringList languageList = KGlobal::locale()->languageList(); 00859 00860 // Replace possible "C" in the language list with "en", unless "en" is 00861 // already pressent. This is to keep user's priorities in order. 00862 // If afterwards "en" is still not present, append it. 00863 int idx = languageList.indexOf(QString::fromLatin1("C")); 00864 if (idx != -1) 00865 { 00866 if (languageList.contains(english)) 00867 languageList.removeAt(idx); 00868 else 00869 languageList[idx] = english; 00870 } 00871 if (!languageList.contains(english)) 00872 languageList += english; 00873 00874 // Some languages may have web codes different from locale codes, 00875 // read them from the config and insert in proper order. 00876 KConfig acclangConf("accept-languages.codes", KConfig::NoGlobals); 00877 KConfigGroup replacementCodes(&acclangConf, "ReplacementCodes"); 00878 QStringList languageListFinal; 00879 Q_FOREACH (const QString &lang, languageList) 00880 { 00881 const QStringList langs = replacementCodes.readEntry(lang, QStringList()); 00882 if (langs.isEmpty()) 00883 languageListFinal += lang; 00884 else 00885 languageListFinal += langs; 00886 } 00887 00888 // The header is composed of comma separated languages, with an optional 00889 // associated priority estimate (q=1..0) defaulting to 1. 00890 // As our language tags are already sorted by priority, we'll just decrease 00891 // the value evenly 00892 int prio = 10; 00893 QString header; 00894 Q_FOREACH (const QString &lang,languageListFinal) { 00895 header += lang; 00896 if (prio < 10) { 00897 header += QL1S(";q=0."); 00898 header += QString::number(prio); 00899 } 00900 // do not add cosmetic whitespace in here : it is less compatible (#220677) 00901 header += QL1S(","); 00902 if (prio > 1) 00903 --prio; 00904 } 00905 header.chop(1); 00906 00907 // Some of the languages may have country specifier delimited by 00908 // underscore, or modifier delimited by at-sign. 00909 // The header should use dashes instead. 00910 header.replace('_', '-'); 00911 header.replace('@', '-'); 00912 00913 return header; 00914 } 00915 00916 /*==================================== OTHERS ===============================*/ 00917 00918 bool KProtocolManager::markPartial() 00919 { 00920 return config()->group(QByteArray()).readEntry( "MarkPartial", true ); 00921 } 00922 00923 int KProtocolManager::minimumKeepSize() 00924 { 00925 return config()->group(QByteArray()).readEntry( "MinimumKeepSize", 00926 DEFAULT_MINIMUM_KEEP_SIZE ); // 5000 byte 00927 } 00928 00929 bool KProtocolManager::autoResume() 00930 { 00931 return config()->group(QByteArray()).readEntry( "AutoResume", false ); 00932 } 00933 00934 bool KProtocolManager::persistentConnections() 00935 { 00936 return config()->group(QByteArray()).readEntry( "PersistentConnections", true ); 00937 } 00938 00939 bool KProtocolManager::persistentProxyConnection() 00940 { 00941 return config()->group(QByteArray()).readEntry( "PersistentProxyConnection", false ); 00942 } 00943 00944 QString KProtocolManager::proxyConfigScript() 00945 { 00946 return config()->group("Proxy Settings").readEntry( "Proxy Config Script" ); 00947 } 00948 00949 /* =========================== PROTOCOL CAPABILITIES ============== */ 00950 00951 static KProtocolInfo::Ptr findProtocol(const KUrl &url) 00952 { 00953 QString protocol = url.protocol(); 00954 00955 if ( !KProtocolInfo::proxiedBy( protocol ).isEmpty() ) 00956 { 00957 QString dummy; 00958 protocol = KProtocolManager::slaveProtocol(url, dummy); 00959 } 00960 00961 return KProtocolInfoFactory::self()->findProtocol(protocol); 00962 } 00963 00964 00965 KProtocolInfo::Type KProtocolManager::inputType( const KUrl &url ) 00966 { 00967 KProtocolInfo::Ptr prot = findProtocol(url); 00968 if ( !prot ) 00969 return KProtocolInfo::T_NONE; 00970 00971 return prot->m_inputType; 00972 } 00973 00974 KProtocolInfo::Type KProtocolManager::outputType( const KUrl &url ) 00975 { 00976 KProtocolInfo::Ptr prot = findProtocol(url); 00977 if ( !prot ) 00978 return KProtocolInfo::T_NONE; 00979 00980 return prot->m_outputType; 00981 } 00982 00983 00984 bool KProtocolManager::isSourceProtocol( const KUrl &url ) 00985 { 00986 KProtocolInfo::Ptr prot = findProtocol(url); 00987 if ( !prot ) 00988 return false; 00989 00990 return prot->m_isSourceProtocol; 00991 } 00992 00993 bool KProtocolManager::supportsListing( const KUrl &url ) 00994 { 00995 KProtocolInfo::Ptr prot = findProtocol(url); 00996 if ( !prot ) 00997 return false; 00998 00999 return prot->m_supportsListing; 01000 } 01001 01002 QStringList KProtocolManager::listing( const KUrl &url ) 01003 { 01004 KProtocolInfo::Ptr prot = findProtocol(url); 01005 if ( !prot ) 01006 return QStringList(); 01007 01008 return prot->m_listing; 01009 } 01010 01011 bool KProtocolManager::supportsReading( const KUrl &url ) 01012 { 01013 KProtocolInfo::Ptr prot = findProtocol(url); 01014 if ( !prot ) 01015 return false; 01016 01017 return prot->m_supportsReading; 01018 } 01019 01020 bool KProtocolManager::supportsWriting( const KUrl &url ) 01021 { 01022 KProtocolInfo::Ptr prot = findProtocol(url); 01023 if ( !prot ) 01024 return false; 01025 01026 return prot->m_supportsWriting; 01027 } 01028 01029 bool KProtocolManager::supportsMakeDir( const KUrl &url ) 01030 { 01031 KProtocolInfo::Ptr prot = findProtocol(url); 01032 if ( !prot ) 01033 return false; 01034 01035 return prot->m_supportsMakeDir; 01036 } 01037 01038 bool KProtocolManager::supportsDeleting( const KUrl &url ) 01039 { 01040 KProtocolInfo::Ptr prot = findProtocol(url); 01041 if ( !prot ) 01042 return false; 01043 01044 return prot->m_supportsDeleting; 01045 } 01046 01047 bool KProtocolManager::supportsLinking( const KUrl &url ) 01048 { 01049 KProtocolInfo::Ptr prot = findProtocol(url); 01050 if ( !prot ) 01051 return false; 01052 01053 return prot->m_supportsLinking; 01054 } 01055 01056 bool KProtocolManager::supportsMoving( const KUrl &url ) 01057 { 01058 KProtocolInfo::Ptr prot = findProtocol(url); 01059 if ( !prot ) 01060 return false; 01061 01062 return prot->m_supportsMoving; 01063 } 01064 01065 bool KProtocolManager::supportsOpening( const KUrl &url ) 01066 { 01067 KProtocolInfo::Ptr prot = findProtocol(url); 01068 if ( !prot ) 01069 return false; 01070 01071 return prot->m_supportsOpening; 01072 } 01073 01074 bool KProtocolManager::canCopyFromFile( const KUrl &url ) 01075 { 01076 KProtocolInfo::Ptr prot = findProtocol(url); 01077 if ( !prot ) 01078 return false; 01079 01080 return prot->m_canCopyFromFile; 01081 } 01082 01083 01084 bool KProtocolManager::canCopyToFile( const KUrl &url ) 01085 { 01086 KProtocolInfo::Ptr prot = findProtocol(url); 01087 if ( !prot ) 01088 return false; 01089 01090 return prot->m_canCopyToFile; 01091 } 01092 01093 bool KProtocolManager::canRenameFromFile( const KUrl &url ) 01094 { 01095 KProtocolInfo::Ptr prot = findProtocol(url); 01096 if ( !prot ) 01097 return false; 01098 01099 return prot->canRenameFromFile(); 01100 } 01101 01102 01103 bool KProtocolManager::canRenameToFile( const KUrl &url ) 01104 { 01105 KProtocolInfo::Ptr prot = findProtocol(url); 01106 if ( !prot ) 01107 return false; 01108 01109 return prot->canRenameToFile(); 01110 } 01111 01112 bool KProtocolManager::canDeleteRecursive( const KUrl &url ) 01113 { 01114 KProtocolInfo::Ptr prot = findProtocol(url); 01115 if ( !prot ) 01116 return false; 01117 01118 return prot->canDeleteRecursive(); 01119 } 01120 01121 KProtocolInfo::FileNameUsedForCopying KProtocolManager::fileNameUsedForCopying( const KUrl &url ) 01122 { 01123 KProtocolInfo::Ptr prot = findProtocol(url); 01124 if ( !prot ) 01125 return KProtocolInfo::FromUrl; 01126 01127 return prot->fileNameUsedForCopying(); 01128 } 01129 01130 QString KProtocolManager::defaultMimetype( const KUrl &url ) 01131 { 01132 KProtocolInfo::Ptr prot = findProtocol(url); 01133 if ( !prot ) 01134 return QString(); 01135 01136 return prot->m_defaultMimetype; 01137 } 01138 01139 QString KProtocolManager::protocolForArchiveMimetype( const QString& mimeType ) 01140 { 01141 PRIVATE_DATA; 01142 if (d->protocolForArchiveMimetypes.isEmpty()) { 01143 const KProtocolInfo::List allProtocols = KProtocolInfoFactory::self()->allProtocols(); 01144 for (KProtocolInfo::List::const_iterator it = allProtocols.begin(); 01145 it != allProtocols.end(); ++it) { 01146 const QStringList archiveMimetypes = (*it)->archiveMimeTypes(); 01147 Q_FOREACH(const QString& mime, archiveMimetypes) { 01148 d->protocolForArchiveMimetypes.insert(mime, (*it)->name()); 01149 } 01150 } 01151 } 01152 return d->protocolForArchiveMimetypes.value(mimeType); 01153 } 01154 01155 #undef PRIVATE_DATA
KDE 4.7 API Reference