kio Library API Documentation

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
KDE Logo
This file is part of the documentation for kio Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed May 5 07:16:52 2004 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003