# kio Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# script.cpp

    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., 59 Temple Place - Suite 330,
    00017    Boston, MA 02111-1307, USA.
    00018 */
    00019
    00020
    00021 #include <cstdlib>
    00022 #include <vector>
    00023 #include <algorithm>
    00024 #include <ctime>
    00025
    00026 #include <netdb.h>
    00027 #include <sys/types.h>
    00028 #include <netinet/in.h>
    00029 #include <arpa/inet.h>
    00030 #include <unistd.h>
    00031
    00032 #include <qregexp.h>
    00033 #include <qstring.h>
    00034
    00035 #include <kextsock.h>
    00036 #include <ksockaddr.h>
    00037 #include <kurl.h>
    00038 #include <kjs/object.h>
    00039
    00040 #include "script.h"
    00041
    00042 using namespace KJS;
    00043
    00044 QString UString::qstring() const
    00045 {
    00046     return QString( reinterpret_cast< const QChar* >( data() ), size() );
    00047 }
    00048
    00049 UString::UString( const QString &s )
    00050 {
    00051     UChar* data = new UChar[ s.length() ];
    00052     std::memcpy( data, s.unicode(), s.length() * sizeof( UChar ) );
    00053     rep = Rep::create( data, s.length() );
    00054 }
    00055
    00056 namespace
    00057 {
    00058     class Address
    00059     {
    00060     public:
    00061         struct Error {};
    00062         static Address resolve( const UString& host )
    00063             { return Address( host.qstring(), false ); }
    00064         static Address parse( const UString& ip )
    00065             { return Address( ip.qstring(), true ); }
    00066
    00067         operator in_addr_t() const { return m_address.s_addr; }
    00068         operator String() const { return String( inet_ntoa( m_address ) ); }
    00069
    00070     private:
    00071         Address( const QString& host, bool numeric )
    00072         {
    00073             int flags = KExtendedSocket::ipv4Socket;
    00074             if ( numeric ) flags |= KExtendedSocket::noResolve;
    00075             QPtrList< KAddressInfo > addresses =
    00076                 KExtendedSocket::lookup( host, QString::null, flags );
    00077             if ( addresses.isEmpty() ) throw Error();
    00078             addresses.setAutoDelete( true );
    00079             m_address = static_cast< const KInetSocketAddress* >(
    00080                 addresses.first()->address() )->hostV4();
    00081         }
    00082
    00083         in_addr m_address;
    00084     };
    00085
    00086     struct Function : public ObjectImp
    00087     {
    00088         struct ResolveError {};
    00089
    00090         virtual bool implementsCall() const { return true; }
    00091
    00092         static int findString( const UString& s, const char* const* values )
    00093         {
    00094             int index = 0;
    00095             UString lower = s.toLower();
    00096             for ( const char* const* p = values; *p; ++p, ++index )
    00097                 if ( lower == *p ) return index;
    00098             return -1;
    00099         }
    00100
    00101         static const tm* getTime( ExecState* exec, const List& args )
    00102         {
    00103             time_t now = std::time( 0 );
    00104             if ( args[ args.size() - 1 ].toString( exec ).toLower() == "gmt" )
    00105                 return std::gmtime( &now );
    00106             else return std::localtime( &now );
    00107         }
    00108
    00109         Boolean checkRange( int value, int min, int max )
    00110         {
    00111             return ( min <= max && value >= min && value <= max ) ||
    00112                    ( min > max && ( value <= min || value >= max ) );
    00113         }
    00114     };
    00115
    00116     // isPlainHostName( host )
    00117     // @returns true if @p host doesn't contains a domain part
    00118     struct IsPlainHostName : public Function
    00119     {
    00120         virtual Value call( ExecState* exec, Object&, const List& args )
    00121         {
    00122             if ( args.size() != 1 ) return Undefined();
    00123             return Boolean( args[ 0 ].toString( exec ).find( "." ) == -1 );
    00124         }
    00125     };
    00126
    00127     // dnsDomainIs( host, domain )
    00128     // @returns true if the domain part of @p host matches @p domain
    00129     struct DNSDomainIs : public Function
    00130     {
    00131         virtual Value call( ExecState* exec, Object&, const List& args )
    00132         {
    00133             if ( args.size() != 2 ) return Undefined();
    00134             QString host = args[ 0 ].toString( exec ).qstring().lower();
    00135             QString domain = args[ 1 ].toString( exec ).qstring().lower();
    00136             return Boolean( host.endsWith( domain ) );
    00137         }
    00138     };
    00139
    00140     // localHostOrDomainIs( host, fqdn )
    00141     // @returns true if @p host is unqualified or equals @p fqdn
    00142     struct LocalHostOrDomainIs : public Function
    00143     {
    00144         virtual Value call( ExecState* exec, Object&, const List& args )
    00145         {
    00146             if ( args.size() != 2 ) return Undefined();
    00147             UString host = args[ 0 ].toString( exec ).toLower();
    00148             if ( host.find( "." ) == -1 ) return Boolean( true );
    00149             UString fqdn = args[ 1 ].toString( exec ).toLower();
    00150             return Boolean( host == fqdn );
    00151         }
    00152     };
    00153
    00154     // isResolvable( host )
    00155     // @returns true if host can be resolved via DNS
    00156     struct IsResolvable : public Function
    00157     {
    00158         virtual Value call( ExecState* exec, Object&, const List& args )
    00159         {
    00160             if ( args.size() != 1 ) return Undefined();
    00161             try { Address::resolve( args[ 0 ].toString( exec ) ); }
    00162             catch ( const Address::Error& ) { return Boolean( false ); }
    00163             return Boolean( true );
    00164         }
    00165     };
    00166
    00167     // isInNet( host, subnet, mask )
    00168     // @returns true if @p host is within the IP subnet
    00169     //          specified via @p subnet and @p mask
    00170     struct IsInNet : public Function
    00171     {
    00172         virtual Value call( ExecState* exec, Object&, const List& args )
    00173         {
    00174             if ( args.size() != 3 ) return Undefined();
    00175             try
    00176             {
    00177                 in_addr_t host = Address::resolve( args[ 0 ].toString( exec ) );
    00178                 in_addr_t subnet = Address::parse( args[ 1 ].toString( exec ) );
    00179                 in_addr_t mask = Address::parse( args[ 2 ].toString( exec ) );
    00180                 return Boolean( ( host & mask ) == ( subnet & mask ) );
    00181             }
    00182             catch ( const Address::Error& )
    00183             {
    00184                 return Undefined();
    00185             }
    00186         }
    00187     };
    00188
    00189     // dnsResolve( host )
    00190     // @returns the IP address of @p host in dotted quad notation
    00191     struct DNSResolve : public Function
    00192     {
    00193         virtual Value call( ExecState* exec, Object&, const List& args )
    00194         {
    00195             if ( args.size() != 1 ) return Undefined();
    00196             try { return Address::resolve( args[ 0 ].toString( exec ) ); }
    00197             catch ( const Address::Error& ) { return Undefined(); }
    00198         }
    00199     };
    00200
    00201     // myIpAddress()
    00202     // @returns the local machine's IP address in dotted quad notation
    00203     struct MyIpAddress : public Function
    00204     {
    00205         virtual Value call( ExecState*, Object&, const List& args )
    00206         {
    00207             if ( args.size() ) return Undefined();
    00208             char hostname[ 256 ];
    00209             gethostname( hostname, 255 );
    00210             hostname[ 255 ] = 0;
    00211             try { return Address::resolve( hostname ); }
    00212             catch ( const Address::Error& ) { return Undefined(); }
    00213         }
    00214     };
    00215
    00216     // dnsDomainLevels( host )
    00217     // @returns the number of dots ('.') in @p host
    00218     struct DNSDomainLevels : public Function
    00219     {
    00220         virtual Value call( ExecState* exec, Object&, const List& args )
    00221         {
    00222             if ( args.size() != 1 ) return Undefined();
    00223             UString host = args[ 0 ].toString( exec );
    00224             if ( host.isNull() ) return Number( 0 );
    00225             return Number( std::count(
    00226                 host.data(), host.data() + host.size(), '.' ) );
    00227         }
    00228     };
    00229
    00230     // shExpMatch( str, pattern )
    00231     // @returns true if @p str matches the shell @p pattern
    00232     struct ShExpMatch : public Function
    00233     {
    00234         virtual Value call( ExecState* exec, Object&, const List& args )
    00235         {
    00236             if ( args.size() != 2 ) return Undefined();
    00237             QRegExp pattern( args[ 1 ].toString( exec ).qstring(), true, true );
    00238             return Boolean( pattern.exactMatch(args[ 0 ].toString( exec ).qstring()) );
    00239         }
    00240     };
    00241
    00242     // weekdayRange( day [, "GMT" ] )
    00243     // weekdayRange( day1, day2 [, "GMT" ] )
    00244     // @returns true if the current day equals day or between day1 and day2 resp.
    00245     // If the last argument is "GMT", GMT timezone is used, otherwise local time
    00246     struct WeekdayRange : public Function
    00247     {
    00248         virtual Value call( ExecState* exec, Object&, const List& args )
    00249         {
    00250             if ( args.size() < 1 || args.size() > 3 ) return Undefined();
    00251             static const char* const days[] =
    00252                 { "sun", "mon", "tue", "wed", "thu", "fri", "sat", 0 };
    00253             int d1 = findString( args[ 0 ].toString( exec ), days );
    00254             if ( d1 == -1 ) return Undefined();
    00255
    00256             int d2 = findString( args[ 1 ].toString( exec ), days );
    00257             if ( d2 == -1 ) d2 = d1;
    00258             return checkRange( getTime( exec, args )->tm_wday, d1, d2 );
    00259         }
    00260     };
    00261
    00262     // dateRange( day [, "GMT" ] )
    00263     // dateRange( day1, day2 [, "GMT" ] )
    00264     // dateRange( month [, "GMT" ] )
    00265     // dateRange( month1, month2 [, "GMT" ] )
    00266     // dateRange( year [, "GMT" ] )
    00267     // dateRange( year1, year2 [, "GMT" ] )
    00268     // dateRange( day1, month1, day2, month2 [, "GMT" ] )
    00269     // dateRange( month1, year1, month2, year2 [, "GMT" ] )
    00270     // dateRange( day1, month1, year1, day2, month2, year2 [, "GMT" ] )
    00271     // @returns true if the current date (GMT or local time according to
    00272     // presence of "GMT" as last argument) is within the given range
    00273     struct DateRange : public Function
    00274     {
    00275         virtual Value call( ExecState* exec, Object&, const List& args )
    00276         {
    00277             if ( args.size() < 1 || args.size() > 7 ) return Undefined();
    00278             static const char* const months[] =
    00279                 { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "nov", "dec", 0 };
    00280
    00281             std::vector< int > values;
    00282             for ( int i = 0; i < args.size(); ++i )
    00283             {
    00284                 int value = -1;
    00285                 if ( args[ i ].isA( NumberType ) )
    00286                     value = args[ i ].toInteger( exec );
    00287                 else value = findString( args[ i ].toString( exec ), months );
    00288                 if ( value >= 0 ) values.push_back( value );
    00289                 else break;
    00290             }
    00291
    00292             const tm* now = getTime( exec, args );
    00293
    00294             // day1, month1, year1, day2, month2, year2
    00295             if ( values.size() == 6 )
    00296                 return checkRange( ( now->tm_year + 1900 ) * 372 + now->tm_mon * 31 + now->tm_mday,
    00297                                    values[ 2 ] * 372 + values[ 1 ] * 31 + values[ 0 ],
    00298                                    values[ 5 ] * 372 + values[ 4 ] * 31 + values[ 3 ] );
    00299
    00300             // day1, month1, day2, month2
    00301             else if ( values.size() == 4 &&
    00302                       values[ 1 ] < 12 &&
    00303                       values[ 3 ] < 12 )
    00304                 return checkRange( now->tm_mon * 31 + now->tm_mday,
    00305                                    values[ 1 ] * 31 + values[ 0 ],
    00306                                    values[ 3 ] * 31 + values[ 2 ] );
    00307
    00308             // month1, year1, month2, year2
    00309             else if ( values.size() == 4 )
    00310                 return checkRange( ( now->tm_year + 1900 ) * 12 + now->tm_mon,
    00311                                    values[ 1 ] * 12 + values[ 0 ],
    00312                                    values[ 3 ] * 12 + values[ 2 ] );
    00313
    00314             // year1, year2
    00315             else if ( values.size() == 2 &&
    00316                       values[ 0 ] >= 1000 &&
    00317                       values[ 1 ] >= 1000 )
    00318                 return checkRange( now->tm_year + 1900, values[ 0 ], values[ 1 ] );
    00319
    00320             // day1, day2
    00321             else if ( values.size() == 2 &&
    00322                       args[ 0 ].isA( NumberType ) &&
    00323                       args[ 1 ].isA( NumberType ) )
    00324                 return checkRange( now->tm_mday, values[ 0 ], values[ 1 ] );
    00325
    00326             // month1, month2
    00327             else if ( values.size() == 2 )
    00328                 return checkRange( now->tm_mon, values[ 0 ], values[ 1 ] );
    00329
    00330             // year
    00331             else if ( values.size() == 1 && values[ 0 ] >= 1000 )
    00332                 return checkRange( now->tm_year + 1900, values[ 0 ], values[ 0 ] );
    00333
    00334             // day
    00335             else if ( values.size() == 1 && args[ 0 ].isA( NumberType ) )
    00336                 return checkRange( now->tm_mday, values[ 0 ], values[ 0 ] );
    00337
    00338             // month
    00339             else if ( values.size() == 1 )
    00340                 return checkRange( now->tm_mon, values[ 0 ], values[ 0 ] );
    00341
    00342             else return Undefined();
    00343         }
    00344     };
    00345
    00346     // timeRange( hour [, "GMT" ] )
    00347     // timeRange( hour1, hour2 [, "GMT" ] )
    00348     // timeRange( hour1, min1, hour2, min2 [, "GMT" ] )
    00349     // timeRange( hour1, min1, sec1, hour2, min2, sec2 [, "GMT" ] )
    00350     // @returns true if the current time (GMT or local based on presence
    00351     // of "GMT" argument) is within the given range
    00352     struct TimeRange : public Function
    00353     {
    00354         virtual Value call( ExecState* exec, Object&, const List& args )
    00355         {
    00356             if ( args.size() < 1 || args.size() > 7 ) return Undefined();
    00357
    00358             std::vector< int > values;
    00359             for ( int i = 0; i < args.size(); ++i )
    00360                 if ( args[ i ].isA( NumberType ) )
    00361                     values.push_back( args[ i ].toInteger( exec ) );
    00362                 else break;
    00363
    00364             const tm* now = getTime( exec, args );
    00365
    00366             // hour1, min1, sec1, hour2, min2, sec2
    00367             if ( values.size() == 6 )
    00368                 return checkRange( now->tm_hour * 3600 + now->tm_min * 60 + now->tm_sec,
    00369                                    values[ 0 ] * 3600 + values[ 1 ] * 60 + values[ 2 ],
    00370                                    values[ 3 ] * 3600 + values[ 4 ] * 60 + values[ 5 ] );
    00371
    00372             // hour1, min1, hour2, min2
    00373             else if ( values.size() == 4 )
    00374                 return checkRange( now->tm_hour * 60 + now->tm_min,
    00375                                    values[ 0 ] * 60 + values[ 1 ],
    00376                                    values[ 2 ] * 60 + values[ 3 ] );
    00377
    00378             // hour1, hour2
    00379             else if ( values.size() == 2 )
    00380                 return checkRange( now->tm_hour, values[ 0 ], values[ 1 ] );
    00381
    00382             // hour
    00383             else if ( values.size() == 1 )
    00384                 return checkRange( now->tm_hour, values[ 0 ], values[ 0 ] );
    00385
    00386             else return Undefined();
    00387         }
    00388     };
    00389
    00390     void registerFunctions( ExecState* exec, Object& global )
    00391     {
    00392         global.put( exec, "isPlainHostName",
    00393                     Object( new IsPlainHostName ) );
    00394         global.put( exec, "dnsDomainIs",
    00395                     Object( new DNSDomainIs ) );
    00396         global.put( exec, "localHostOrDomainIs",
    00397                     Object( new LocalHostOrDomainIs ) );
    00398         global.put( exec, "isResolvable",
    00399                     Object( new IsResolvable ) );
    00400         global.put( exec, "isInNet",
    00401                     Object( new IsInNet ) );
    00402         global.put( exec, "dnsResolve",
    00403                     Object( new DNSResolve ) );
    00404         global.put( exec, "myIpAddress",
    00405                     Object( new MyIpAddress ) );
    00406         global.put( exec, "dnsDomainLevels",
    00407                     Object( new DNSDomainLevels ) );
    00408         global.put( exec, "shExpMatch",
    00409                     Object( new ShExpMatch ) );
    00410         global.put( exec, "weekdayRange",
    00411                     Object( new WeekdayRange ) );
    00412         global.put( exec, "dateRange",
    00413                     Object( new DateRange ) );
    00414         global.put( exec, "timeRange",
    00415                     Object( new TimeRange ) );
    00416     }
    00417 }
    00418
    00419 namespace KPAC
    00420 {
    00421     Script::Script( const QString& code )
    00422     {
    00423         ExecState* exec = m_interpreter.globalExec();
    00424         Object global = m_interpreter.globalObject();
    00425         registerFunctions( exec, global );
    00426
    00427         Completion result = m_interpreter.evaluate( code );
    00428         if ( result.complType() == Throw )
    00429             throw Error( result.value().toString( exec ).qstring() );
    00430     }
    00431
    00432     QString Script::evaluate( const KURL& url )
    00433     {
    00434     ExecState *exec = m_interpreter.globalExec();
    00435     Value findFunc = m_interpreter.globalObject().get( exec, "FindProxyForURL" );
    00436     Object findObj = Object::dynamicCast( findFunc );
    00437     if (!findObj.isValid() || !findObj.implementsCall())
    00438       throw Error( "No such function FindProxyForURL" );
    00439
    00440     Object thisObj;
    00441     List args;
    00442     args.append(String(url.url()));
    00443     args.append(String(url.host()));
    00444     Value retval = findObj.call( exec, thisObj, args );
    00445
    00446     if ( exec->hadException() ) {
    00447       Value ex = exec->exception();
    00448       exec->clearException();
    00449       throw Error( ex.toString( exec ).qstring() );
    00450     }
    00451
    00452         return retval.toString( exec ).qstring();
    00453     }
    00454 }
    00455
    00456 // vim: ts=4 sw=4 et

This file is part of the documentation for kio Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:24:07 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003