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