• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KIO

script.cpp

Go to the documentation of this file.
00001 /*
00002    Copyright (c) 2003 Malte Starostik <malte@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017    Boston, MA 02110-1301, USA.
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     // isPlainHostName( host )
00121     // @returns true if @p host doesn't contains a domain part
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     // dnsDomainIs( host, domain )
00132     // @returns true if the domain part of @p host matches @p domain
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     // localHostOrDomainIs( host, fqdn )
00145     // @returns true if @p host is unqualified or equals @p fqdn
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     // isResolvable( host )
00159     // @returns true if host can be resolved via DNS
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     // isInNet( host, subnet, mask )
00172     // @returns true if @p host is within the IP subnet
00173     //          specified via @p subnet and @p mask
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     // dnsResolve( host )
00196     // @returns the IP address of @p host in dotted quad notation
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     // myIpAddress()
00208     // @returns the local machine's IP address in dotted quad notation
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     // dnsDomainLevels( host )
00223     // @returns the number of dots ('.') in @p host
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              * Under Solaris, the default STL is the old broken interface 
00234              * to ::count which takes an extra Size& parameter.
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     // shExpMatch( str, pattern )
00247     // @returns true if @p str matches the shell @p pattern
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     // weekdayRange( day [, "GMT" ] )
00259     // weekdayRange( day1, day2 [, "GMT" ] )
00260     // @returns true if the current day equals day or between day1 and day2 resp.
00261     // If the last argument is "GMT", GMT timezone is used, otherwise local time
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     // dateRange( day [, "GMT" ] )
00279     // dateRange( day1, day2 [, "GMT" ] )
00280     // dateRange( month [, "GMT" ] )
00281     // dateRange( month1, month2 [, "GMT" ] )
00282     // dateRange( year [, "GMT" ] )
00283     // dateRange( year1, year2 [, "GMT" ] )
00284     // dateRange( day1, month1, day2, month2 [, "GMT" ] )
00285     // dateRange( month1, year1, month2, year2 [, "GMT" ] )
00286     // dateRange( day1, month1, year1, day2, month2, year2 [, "GMT" ] )
00287     // @returns true if the current date (GMT or local time according to
00288     // presence of "GMT" as last argument) is within the given range
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             // day1, month1, year1, day2, month2, year2
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             // day1, month1, day2, month2
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             // month1, year1, month2, year2
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             // year1, year2
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             // day1, day2
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             // month1, month2
00343             else if ( values.size() == 2 )
00344                 return checkRange( now->tm_mon, values[ 0 ], values[ 1 ] );
00345 
00346             // year
00347             else if ( values.size() == 1 && values[ 0 ] >= 1000 )
00348                 return checkRange( now->tm_year + 1900, values[ 0 ], values[ 0 ] );
00349 
00350             // day
00351             else if ( values.size() == 1 && args[ 0 ]->type() == NumberType )
00352                 return checkRange( now->tm_mday, values[ 0 ], values[ 0 ] );
00353 
00354             // month
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     // timeRange( hour [, "GMT" ] )
00363     // timeRange( hour1, hour2 [, "GMT" ] )
00364     // timeRange( hour1, min1, hour2, min2 [, "GMT" ] )
00365     // timeRange( hour1, min1, sec1, hour2, min2, sec2 [, "GMT" ] )
00366     // @returns true if the current time (GMT or local based on presence
00367     // of "GMT" argument) is within the given range
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             // hour1, min1, sec1, hour2, min2, sec2
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             // hour1, min1, hour2, min2
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             // hour1, hour2
00395             else if ( values.size() == 2 )
00396                 return checkRange( now->tm_hour, values[ 0 ], values[ 1 ] );
00397 
00398             // hour
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 // vim: ts=4 sw=4 et

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal