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 d->useragent += QL1S(" Fedora/4.7.2-5.fc16"); 00707 } 00708 else 00709 { 00710 QString appName = QCoreApplication::applicationName(); 00711 if (appName.isEmpty() || appName.startsWith(QL1S("kcmshell"), Qt::CaseInsensitive)) 00712 appName = QL1S ("KDE"); 00713 00714 QString appVersion = QCoreApplication::applicationVersion(); 00715 if (appVersion.isEmpty()) { 00716 appVersion += QString::number(KDE::versionMajor()); 00717 appVersion += QL1C('.'); 00718 appVersion += QString::number(KDE::versionMinor()); 00719 appVersion += QL1C('.'); 00720 appVersion += QString::number(KDE::versionRelease()); 00721 } 00722 00723 appName += QL1C('/'); 00724 appName += appVersion; 00725 00726 agentStr.replace(QL1S("%appversion%"), appName, Qt::CaseInsensitive); 00727 00728 if (!QSslSocket::supportsSsl()) 00729 agentStr.replace(QL1S("%security%"), QL1S("N"), Qt::CaseInsensitive); 00730 else 00731 agentStr.remove(QL1S("%security%"), Qt::CaseInsensitive); 00732 00733 if (sysInfoFound) 00734 { 00735 // Platform (e.g. X11). It is no longer configurable from UI. 00736 agentStr.replace(QL1S("%platform%"), platform(), Qt::CaseInsensitive); 00737 00738 // Operating system (e.g. Linux) 00739 if (modifiers.contains('o')) 00740 { 00741 agentStr.replace(QL1S("%osname%"), systemName, Qt::CaseInsensitive); 00742 00743 // OS version (e.g. 2.6.36) 00744 if (modifiers.contains('v')) 00745 agentStr.replace(QL1S("%osversion%"), systemVersion, Qt::CaseInsensitive); 00746 else 00747 agentStr.remove(QL1S("%osversion%"), Qt::CaseInsensitive); 00748 00749 // Machine type (i686, x86-64, etc.) 00750 if (modifiers.contains('m')) 00751 agentStr.replace(QL1S("%systype%"), machine, Qt::CaseInsensitive); 00752 else 00753 agentStr.remove(QL1S("%systype%"), Qt::CaseInsensitive); 00754 } 00755 else 00756 { 00757 agentStr.remove(QL1S("%osname%"), Qt::CaseInsensitive); 00758 agentStr.remove(QL1S("%osversion%"), Qt::CaseInsensitive); 00759 agentStr.remove(QL1S("%systype%"), Qt::CaseInsensitive); 00760 } 00761 00762 // Language (e.g. en_US) 00763 if (modifiers.contains('l')) 00764 agentStr.replace(QL1S("%language%"), KGlobal::locale()->language(), Qt::CaseInsensitive); 00765 else 00766 agentStr.remove(QL1S("%language%"), Qt::CaseInsensitive); 00767 00768 // Clean up unnecessary separators that could be left over from the 00769 // possible keyword removal above... 00770 agentStr.replace(QRegExp("[(]\\s*[;]\\s*"), QL1S("(")); 00771 agentStr.replace(QRegExp("[;]\\s*[;]\\s*"), QL1S("; ")); 00772 agentStr.replace(QRegExp("\\s*[;]\\s*[)]"), QL1S(")")); 00773 } 00774 else 00775 { 00776 agentStr.remove(QL1S("%osname%")); 00777 agentStr.remove(QL1S("%osversion%")); 00778 agentStr.remove(QL1S("%platform%")); 00779 agentStr.remove(QL1S("%systype%")); 00780 agentStr.remove(QL1S("%language%")); 00781 } 00782 00783 d->useragent = agentStr.simplified(); 00784 } 00785 00786 //kDebug() << "USERAGENT STRING:" << d->useragent; 00787 return d->useragent; 00788 } 00789 00790 QString KProtocolManager::userAgentForApplication( const QString &appName, const QString& appVersion, 00791 const QStringList& extraInfo ) 00792 { 00793 QString systemName, systemVersion, machine, info; 00794 00795 if (getSystemNameVersionAndMachine( systemName, systemVersion, machine )) 00796 { 00797 info += systemName; 00798 info += QL1C('/'); 00799 info += systemVersion; 00800 info += QL1S("; "); 00801 } 00802 00803 info += QL1S("KDE/"); 00804 info += QString::number(KDE::versionMajor()); 00805 info += QL1C('.'); 00806 info += QString::number(KDE::versionMinor()); 00807 info += QL1C('.'); 00808 info += QString::number(KDE::versionRelease()); 00809 00810 if (!machine.isEmpty()) 00811 { 00812 info += QL1S("; "); 00813 info += machine; 00814 } 00815 00816 info += QL1S("; "); 00817 info += extraInfo.join(QL1S("; ")); 00818 00819 return (appName + QL1C('/') + appVersion + QL1S(" (") + info + QL1C(')')); 00820 } 00821 00822 bool KProtocolManager::getSystemNameVersionAndMachine( 00823 QString& systemName, QString& systemVersion, QString& machine ) 00824 { 00825 struct utsname unameBuf; 00826 if ( 0 != uname( &unameBuf ) ) 00827 return false; 00828 #if defined(Q_WS_WIN) && !defined(_WIN32_WCE) 00829 // we do not use unameBuf.sysname information constructed in kdewin32 00830 // because we want to get separate name and version 00831 systemName = QL1S( "Windows" ); 00832 OSVERSIONINFOEX versioninfo; 00833 ZeroMemory(&versioninfo, sizeof(OSVERSIONINFOEX)); 00834 // try calling GetVersionEx using the OSVERSIONINFOEX, if that fails, try using the OSVERSIONINFO 00835 versioninfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); 00836 bool ok = GetVersionEx( (OSVERSIONINFO *) &versioninfo ); 00837 if ( !ok ) { 00838 versioninfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); 00839 ok = GetVersionEx( (OSVERSIONINFO *) &versioninfo ); 00840 } 00841 if ( ok ) { 00842 systemVersion = QString::number(versioninfo.dwMajorVersion); 00843 systemVersion += QL1C('.'); 00844 systemVersion += QString::number(versioninfo.dwMinorVersion); 00845 } 00846 #else 00847 systemName = unameBuf.sysname; 00848 systemVersion = unameBuf.release; 00849 #endif 00850 machine = unameBuf.machine; 00851 return true; 00852 } 00853 00854 QString KProtocolManager::acceptLanguagesHeader() 00855 { 00856 static const QString &english = KGlobal::staticQString("en"); 00857 00858 // User's desktop language preference. 00859 QStringList languageList = KGlobal::locale()->languageList(); 00860 00861 // Replace possible "C" in the language list with "en", unless "en" is 00862 // already pressent. This is to keep user's priorities in order. 00863 // If afterwards "en" is still not present, append it. 00864 int idx = languageList.indexOf(QString::fromLatin1("C")); 00865 if (idx != -1) 00866 { 00867 if (languageList.contains(english)) 00868 languageList.removeAt(idx); 00869 else 00870 languageList[idx] = english; 00871 } 00872 if (!languageList.contains(english)) 00873 languageList += english; 00874 00875 // Some languages may have web codes different from locale codes, 00876 // read them from the config and insert in proper order. 00877 KConfig acclangConf("accept-languages.codes", KConfig::NoGlobals); 00878 KConfigGroup replacementCodes(&acclangConf, "ReplacementCodes"); 00879 QStringList languageListFinal; 00880 Q_FOREACH (const QString &lang, languageList) 00881 { 00882 const QStringList langs = replacementCodes.readEntry(lang, QStringList()); 00883 if (langs.isEmpty()) 00884 languageListFinal += lang; 00885 else 00886 languageListFinal += langs; 00887 } 00888 00889 // The header is composed of comma separated languages, with an optional 00890 // associated priority estimate (q=1..0) defaulting to 1. 00891 // As our language tags are already sorted by priority, we'll just decrease 00892 // the value evenly 00893 int prio = 10; 00894 QString header; 00895 Q_FOREACH (const QString &lang,languageListFinal) { 00896 header += lang; 00897 if (prio < 10) { 00898 header += QL1S(";q=0."); 00899 header += QString::number(prio); 00900 } 00901 // do not add cosmetic whitespace in here : it is less compatible (#220677) 00902 header += QL1S(","); 00903 if (prio > 1) 00904 --prio; 00905 } 00906 header.chop(1); 00907 00908 // Some of the languages may have country specifier delimited by 00909 // underscore, or modifier delimited by at-sign. 00910 // The header should use dashes instead. 00911 header.replace('_', '-'); 00912 header.replace('@', '-'); 00913 00914 return header; 00915 } 00916 00917 /*==================================== OTHERS ===============================*/ 00918 00919 bool KProtocolManager::markPartial() 00920 { 00921 return config()->group(QByteArray()).readEntry( "MarkPartial", true ); 00922 } 00923 00924 int KProtocolManager::minimumKeepSize() 00925 { 00926 return config()->group(QByteArray()).readEntry( "MinimumKeepSize", 00927 DEFAULT_MINIMUM_KEEP_SIZE ); // 5000 byte 00928 } 00929 00930 bool KProtocolManager::autoResume() 00931 { 00932 return config()->group(QByteArray()).readEntry( "AutoResume", false ); 00933 } 00934 00935 bool KProtocolManager::persistentConnections() 00936 { 00937 return config()->group(QByteArray()).readEntry( "PersistentConnections", true ); 00938 } 00939 00940 bool KProtocolManager::persistentProxyConnection() 00941 { 00942 return config()->group(QByteArray()).readEntry( "PersistentProxyConnection", false ); 00943 } 00944 00945 QString KProtocolManager::proxyConfigScript() 00946 { 00947 return config()->group("Proxy Settings").readEntry( "Proxy Config Script" ); 00948 } 00949 00950 /* =========================== PROTOCOL CAPABILITIES ============== */ 00951 00952 static KProtocolInfo::Ptr findProtocol(const KUrl &url) 00953 { 00954 QString protocol = url.protocol(); 00955 00956 if ( !KProtocolInfo::proxiedBy( protocol ).isEmpty() ) 00957 { 00958 QString dummy; 00959 protocol = KProtocolManager::slaveProtocol(url, dummy); 00960 } 00961 00962 return KProtocolInfoFactory::self()->findProtocol(protocol); 00963 } 00964 00965 00966 KProtocolInfo::Type KProtocolManager::inputType( const KUrl &url ) 00967 { 00968 KProtocolInfo::Ptr prot = findProtocol(url); 00969 if ( !prot ) 00970 return KProtocolInfo::T_NONE; 00971 00972 return prot->m_inputType; 00973 } 00974 00975 KProtocolInfo::Type KProtocolManager::outputType( const KUrl &url ) 00976 { 00977 KProtocolInfo::Ptr prot = findProtocol(url); 00978 if ( !prot ) 00979 return KProtocolInfo::T_NONE; 00980 00981 return prot->m_outputType; 00982 } 00983 00984 00985 bool KProtocolManager::isSourceProtocol( const KUrl &url ) 00986 { 00987 KProtocolInfo::Ptr prot = findProtocol(url); 00988 if ( !prot ) 00989 return false; 00990 00991 return prot->m_isSourceProtocol; 00992 } 00993 00994 bool KProtocolManager::supportsListing( const KUrl &url ) 00995 { 00996 KProtocolInfo::Ptr prot = findProtocol(url); 00997 if ( !prot ) 00998 return false; 00999 01000 return prot->m_supportsListing; 01001 } 01002 01003 QStringList KProtocolManager::listing( const KUrl &url ) 01004 { 01005 KProtocolInfo::Ptr prot = findProtocol(url); 01006 if ( !prot ) 01007 return QStringList(); 01008 01009 return prot->m_listing; 01010 } 01011 01012 bool KProtocolManager::supportsReading( const KUrl &url ) 01013 { 01014 KProtocolInfo::Ptr prot = findProtocol(url); 01015 if ( !prot ) 01016 return false; 01017 01018 return prot->m_supportsReading; 01019 } 01020 01021 bool KProtocolManager::supportsWriting( const KUrl &url ) 01022 { 01023 KProtocolInfo::Ptr prot = findProtocol(url); 01024 if ( !prot ) 01025 return false; 01026 01027 return prot->m_supportsWriting; 01028 } 01029 01030 bool KProtocolManager::supportsMakeDir( const KUrl &url ) 01031 { 01032 KProtocolInfo::Ptr prot = findProtocol(url); 01033 if ( !prot ) 01034 return false; 01035 01036 return prot->m_supportsMakeDir; 01037 } 01038 01039 bool KProtocolManager::supportsDeleting( const KUrl &url ) 01040 { 01041 KProtocolInfo::Ptr prot = findProtocol(url); 01042 if ( !prot ) 01043 return false; 01044 01045 return prot->m_supportsDeleting; 01046 } 01047 01048 bool KProtocolManager::supportsLinking( const KUrl &url ) 01049 { 01050 KProtocolInfo::Ptr prot = findProtocol(url); 01051 if ( !prot ) 01052 return false; 01053 01054 return prot->m_supportsLinking; 01055 } 01056 01057 bool KProtocolManager::supportsMoving( const KUrl &url ) 01058 { 01059 KProtocolInfo::Ptr prot = findProtocol(url); 01060 if ( !prot ) 01061 return false; 01062 01063 return prot->m_supportsMoving; 01064 } 01065 01066 bool KProtocolManager::supportsOpening( const KUrl &url ) 01067 { 01068 KProtocolInfo::Ptr prot = findProtocol(url); 01069 if ( !prot ) 01070 return false; 01071 01072 return prot->m_supportsOpening; 01073 } 01074 01075 bool KProtocolManager::canCopyFromFile( const KUrl &url ) 01076 { 01077 KProtocolInfo::Ptr prot = findProtocol(url); 01078 if ( !prot ) 01079 return false; 01080 01081 return prot->m_canCopyFromFile; 01082 } 01083 01084 01085 bool KProtocolManager::canCopyToFile( const KUrl &url ) 01086 { 01087 KProtocolInfo::Ptr prot = findProtocol(url); 01088 if ( !prot ) 01089 return false; 01090 01091 return prot->m_canCopyToFile; 01092 } 01093 01094 bool KProtocolManager::canRenameFromFile( const KUrl &url ) 01095 { 01096 KProtocolInfo::Ptr prot = findProtocol(url); 01097 if ( !prot ) 01098 return false; 01099 01100 return prot->canRenameFromFile(); 01101 } 01102 01103 01104 bool KProtocolManager::canRenameToFile( const KUrl &url ) 01105 { 01106 KProtocolInfo::Ptr prot = findProtocol(url); 01107 if ( !prot ) 01108 return false; 01109 01110 return prot->canRenameToFile(); 01111 } 01112 01113 bool KProtocolManager::canDeleteRecursive( const KUrl &url ) 01114 { 01115 KProtocolInfo::Ptr prot = findProtocol(url); 01116 if ( !prot ) 01117 return false; 01118 01119 return prot->canDeleteRecursive(); 01120 } 01121 01122 KProtocolInfo::FileNameUsedForCopying KProtocolManager::fileNameUsedForCopying( const KUrl &url ) 01123 { 01124 KProtocolInfo::Ptr prot = findProtocol(url); 01125 if ( !prot ) 01126 return KProtocolInfo::FromUrl; 01127 01128 return prot->fileNameUsedForCopying(); 01129 } 01130 01131 QString KProtocolManager::defaultMimetype( const KUrl &url ) 01132 { 01133 KProtocolInfo::Ptr prot = findProtocol(url); 01134 if ( !prot ) 01135 return QString(); 01136 01137 return prot->m_defaultMimetype; 01138 } 01139 01140 QString KProtocolManager::protocolForArchiveMimetype( const QString& mimeType ) 01141 { 01142 PRIVATE_DATA; 01143 if (d->protocolForArchiveMimetypes.isEmpty()) { 01144 const KProtocolInfo::List allProtocols = KProtocolInfoFactory::self()->allProtocols(); 01145 for (KProtocolInfo::List::const_iterator it = allProtocols.begin(); 01146 it != allProtocols.end(); ++it) { 01147 const QStringList archiveMimetypes = (*it)->archiveMimeTypes(); 01148 Q_FOREACH(const QString& mime, archiveMimetypes) { 01149 d->protocolForArchiveMimetypes.insert(mime, (*it)->name()); 01150 } 01151 } 01152 } 01153 return d->protocolForArchiveMimetypes.value(mimeType); 01154 } 01155 01156 #undef PRIVATE_DATA
KDE 4.7 API Reference