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