00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "script.h"
00021
00022
00023 #include <cstdlib>
00024 #include <vector>
00025 #include <algorithm>
00026 #include <ctime>
00027 #include <cstring>
00028
00029 #include <netdb.h>
00030 #include <sys/types.h>
00031 #include <netinet/in.h>
00032 #include <arpa/inet.h>
00033 #include <unistd.h>
00034
00035 #include <QtCore/QRegExp>
00036 #include <QtCore/QString>
00037 #include <QtNetwork/QHostAddress>
00038 #include <QtNetwork/QHostInfo>
00039
00040 #include <kurl.h>
00041 #include <kjs/object.h>
00042
00043 using namespace KJS;
00044
00045 QString UString::qstring() const
00046 {
00047 return QString( reinterpret_cast< const QChar* >( data() ), size() );
00048 }
00049
00050 UString::UString( const QString &s )
00051 {
00052 const unsigned int len = s.length();
00053 UChar *data = static_cast<UChar*>( fastMalloc( sizeof(UChar) * len ) );
00054 memcpy( data, s.unicode(), len * sizeof( UChar ) );
00055 m_rep = Rep::create( data, len );
00056 }
00057
00058 namespace
00059 {
00060 class Address
00061 {
00062 public:
00063 struct Error {};
00064 static Address resolve( const UString& host )
00065 { return Address( host.qstring(), false ); }
00066 static Address parse( const UString& ip )
00067 { return Address( ip.qstring(), true ); }
00068
00069 operator QHostAddress() const { return m_address; }
00070 operator UString() const { return UString( m_address.toString() ); }
00071
00072 private:
00073 Address( const QString& host, bool numeric )
00074 {
00075 if ( numeric ) {
00076 m_address = QHostAddress( host );
00077 if ( m_address.isNull() )
00078 throw Error();
00079 } else {
00080 QHostInfo addresses = QHostInfo::fromName(host);
00081 if ( addresses.error() || addresses.addresses().isEmpty() )
00082 throw Error();
00083 m_address = addresses.addresses().at(0);
00084 }
00085 }
00086
00087 QHostAddress m_address;
00088 };
00089
00090 struct Function : public JSObject
00091 {
00092 struct ResolveError {};
00093
00094 virtual bool implementsCall() const { return true; }
00095
00096 static int findString( const UString& s, const char* const* values )
00097 {
00098 int index = 0;
00099 UString lower = s.qstring().toLower();
00100 for ( const char* const* p = values; *p; ++p, ++index )
00101 if ( lower == *p ) return index;
00102 return -1;
00103 }
00104
00105 static const tm* getTime( ExecState* exec, const List& args )
00106 {
00107 time_t now = std::time( 0 );
00108 if ( args[ args.size() - 1 ]->toString( exec ).qstring().toLower() == "gmt" )
00109 return std::gmtime( &now );
00110 else return std::localtime( &now );
00111 }
00112
00113 JSValue *checkRange( double value, double min, double max )
00114 {
00115 return jsBoolean(( min <= max && value >= min && value <= max ) || ( min > max && ( value <= min || value >= max ) ));
00116 }
00117 };
00118
00119
00120
00121 struct IsPlainHostName : public Function
00122 {
00123 virtual JSValue *callAsFunction( ExecState* exec, JSObject*, const List& args )
00124 {
00125 if ( args.size() != 1 ) return jsUndefined();
00126 return jsBoolean( args[ 0 ]->toString( exec ).qstring().indexOf( "." ) == -1 );
00127 }
00128 };
00129
00130
00131
00132 struct DNSDomainIs : public Function
00133 {
00134 virtual JSValue *callAsFunction( ExecState* exec, JSObject*, const List& args )
00135 {
00136 if ( args.size() != 2 ) return jsUndefined();
00137 QString host = args[ 0 ]->toString( exec ).qstring().toLower();
00138 QString domain = args[ 1 ]->toString( exec ).qstring().toLower();
00139 return jsBoolean( host.endsWith( domain ) );
00140 }
00141 };
00142
00143
00144
00145 struct LocalHostOrDomainIs : public Function
00146 {
00147 virtual JSValue *callAsFunction( ExecState* exec, JSObject*, const List& args )
00148 {
00149 if ( args.size() != 2 ) return jsUndefined();
00150 UString host = args[ 0 ]->toString( exec ).qstring().toLower();
00151 if ( host.find( "." ) == -1 ) return jsBoolean( true );
00152 UString fqdn = args[ 1 ]->toString( exec ).qstring().toLower();
00153 return jsBoolean( host == fqdn );
00154 }
00155 };
00156
00157
00158
00159 struct IsResolvable : public Function
00160 {
00161 virtual JSValue *callAsFunction( ExecState* exec, JSObject*, const List& args )
00162 {
00163 if ( args.size() != 1 ) return jsUndefined();
00164 try { Address::resolve( args[ 0 ]->toString( exec ) ); }
00165 catch ( const Address::Error& ) { return jsBoolean( false ); }
00166 return jsBoolean( true );
00167 }
00168 };
00169
00170
00171
00172
00173 struct IsInNet : public Function
00174 {
00175 virtual JSValue *callAsFunction( ExecState* exec, JSObject*, const List& args )
00176 {
00177 if ( args.size() != 3 ) return jsUndefined();
00178 try
00179 {
00180 QHostAddress host = Address::resolve( args[ 0 ]->toString( exec ) );
00181 QHostAddress subnet = Address::parse( args[ 1 ]->toString( exec ) );
00182 QHostAddress mask = Address::parse( args[ 2 ]->toString( exec ) );
00183
00184 return jsBoolean( ( host.toIPv4Address() & mask.toIPv4Address() ) ==
00185 ( subnet.toIPv4Address() & mask.toIPv4Address() ) );
00186 }
00187 catch ( const Address::Error& )
00188 {
00189 return jsUndefined();
00190 }
00191 }
00192 };
00193
00194
00195
00196 struct DNSResolve : public Function
00197 {
00198 virtual JSValue *callAsFunction( ExecState* exec, JSObject*, const List& args )
00199 {
00200 if ( args.size() != 1 ) return jsUndefined();
00201 try { return jsString(Address::resolve( args[ 0 ]->toString( exec ) )); }
00202 catch ( const Address::Error& ) { return jsUndefined(); }
00203 }
00204 };
00205
00206
00207
00208 struct MyIpAddress : public Function
00209 {
00210 virtual JSValue *callAsFunction( ExecState*, JSObject*, const List& args )
00211 {
00212 if ( args.size() ) return jsUndefined();
00213 char hostname[ 256 ];
00214 gethostname( hostname, 255 );
00215 hostname[ 255 ] = 0;
00216 try { return jsString(Address::resolve( hostname )); }
00217 catch ( const Address::Error& ) { return jsUndefined(); }
00218 }
00219 };
00220
00221
00222
00223 struct DNSDomainLevels : public Function
00224 {
00225 virtual JSValue *callAsFunction( ExecState* exec, JSObject*, const List& args )
00226 {
00227 if ( args.size() != 1 ) return jsUndefined();
00228 UString host = args[ 0 ]->toString( exec );
00229 if ( host.isNull() ) return jsNumber( 0 );
00230 #ifdef __SUNPRO_CC
00231
00232
00233
00234
00235 int c = 0;
00236 std::count( host.data(), host.data() + host.size(), '.', c );
00237 return jsNumber(c);
00238 #else
00239 return jsNumber( std::count(
00240 host.data(), host.data() + host.size(), '.' ) );
00241 #endif
00242 }
00243 };
00244
00245
00246
00247 struct ShExpMatch : public Function
00248 {
00249 virtual JSValue *callAsFunction( ExecState* exec, JSObject*, const List& args )
00250 {
00251 if ( args.size() != 2 ) return jsUndefined();
00252 QRegExp pattern( args[ 1 ]->toString( exec ).qstring(), Qt::CaseSensitive, QRegExp::Wildcard );
00253 return jsBoolean( pattern.exactMatch(args[ 0 ]->toString( exec ).qstring()) );
00254 }
00255 };
00256
00257
00258
00259
00260
00261 struct WeekdayRange : public Function
00262 {
00263 virtual JSValue *callAsFunction( ExecState* exec, JSObject*, const List& args )
00264 {
00265 if ( args.size() < 1 || args.size() > 3 ) return jsUndefined();
00266 static const char* const days[] =
00267 { "sun", "mon", "tue", "wed", "thu", "fri", "sat", 0 };
00268 int d1 = findString( args[ 0 ]->toString( exec ), days );
00269 if ( d1 == -1 ) return jsUndefined();
00270
00271 int d2 = findString( args[ 1 ]->toString( exec ), days );
00272 if ( d2 == -1 ) d2 = d1;
00273 return checkRange( getTime( exec, args )->tm_wday, d1, d2 );
00274 }
00275 };
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288 struct DateRange : public Function
00289 {
00290 virtual JSValue *callAsFunction( ExecState* exec, JSObject*, const List& args )
00291 {
00292 if ( args.size() < 1 || args.size() > 7 ) return jsUndefined();
00293 static const char* const months[] =
00294 { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "nov", "dec", 0 };
00295
00296 std::vector< double > values;
00297 for ( int i = 0; i < args.size(); ++i )
00298 {
00299 double value = -1;
00300 if ( args[ i ]->type() == NumberType )
00301 value = args[ i ]->toInteger( exec );
00302 else value = findString( args[ i ]->toString( exec ), months );
00303 if ( value >= 0 ) values.push_back( value );
00304 else break;
00305 }
00306
00307 const tm* now = getTime( exec, args );
00308
00309
00310 if ( values.size() == 6 )
00311 return checkRange( ( now->tm_year + 1900 ) * 372 + now->tm_mon * 31 + now->tm_mday,
00312 values[ 2 ] * 372 + values[ 1 ] * 31 + values[ 0 ],
00313 values[ 5 ] * 372 + values[ 4 ] * 31 + values[ 3 ] );
00314
00315
00316 else if ( values.size() == 4 &&
00317 values[ 1 ] < 12 &&
00318 values[ 3 ] < 12 )
00319 return checkRange( now->tm_mon * 31 + now->tm_mday,
00320 values[ 1 ] * 31 + values[ 0 ],
00321 values[ 3 ] * 31 + values[ 2 ] );
00322
00323
00324 else if ( values.size() == 4 )
00325 return checkRange( ( now->tm_year + 1900 ) * 12 + now->tm_mon,
00326 values[ 1 ] * 12 + values[ 0 ],
00327 values[ 3 ] * 12 + values[ 2 ] );
00328
00329
00330 else if ( values.size() == 2 &&
00331 values[ 0 ] >= 1000 &&
00332 values[ 1 ] >= 1000 )
00333 return checkRange( now->tm_year + 1900, values[ 0 ], values[ 1 ] );
00334
00335
00336 else if ( values.size() == 2 &&
00337 args[ 0 ]->type() == NumberType &&
00338 args[ 1 ]->type() == NumberType )
00339 return checkRange( now->tm_mday, values[ 0 ], values[ 1 ] );
00340
00341
00342 else if ( values.size() == 2 )
00343 return checkRange( now->tm_mon, values[ 0 ], values[ 1 ] );
00344
00345
00346 else if ( values.size() == 1 && values[ 0 ] >= 1000 )
00347 return checkRange( now->tm_year + 1900, values[ 0 ], values[ 0 ] );
00348
00349
00350 else if ( values.size() == 1 && args[ 0 ]->type() == NumberType )
00351 return checkRange( now->tm_mday, values[ 0 ], values[ 0 ] );
00352
00353
00354 else if ( values.size() == 1 )
00355 return checkRange( now->tm_mon, values[ 0 ], values[ 0 ] );
00356
00357 else return jsUndefined();
00358 }
00359 };
00360
00361
00362
00363
00364
00365
00366
00367 struct TimeRange : public Function
00368 {
00369 virtual JSValue *callAsFunction( ExecState* exec, JSObject*, const List& args )
00370 {
00371 if ( args.size() < 1 || args.size() > 7 ) return jsUndefined();
00372
00373 std::vector< double > values;
00374 for ( int i = 0; i < args.size(); ++i )
00375 if ( args[ i ]->type() == NumberType )
00376 values.push_back( args[ i ]->toInteger( exec ) );
00377 else break;
00378
00379 const tm* now = getTime( exec, args );
00380
00381
00382 if ( values.size() == 6 )
00383 return checkRange( now->tm_hour * 3600 + now->tm_min * 60 + now->tm_sec,
00384 values[ 0 ] * 3600 + values[ 1 ] * 60 + values[ 2 ],
00385 values[ 3 ] * 3600 + values[ 4 ] * 60 + values[ 5 ] );
00386
00387
00388 else if ( values.size() == 4 )
00389 return checkRange( now->tm_hour * 60 + now->tm_min,
00390 values[ 0 ] * 60 + values[ 1 ],
00391 values[ 2 ] * 60 + values[ 3 ] );
00392
00393
00394 else if ( values.size() == 2 )
00395 return checkRange( now->tm_hour, values[ 0 ], values[ 1 ] );
00396
00397
00398 else if ( values.size() == 1 )
00399 return checkRange( now->tm_hour, values[ 0 ], values[ 0 ] );
00400
00401 else return jsUndefined();
00402 }
00403 };
00404
00405 void registerFunctions( ExecState* exec, JSObject *global )
00406 {
00407 global->put( exec, "isPlainHostName", new IsPlainHostName );
00408 global->put( exec, "dnsDomainIs", new DNSDomainIs );
00409 global->put( exec, "localHostOrDomainIs", new LocalHostOrDomainIs );
00410 global->put( exec, "isResolvable", new IsResolvable );
00411 global->put( exec, "isInNet", new IsInNet );
00412 global->put( exec, "dnsResolve", new DNSResolve );
00413 global->put( exec, "myIpAddress", new MyIpAddress );
00414 global->put( exec, "dnsDomainLevels", new DNSDomainLevels );
00415 global->put( exec, "shExpMatch", new ShExpMatch );
00416 global->put( exec, "weekdayRange", new WeekdayRange );
00417 global->put( exec, "dateRange", new DateRange );
00418 global->put( exec, "timeRange", new TimeRange );
00419 }
00420 }
00421
00422 namespace KPAC
00423 {
00424 Script::Script( const QString& code )
00425 {
00426 m_interpreter = new KJS::Interpreter();
00427 m_interpreter->ref();
00428 ExecState* exec = m_interpreter->globalExec();
00429 JSObject* global = m_interpreter->globalObject();
00430 registerFunctions( exec, global );
00431
00432 Completion result = m_interpreter->evaluate( "", 0, code );
00433 if ( result.complType() == Throw )
00434 throw Error( result.value()->toString( exec ).qstring() );
00435 }
00436
00437 Script::~Script()
00438 {
00439 m_interpreter->deref();
00440 }
00441
00442 QString Script::evaluate( const KUrl& url )
00443 {
00444 ExecState *exec = m_interpreter->globalExec();
00445 JSValue *findFunc = m_interpreter->globalObject()->get( exec, "FindProxyForURL" );
00446 JSObject *findObj = findFunc->getObject();
00447 if (!findObj || !findObj->implementsCall())
00448 throw Error( "No such function FindProxyForURL" );
00449
00450 List args;
00451 args.append(jsString(url.url()));
00452 args.append(jsString(url.host()));
00453 JSValue *retval = findObj->call( exec, m_interpreter->globalObject(), args );
00454
00455 if ( exec->hadException() ) {
00456 JSValue *ex = exec->exception();
00457 exec->clearException();
00458 throw Error( ex->toString( exec ).qstring() );
00459 }
00460
00461 return retval->toString( exec ).qstring();
00462 }
00463 }
00464
00465