File indexing completed on 2024-10-06 12:22:03
0001 /* 0002 SPDX-FileCopyrightText: 2003 Malte Starostik <malte@kde.org> 0003 SPDX-FileCopyrightText: 2011 Dawit Alemayehu <adawit@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "script.h" 0009 0010 #include <QDateTime> 0011 #include <QRegularExpression> 0012 #include <QUrl> 0013 0014 #include <QHostAddress> 0015 #include <QHostInfo> 0016 #include <QNetworkInterface> 0017 0018 #include <QJSEngine> 0019 #include <QJSValue> 0020 #include <QJSValueIterator> 0021 0022 #include <KLocalizedString> 0023 #include <kio/hostinfo.h> 0024 0025 namespace 0026 { 0027 static int findString(const QString &s, const char *const *values) 0028 { 0029 int index = 0; 0030 for (const char *const *p = values; *p; ++p, ++index) { 0031 if (s.compare(QLatin1String(*p), Qt::CaseInsensitive) == 0) { 0032 return index; 0033 } 0034 } 0035 return -1; 0036 } 0037 0038 static const QDateTime getTime(QString tz) 0039 { 0040 if (tz.compare(QLatin1String("gmt"), Qt::CaseInsensitive) == 0) { 0041 return QDateTime::currentDateTimeUtc(); 0042 } 0043 return QDateTime::currentDateTime(); 0044 } 0045 0046 template<typename T> 0047 static bool checkRange(T value, T min, T max) 0048 { 0049 return ((min <= max && value >= min && value <= max) || (min > max && (value <= min || value >= max))); 0050 } 0051 0052 static bool isLocalHostAddress(const QHostAddress &address) 0053 { 0054 if (address == QHostAddress::LocalHost) { 0055 return true; 0056 } 0057 0058 if (address == QHostAddress::LocalHostIPv6) { 0059 return true; 0060 } 0061 0062 return false; 0063 } 0064 0065 static bool isIPv6Address(const QHostAddress &address) 0066 { 0067 return address.protocol() == QAbstractSocket::IPv6Protocol; 0068 } 0069 0070 static bool isIPv4Address(const QHostAddress &address) 0071 { 0072 return (address.protocol() == QAbstractSocket::IPv4Protocol); 0073 } 0074 0075 static bool isSpecialAddress(const QHostAddress &address) 0076 { 0077 // Catch all the special addresses and return false. 0078 if (address == QHostAddress::Null) { 0079 return true; 0080 } 0081 0082 if (address == QHostAddress::Any) { 0083 return true; 0084 } 0085 0086 if (address == QHostAddress::AnyIPv6) { 0087 return true; 0088 } 0089 0090 if (address == QHostAddress::Broadcast) { 0091 return true; 0092 } 0093 0094 return false; 0095 } 0096 0097 static bool addressLessThanComparison(const QHostAddress &addr1, const QHostAddress &addr2) 0098 { 0099 if (addr1.protocol() == QAbstractSocket::IPv4Protocol && addr2.protocol() == QAbstractSocket::IPv4Protocol) { 0100 return addr1.toIPv4Address() < addr2.toIPv4Address(); 0101 } 0102 0103 if (addr1.protocol() == QAbstractSocket::IPv6Protocol && addr2.protocol() == QAbstractSocket::IPv6Protocol) { 0104 const Q_IPV6ADDR ipv6addr1 = addr1.toIPv6Address(); 0105 const Q_IPV6ADDR ipv6addr2 = addr2.toIPv6Address(); 0106 for (int i = 0; i < 16; ++i) { 0107 if (ipv6addr1[i] != ipv6addr2[i]) { 0108 return ((ipv6addr1[i] & 0xff) - (ipv6addr2[i] & 0xff)); 0109 } 0110 } 0111 } 0112 0113 return false; 0114 } 0115 0116 static QString addressListToString(const QList<QHostAddress> &addressList, const QHash<QString, QString> &actualEntryMap) 0117 { 0118 QString result; 0119 for (const QHostAddress &address : addressList) { 0120 if (!result.isEmpty()) { 0121 result += QLatin1Char(';'); 0122 } 0123 result += actualEntryMap.value(address.toString()); 0124 } 0125 return result; 0126 } 0127 0128 class Address 0129 { 0130 public: 0131 struct Error { 0132 }; 0133 static Address resolve(const QString &host) 0134 { 0135 return Address(host); 0136 } 0137 0138 const QList<QHostAddress> &addresses() const 0139 { 0140 return m_addressList; 0141 } 0142 0143 QHostAddress address() const 0144 { 0145 if (m_addressList.isEmpty()) { 0146 return QHostAddress(); 0147 } 0148 0149 return m_addressList.first(); 0150 } 0151 0152 private: 0153 Address(const QString &host) 0154 { 0155 // Always try to see if it's already an IP first, to avoid Qt doing a 0156 // needless reverse lookup 0157 QHostAddress address(host); 0158 if (address.isNull()) { 0159 QHostInfo hostInfo = KIO::HostInfo::lookupCachedHostInfoFor(host); 0160 if (hostInfo.hostName().isEmpty() || hostInfo.error() != QHostInfo::NoError) { 0161 hostInfo = QHostInfo::fromName(host); 0162 KIO::HostInfo::cacheLookup(hostInfo); 0163 } 0164 m_addressList = hostInfo.addresses(); 0165 } else { 0166 m_addressList.clear(); 0167 m_addressList.append(address); 0168 } 0169 } 0170 0171 QList<QHostAddress> m_addressList; 0172 }; 0173 0174 class ScriptHelper : public QObject 0175 { 0176 Q_OBJECT 0177 QJSEngine *m_engine; 0178 0179 public: 0180 ScriptHelper(QJSEngine *engine, QObject *parent) 0181 : QObject(parent) 0182 , m_engine(engine) 0183 { 0184 } 0185 0186 // isPlainHostName(host) 0187 // @returns true if @p host doesn't contains a domain part 0188 Q_INVOKABLE QJSValue IsPlainHostName(QString string) 0189 { 0190 return QJSValue(string.indexOf(QLatin1Char('.')) == -1); 0191 } 0192 0193 // dnsDomainIs(host, domain) 0194 // @returns true if the domain part of @p host matches @p domain 0195 Q_INVOKABLE QJSValue DNSDomainIs(QString host, QString domain) 0196 { 0197 return QJSValue(host.endsWith(domain, Qt::CaseInsensitive)); 0198 } 0199 0200 // localHostOrDomainIs(host, fqdn) 0201 // @returns true if @p host is unqualified or equals @p fqdn 0202 Q_INVOKABLE QJSValue LocalHostOrDomainIs(QString host, QString fqdn) 0203 { 0204 if (!host.contains(QLatin1Char('.'))) { 0205 return QJSValue(true); 0206 } 0207 return QJSValue(host.compare(fqdn, Qt::CaseInsensitive) == 0); 0208 } 0209 0210 // isResolvable(host) 0211 // @returns true if host is resolvable to a IPv4 address. 0212 Q_INVOKABLE QJSValue IsResolvable(QString host) 0213 { 0214 try { 0215 const Address info = Address::resolve(host); 0216 bool hasResolvableIPv4Address = false; 0217 for (const QHostAddress &address : info.addresses()) { 0218 if (!isSpecialAddress(address) && isIPv4Address(address)) { 0219 hasResolvableIPv4Address = true; 0220 break; 0221 } 0222 } 0223 0224 return QJSValue(hasResolvableIPv4Address); 0225 } catch (const Address::Error &) { 0226 return QJSValue(false); 0227 } 0228 } 0229 0230 // isInNet(host, subnet, mask) 0231 // @returns true if the IPv4 address of host is within the specified subnet 0232 // and mask, false otherwise. 0233 Q_INVOKABLE QJSValue IsInNet(QString host, QString subnet, QString mask) 0234 { 0235 try { 0236 const Address info = Address::resolve(host); 0237 bool isInSubNet = false; 0238 const QString subnetStr = subnet + QLatin1Char('/') + mask; 0239 const QPair<QHostAddress, int> subnet = QHostAddress::parseSubnet(subnetStr); 0240 for (const QHostAddress &address : info.addresses()) { 0241 if (!isSpecialAddress(address) && isIPv4Address(address) && address.isInSubnet(subnet)) { 0242 isInSubNet = true; 0243 break; 0244 } 0245 } 0246 return QJSValue(isInSubNet); 0247 } catch (const Address::Error &) { 0248 return QJSValue(false); 0249 } 0250 } 0251 0252 // dnsResolve(host) 0253 // @returns the IPv4 address for host or an empty string if host is not resolvable. 0254 Q_INVOKABLE QJSValue DNSResolve(QString host) 0255 { 0256 try { 0257 const Address info = Address::resolve(host); 0258 QString resolvedAddress(QLatin1String("")); 0259 for (const QHostAddress &address : info.addresses()) { 0260 if (!isSpecialAddress(address) && isIPv4Address(address)) { 0261 resolvedAddress = address.toString(); 0262 break; 0263 } 0264 } 0265 return QJSValue(resolvedAddress); 0266 } catch (const Address::Error &) { 0267 return QJSValue(QString(QLatin1String(""))); 0268 } 0269 } 0270 0271 // myIpAddress() 0272 // @returns the local machine's IPv4 address. Note that this will return 0273 // the address for the first interfaces that match its criteria even if the 0274 // machine has multiple interfaces. 0275 Q_INVOKABLE QJSValue MyIpAddress() 0276 { 0277 QString ipAddress; 0278 const QList<QHostAddress> addresses = QNetworkInterface::allAddresses(); 0279 for (const QHostAddress &address : addresses) { 0280 if (isIPv4Address(address) && !isSpecialAddress(address) && !isLocalHostAddress(address)) { 0281 ipAddress = address.toString(); 0282 break; 0283 } 0284 } 0285 0286 return QJSValue(ipAddress); 0287 } 0288 0289 // dnsDomainLevels(host) 0290 // @returns the number of dots ('.') in @p host 0291 Q_INVOKABLE QJSValue DNSDomainLevels(QString host) 0292 { 0293 if (host.isNull()) { 0294 return QJSValue(0); 0295 } 0296 0297 return QJSValue(static_cast<int>(host.count(QLatin1Char('.')))); 0298 } 0299 0300 // shExpMatch(str, pattern) 0301 // @returns true if @p str matches the shell @p pattern 0302 Q_INVOKABLE QJSValue ShExpMatch(QString str, QString patternStr) 0303 { 0304 const QRegularExpression pattern(QRegularExpression::wildcardToRegularExpression(patternStr)); 0305 return QJSValue(pattern.match(str).hasMatch()); 0306 } 0307 0308 // weekdayRange(day [, "GMT" ]) 0309 // weekdayRange(day1, day2 [, "GMT" ]) 0310 // @returns true if the current day equals day or between day1 and day2 resp. 0311 // If the last argument is "GMT", GMT timezone is used, otherwise local time 0312 Q_INVOKABLE QJSValue WeekdayRange(QString day1, QString arg2 = QString(), QString tz = QString()) 0313 { 0314 static const char *const days[] = {"sun", "mon", "tue", "wed", "thu", "fri", "sat", nullptr}; 0315 0316 const int d1 = findString(day1, days); 0317 if (d1 == -1) { 0318 return QJSValue::UndefinedValue; 0319 } 0320 0321 int d2 = findString(arg2, days); 0322 if (d2 == -1) { 0323 d2 = d1; 0324 tz = arg2; 0325 } 0326 0327 // Adjust the days of week coming from QDateTime since it starts 0328 // counting with Monday as 1 and ends with Sunday as day 7. 0329 int dayOfWeek = getTime(tz).date().dayOfWeek(); 0330 if (dayOfWeek == 7) { 0331 dayOfWeek = 0; 0332 } 0333 return QJSValue(checkRange(dayOfWeek, d1, d2)); 0334 } 0335 0336 // dateRange(day [, "GMT" ]) 0337 // dateRange(day1, day2 [, "GMT" ]) 0338 // dateRange(month [, "GMT" ]) 0339 // dateRange(month1, month2 [, "GMT" ]) 0340 // dateRange(year [, "GMT" ]) 0341 // dateRange(year1, year2 [, "GMT" ]) 0342 // dateRange(day1, month1, day2, month2 [, "GMT" ]) 0343 // dateRange(month1, year1, month2, year2 [, "GMT" ]) 0344 // dateRange(day1, month1, year1, day2, month2, year2 [, "GMT" ]) 0345 // @returns true if the current date (GMT or local time according to 0346 // presence of "GMT" as last argument) is within the given range 0347 Q_INVOKABLE QJSValue DateRangeInternal(QJSValue args) 0348 { 0349 static const char *const months[] = {"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec", nullptr}; 0350 QVector<int> values; 0351 QJSValueIterator it(args); 0352 QString tz; 0353 bool onlySeenNumbers = true; 0354 int initialNumbers = 0; 0355 while (it.next()) { 0356 int value = -1; 0357 if (it.value().isNumber()) { 0358 value = it.value().toInt(); 0359 if (onlySeenNumbers) { 0360 initialNumbers++; 0361 } 0362 } else { 0363 onlySeenNumbers = false; 0364 // QDate starts counting months from 1, so we add 1 here. 0365 value = findString(it.value().toString(), months) + 1; 0366 if (value <= 0) { 0367 tz = it.value().toString(); 0368 } 0369 } 0370 0371 if (value > 0) { 0372 values.append(value); 0373 } else { 0374 break; 0375 } 0376 } 0377 // Our variable args calling indirection means argument.length was appended 0378 if (values.count() == initialNumbers) { 0379 --initialNumbers; 0380 } 0381 values.resize(values.size() - 1); 0382 0383 if (values.count() < 1 || values.count() > 7) { 0384 return QJSValue::UndefinedValue; 0385 } 0386 0387 const QDate now = getTime(tz).date(); 0388 0389 // day1, month1, year1, day2, month2, year2 0390 if (values.size() == 6) { 0391 const QDate d1(values[2], values[1], values[0]); 0392 const QDate d2(values[5], values[4], values[3]); 0393 return QJSValue(checkRange(now, d1, d2)); 0394 } 0395 // day1, month1, day2, month2 0396 else if (values.size() == 4 && values[1] < 13 && values[3] < 13) { 0397 const QDate d1(now.year(), values[1], values[0]); 0398 const QDate d2(now.year(), values[3], values[2]); 0399 return QJSValue(checkRange(now, d1, d2)); 0400 } 0401 // month1, year1, month2, year2 0402 else if (values.size() == 4) { 0403 const QDate d1(values[1], values[0], now.day()); 0404 const QDate d2(values[3], values[2], now.day()); 0405 return QJSValue(checkRange(now, d1, d2)); 0406 } 0407 // year1, year2 0408 else if (values.size() == 2 && values[0] >= 1000 && values[1] >= 1000) { 0409 return QJSValue(checkRange(now.year(), values[0], values[1])); 0410 } 0411 // day1, day2 0412 else if (values.size() == 2 && initialNumbers == 2) { 0413 return QJSValue(checkRange(now.day(), values[0], values[1])); 0414 } 0415 // month1, month2 0416 else if (values.size() == 2) { 0417 return QJSValue(checkRange(now.month(), values[0], values[1])); 0418 } 0419 // year 0420 else if (values.size() == 1 && values[0] >= 1000) { 0421 return QJSValue(checkRange(now.year(), values[0], values[0])); 0422 } 0423 // day 0424 else if (values.size() == 1 && initialNumbers == 1) { 0425 return QJSValue(checkRange(now.day(), values[0], values[0])); 0426 } 0427 // month 0428 else if (values.size() == 1) { 0429 return QJSValue(checkRange(now.month(), values[0], values[0])); 0430 } 0431 0432 return QJSValue::UndefinedValue; 0433 } 0434 0435 // timeRange(hour [, "GMT" ]) 0436 // timeRange(hour1, hour2 [, "GMT" ]) 0437 // timeRange(hour1, min1, hour2, min2 [, "GMT" ]) 0438 // timeRange(hour1, min1, sec1, hour2, min2, sec2 [, "GMT" ]) 0439 // @returns true if the current time (GMT or local based on presence 0440 // of "GMT" argument) is within the given range 0441 Q_INVOKABLE QJSValue TimeRange(int hour, QString tz = QString()) 0442 { 0443 const QTime now = getTime(tz).time(); 0444 return m_engine->toScriptValue(checkRange(now.hour(), hour, hour)); 0445 } 0446 0447 Q_INVOKABLE QJSValue TimeRange(int hour1, int hour2, QString tz = QString()) 0448 { 0449 const QTime now = getTime(tz).time(); 0450 return m_engine->toScriptValue(checkRange(now.hour(), hour1, hour2)); 0451 } 0452 0453 Q_INVOKABLE QJSValue TimeRange(int hour1, int min1, int hour2, int min2, QString tz = QString()) 0454 { 0455 const QTime now = getTime(tz).time(); 0456 const QTime t1(hour1, min1); 0457 const QTime t2(hour2, min2); 0458 return m_engine->toScriptValue(checkRange(now, t1, t2)); 0459 } 0460 0461 Q_INVOKABLE QJSValue TimeRange(int hour1, int min1, int sec1, int hour2, int min2, int sec2, QString tz = QString()) 0462 { 0463 const QTime now = getTime(tz).time(); 0464 0465 const QTime t1(hour1, min1, sec1); 0466 const QTime t2(hour2, min2, sec2); 0467 return m_engine->toScriptValue(checkRange(now, t1, t2)); 0468 } 0469 0470 /* 0471 * Implementation of Microsoft's IPv6 Extension for PAC 0472 * 0473 * Documentation: 0474 * http://msdn.microsoft.com/en-us/library/gg308477(v=vs.85).aspx 0475 * http://msdn.microsoft.com/en-us/library/gg308478(v=vs.85).aspx 0476 * http://msdn.microsoft.com/en-us/library/gg308474(v=vs.85).aspx 0477 * http://blogs.msdn.com/b/wndp/archive/2006/07/13/ipv6-pac-extensions-v0-9.aspx 0478 */ 0479 0480 // isResolvableEx(host) 0481 // @returns true if host is resolvable to an IPv4 or IPv6 address. 0482 Q_INVOKABLE QJSValue IsResolvableEx(QString host) 0483 { 0484 try { 0485 const Address info = Address::resolve(host); 0486 bool hasResolvableIPAddress = false; 0487 for (const QHostAddress &address : info.addresses()) { 0488 if (isIPv4Address(address) || isIPv6Address(address)) { 0489 hasResolvableIPAddress = true; 0490 break; 0491 } 0492 } 0493 return QJSValue(hasResolvableIPAddress); 0494 } catch (const Address::Error &) { 0495 return QJSValue(false); 0496 } 0497 } 0498 0499 // isInNetEx(ipAddress, ipPrefix ) 0500 // @returns true if ipAddress is within the specified ipPrefix. 0501 Q_INVOKABLE QJSValue IsInNetEx(QString ipAddress, QString ipPrefix) 0502 { 0503 try { 0504 const Address info = Address::resolve(ipAddress); 0505 bool isInSubNet = false; 0506 const QString subnetStr = ipPrefix; 0507 const QPair<QHostAddress, int> subnet = QHostAddress::parseSubnet(subnetStr); 0508 for (const QHostAddress &address : info.addresses()) { 0509 if (isSpecialAddress(address)) { 0510 continue; 0511 } 0512 0513 if (address.isInSubnet(subnet)) { 0514 isInSubNet = true; 0515 break; 0516 } 0517 } 0518 return QJSValue(isInSubNet); 0519 } catch (const Address::Error &) { 0520 return QJSValue(false); 0521 } 0522 } 0523 0524 // dnsResolveEx(host) 0525 // @returns a semi-colon delimited string containing IPv6 and IPv4 addresses 0526 // for host or an empty string if host is not resolvable. 0527 Q_INVOKABLE QJSValue DNSResolveEx(QString host) 0528 { 0529 try { 0530 const Address info = Address::resolve(host); 0531 0532 QStringList addressList; 0533 QString resolvedAddress(QLatin1String("")); 0534 for (const QHostAddress &address : info.addresses()) { 0535 if (!isSpecialAddress(address)) { 0536 addressList << address.toString(); 0537 } 0538 } 0539 if (!addressList.isEmpty()) { 0540 resolvedAddress = addressList.join(QLatin1Char(';')); 0541 } 0542 0543 return QJSValue(resolvedAddress); 0544 } catch (const Address::Error &) { 0545 return QJSValue(QString(QLatin1String(""))); 0546 } 0547 } 0548 0549 // myIpAddressEx() 0550 // @returns a semi-colon delimited string containing all IP addresses for localhost (IPv6 and/or IPv4), 0551 // or an empty string if unable to resolve localhost to an IP address. 0552 Q_INVOKABLE QJSValue MyIpAddressEx() 0553 { 0554 QStringList ipAddressList; 0555 const QList<QHostAddress> addresses = QNetworkInterface::allAddresses(); 0556 for (const QHostAddress &address : addresses) { 0557 if (!isSpecialAddress(address) && !isLocalHostAddress(address)) { 0558 ipAddressList << address.toString(); 0559 } 0560 } 0561 0562 return m_engine->toScriptValue(ipAddressList.join(QLatin1Char(';'))); 0563 } 0564 0565 // sortIpAddressList(ipAddressList) 0566 // @returns a sorted ipAddressList. If both IPv4 and IPv6 addresses are present in 0567 // the list. The sorted IPv6 addresses will precede the sorted IPv4 addresses. 0568 Q_INVOKABLE QJSValue SortIpAddressList(QString ipAddressListStr) 0569 { 0570 QHash<QString, QString> actualEntryMap; 0571 QList<QHostAddress> ipV4List; 0572 QList<QHostAddress> ipV6List; 0573 const QStringList ipAddressList = ipAddressListStr.split(QLatin1Char(';')); 0574 0575 for (const QString &ipAddress : ipAddressList) { 0576 QHostAddress address(ipAddress); 0577 switch (address.protocol()) { 0578 case QAbstractSocket::IPv4Protocol: 0579 ipV4List << address; 0580 actualEntryMap.insert(address.toString(), ipAddress); 0581 break; 0582 case QAbstractSocket::IPv6Protocol: 0583 ipV6List << address; 0584 actualEntryMap.insert(address.toString(), ipAddress); 0585 break; 0586 default: 0587 break; 0588 } 0589 } 0590 0591 QString sortedAddress(QLatin1String("")); 0592 0593 if (!ipV6List.isEmpty()) { 0594 std::sort(ipV6List.begin(), ipV6List.end(), addressLessThanComparison); 0595 sortedAddress += addressListToString(ipV6List, actualEntryMap); 0596 } 0597 0598 if (!ipV4List.isEmpty()) { 0599 std::sort(ipV4List.begin(), ipV4List.end(), addressLessThanComparison); 0600 if (!sortedAddress.isEmpty()) { 0601 sortedAddress += QLatin1Char(';'); 0602 } 0603 sortedAddress += addressListToString(ipV4List, actualEntryMap); 0604 } 0605 0606 return QJSValue(sortedAddress); 0607 } 0608 0609 // getClientVersion 0610 // @return the version number of this engine for future extension. We too start 0611 // this at version 1.0. 0612 Q_INVOKABLE QJSValue GetClientVersion() 0613 { 0614 const QString version(QStringLiteral("1.0")); 0615 return QJSValue(version); 0616 } 0617 }; // class ScriptHelper 0618 0619 void registerFunctions(QJSEngine *engine) 0620 { 0621 QJSValue value = engine->globalObject(); 0622 auto scriptHelper = new ScriptHelper(engine, engine); 0623 QJSValue functions = engine->newQObject(scriptHelper); 0624 0625 value.setProperty(QStringLiteral("isPlainHostName"), functions.property(QStringLiteral("IsPlainHostName"))); 0626 value.setProperty(QStringLiteral("dnsDomainIs"), functions.property(QStringLiteral("DNSDomainIs"))); 0627 value.setProperty(QStringLiteral("localHostOrDomainIs"), functions.property(QStringLiteral("LocalHostOrDomainIs"))); 0628 value.setProperty(QStringLiteral("isResolvable"), functions.property(QStringLiteral("IsResolvable"))); 0629 value.setProperty(QStringLiteral("isInNet"), functions.property(QStringLiteral("IsInNet"))); 0630 value.setProperty(QStringLiteral("dnsResolve"), functions.property(QStringLiteral("DNSResolve"))); 0631 value.setProperty(QStringLiteral("myIpAddress"), functions.property(QStringLiteral("MyIpAddress"))); 0632 value.setProperty(QStringLiteral("dnsDomainLevels"), functions.property(QStringLiteral("DNSDomainLevels"))); 0633 value.setProperty(QStringLiteral("shExpMatch"), functions.property(QStringLiteral("ShExpMatch"))); 0634 value.setProperty(QStringLiteral("weekdayRange"), functions.property(QStringLiteral("WeekdayRange"))); 0635 value.setProperty(QStringLiteral("timeRange"), functions.property(QStringLiteral("TimeRange"))); 0636 value.setProperty(QStringLiteral("dateRangeInternal"), functions.property(QStringLiteral("DateRangeInternal"))); 0637 engine->evaluate(QStringLiteral("dateRange = function() { return dateRangeInternal(Array.prototype.slice.call(arguments)); };")); 0638 0639 // Microsoft's IPv6 PAC Extensions... 0640 value.setProperty(QStringLiteral("isResolvableEx"), functions.property(QStringLiteral("IsResolvableEx"))); 0641 value.setProperty(QStringLiteral("isInNetEx"), functions.property(QStringLiteral("IsInNetEx"))); 0642 value.setProperty(QStringLiteral("dnsResolveEx"), functions.property(QStringLiteral("DNSResolveEx"))); 0643 value.setProperty(QStringLiteral("myIpAddressEx"), functions.property(QStringLiteral("MyIpAddressEx"))); 0644 value.setProperty(QStringLiteral("sortIpAddressList"), functions.property(QStringLiteral("SortIpAddressList"))); 0645 value.setProperty(QStringLiteral("getClientVersion"), functions.property(QStringLiteral("GetClientVersion"))); 0646 } 0647 } // namespace 0648 0649 namespace KPAC 0650 { 0651 Script::Script(const QString &code) 0652 { 0653 m_engine = new QJSEngine; 0654 registerFunctions(m_engine); 0655 0656 const QJSValue result = m_engine->evaluate(code); 0657 if (result.isError()) { 0658 throw Error(result.toString()); 0659 } 0660 } 0661 0662 Script::~Script() 0663 { 0664 delete m_engine; 0665 } 0666 0667 QString Script::evaluate(const QUrl &url) 0668 { 0669 QJSValue func = m_engine->globalObject().property(QStringLiteral("FindProxyForURL")); 0670 0671 if (!func.isCallable()) { 0672 func = m_engine->globalObject().property(QStringLiteral("FindProxyForURLEx")); 0673 if (!func.isCallable()) { 0674 throw Error(i18n("Could not find 'FindProxyForURL' or 'FindProxyForURLEx'")); 0675 return QString(); 0676 } 0677 } 0678 0679 QUrl cleanUrl = url; 0680 cleanUrl.setUserInfo(QString()); 0681 if (cleanUrl.scheme() == QLatin1String("https")) { 0682 cleanUrl.setPath(QString()); 0683 cleanUrl.setQuery(QString()); 0684 } 0685 0686 QJSValueList args; 0687 args << cleanUrl.url(); 0688 args << cleanUrl.host(); 0689 0690 QJSValue result = func.call(args); 0691 if (result.isError()) { 0692 throw Error(i18n("Got an invalid reply when calling %1 -> %2", func.toString(), result.toString())); 0693 } 0694 0695 return result.toString(); 0696 } 0697 } // namespace KPAC 0698 0699 #include "script.moc"