KIO
script.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (c) 2003 Malte Starostik <malte@kde.org> 00003 Copyright (c) 2011 Dawit Alemayehu <adawit@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "script.h" 00022 00023 #include <QtCore/QString> 00024 #include <QtCore/QRegExp> 00025 #include <QtCore/QDateTime> 00026 #include <QtCore/QTimer> 00027 #include <QtCore/QEventLoop> 00028 00029 #include <QtNetwork/QHostInfo> 00030 #include <QtNetwork/QHostAddress> 00031 #include <QtNetwork/QNetworkInterface> 00032 00033 #include <QtScript/QScriptValue> 00034 #include <QtScript/QScriptEngine> 00035 #include <QtScript/QScriptProgram> 00036 #include <QtScript/QScriptContextInfo> 00037 00038 #include <kurl.h> 00039 #include <klocalizedstring.h> 00040 #include <kio/hostinfo_p.h> 00041 00042 #define QL1S(x) QLatin1String(x) 00043 00044 namespace 00045 { 00046 static int findString (const QString& s, const char* const* values) 00047 { 00048 int index = 0; 00049 const QString lower = s.toLower(); 00050 for (const char* const* p = values; *p; ++p, ++index) { 00051 if (s.compare(QLatin1String(*p), Qt::CaseInsensitive) == 0) { 00052 return index; 00053 } 00054 } 00055 return -1; 00056 } 00057 00058 static const QDateTime getTime (QScriptContext* context) 00059 { 00060 const QString tz = context->argument(context->argumentCount() - 1).toString(); 00061 if (tz.compare(QLatin1String("gmt"), Qt::CaseInsensitive) == 0) { 00062 return QDateTime::currentDateTimeUtc(); 00063 } 00064 return QDateTime::currentDateTime(); 00065 } 00066 00067 template <typename T> 00068 static bool checkRange (T value, T min, T max) 00069 { 00070 return ((min <= max && value >= min && value <= max) || 00071 (min > max && (value <= min || value >= max))); 00072 } 00073 00074 static bool isLocalHostAddress (const QHostAddress& address) 00075 { 00076 if (address == QHostAddress::LocalHost) 00077 return true; 00078 00079 if (address == QHostAddress::LocalHostIPv6) 00080 return true; 00081 00082 return false; 00083 } 00084 00085 static bool isIPv6Address (const QHostAddress& address) 00086 { 00087 return address.protocol() == QAbstractSocket::IPv6Protocol; 00088 } 00089 00090 static bool isIPv4Address (const QHostAddress& address) 00091 { 00092 return (address.protocol() == QAbstractSocket::IPv4Protocol); 00093 } 00094 00095 static bool isSpecialAddress(const QHostAddress& address) 00096 { 00097 // Catch all the special addresses and return false. 00098 if (address == QHostAddress::Null) 00099 return true; 00100 00101 if (address == QHostAddress::Any) 00102 return true; 00103 00104 if (address == QHostAddress::AnyIPv6) 00105 return true; 00106 00107 if (address == QHostAddress::Broadcast) 00108 return true; 00109 00110 return false; 00111 } 00112 00113 static bool addressLessThanComparison(const QHostAddress& addr1, const QHostAddress& addr2) 00114 { 00115 if (addr1.protocol() == QAbstractSocket::IPv4Protocol && 00116 addr2.protocol() == QAbstractSocket::IPv4Protocol) { 00117 return addr1.toIPv4Address() < addr2.toIPv4Address(); 00118 } 00119 00120 if (addr1.protocol() == QAbstractSocket::IPv6Protocol && 00121 addr2.protocol() == QAbstractSocket::IPv6Protocol) { 00122 const Q_IPV6ADDR ipv6addr1 = addr1.toIPv6Address(); 00123 const Q_IPV6ADDR ipv6addr2 = addr2.toIPv6Address(); 00124 for (int i=0; i < 16; ++i) { 00125 if (ipv6addr1[i] != ipv6addr2[i]) { 00126 return ((ipv6addr1[i] & 0xff) - (ipv6addr2[i] & 0xff)); 00127 } 00128 } 00129 } 00130 00131 return false; 00132 } 00133 00134 static QString addressListToString(const QList<QHostAddress>& addressList, 00135 const QHash<QString, QString>& actualEntryMap) 00136 { 00137 QString result; 00138 Q_FOREACH(const QHostAddress& address, addressList) { 00139 if (!result.isEmpty()) { 00140 result += QLatin1Char(';'); 00141 } 00142 result += actualEntryMap.value(address.toString()); 00143 } 00144 return result; 00145 } 00146 00147 class Address 00148 { 00149 public: 00150 struct Error {}; 00151 static Address resolve( const QString& host ) 00152 { 00153 return Address( host ); 00154 } 00155 00156 QList<QHostAddress> addresses() const 00157 { 00158 return m_addressList; 00159 } 00160 00161 QHostAddress address() const 00162 { 00163 if (m_addressList.isEmpty()) 00164 return QHostAddress(); 00165 00166 return m_addressList.first(); 00167 } 00168 00169 private: 00170 Address( const QString& host ) 00171 { 00172 // Always try to see if it's already an IP first, to avoid Qt doing a 00173 // needless reverse lookup 00174 QHostAddress address ( host ); 00175 if ( address.isNull() ) { 00176 QHostInfo hostInfo = KIO::HostInfo::lookupCachedHostInfoFor(host); 00177 if (hostInfo.hostName().isEmpty() || hostInfo.error() != QHostInfo::NoError) { 00178 hostInfo = QHostInfo::fromName(host); 00179 KIO::HostInfo::cacheLookup(hostInfo); 00180 } 00181 m_addressList = hostInfo.addresses(); 00182 } else { 00183 m_addressList.clear(); 00184 m_addressList.append(address); 00185 } 00186 } 00187 00188 QList<QHostAddress> m_addressList; 00189 }; 00190 00191 00192 // isPlainHostName(host) 00193 // @returns true if @p host doesn't contains a domain part 00194 QScriptValue IsPlainHostName(QScriptContext* context, QScriptEngine* engine) 00195 { 00196 if (context->argumentCount() != 1) { 00197 return engine->undefinedValue(); 00198 } 00199 return engine->toScriptValue(context->argument(0).toString().indexOf(QLatin1Char('.')) == -1); 00200 } 00201 00202 // dnsDomainIs(host, domain) 00203 // @returns true if the domain part of @p host matches @p domain 00204 QScriptValue DNSDomainIs (QScriptContext* context, QScriptEngine* engine) 00205 { 00206 if (context->argumentCount() != 2) { 00207 return engine->undefinedValue(); 00208 } 00209 00210 const QString host = context->argument(0).toString(); 00211 const QString domain = context->argument(1).toString(); 00212 return engine->toScriptValue(host.endsWith(domain, Qt::CaseInsensitive)); 00213 } 00214 00215 // localHostOrDomainIs(host, fqdn) 00216 // @returns true if @p host is unqualified or equals @p fqdn 00217 QScriptValue LocalHostOrDomainIs (QScriptContext* context, QScriptEngine* engine) 00218 { 00219 if (context->argumentCount() != 2) { 00220 return engine->undefinedValue(); 00221 } 00222 00223 const QString host = context->argument(0).toString(); 00224 if (!host.contains(QLatin1Char('.'))) { 00225 return engine->toScriptValue(true); 00226 } 00227 const QString fqdn = context->argument(1).toString(); 00228 return engine->toScriptValue((host.compare(fqdn, Qt::CaseInsensitive) == 0)); 00229 } 00230 00231 // isResolvable(host) 00232 // @returns true if host is resolvable to a IPv4 address. 00233 QScriptValue IsResolvable (QScriptContext* context, QScriptEngine* engine) 00234 { 00235 if (context->argumentCount() != 1) { 00236 return engine->undefinedValue(); 00237 } 00238 00239 try { 00240 const Address info = Address::resolve(context->argument(0).toString()); 00241 bool hasResolvableIPv4Address = false; 00242 00243 Q_FOREACH(const QHostAddress& address, info.addresses()) { 00244 if (!isSpecialAddress(address) && isIPv4Address(address)) { 00245 hasResolvableIPv4Address = true; 00246 break; 00247 } 00248 } 00249 00250 return engine->toScriptValue(hasResolvableIPv4Address); 00251 } 00252 catch (const Address::Error&) { 00253 return engine->toScriptValue(false); 00254 } 00255 } 00256 00257 // isInNet(host, subnet, mask) 00258 // @returns true if the IPv4 address of host is within the specified subnet 00259 // and mask, false otherwise. 00260 QScriptValue IsInNet (QScriptContext* context, QScriptEngine* engine) 00261 { 00262 if (context->argumentCount() != 3) { 00263 return engine->undefinedValue(); 00264 } 00265 00266 try { 00267 const Address info = Address::resolve(context->argument(0).toString()); 00268 bool isInSubNet = false; 00269 QString subnetStr = context->argument(1).toString(); 00270 subnetStr += QLatin1Char('/'); 00271 subnetStr += context->argument(2).toString(); 00272 const QPair<QHostAddress, int> subnet = QHostAddress::parseSubnet(subnetStr); 00273 Q_FOREACH(const QHostAddress& address, info.addresses()) { 00274 if (!isSpecialAddress(address) && isIPv4Address(address) && address.isInSubnet(subnet)) { 00275 isInSubNet = true; 00276 break; 00277 } 00278 } 00279 return engine->toScriptValue(isInSubNet); 00280 } 00281 catch (const Address::Error&) { 00282 return engine->toScriptValue(false); 00283 } 00284 } 00285 00286 // dnsResolve(host) 00287 // @returns the IPv4 address for host or an empty string if host is not resolvable. 00288 QScriptValue DNSResolve (QScriptContext* context, QScriptEngine* engine) 00289 { 00290 if (context->argumentCount() != 1) { 00291 return engine->undefinedValue(); 00292 } 00293 00294 try { 00295 const Address info = Address::resolve(context->argument(0).toString()); 00296 QString resolvedAddress (QLatin1String("")); 00297 Q_FOREACH(const QHostAddress& address, info.addresses()) { 00298 if (!isSpecialAddress(address) && isIPv4Address(address)) { 00299 resolvedAddress = address.toString(); 00300 break; 00301 } 00302 } 00303 return engine->toScriptValue(resolvedAddress); 00304 } 00305 catch (const Address::Error&) { 00306 return engine->toScriptValue(QString(QLatin1String(""))); 00307 } 00308 } 00309 00310 // myIpAddress() 00311 // @returns the local machine's IPv4 address. Note that this will return 00312 // the address for the first interfaces that match its criteria even if the 00313 // machine has multiple interfaces. 00314 QScriptValue MyIpAddress (QScriptContext* context, QScriptEngine* engine) 00315 { 00316 if (context->argumentCount()) { 00317 return engine->undefinedValue(); 00318 } 00319 00320 QString ipAddress; 00321 const QList<QHostAddress> addresses = QNetworkInterface::allAddresses(); 00322 Q_FOREACH(const QHostAddress address, addresses) { 00323 if (isIPv4Address(address) && !isSpecialAddress(address) && !isLocalHostAddress(address)) { 00324 ipAddress = address.toString(); 00325 break; 00326 } 00327 } 00328 00329 return engine->toScriptValue(ipAddress); 00330 } 00331 00332 // dnsDomainLevels(host) 00333 // @returns the number of dots ('.') in @p host 00334 QScriptValue DNSDomainLevels (QScriptContext* context, QScriptEngine* engine) 00335 { 00336 if (context->argumentCount() != 1) { 00337 return engine->undefinedValue(); 00338 } 00339 00340 const QString host = context->argument(0).toString(); 00341 if (host.isNull()) { 00342 return engine->toScriptValue(0); 00343 } 00344 00345 return engine->toScriptValue(host.count(QLatin1Char('.'))); 00346 } 00347 00348 // shExpMatch(str, pattern) 00349 // @returns true if @p str matches the shell @p pattern 00350 QScriptValue ShExpMatch (QScriptContext* context, QScriptEngine* engine) 00351 { 00352 if (context->argumentCount() != 2) { 00353 return engine->undefinedValue(); 00354 } 00355 00356 QRegExp pattern(context->argument(1).toString(), Qt::CaseSensitive, QRegExp::Wildcard); 00357 return engine->toScriptValue(pattern.exactMatch(context->argument(0).toString())); 00358 } 00359 00360 // weekdayRange(day [, "GMT" ]) 00361 // weekdayRange(day1, day2 [, "GMT" ]) 00362 // @returns true if the current day equals day or between day1 and day2 resp. 00363 // If the last argument is "GMT", GMT timezone is used, otherwise local time 00364 QScriptValue WeekdayRange (QScriptContext* context, QScriptEngine* engine) 00365 { 00366 if (context->argumentCount() < 1 || context->argumentCount() > 3) { 00367 return engine->undefinedValue(); 00368 } 00369 00370 static const char* const days[] = { "sun", "mon", "tue", "wed", "thu", "fri", "sat", 0 }; 00371 00372 const int d1 = findString(context->argument(0).toString(), days); 00373 if (d1 == -1) { 00374 return engine->undefinedValue(); 00375 } 00376 00377 int d2 = findString(context->argument(1).toString(), days); 00378 if (d2 == -1) { 00379 d2 = d1; 00380 } 00381 00382 // Adjust the days of week coming from QDateTime since it starts 00383 // counting with Monday as 1 and ends with Sunday as day 7. 00384 int dayOfWeek = getTime(context).date().dayOfWeek(); 00385 if (dayOfWeek == 7) { 00386 dayOfWeek = 0; 00387 } 00388 return engine->toScriptValue(checkRange(dayOfWeek, d1, d2)); 00389 } 00390 00391 // dateRange(day [, "GMT" ]) 00392 // dateRange(day1, day2 [, "GMT" ]) 00393 // dateRange(month [, "GMT" ]) 00394 // dateRange(month1, month2 [, "GMT" ]) 00395 // dateRange(year [, "GMT" ]) 00396 // dateRange(year1, year2 [, "GMT" ]) 00397 // dateRange(day1, month1, day2, month2 [, "GMT" ]) 00398 // dateRange(month1, year1, month2, year2 [, "GMT" ]) 00399 // dateRange(day1, month1, year1, day2, month2, year2 [, "GMT" ]) 00400 // @returns true if the current date (GMT or local time according to 00401 // presence of "GMT" as last argument) is within the given range 00402 QScriptValue DateRange (QScriptContext* context, QScriptEngine* engine) 00403 { 00404 if (context->argumentCount() < 1 || context->argumentCount() > 7) { 00405 return engine->undefinedValue(); 00406 } 00407 00408 static const char* const months[] = { "jan", "feb", "mar", "apr", "may", "jun", 00409 "jul", "aug", "sep", "oct", "nov", "dec", 0 }; 00410 00411 QVector<int> values; 00412 for (int i = 0; i < context->argumentCount(); ++i) 00413 { 00414 int value = -1; 00415 if (context->argument(i).isNumber()) { 00416 value = context->argument(i).toInt32(); 00417 } else { 00418 // QDate starts counting months from 1, so we add 1 here. 00419 value = findString(context->argument(i).toString(), months) + 1; 00420 } 00421 00422 if (value > 0) { 00423 values.append(value); 00424 } else { 00425 break; 00426 } 00427 } 00428 00429 const QDate now = getTime(context).date(); 00430 00431 // day1, month1, year1, day2, month2, year2 00432 if (values.size() == 6) { 00433 const QDate d1 (values[2], values[1], values[0]); 00434 const QDate d2 (values[5], values[4], values[3]); 00435 return engine->toScriptValue(checkRange(now, d1, d2)); 00436 } 00437 // day1, month1, day2, month2 00438 else if (values.size() == 4 && values[ 1 ] < 13 && values[ 3 ] < 13) { 00439 const QDate d1 (now.year(), values[1], values[0]); 00440 const QDate d2 (now.year(), values[3], values[2]); 00441 return engine->toScriptValue(checkRange(now, d1, d2)); 00442 } 00443 // month1, year1, month2, year2 00444 else if (values.size() == 4) { 00445 const QDate d1 (values[1], values[0], now.day()); 00446 const QDate d2 (values[3], values[2], now.day()); 00447 return engine->toScriptValue(checkRange(now, d1, d2)); 00448 } 00449 // year1, year2 00450 else if (values.size() == 2 && values[0] >= 1000 && values[1] >= 1000) { 00451 return engine->toScriptValue(checkRange(now.year(), values[0], values[1])); 00452 } 00453 // day1, day2 00454 else if (values.size() == 2 && context->argument(0).isNumber() && context->argument(1).isNumber()) { 00455 return engine->toScriptValue(checkRange(now.day(), values[0], values[1])); 00456 } 00457 // month1, month2 00458 else if (values.size() == 2) { 00459 return engine->toScriptValue(checkRange(now.month(), values[0], values[1])); 00460 } 00461 // year 00462 else if (values.size() == 1 && values[ 0 ] >= 1000) { 00463 return engine->toScriptValue(checkRange(now.year(), values[0], values[0])); 00464 } 00465 // day 00466 else if (values.size() == 1 && context->argument(0).isNumber()) { 00467 return engine->toScriptValue(checkRange(now.day(), values[0], values[0])); 00468 } 00469 // month 00470 else if (values.size() == 1) { 00471 return engine->toScriptValue(checkRange(now.month(), values[0], values[0])); 00472 } 00473 00474 return engine->undefinedValue(); 00475 } 00476 00477 // timeRange(hour [, "GMT" ]) 00478 // timeRange(hour1, hour2 [, "GMT" ]) 00479 // timeRange(hour1, min1, hour2, min2 [, "GMT" ]) 00480 // timeRange(hour1, min1, sec1, hour2, min2, sec2 [, "GMT" ]) 00481 // @returns true if the current time (GMT or local based on presence 00482 // of "GMT" argument) is within the given range 00483 QScriptValue TimeRange (QScriptContext* context, QScriptEngine* engine) 00484 { 00485 if (context->argumentCount() < 1 || context->argumentCount() > 7) { 00486 return engine->undefinedValue(); 00487 } 00488 00489 QVector<int> values; 00490 for (int i = 0; i < context->argumentCount(); ++i) { 00491 if (!context->argument(i).isNumber()) { 00492 break; 00493 } 00494 values.append(context->argument(i).toNumber()); 00495 } 00496 00497 const QTime now = getTime(context).time(); 00498 00499 // hour1, min1, sec1, hour2, min2, sec2 00500 if (values.size() == 6) { 00501 const QTime t1 (values[0], values[1], values[2]); 00502 const QTime t2 (values[3], values[4], values[5]); 00503 return engine->toScriptValue(checkRange(now, t1, t2)); 00504 } 00505 // hour1, min1, hour2, min2 00506 else if (values.size() == 4) { 00507 const QTime t1 (values[0], values[1]); 00508 const QTime t2 (values[2], values[3]); 00509 return engine->toScriptValue(checkRange(now, t1, t2)); 00510 } 00511 // hour1, hour2 00512 else if (values.size() == 2) { 00513 return engine->toScriptValue(checkRange(now.hour(), values[0], values[1])); 00514 } 00515 // hour 00516 else if (values.size() == 1) { 00517 return engine->toScriptValue(checkRange(now.hour(), values[0], values[0])); 00518 } 00519 00520 return engine->undefinedValue(); 00521 } 00522 00523 00524 /* 00525 * Implementation of Microsoft's IPv6 Extension for PAC 00526 * 00527 * Documentation: 00528 * http://msdn.microsoft.com/en-us/library/gg308477(v=vs.85).aspx 00529 * http://msdn.microsoft.com/en-us/library/gg308478(v=vs.85).aspx 00530 * http://msdn.microsoft.com/en-us/library/gg308474(v=vs.85).aspx 00531 * http://blogs.msdn.com/b/wndp/archive/2006/07/13/ipv6-pac-extensions-v0-9.aspx 00532 */ 00533 00534 // isResolvableEx(host) 00535 // @returns true if host is resolvable to an IPv4 or IPv6 address. 00536 QScriptValue IsResolvableEx (QScriptContext* context, QScriptEngine* engine) 00537 { 00538 if (context->argumentCount() != 1) { 00539 return engine->undefinedValue(); 00540 } 00541 00542 try { 00543 const Address info = Address::resolve(context->argument(0).toString()); 00544 bool hasResolvableIPAddress = false; 00545 Q_FOREACH(const QHostAddress& address, info.addresses()) { 00546 if (isIPv4Address(address) || isIPv6Address(address)) { 00547 hasResolvableIPAddress = true; 00548 break; 00549 } 00550 } 00551 return engine->toScriptValue(hasResolvableIPAddress); 00552 } 00553 catch (const Address::Error&) { 00554 return engine->toScriptValue(false); 00555 } 00556 } 00557 00558 // isInNetEx(ipAddress, ipPrefix ) 00559 // @returns true if ipAddress is within the specified ipPrefix. 00560 QScriptValue IsInNetEx (QScriptContext* context, QScriptEngine* engine) 00561 { 00562 if (context->argumentCount() != 2) { 00563 return engine->undefinedValue(); 00564 } 00565 00566 try { 00567 const Address info = Address::resolve(context->argument(0).toString()); 00568 bool isInSubNet = false; 00569 const QString subnetStr = context->argument(1).toString(); 00570 const QPair<QHostAddress, int> subnet = QHostAddress::parseSubnet(subnetStr); 00571 00572 Q_FOREACH(const QHostAddress& address, info.addresses()) { 00573 if (isSpecialAddress(address)) { 00574 continue; 00575 } 00576 00577 if (address.isInSubnet(subnet)) { 00578 isInSubNet = true; 00579 break; 00580 } 00581 } 00582 return engine->toScriptValue(isInSubNet); 00583 } 00584 catch (const Address::Error&) { 00585 return engine->toScriptValue(false); 00586 } 00587 } 00588 00589 // dnsResolveEx(host) 00590 // @returns a semi-colon delimited string containing IPv6 and IPv4 addresses 00591 // for host or an empty string if host is not resolvable. 00592 QScriptValue DNSResolveEx (QScriptContext* context, QScriptEngine* engine) 00593 { 00594 if (context->argumentCount() != 1) { 00595 return engine->undefinedValue(); 00596 } 00597 00598 try { 00599 const Address info = Address::resolve (context->argument(0).toString()); 00600 00601 QStringList addressList; 00602 QString resolvedAddress (QLatin1String("")); 00603 00604 Q_FOREACH(const QHostAddress& address, info.addresses()) { 00605 if (!isSpecialAddress(address)) { 00606 addressList << address.toString(); 00607 } 00608 } 00609 if (!addressList.isEmpty()) { 00610 resolvedAddress = addressList.join(QLatin1String(";")); 00611 } 00612 00613 return engine->toScriptValue(resolvedAddress); 00614 } 00615 catch (const Address::Error&) { 00616 return engine->toScriptValue(QString(QLatin1String(""))); 00617 } 00618 } 00619 00620 // myIpAddressEx() 00621 // @returns a semi-colon delimited string containing all IP addresses for localhost (IPv6 and/or IPv4), 00622 // or an empty string if unable to resolve localhost to an IP address. 00623 QScriptValue MyIpAddressEx (QScriptContext* context, QScriptEngine* engine) 00624 { 00625 if (context->argumentCount()) { 00626 return engine->undefinedValue(); 00627 } 00628 00629 QStringList ipAddressList; 00630 const QList<QHostAddress> addresses = QNetworkInterface::allAddresses(); 00631 Q_FOREACH(const QHostAddress address, addresses) { 00632 if (!isSpecialAddress(address) && !isLocalHostAddress(address)) { 00633 ipAddressList << address.toString(); 00634 } 00635 } 00636 00637 return engine->toScriptValue(ipAddressList.join(QLatin1String(";"))); 00638 } 00639 00640 // sortIpAddressList(ipAddressList) 00641 // @returns a sorted ipAddressList. If both IPv4 and IPv6 addresses are present in 00642 // the list. The sorted IPv6 addresses will precede the sorted IPv4 addresses. 00643 QScriptValue SortIpAddressList(QScriptContext* context, QScriptEngine* engine) 00644 { 00645 if (context->argumentCount() != 1) { 00646 return engine->undefinedValue(); 00647 } 00648 00649 QHash<QString, QString> actualEntryMap; 00650 QList<QHostAddress> ipV4List, ipV6List; 00651 const QStringList ipAddressList = context->argument(0).toString().split(QLatin1Char(';')); 00652 00653 Q_FOREACH(const QString& ipAddress, ipAddressList) { 00654 QHostAddress address(ipAddress); 00655 switch (address.protocol()) { 00656 case QAbstractSocket::IPv4Protocol: 00657 ipV4List << address; 00658 actualEntryMap.insert(address.toString(), ipAddress); 00659 break; 00660 case QAbstractSocket::IPv6Protocol: 00661 ipV6List << address; 00662 actualEntryMap.insert(address.toString(), ipAddress); 00663 break; 00664 default: 00665 break; 00666 } 00667 } 00668 00669 QString sortedAddress (QLatin1String("")); 00670 00671 if (!ipV6List.isEmpty()) { 00672 qSort(ipV6List.begin(), ipV6List.end(), addressLessThanComparison); 00673 sortedAddress += addressListToString(ipV6List, actualEntryMap); 00674 } 00675 00676 if (!ipV4List.isEmpty()) { 00677 qSort(ipV4List.begin(), ipV4List.end(), addressLessThanComparison); 00678 if (!sortedAddress.isEmpty()) { 00679 sortedAddress += QLatin1Char(';'); 00680 } 00681 sortedAddress += addressListToString(ipV4List, actualEntryMap); 00682 } 00683 00684 return engine->toScriptValue(sortedAddress); 00685 00686 } 00687 00688 // getClientVersion 00689 // @return the version number of this engine for future extension. We too start 00690 // this at version 1.0. 00691 QScriptValue GetClientVersion (QScriptContext* context, QScriptEngine* engine) 00692 { 00693 if (context->argumentCount()) { 00694 return engine->undefinedValue(); 00695 } 00696 00697 const QString version (QLatin1String("1.0")); 00698 return engine->toScriptValue(version); 00699 } 00700 00701 void registerFunctions(QScriptEngine* engine) 00702 { 00703 QScriptValue value = engine->globalObject(); 00704 value.setProperty(QL1S("isPlainHostName"), engine->newFunction(IsPlainHostName)); 00705 value.setProperty(QL1S("dnsDomainIs"), engine->newFunction(DNSDomainIs)); 00706 value.setProperty(QL1S("localHostOrDomainIs"), engine->newFunction(LocalHostOrDomainIs)); 00707 value.setProperty(QL1S("isResolvable"), engine->newFunction(IsResolvable)); 00708 value.setProperty(QL1S("isInNet"), engine->newFunction(IsInNet)); 00709 value.setProperty(QL1S("dnsResolve"), engine->newFunction(DNSResolve)); 00710 value.setProperty(QL1S("myIpAddress"), engine->newFunction(MyIpAddress)); 00711 value.setProperty(QL1S("dnsDomainLevels"), engine->newFunction(DNSDomainLevels)); 00712 value.setProperty(QL1S("shExpMatch"), engine->newFunction(ShExpMatch)); 00713 value.setProperty(QL1S("weekdayRange"), engine->newFunction(WeekdayRange)); 00714 value.setProperty(QL1S("dateRange"), engine->newFunction(DateRange)); 00715 value.setProperty(QL1S("timeRange"), engine->newFunction(TimeRange)); 00716 00717 // Microsoft's IPv6 PAC Extensions... 00718 value.setProperty(QL1S("isResolvableEx"), engine->newFunction(IsResolvableEx)); 00719 value.setProperty(QL1S("isInNetEx"), engine->newFunction(IsInNetEx)); 00720 value.setProperty(QL1S("dnsResolveEx"), engine->newFunction(DNSResolveEx)); 00721 value.setProperty(QL1S("myIpAddressEx"), engine->newFunction(MyIpAddressEx)); 00722 value.setProperty(QL1S("sortIpAddressList"), engine->newFunction(SortIpAddressList)); 00723 value.setProperty(QL1S("getClientVersion"), engine->newFunction(GetClientVersion)); 00724 } 00725 } 00726 00727 namespace KPAC 00728 { 00729 Script::Script(const QString& code) 00730 { 00731 m_engine = new QScriptEngine; 00732 registerFunctions(m_engine); 00733 00734 QScriptProgram program (code); 00735 const QScriptValue result = m_engine->evaluate(program); 00736 if (m_engine->hasUncaughtException() || result.isError()) 00737 throw Error(m_engine->uncaughtException().toString()); 00738 } 00739 00740 Script::~Script() 00741 { 00742 delete m_engine; 00743 } 00744 00745 QString Script::evaluate(const KUrl& url) 00746 { 00747 QScriptValue func = m_engine->globalObject().property(QL1S("FindProxyForURL")); 00748 00749 if (!func.isValid()) { 00750 func = m_engine->globalObject().property(QL1S("FindProxyForURLEx")); 00751 if (!func.isValid()) { 00752 throw Error(i18n("Could not find 'FindProxyForURL' or 'FindProxyForURLEx'")); 00753 return QString(); 00754 } 00755 } 00756 00757 QScriptValueList args; 00758 args << url.url(); 00759 args << url.host(); 00760 00761 QScriptValue result = func.call(QScriptValue(), args); 00762 if (result.isError()) { 00763 throw Error(i18n("Got an invalid reply when calling %1", func.toString())); 00764 } 00765 00766 return result.toString(); 00767 } 00768 } 00769 00770 // vim: ts=4 sw=4 et
KDE 4.7 API Reference