23 #include <QtCore/QString>
24 #include <QtCore/QRegExp>
25 #include <QtCore/QDateTime>
26 #include <QtCore/QTimer>
27 #include <QtCore/QEventLoop>
29 #include <QtNetwork/QHostInfo>
30 #include <QtNetwork/QHostAddress>
31 #include <QtNetwork/QNetworkInterface>
33 #include <QtScript/QScriptValue>
34 #include <QtScript/QScriptEngine>
35 #include <QtScript/QScriptProgram>
36 #include <QtScript/QScriptContextInfo>
42 #define QL1S(x) QLatin1String(x)
46 static int findString (
const QString& s,
const char*
const* values)
49 const QString lower = s.toLower();
50 for (
const char*
const* p = values; *p; ++p, ++index) {
51 if (s.compare(QLatin1String(*p), Qt::CaseInsensitive) == 0) {
58 static const QDateTime getTime (QScriptContext* context)
60 const QString tz = context->argument(context->argumentCount() - 1).toString();
61 if (tz.compare(QLatin1String(
"gmt"), Qt::CaseInsensitive) == 0) {
62 return QDateTime::currentDateTimeUtc();
64 return QDateTime::currentDateTime();
68 static bool checkRange (
T value,
T min,
T max)
70 return ((min <= max && value >= min && value <= max) ||
71 (min > max && (value <= min || value >= max)));
74 static bool isLocalHostAddress (
const QHostAddress& address)
76 if (address == QHostAddress::LocalHost)
79 if (address == QHostAddress::LocalHostIPv6)
85 static bool isIPv6Address (
const QHostAddress& address)
87 return address.protocol() == QAbstractSocket::IPv6Protocol;
90 static bool isIPv4Address (
const QHostAddress& address)
92 return (address.protocol() == QAbstractSocket::IPv4Protocol);
95 static bool isSpecialAddress(
const QHostAddress& address)
98 if (address == QHostAddress::Null)
101 if (address == QHostAddress::Any)
104 if (address == QHostAddress::AnyIPv6)
107 if (address == QHostAddress::Broadcast)
113 static bool addressLessThanComparison(
const QHostAddress& addr1,
const QHostAddress& addr2)
115 if (addr1.protocol() == QAbstractSocket::IPv4Protocol &&
116 addr2.protocol() == QAbstractSocket::IPv4Protocol) {
117 return addr1.toIPv4Address() < addr2.toIPv4Address();
120 if (addr1.protocol() == QAbstractSocket::IPv6Protocol &&
121 addr2.protocol() == QAbstractSocket::IPv6Protocol) {
122 const Q_IPV6ADDR ipv6addr1 = addr1.toIPv6Address();
123 const Q_IPV6ADDR ipv6addr2 = addr2.toIPv6Address();
124 for (
int i=0; i < 16; ++i) {
125 if (ipv6addr1[i] != ipv6addr2[i]) {
126 return ((ipv6addr1[i] & 0xff) - (ipv6addr2[i] & 0xff));
138 Q_FOREACH(
const QHostAddress& address, addressList) {
139 if (!result.isEmpty()) {
140 result += QLatin1Char(
';');
142 result += actualEntryMap.value(address.toString());
158 return m_addressList;
161 QHostAddress address()
const
163 if (m_addressList.isEmpty())
164 return QHostAddress();
166 return m_addressList.first();
174 QHostAddress address ( host );
175 if ( address.isNull() ) {
177 if (hostInfo.hostName().isEmpty() || hostInfo.error() != QHostInfo::NoError) {
178 hostInfo = QHostInfo::fromName(host);
181 m_addressList = hostInfo.addresses();
183 m_addressList.clear();
184 m_addressList.append(address);
194 QScriptValue IsPlainHostName(QScriptContext* context, QScriptEngine* engine)
196 if (context->argumentCount() != 1) {
197 return engine->undefinedValue();
199 return engine->toScriptValue(context->argument(0).toString().indexOf(QLatin1Char(
'.')) == -1);
204 QScriptValue DNSDomainIs (QScriptContext* context, QScriptEngine* engine)
206 if (context->argumentCount() != 2) {
207 return engine->undefinedValue();
210 const QString host = context->argument(0).toString();
211 const QString domain = context->argument(1).toString();
212 return engine->toScriptValue(host.endsWith(domain, Qt::CaseInsensitive));
217 QScriptValue LocalHostOrDomainIs (QScriptContext* context, QScriptEngine* engine)
219 if (context->argumentCount() != 2) {
220 return engine->undefinedValue();
223 const QString host = context->argument(0).toString();
224 if (!host.contains(QLatin1Char(
'.'))) {
225 return engine->toScriptValue(
true);
227 const QString fqdn = context->argument(1).toString();
228 return engine->toScriptValue((host.compare(fqdn, Qt::CaseInsensitive) == 0));
233 QScriptValue IsResolvable (QScriptContext* context, QScriptEngine* engine)
235 if (context->argumentCount() != 1) {
236 return engine->undefinedValue();
240 const Address info = Address::resolve(context->argument(0).toString());
241 bool hasResolvableIPv4Address =
false;
243 Q_FOREACH(
const QHostAddress& address, info.addresses()) {
244 if (!isSpecialAddress(address) && isIPv4Address(address)) {
245 hasResolvableIPv4Address =
true;
250 return engine->toScriptValue(hasResolvableIPv4Address);
252 catch (
const Address::Error&) {
253 return engine->toScriptValue(
false);
260 QScriptValue IsInNet (QScriptContext* context, QScriptEngine* engine)
262 if (context->argumentCount() != 3) {
263 return engine->undefinedValue();
267 const Address info = Address::resolve(context->argument(0).toString());
268 bool isInSubNet =
false;
269 QString subnetStr = context->argument(1).toString();
270 subnetStr += QLatin1Char(
'/');
271 subnetStr += context->argument(2).toString();
273 Q_FOREACH(
const QHostAddress& address, info.addresses()) {
274 if (!isSpecialAddress(address) && isIPv4Address(address) && address.isInSubnet(subnet)) {
279 return engine->toScriptValue(isInSubNet);
281 catch (
const Address::Error&) {
282 return engine->toScriptValue(
false);
288 QScriptValue DNSResolve (QScriptContext* context, QScriptEngine* engine)
290 if (context->argumentCount() != 1) {
291 return engine->undefinedValue();
295 const Address info = Address::resolve(context->argument(0).toString());
296 QString resolvedAddress (QLatin1String(
""));
297 Q_FOREACH(
const QHostAddress& address, info.addresses()) {
298 if (!isSpecialAddress(address) && isIPv4Address(address)) {
299 resolvedAddress = address.toString();
303 return engine->toScriptValue(resolvedAddress);
305 catch (
const Address::Error&) {
306 return engine->toScriptValue(
QString(QLatin1String(
"")));
314 QScriptValue MyIpAddress (QScriptContext* context, QScriptEngine* engine)
316 if (context->argumentCount()) {
317 return engine->undefinedValue();
322 Q_FOREACH(
const QHostAddress address, addresses) {
323 if (isIPv4Address(address) && !isSpecialAddress(address) && !isLocalHostAddress(address)) {
324 ipAddress = address.toString();
329 return engine->toScriptValue(ipAddress);
334 QScriptValue DNSDomainLevels (QScriptContext* context, QScriptEngine* engine)
336 if (context->argumentCount() != 1) {
337 return engine->undefinedValue();
340 const QString host = context->argument(0).toString();
342 return engine->toScriptValue(0);
345 return engine->toScriptValue(host.count(QLatin1Char(
'.')));
350 QScriptValue ShExpMatch (QScriptContext* context, QScriptEngine* engine)
352 if (context->argumentCount() != 2) {
353 return engine->undefinedValue();
356 QRegExp
pattern(context->argument(1).toString(), Qt::CaseSensitive, QRegExp::Wildcard);
357 return engine->toScriptValue(
pattern.exactMatch(context->argument(0).toString()));
364 QScriptValue WeekdayRange (QScriptContext* context, QScriptEngine* engine)
366 if (context->argumentCount() < 1 || context->argumentCount() > 3) {
367 return engine->undefinedValue();
370 static const char*
const days[] = {
"sun",
"mon",
"tue",
"wed",
"thu",
"fri",
"sat", 0 };
372 const int d1 = findString(context->argument(0).toString(), days);
374 return engine->undefinedValue();
377 int d2 = findString(context->argument(1).toString(), days);
384 int dayOfWeek = getTime(context).date().dayOfWeek();
385 if (dayOfWeek == 7) {
388 return engine->toScriptValue(checkRange(dayOfWeek, d1, d2));
402 QScriptValue DateRange (QScriptContext* context, QScriptEngine* engine)
404 if (context->argumentCount() < 1 || context->argumentCount() > 7) {
405 return engine->undefinedValue();
408 static const char*
const months[] = {
"jan",
"feb",
"mar",
"apr",
"may",
"jun",
409 "jul",
"aug",
"sep",
"oct",
"nov",
"dec", 0 };
412 for (
int i = 0; i < context->argumentCount(); ++i)
415 if (context->argument(i).isNumber()) {
416 value = context->argument(i).toInt32();
419 value = findString(context->argument(i).toString(), months) + 1;
423 values.append(value);
429 const QDate now = getTime(context).date();
432 if (values.size() == 6) {
433 const QDate d1 (values[2], values[1], values[0]);
434 const QDate d2 (values[5], values[4], values[3]);
435 return engine->toScriptValue(checkRange(now, d1, d2));
438 else if (values.size() == 4 && values[ 1 ] < 13 && values[ 3 ] < 13) {
439 const QDate d1 (now.year(), values[1], values[0]);
440 const QDate d2 (now.year(), values[3], values[2]);
441 return engine->toScriptValue(checkRange(now, d1, d2));
444 else if (values.size() == 4) {
445 const QDate d1 (values[1], values[0], now.day());
446 const QDate d2 (values[3], values[2], now.day());
447 return engine->toScriptValue(checkRange(now, d1, d2));
450 else if (values.size() == 2 && values[0] >= 1000 && values[1] >= 1000) {
451 return engine->toScriptValue(checkRange(now.year(), values[0], values[1]));
454 else if (values.size() == 2 && context->argument(0).isNumber() && context->argument(1).isNumber()) {
455 return engine->toScriptValue(checkRange(now.day(), values[0], values[1]));
458 else if (values.size() == 2) {
459 return engine->toScriptValue(checkRange(now.month(), values[0], values[1]));
462 else if (values.size() == 1 && values[ 0 ] >= 1000) {
463 return engine->toScriptValue(checkRange(now.year(), values[0], values[0]));
466 else if (values.size() == 1 && context->argument(0).isNumber()) {
467 return engine->toScriptValue(checkRange(now.day(), values[0], values[0]));
470 else if (values.size() == 1) {
471 return engine->toScriptValue(checkRange(now.month(), values[0], values[0]));
474 return engine->undefinedValue();
483 QScriptValue TimeRange (QScriptContext* context, QScriptEngine* engine)
485 if (context->argumentCount() < 1 || context->argumentCount() > 7) {
486 return engine->undefinedValue();
490 for (
int i = 0; i < context->argumentCount(); ++i) {
491 if (!context->argument(i).isNumber()) {
494 values.append(context->argument(i).toNumber());
497 const QTime now = getTime(context).time();
500 if (values.size() == 6) {
501 const QTime t1 (values[0], values[1], values[2]);
502 const QTime t2 (values[3], values[4], values[5]);
503 return engine->toScriptValue(checkRange(now, t1, t2));
506 else if (values.size() == 4) {
507 const QTime t1 (values[0], values[1]);
508 const QTime t2 (values[2], values[3]);
509 return engine->toScriptValue(checkRange(now, t1, t2));
512 else if (values.size() == 2) {
513 return engine->toScriptValue(checkRange(now.hour(), values[0], values[1]));
516 else if (values.size() == 1) {
517 return engine->toScriptValue(checkRange(now.hour(), values[0], values[0]));
520 return engine->undefinedValue();
536 QScriptValue IsResolvableEx (QScriptContext* context, QScriptEngine* engine)
538 if (context->argumentCount() != 1) {
539 return engine->undefinedValue();
543 const Address info = Address::resolve(context->argument(0).toString());
544 bool hasResolvableIPAddress =
false;
545 Q_FOREACH(
const QHostAddress& address, info.addresses()) {
546 if (isIPv4Address(address) || isIPv6Address(address)) {
547 hasResolvableIPAddress =
true;
551 return engine->toScriptValue(hasResolvableIPAddress);
553 catch (
const Address::Error&) {
554 return engine->toScriptValue(
false);
560 QScriptValue IsInNetEx (QScriptContext* context, QScriptEngine* engine)
562 if (context->argumentCount() != 2) {
563 return engine->undefinedValue();
567 const Address info = Address::resolve(context->argument(0).toString());
568 bool isInSubNet =
false;
569 const QString subnetStr = context->argument(1).toString();
572 Q_FOREACH(
const QHostAddress& address, info.addresses()) {
573 if (isSpecialAddress(address)) {
577 if (address.isInSubnet(subnet)) {
582 return engine->toScriptValue(isInSubNet);
584 catch (
const Address::Error&) {
585 return engine->toScriptValue(
false);
592 QScriptValue DNSResolveEx (QScriptContext* context, QScriptEngine* engine)
594 if (context->argumentCount() != 1) {
595 return engine->undefinedValue();
599 const Address info = Address::resolve (context->argument(0).toString());
602 QString resolvedAddress (QLatin1String(
""));
604 Q_FOREACH(
const QHostAddress& address, info.addresses()) {
605 if (!isSpecialAddress(address)) {
606 addressList << address.toString();
609 if (!addressList.isEmpty()) {
610 resolvedAddress = addressList.join(QLatin1String(
";"));
613 return engine->toScriptValue(resolvedAddress);
615 catch (
const Address::Error&) {
616 return engine->toScriptValue(
QString(QLatin1String(
"")));
623 QScriptValue MyIpAddressEx (QScriptContext* context, QScriptEngine* engine)
625 if (context->argumentCount()) {
626 return engine->undefinedValue();
631 Q_FOREACH(
const QHostAddress address, addresses) {
632 if (!isSpecialAddress(address) && !isLocalHostAddress(address)) {
633 ipAddressList << address.toString();
637 return engine->toScriptValue(ipAddressList.join(QLatin1String(
";")));
643 QScriptValue SortIpAddressList(QScriptContext* context, QScriptEngine* engine)
645 if (context->argumentCount() != 1) {
646 return engine->undefinedValue();
651 const QStringList ipAddressList = context->argument(0).toString().split(QLatin1Char(
';'));
653 Q_FOREACH(
const QString& ipAddress, ipAddressList) {
654 QHostAddress address(ipAddress);
655 switch (address.protocol()) {
656 case QAbstractSocket::IPv4Protocol:
658 actualEntryMap.insert(address.toString(), ipAddress);
660 case QAbstractSocket::IPv6Protocol:
662 actualEntryMap.insert(address.toString(), ipAddress);
669 QString sortedAddress (QLatin1String(
""));
671 if (!ipV6List.isEmpty()) {
672 qSort(ipV6List.begin(), ipV6List.end(), addressLessThanComparison);
673 sortedAddress += addressListToString(ipV6List, actualEntryMap);
676 if (!ipV4List.isEmpty()) {
677 qSort(ipV4List.begin(), ipV4List.end(), addressLessThanComparison);
678 if (!sortedAddress.isEmpty()) {
679 sortedAddress += QLatin1Char(
';');
681 sortedAddress += addressListToString(ipV4List, actualEntryMap);
684 return engine->toScriptValue(sortedAddress);
691 QScriptValue GetClientVersion (QScriptContext* context, QScriptEngine* engine)
693 if (context->argumentCount()) {
694 return engine->undefinedValue();
698 return engine->toScriptValue(version);
701 void registerFunctions(QScriptEngine* engine)
703 QScriptValue value = engine->globalObject();
704 value.setProperty(
QL1S(
"isPlainHostName"), engine->newFunction(IsPlainHostName));
705 value.setProperty(
QL1S(
"dnsDomainIs"), engine->newFunction(DNSDomainIs));
706 value.setProperty(
QL1S(
"localHostOrDomainIs"), engine->newFunction(LocalHostOrDomainIs));
707 value.setProperty(
QL1S(
"isResolvable"), engine->newFunction(IsResolvable));
708 value.setProperty(
QL1S(
"isInNet"), engine->newFunction(IsInNet));
709 value.setProperty(
QL1S(
"dnsResolve"), engine->newFunction(DNSResolve));
710 value.setProperty(
QL1S(
"myIpAddress"), engine->newFunction(MyIpAddress));
711 value.setProperty(
QL1S(
"dnsDomainLevels"), engine->newFunction(DNSDomainLevels));
712 value.setProperty(
QL1S(
"shExpMatch"), engine->newFunction(ShExpMatch));
713 value.setProperty(
QL1S(
"weekdayRange"), engine->newFunction(WeekdayRange));
714 value.setProperty(
QL1S(
"dateRange"), engine->newFunction(DateRange));
715 value.setProperty(
QL1S(
"timeRange"), engine->newFunction(TimeRange));
718 value.setProperty(
QL1S(
"isResolvableEx"), engine->newFunction(IsResolvableEx));
719 value.setProperty(
QL1S(
"isInNetEx"), engine->newFunction(IsInNetEx));
720 value.setProperty(
QL1S(
"dnsResolveEx"), engine->newFunction(DNSResolveEx));
721 value.setProperty(
QL1S(
"myIpAddressEx"), engine->newFunction(MyIpAddressEx));
722 value.setProperty(
QL1S(
"sortIpAddressList"), engine->newFunction(SortIpAddressList));
723 value.setProperty(
QL1S(
"getClientVersion"), engine->newFunction(GetClientVersion));
731 m_engine =
new QScriptEngine;
732 registerFunctions(m_engine);
734 QScriptProgram program (code);
735 const QScriptValue result = m_engine->evaluate(program);
736 if (m_engine->hasUncaughtException() || result.isError())
737 throw Error(m_engine->uncaughtException().toString());
747 QScriptValue func = m_engine->globalObject().property(
QL1S(
"FindProxyForURL"));
749 if (!func.isValid()) {
750 func = m_engine->globalObject().property(
QL1S(
"FindProxyForURLEx"));
751 if (!func.isValid()) {
752 throw Error(
i18n(
"Could not find 'FindProxyForURL' or 'FindProxyForURLEx'"));
757 QScriptValueList args;
761 QScriptValue result = func.call(QScriptValue(), args);
762 if (result.isError()) {
763 throw Error(
i18n(
"Got an invalid reply when calling %1", func.toString()));
766 return result.toString();
QString evaluate(const KUrl &)
QString i18n(const char *text)
QString pattern(Mode mode=Reading)
Returns a list of patterns of all KImageIO supported formats.
void cacheLookup(const QHostInfo &info)
QHostInfo lookupCachedHostInfoFor(const QString &hostName)
QString url(AdjustPathOption trailing=LeaveTrailingSlash) const
Script(const QString &code)