From ce4a32fe52ef09d8f5ff1dd22c001110902b60a2 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- dcop/client/Makefile.am | 28 ++ dcop/client/README.dcop | 78 ++++ dcop/client/dcop.cpp | 924 ++++++++++++++++++++++++++++++++++++++++++++++ dcop/client/dcopclient.c | 59 +++ dcop/client/dcopfind.cpp | 282 ++++++++++++++ dcop/client/dcopobject.c | 59 +++ dcop/client/dcopquit.cpp | 2 + dcop/client/dcopref.c | 40 ++ dcop/client/dcopstart.cpp | 99 +++++ dcop/client/marshall.cpp | 399 ++++++++++++++++++++ 10 files changed, 1970 insertions(+) create mode 100644 dcop/client/Makefile.am create mode 100644 dcop/client/README.dcop create mode 100644 dcop/client/dcop.cpp create mode 100644 dcop/client/dcopclient.c create mode 100644 dcop/client/dcopfind.cpp create mode 100644 dcop/client/dcopobject.c create mode 100644 dcop/client/dcopquit.cpp create mode 100644 dcop/client/dcopref.c create mode 100644 dcop/client/dcopstart.cpp create mode 100644 dcop/client/marshall.cpp (limited to 'dcop/client') diff --git a/dcop/client/Makefile.am b/dcop/client/Makefile.am new file mode 100644 index 000000000..bae7ddd26 --- /dev/null +++ b/dcop/client/Makefile.am @@ -0,0 +1,28 @@ + +INCLUDES = $(all_includes) +AM_LDFLAGS = $(all_libraries) +DCOP_LIB = ../libDCOP.la + +####### Files + +bin_PROGRAMS = dcop dcopfind dcopclient dcopobject dcopref dcopstart dcopquit + +dcop_SOURCES = dcop.cpp +dcop_LDADD = $(LIB_QT) $(DCOP_LIB) +dcop_LDFLAGS = $(KDE_RPATH) + +dcopstart_SOURCES = dcopstart.cpp +dcopstart_LDADD = $(LIB_QT) $(DCOP_LIB) +dcopstart_LDFLAGS = $(KDE_RPATH) + +dcopquit_SOURCES = dcopquit.cpp +dcopquit_LDADD = $(LIB_QT) $(DCOP_LIB) +dcopquit_LDFLAGS = $(KDE_RPATH) + +dcopfind_SOURCES = dcopfind.cpp +dcopfind_LDADD = $(LIB_QT) $(DCOP_LIB) +dcopfind_LDFLAGS = $(KDE_RPATH) + +dcopclient_SOURCES = dcopclient.c +dcopobject_SOURCES = dcopobject.c +dcopref_SOURCES = dcopref.c diff --git a/dcop/client/README.dcop b/dcop/client/README.dcop new file mode 100644 index 000000000..e352cb439 --- /dev/null +++ b/dcop/client/README.dcop @@ -0,0 +1,78 @@ +Overview of dcop command line utilities + +dcop [ [ [ [args]]]] + +Make a dcop call to the specified function. +If no function is specified, a list of available functions is listed. +If no object is specified, a list of available objects is listed. +If no app-id is specified, a list of available application-ids is listed. + +**** +* As of KDE 3.0: You will NO LONGER be able to use "dcop konqueror" to +* communicate with e.g. "konqueror-4783". You will have to use "dcop +* konqueror-4783" for that (or the DCOPRef notation, see below) +**** + +dcopstart + +Starts and returns the on stdout that can be used for the +other commands. E.g. "dcopstart kedit" might return "kedit-29322". An +exit-code of '0' means success. An exit-code of '1' means error, the error +msg is printed to stderr and no data is printed to stdout. + + +dcopfind [-l] [-a] [ [ [args]]] + +Finds an existing DCOP application/object. The select_func can be used to +select a specific single instance out of many based on some criteria. + and may end with a '*' as wildcard. + +The function returns a to stdout in the form + + "DCOPRef(, )" + +if an object is found and returns an exit-code of '0'. +If no object is found, nothing is written to stdout and the exit-code is '1'. + +With the -a option it prints out "" instead of a DCOPRef. + +With the -l option it calls "dcopstart " if no object is found, +stripping off any wildcard from the . If the dcopstart command is +successful the find command is repeated, if the dcopstart command fails, an +error message is printed to stderr and the command exits with exit-code '2'. + +The default selection criteria is "any". Applications can declare their own +select_func as they see fit, e.g. konqueror could declare +"isDoingProtocol(QString protocol)" and then the following command would +select a konqueror mainwindow that is currently handling the help-protocol: + + "dcopfind 'konqueror*' 'konqueror-mainwindow*' 'isDoingProtocol(QString +protocol)' help" + + +dcop args + +In addtion to the current syntax of + + dcop args + +you will now also be able to use to make calls with being +"DCOPRef(, )" as returned by dcopfind. + +Additional utilities: + + "dcopref " + +Creates a DCOPRef from appid and object. + + + "dcopclient " + +Extracts the appid from dcopref. + + + "dcopobject " + +Extracts the object from dcopref. + + diff --git a/dcop/client/dcop.cpp b/dcop/client/dcop.cpp new file mode 100644 index 000000000..e8fd7683a --- /dev/null +++ b/dcop/client/dcop.cpp @@ -0,0 +1,924 @@ +/***************************************************************** +Copyright (c) 2000 Matthias Ettrich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +// putenv() is not available on all platforms, so make sure the emulation +// wrapper is available in those cases by loading config.h! +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../dcopclient.h" +#include "../dcopref.h" +#include "../kdatastream.h" + +#include "marshall.cpp" + +#if defined Q_WS_X11 +#include +#include +#endif + +typedef QMap UserList; + +static DCOPClient* dcop = 0; + +static QTextStream cin_ ( stdin, IO_ReadOnly ); +static QTextStream cout_( stdout, IO_WriteOnly ); +static QTextStream cerr_( stderr, IO_WriteOnly ); + +/** + * Session to send call to + * DefaultSession - current session. Current KDE session when called without + * --user or --all-users option. Otherwise this value ignores + * all users with more than one active session. + * AllSessions - Send to all sessions found. requires --user or --all-users. + * QuerySessions - Don't call DCOP, return a list of available sessions. + * CustomSession - Use the specified session + */ +enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession }; + +bool startsWith(const QCString &id, const char *str, int n) +{ + return !n || (strncmp(id.data(), str, n) == 0); +} + +bool endsWith(QCString &id, char c) +{ + if (id.length() && (id[id.length()-1] == c)) + { + id.truncate(id.length()-1); + return true; + } + return false; +} + +void queryApplications(const QCString &filter) +{ + int filterLen = filter.length(); + QCStringList apps = dcop->registeredApplications(); + for ( QCStringList::Iterator it = apps.begin(); it != apps.end(); ++it ) + { + QCString &clientId = *it; + if ( (clientId != dcop->appId()) && + !startsWith(clientId, "anonymous",9) && + startsWith(clientId, filter, filterLen) + ) + printf( "%s\n", clientId.data() ); + } + + if ( !dcop->isAttached() ) + { + qWarning( "server not accessible" ); + exit(1); + } +} + +void queryObjects( const QCString &app, const QCString &filter ) +{ + int filterLen = filter.length(); + bool ok = false; + bool isDefault = false; + QCStringList objs = dcop->remoteObjects( app, &ok ); + for ( QCStringList::Iterator it = objs.begin(); it != objs.end(); ++it ) + { + QCString &objId = *it; + + if (objId == "default") + { + isDefault = true; + continue; + } + + if (startsWith(objId, filter, filterLen)) + { + if (isDefault) + printf( "%s (default)\n", objId.data() ); + else + printf( "%s\n", objId.data() ); + } + isDefault = false; + } + if ( !ok ) + { + if (!dcop->isApplicationRegistered(app)) + qWarning( "No such application: '%s'", app.data()); + else + qWarning( "Application '%s' not accessible", app.data() ); + exit(1); + } +} + +void queryFunctions( const char* app, const char* obj ) +{ + bool ok = false; + QCStringList funcs = dcop->remoteFunctions( app, obj, &ok ); + for ( QCStringList::Iterator it = funcs.begin(); it != funcs.end(); ++it ) { + printf( "%s\n", (*it).data() ); + } + if ( !ok ) + { + qWarning( "object '%s' in application '%s' not accessible", obj, app ); + exit( 1 ); + } +} + +int callFunction( const char* app, const char* obj, const char* func, const QCStringList args ) +{ + QString f = func; // Qt is better with unicode strings, so use one. + int left = f.find( '(' ); + int right = f.find( ')' ); + + if ( right < left ) + { + qWarning( "parentheses do not match" ); + return( 1 ); + } + + if ( left < 0 ) { + // try to get the interface from the server + bool ok = false; + QCStringList funcs = dcop->remoteFunctions( app, obj, &ok ); + QCString realfunc; + if ( !ok && args.isEmpty() ) + goto doit; + if ( !ok ) + { + qWarning( "object not accessible" ); + return( 1 ); + } + for ( QCStringList::Iterator it = funcs.begin(); it != funcs.end(); ++it ) { + int l = (*it).find( '(' ); + int s; + if (l > 0) + s = (*it).findRev( ' ', l); + else + s = (*it).find( ' ' ); + + if ( s < 0 ) + s = 0; + else + s++; + + if ( l > 0 && (*it).mid( s, l - s ) == func ) { + realfunc = (*it).mid( s ); + const QString arguments = (*it).mid(l+1,(*it).find( ')' )-l-1); + uint a = arguments.contains(','); + if ( (a==0 && !arguments.isEmpty()) || a>0) + a++; + if ( a == args.count() ) + break; + } + } + if ( realfunc.isEmpty() ) + { + qWarning("no such function"); + return( 1 ); + } + f = realfunc; + left = f.find( '(' ); + right = f.find( ')' ); + } + + doit: + if ( left < 0 ) + f += "()"; + + // This may seem expensive but is done only once per invocation + // of dcop, so it should be OK. + // + // + QStringList intTypes; + intTypes << "int" << "unsigned" << "long" << "bool" ; + + QStringList types; + if ( left >0 && left + 1 < right - 1) { + types = QStringList::split( ',', f.mid( left + 1, right - left - 1) ); + for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) { + QString lt = (*it).simplifyWhiteSpace(); + + int s = lt.find(' '); + + // If there are spaces in the name, there may be two + // reasons: the parameter name is still there, ie. + // "QString URL" or it's a complicated int type, ie. + // "unsigned long long int bool". + // + // + if ( s > 0 ) + { + QStringList partl = QStringList::split(' ' , lt); + + // The zero'th part is -- at the very least -- a + // type part. Any trailing parts *might* be extra + // int-type keywords, or at most one may be the + // parameter name. + // + // + s=1; + + while (s < static_cast(partl.count()) && intTypes.contains(partl[s])) + { + s++; + } + + if ( s < static_cast(partl.count())-1) + { + qWarning("The argument `%s' seems syntactically wrong.", + lt.latin1()); + } + if ( s == static_cast(partl.count())-1) + { + partl.remove(partl.at(s)); + } + + lt = partl.join(" "); + lt = lt.simplifyWhiteSpace(); + } + + (*it) = lt; + } + QString fc = f.left( left ); + fc += '('; + bool first = true; + for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) { + if ( !first ) + fc +=","; + first = false; + fc += *it; + } + fc += ')'; + f = fc; + } + + QByteArray data, replyData; + QCString replyType; + QDataStream arg(data, IO_WriteOnly); + + uint i = 0; + for( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) + marshall( arg, args, i, *it ); + + if ( i != args.count() ) + { + qWarning( "arguments do not match" ); + return( 1 ); + } + + if ( !dcop->call( app, obj, f.latin1(), data, replyType, replyData) ) { + qWarning( "call failed"); + return( 1 ); + } else { + QDataStream reply(replyData, IO_ReadOnly); + + if ( replyType != "void" && replyType != "ASYNC" ) + { + QCString replyString = demarshal( reply, replyType ); + if ( !replyString.isEmpty() ) + printf( "%s\n", replyString.data() ); + else + printf("\n"); + } + } + return 0; +} + +/** + * Show command-line help and exit + */ +void showHelp( int exitCode = 0 ) +{ +#ifdef DCOPQUIT + cout_ << "Usage: dcopquit [options] [application]" << endl +#else + cout_ << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl +#endif + << "" << endl + << "Console DCOP client" << endl + << "" << endl + << "Generic options:" << endl + << " --help Show help about options" << endl + << "" << endl + << "Options:" << endl + << " --pipe Call DCOP for each line read from stdin. The string '%1'" << endl + << " will be used in the argument list as a placeholder for" << endl + << " the substituted line." << endl + << " For example," << endl + << " dcop --pipe konqueror html-widget1 evalJS %1" << endl + << " is equivalent to calling" << endl + << " while read line ; do" << endl + << " dcop konqueror html-widget1 evalJS \"$line\"" << endl + << " done" << endl + << " in bash, but because no new dcop instance has to be started" << endl + << " for each line this is generally much faster, especially for" << endl + << " the slower GNU dynamic linkers." << endl + << " The '%1' placeholder cannot be used to replace e.g. the" << endl + << " program, object or method name." << endl + << " --user Connect to the given user's DCOP server. This option will" << endl + << " ignore the values of the environment vars $DCOPSERVER and" << endl + << " $ICEAUTHORITY, even if they are set." << endl + << " If the user has more than one open session, you must also" << endl + << " use one of the --list-sessions, --session or --all-sessions" << endl + << " command-line options." << endl + << " --all-users Send the same DCOP call to all users with a running DCOP" << endl + << " server. Only failed calls to existing DCOP servers will" << endl + << " generate an error message. If no DCOP server is available" << endl + << " at all, no error will be generated." << endl + << " --session Send to the given KDE session. This option can only be" << endl + << " used in combination with the --user option." << endl + << " --all-sessions Send to all sessions found. Only works with the --user" << endl + << " and --all-users options." << endl + << " --list-sessions List all active KDE session for a user or all users." << endl + << " --no-user-time Don't update the user activity timestamp in the called" << endl + << " application (for usage in scripts running" << endl + << " in the background)." << endl + << endl; + + exit( exitCode ); +} + +/** + * Return a list of all users and their home directories. + * Returns an empty list if /etc/passwd cannot be read for some reason. + */ +static UserList userList() +{ + UserList result; + + while( passwd* pstruct = getpwent() ) + { + result[ QString::fromLocal8Bit(pstruct->pw_name) ] = QFile::decodeName(pstruct->pw_dir); + } + + return result; +} + +/** + * Return a list of available DCOP sessions for the specified user + * An empty list means no sessions are available, or an error occurred. + */ +QStringList dcopSessionList( const QString &user, const QString &home ) +{ + if( home.isEmpty() ) + { + cerr_ << "WARNING: Cannot determine home directory for user " + << user << "!" << endl + << "Please check permissions or set the $DCOPSERVER variable manually before" << endl + << "calling dcop." << endl; + return QStringList(); + } + + QStringList result; + QFileInfo dirInfo( home ); + if( !dirInfo.exists() || !dirInfo.isReadable() ) + return result; + + QDir d( home ); + d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks ); + d.setNameFilter( ".DCOPserver*" ); + + const QFileInfoList *list = d.entryInfoList(); + if( !list ) + return result; + + QFileInfoListIterator it( *list ); + QFileInfo *fi; + + while ( ( fi = it.current() ) != 0 ) + { + if( fi->isReadable() ) + result.append( fi->fileName() ); + ++it; + } + return result; +} + +void sendUserTime( const char* app ) +{ +#if defined Q_WS_X11 + static unsigned long time = 0; + if( time == 0 ) + { + Display* dpy = XOpenDisplay( NULL ); + if( dpy != NULL ) + { + Window w = XCreateSimpleWindow( dpy, DefaultRootWindow( dpy ), 0, 0, 1, 1, 0, 0, 0 ); + XSelectInput( dpy, w, PropertyChangeMask ); + unsigned char data[ 1 ]; + XChangeProperty( dpy, w, XA_ATOM, XA_ATOM, 8, PropModeAppend, data, 1 ); + XEvent ev; + XWindowEvent( dpy, w, PropertyChangeMask, &ev ); + time = ev.xproperty.time; + XDestroyWindow( dpy, w ); + } + } + DCOPRef( app, "MainApplication-Interface" ).call( "updateUserTimestamp", time ); +#else +// ... +#endif +} + +/** + * Do the actual DCOP call + */ +int runDCOP( QCStringList args, UserList users, Session session, + const QString sessionName, bool readStdin, bool updateUserTime ) +{ + bool DCOPrefmode=false; + QCString app; + QCString objid; + QCString function; + QCStringList params; + DCOPClient *client = 0L; + int retval = 0; + if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 ) + { + int delimPos = args[ 0 ].findRev( ',' ); + if( delimPos == -1 ) + { + cerr_ << "Error: '" << args[ 0 ] + << "' is not a valid DCOP reference." << endl; + exit( -1 ); + } + app = args[ 0 ].mid( 8, delimPos-8 ); + delimPos++; + objid = args[ 0 ].mid( delimPos, args[ 0 ].length()-delimPos-1 ); + if( args.count() > 1 ) + function = args[ 1 ]; + if( args.count() > 2 ) + { + params = args; + params.remove( params.begin() ); + params.remove( params.begin() ); + } + DCOPrefmode=true; + } + else + { + if( !args.isEmpty() ) + app = args[ 0 ]; + if( args.count() > 1 ) + objid = args[ 1 ]; + if( args.count() > 2 ) + function = args[ 2 ]; + if( args.count() > 3) + { + params = args; + params.remove( params.begin() ); + params.remove( params.begin() ); + params.remove( params.begin() ); + } + } + + bool firstRun = true; + UserList::Iterator it; + QStringList sessions; + bool presetDCOPServer = false; +// char *dcopStr = 0L; + QString dcopServer; + + for( it = users.begin(); it != users.end() || firstRun; ++it ) + { + firstRun = false; + + //cout_ << "Iterating '" << it.key() << "'" << endl; + + if( session == QuerySessions ) + { + QStringList sessions = dcopSessionList( it.key(), it.data() ); + if( sessions.isEmpty() ) + { + if( users.count() <= 1 ) + { + cout_ << "No active sessions"; + if( !( *it ).isEmpty() ) + cout_ << " for user " << *it; + cout_ << endl; + } + } + else + { + cout_ << "Active sessions "; + if( !( *it ).isEmpty() ) + cout_ << "for user " << *it << " "; + cout_ << ":" << endl; + + QStringList::Iterator sIt = sessions.begin(); + for( ; sIt != sessions.end(); ++sIt ) + cout_ << " " << *sIt << endl; + + cout_ << endl; + } + continue; + } + + if( getenv( "DCOPSERVER" ) ) + { + sessions.append( getenv( "DCOPSERVER" ) ); + presetDCOPServer = true; + } + + if( users.count() > 1 || ( users.count() == 1 && + ( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) ) + { + sessions = dcopSessionList( it.key(), it.data() ); + if( sessions.isEmpty() ) + { + if( users.count() > 1 ) + continue; + else + { + cerr_ << "ERROR: No active KDE sessions!" << endl + << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl + << "before calling dcop." << endl; + exit( -1 ); + } + } + else if( !sessionName.isEmpty() ) + { + if( sessions.contains( sessionName ) ) + { + sessions.clear(); + sessions.append( sessionName ); + } + else + { + cerr_ << "ERROR: The specified session doesn't exist!" << endl; + exit( -1 ); + } + } + else if( sessions.count() > 1 && session != AllSessions ) + { + cerr_ << "ERROR: Multiple available KDE sessions!" << endl + << "Please specify the correct session to use with --session or use the" << endl + << "--all-sessions option to broadcast to all sessions." << endl; + exit( -1 ); + } + } + + if( users.count() > 1 || ( users.count() == 1 && + ( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) ) + { + // Check for ICE authority file and if the file can be read by us + QString home = it.data(); + QString iceFile = it.data() + "/.ICEauthority"; + QFileInfo fi( iceFile ); + if( iceFile.isEmpty() ) + { + cerr_ << "WARNING: Cannot determine home directory for user " + << it.key() << "!" << endl + << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl + << "calling dcop." << endl; + } + else if( fi.exists() ) + { + if( fi.isReadable() ) + { + char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() ); + putenv( envStr ); + //cerr_ << "ice: " << envStr << endl; + } + else + { + cerr_ << "WARNING: ICE authority file " << iceFile + << "is not readable by you!" << endl + << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl + << "calling dcop." << endl; + } + } + else + { + if( users.count() > 1 ) + continue; + else + { + cerr_ << "WARNING: Cannot find ICE authority file " + << iceFile << "!" << endl + << "Please check permissions or set the $ICEAUTHORITY" + << " variable manually before" << endl + << "calling dcop." << endl; + } + } + } + + // Main loop + // If users is an empty list we're calling for the currently logged + // in user. In this case we don't have a session, but still want + // to iterate the loop once. + QStringList::Iterator sIt = sessions.begin(); + for( ; sIt != sessions.end() || users.isEmpty(); ++sIt ) + { + if( !presetDCOPServer && !users.isEmpty() ) + { + QString dcopFile = it.data() + "/" + *sIt; + QFile f( dcopFile ); + if( !f.open( IO_ReadOnly ) ) + { + cerr_ << "Can't open " << dcopFile << " for reading!" << endl; + exit( -1 ); + } + + QStringList l( QStringList::split( '\n', f.readAll() ) ); + dcopServer = l.first(); + + if( dcopServer.isEmpty() ) + { + cerr_ << "WARNING: Unable to determine DCOP server for session " + << *sIt << "!" << endl + << "Please check permissions or set the $DCOPSERVER variable manually before" << endl + << "calling dcop." << endl; + exit( -1 ); + } + } + + delete client; + client = new DCOPClient; + if( !dcopServer.isEmpty() ) + client->setServerAddress( dcopServer.ascii() ); + bool success = client->attach(); + if( !success ) + { + cerr_ << "ERROR: Couldn't attach to DCOP server!" << endl; + retval = QMAX( retval, 1 ); + if( users.isEmpty() ) + break; + else + continue; + } + dcop = client; + + int argscount = args.count(); + if ( DCOPrefmode ) + argscount++; + switch ( argscount ) + { + case 0: + queryApplications(""); + break; + case 1: + if (endsWith(app, '*')) + queryApplications(app); + else + queryObjects( app, "" ); + break; + case 2: + if (endsWith(objid, '*')) + queryObjects(app, objid); + else + queryFunctions( app, objid ); + break; + case 3: + default: + if( updateUserTime ) + sendUserTime( app ); + if( readStdin ) + { + QCStringList::Iterator replaceArg = params.end(); + + QCStringList::Iterator it = params.begin(); + for( ; it != params.end(); ++it ) + if( *it == "%1" ) + replaceArg = it; + + // Read from stdin until EOF and call function for each + // read line + while ( !cin_.atEnd() ) + { + QString buf = cin_.readLine(); + + if( replaceArg != params.end() ) + *replaceArg = buf.local8Bit(); + + if( !buf.isNull() ) + { + int res = callFunction( app, objid, function, params ); + retval = QMAX( retval, res ); + } + } + } + else + { + // Just call function +// cout_ << "call " << app << ", " << objid << ", " << function << ", (params)" << endl; + int res = callFunction( app, objid, function, params ); + retval = QMAX( retval, res ); + } + break; + } + // Another sIt++ would make the loop infinite... + if( users.isEmpty() ) + break; + } + + // Another it++ would make the loop infinite... + if( it == users.end() ) + break; + } + + return retval; +} + +#ifdef Q_OS_WIN +# define main kdemain +#endif + +int main( int argc, char** argv ) +{ + bool readStdin = false; + int numOptions = 0; + QString user; + Session session = DefaultSession; + QString sessionName; + bool updateUserTime = true; + + cin_.setEncoding( QTextStream::Locale ); + + // Scan for command-line options first + for( int pos = 1 ; pos <= argc - 1 ; pos++ ) + { + if( strcmp( argv[ pos ], "--help" ) == 0 ) + showHelp( 0 ); + else if( strcmp( argv[ pos ], "--pipe" ) == 0 ) + { + readStdin = true; + numOptions++; + } + else if( strcmp( argv[ pos ], "--user" ) == 0 ) + { + if( pos <= argc - 2 ) + { + user = QString::fromLocal8Bit( argv[ pos + 1] ); + numOptions +=2; + pos++; + } + else + { + cerr_ << "Missing username for '--user' option!" << endl << endl; + showHelp( -1 ); + } + } + else if( strcmp( argv[ pos ], "--session" ) == 0 ) + { + if( session == AllSessions ) + { + cerr_ << "ERROR: --session cannot be mixed with --all-sessions!" << endl << endl; + showHelp( -1 ); + } + else if( pos <= argc - 2 ) + { + sessionName = QString::fromLocal8Bit( argv[ pos + 1] ); + numOptions +=2; + pos++; + } + else + { + cerr_ << "Missing session name for '--session' option!" << endl << endl; + showHelp( -1 ); + } + } + else if( strcmp( argv[ pos ], "--all-users" ) == 0 ) + { + user = "*"; + numOptions ++; + } + else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 ) + { + session = QuerySessions; + numOptions ++; + } + else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 ) + { + if( !sessionName.isEmpty() ) + { + cerr_ << "ERROR: --session cannot be mixed with --all-sessions!" << endl << endl; + showHelp( -1 ); + } + session = AllSessions; + numOptions ++; + } + else if( strcmp( argv[ pos ], "--no-user-time" ) == 0 ) + { + updateUserTime = false; + numOptions ++; + } + else if( argv[ pos ][ 0 ] == '-' ) + { + cerr_ << "Unknown command-line option '" << argv[ pos ] + << "'." << endl << endl; + showHelp( -1 ); + } + else + break; // End of options + } + + argc -= numOptions; + + QCStringList args; + +#ifdef DCOPQUIT + if (argc > 1) + { + QCString prog = argv[ numOptions + 1 ]; + + if (!prog.isEmpty()) + { + args.append( prog ); + + // Pass as-is if it ends with a wildcard + if (prog[prog.length()-1] != '*') + { + // Strip a trailing - part. + int i = prog.findRev('-'); + if ((i >= 0) && prog.mid(i+1).toLong()) + { + prog = prog.left(i); + } + args.append( "qt/"+prog ); + args.append( "quit()" ); + } + } + } +#else + for( int i = numOptions; i < argc + numOptions - 1; i++ ) + args.append( argv[ i + 1 ] ); +#endif + + if( readStdin && args.count() < 3 ) + { + cerr_ << "--pipe option only supported for function calls!" << endl << endl; + showHelp( -1 ); + } + + if( user == "*" && args.count() < 3 && session != QuerySessions ) + { + cerr_ << "ERROR: The --all-users option is only supported for function calls!" << endl << endl; + showHelp( -1 ); + } + + if( session == QuerySessions && !args.isEmpty() ) + { + cerr_ << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl; + showHelp( -1 ); + } + + if( session == QuerySessions && user.isEmpty() ) + { + cerr_ << "ERROR: The --list-sessions option can only be used with the --user or" << endl + << "--all-users options!" << endl << endl; + showHelp( -1 ); + } + + if( session != DefaultSession && session != QuerySessions && + args.count() < 3 ) + { + cerr_ << "ERROR: The --session and --all-sessions options are only supported for function" << endl + << "calls!" << endl << endl; + showHelp( -1 ); + } + + UserList users; + if( user == "*" ) + users = userList(); + else if( !user.isEmpty() ) + users[ user ] = userList()[ user ]; + + int retval = runDCOP( args, users, session, sessionName, readStdin, updateUserTime ); + + return retval; +} + +// vim: set ts=8 sts=4 sw=4 noet: + diff --git a/dcop/client/dcopclient.c b/dcop/client/dcopclient.c new file mode 100644 index 000000000..0ca67d465 --- /dev/null +++ b/dcop/client/dcopclient.c @@ -0,0 +1,59 @@ +/* vi: set ts=2 sw=2 tw=78: + + Extracts the dcopclient form a DCOPRef + + Copyright 2001 Waldo Bastian + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + const char *dcopref; + char *delim; + if ((argc != 2) || (argv[1][0] == '-')) + { + fprintf(stderr, "Usage: dcopclient \n"); + return 1; + } + dcopref = argv[1]; + if (strncmp(dcopref, "DCOPRef(", 8) != 0) + goto bad_ref; + + if (dcopref[strlen(dcopref)-1] != ')') + goto bad_ref; + + delim = strchr(dcopref, ','); + if (!delim) + goto bad_ref; + + dcopref += 8; + *delim = 0; + puts(dcopref); + return 0; + +bad_ref: + fprintf(stderr, "Error: '%s' is not a valid DCOP reference.\n", dcopref); + return 1; +} diff --git a/dcop/client/dcopfind.cpp b/dcop/client/dcopfind.cpp new file mode 100644 index 000000000..4f69f848f --- /dev/null +++ b/dcop/client/dcopfind.cpp @@ -0,0 +1,282 @@ +/***************************************************************** +Copyright (c) 2000 Matthias Ettrich +Copyright (c) 2001 Waldo Bastian + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include +#include +#include +#include +#include "../kdatastream.h" +#include "../dcopclient.h" +#include "../dcopref.h" +#include +#include +#include + +#include "marshall.cpp" + +static DCOPClient* dcop = 0; +static bool bAppIdOnly = 0; +static bool bLaunchApp = 0; + +bool findObject( const char* app, const char* obj, const char* func, QCStringList args ) +{ + QString f = func; // Qt is better with unicode strings, so use one. + int left = f.find( '(' ); + int right = f.find( ')' ); + + if ( right < left ) + { + qWarning( "parentheses do not match" ); + exit(1); + } + + if ( !f.isEmpty() && (left < 0) ) + f += "()"; + + // This may seem expensive but is done only once per invocation + // of dcop, so it should be OK. + // + // + QStringList intTypes; + intTypes << "int" << "unsigned" << "long" << "bool" ; + + QStringList types; + if ( left >0 && left + 1 < right - 1) { + types = QStringList::split( ',', f.mid( left + 1, right - left - 1) ); + for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) { + QString lt = (*it).simplifyWhiteSpace(); + + int s = lt.find(' '); + + // If there are spaces in the name, there may be two + // reasons: the parameter name is still there, ie. + // "QString URL" or it's a complicated int type, ie. + // "unsigned long long int bool". + // + // + if ( s > 0 ) + { + QStringList partl = QStringList::split(' ' , lt); + + // The zero'th part is -- at the very least -- a + // type part. Any trailing parts *might* be extra + // int-type keywords, or at most one may be the + // parameter name. + // + // + s=1; + + while (s < (int)partl.count() && intTypes.contains(partl[s])) + { + s++; + } + + if (s<(int)partl.count()-1) + { + qWarning("The argument `%s' seems syntactically wrong.", + lt.latin1()); + } + if (s==(int)partl.count()-1) + { + partl.remove(partl.at(s)); + } + + lt = partl.join(" "); + lt = lt.simplifyWhiteSpace(); + } + + (*it) = lt; + } + QString fc = f.left( left ); + fc += '('; + bool first = true; + for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) { + if ( !first ) + fc +=","; + first = false; + fc += *it; + } + fc += ')'; + f = fc; + } + + if ( types.count() != args.count() ) { + qWarning( "arguments do not match" ); + exit(1); + } + + QByteArray data; + QDataStream arg(data, IO_WriteOnly); + + uint i = 0; + for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) { + marshall(arg, args, i, *it); + } + if ( (uint) i != args.count() ) { + qWarning( "arguments do not match" ); + exit(1); + } + + QCString foundApp; + QCString foundObj; + if ( dcop->findObject( app, obj, f.latin1(), data, foundApp, foundObj) ) + { + if (bAppIdOnly) + puts(foundApp.data()); + else + printf("DCOPRef(%s,%s)\n", qStringToC(foundApp), qStringToC(foundObj)); + return true; + } + return false; +} + +bool launchApp(QString app) +{ + int l = app.length(); + if (l && (app[l-1] == '*')) + l--; + if (l && (app[l-1] == '-')) + l--; + if (!l) return false; + app.truncate(l); + + QStringList URLs; + QByteArray data, replyData; + QCString replyType; + QDataStream arg(data, IO_WriteOnly); + arg << app << URLs; + + if ( !dcop->call( "klauncher", "klauncher", "start_service_by_desktop_name(QString,QStringList)", + data, replyType, replyData) ) { + qWarning( "call to klauncher failed."); + return false; + } + QDataStream reply(replyData, IO_ReadOnly); + + if ( replyType != "serviceResult" ) + { + qWarning( "unexpected result '%s' from klauncher.", replyType.data()); + return false; + } + int result; + QCString dcopName; + QString error; + reply >> result >> dcopName >> error; + if (result != 0) + { + qWarning("Error starting '%s': %s", app.local8Bit().data(), error.local8Bit().data()); + return false; + } + return true; +} + +void usage() +{ + fprintf( stderr, "Usage: dcopfind [-l] [-a] application [object [function [arg1] [arg2] [arg3] ... ] ] ] \n" ); + exit(0); +} + +#ifdef Q_OS_WIN +# define main kdemain +#endif + +int main( int argc, char** argv ) +{ + int argi = 1; + + while ((argi < argc) && (argv[argi][0] == '-')) + { + switch ( argv[argi][1] ) { + case 'l': + bLaunchApp = true; + break; + case 'a': + bAppIdOnly = true; + break; + default: + usage(); + } + argi++; + } + + if (argc <= argi) + usage(); + + DCOPClient client; + client.attach(); + dcop = &client; + + QCString app; + QCString objid; + QCString function; + char **args = 0; + if ((argc > argi) && (strncmp(argv[argi], "DCOPRef(", 8)) == 0) + { + char *delim = strchr(argv[argi], ','); + if (!delim) + { + fprintf(stderr, "Error: '%s' is not a valid DCOP reference.\n", argv[argi]); + return 1; + } + *delim = 0; + app = argv[argi++] + 8; + delim++; + delim[strlen(delim)-1] = 0; + objid = delim; + } + else + { + if (argc > argi) + app = argv[argi++]; + if (argc > argi) + objid = argv[argi++]; + } + if (argc > argi) + function = argv[argi++]; + + if (argc > argi) + { + args = &argv[argi]; + argc = argc-argi; + } + else + { + argc = 0; + } + + QCStringList params; + for( int i = 0; i < argc; i++ ) + params.append( args[ i ] ); + bool ok = findObject( app, objid, function, params ); + if (ok) + return 0; + if (bLaunchApp) + { + ok = launchApp(app); + if (!ok) + return 2; + ok = findObject( app, objid, function, params ); + } + + return 1; +} diff --git a/dcop/client/dcopobject.c b/dcop/client/dcopobject.c new file mode 100644 index 000000000..a0ec31469 --- /dev/null +++ b/dcop/client/dcopobject.c @@ -0,0 +1,59 @@ +/* vi: set ts=2 sw=2 tw=78: + + Extracts the dcopobject form a DCOPRef + + Copyright 2001 Waldo Bastian + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + char *dcopref; + char *delim; + if ((argc != 2) || (argv[1][0] == '-')) + { + fprintf(stderr, "Usage: dcopobject \n"); + return 1; + } + dcopref = argv[1]; + if (strncmp(dcopref, "DCOPRef(", 8) != 0) + goto bad_ref; + + if (dcopref[strlen(dcopref)-1] != ')') + goto bad_ref; + + delim = strchr(dcopref, ','); + if (!delim) + goto bad_ref; + + dcopref = delim+1; + dcopref[strlen(dcopref)-1] = 0; + puts(dcopref); + return 0; + +bad_ref: + fprintf(stderr, "Error: '%s' is not a valid DCOP reference.\n", dcopref); + return 1; +} diff --git a/dcop/client/dcopquit.cpp b/dcop/client/dcopquit.cpp new file mode 100644 index 000000000..8fdeedf02 --- /dev/null +++ b/dcop/client/dcopquit.cpp @@ -0,0 +1,2 @@ +#define DCOPQUIT 1 +#include "dcop.cpp" diff --git a/dcop/client/dcopref.c b/dcop/client/dcopref.c new file mode 100644 index 000000000..f096db27a --- /dev/null +++ b/dcop/client/dcopref.c @@ -0,0 +1,40 @@ +/* vi: set ts=2 sw=2 tw=78: + + Creates a DCOPRef from a dcopclient and a dcopobject. + + Copyright 2001 Waldo Bastian + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + if ((argc != 3) || (argv[1][0] == '-')) + { + fprintf(stderr, "Usage: dcopref \n"); + return 1; + } + printf("DCOPRef(%s,%s)\n", argv[1], argv[2]); + return 0; +} diff --git a/dcop/client/dcopstart.cpp b/dcop/client/dcopstart.cpp new file mode 100644 index 000000000..2b870964f --- /dev/null +++ b/dcop/client/dcopstart.cpp @@ -0,0 +1,99 @@ +/***************************************************************** +Copyright (c) 2001 Waldo Bastian + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include "../kdatastream.h" +#include "../dcopclient.h" +#include +#include +#include + +#include + +static DCOPClient* dcop = 0; + +void startApp(const char *_app, int argc, const char **args) +{ + const char *function = 0; + QString app = QString::fromLatin1(_app); + if (app.endsWith(".desktop")) + function = "start_service_by_desktop_path(QString,QStringList)"; + else + function = "start_service_by_desktop_name(QString,QStringList)"; + QStringList URLs; + for(int i = 0; i < argc; i++) + { + URLs.append(QString::fromLocal8Bit(args[i])); + } + + QByteArray data, replyData; + QCString replyType; + QDataStream arg(data, IO_WriteOnly); + arg << app << URLs; + + if ( !dcop->call( "klauncher", "klauncher", function, data, replyType, replyData) ) { + qWarning( "call failed"); + exit(1); + } else { + QDataStream reply(replyData, IO_ReadOnly); + + if ( replyType != "serviceResult" ) + { + qWarning( "unexpected result '%s'", replyType.data()); + exit(1); + } + int result; + QCString dcopName; + QString error; + reply >> result >> dcopName >> error; + if (result != 0) + { + qWarning("Error: %s", error.local8Bit().data()); + exit(1); + } + if (!dcopName.isEmpty()) + puts(dcopName.data()); + } +} + +#ifdef Q_OS_WIN +# define main kdemain +#endif + +int main( int argc, char** argv ) +{ + if (( argc < 2) || (argv[1][0] == '-' )) { + fprintf( stderr, "Usage: dcopstart [url1] [url2] ...\n" ); + exit(0); + } + + DCOPClient client; + client.attach(); + dcop = &client; + + QCString app; + QCString objid; + QCString function; + /*char **args = 0;*/ + startApp( argv[1], argc - 2, (const char**)&argv[2] ); + + return 0; +} diff --git a/dcop/client/marshall.cpp b/dcop/client/marshall.cpp new file mode 100644 index 000000000..d7d5c260a --- /dev/null +++ b/dcop/client/marshall.cpp @@ -0,0 +1,399 @@ +/***************************************************************** +Copyright (c) 2000 Matthias Ettrich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#define KDE_QT_ONLY +#include "../../kdecore/kurl.cpp" + +bool mkBool( const QString& s ) +{ + if ( s.lower() == "true" ) + return true; + if ( s.lower() == "yes" ) + return true; + if ( s.lower() == "on" ) + return true; + if ( s.toInt() != 0 ) + return true; + + return false; +} + +QPoint mkPoint( const QString &str ) +{ + const char *s = str.latin1(); + char *end; + while(*s && !isdigit(*s) && *s != '-') s++; + int x = strtol(s, &end, 10); + s = (const char *)end; + while(*s && !isdigit(*s) && *s != '-') s++; + int y = strtol(s, &end, 10); + return QPoint( x, y ); +} + +QSize mkSize( const QString &str ) +{ + const char *s = str.latin1(); + char *end; + while(*s && !isdigit(*s) && *s != '-') s++; + int w = strtol(s, &end, 10); + s = (const char *)end; + while(*s && !isdigit(*s) && *s != '-') s++; + int h = strtol(s, &end, 10); + return QSize( w, h ); +} + +QRect mkRect( const QString &str ) +{ + const char *s = str.latin1(); + char *end; + while(*s && !isdigit(*s) && *s != '-') s++; + int p1 = strtol(s, &end, 10); + s = (const char *)end; + bool legacy = (*s == 'x'); + while(*s && !isdigit(*s) && *s != '-') s++; + int p2 = strtol(s, &end, 10); + s = (const char *)end; + while(*s && !isdigit(*s) && *s != '-') s++; + int p3 = strtol(s, &end, 10); + s = (const char *)end; + while(*s && !isdigit(*s) && *s != '-') s++; + int p4 = strtol(s, &end, 10); + if (legacy) + { + return QRect( p3, p4, p1, p2 ); + } + return QRect( p1, p2, p3, p4 ); +} + +QColor mkColor( const QString& s ) +{ + QColor c; + c.setNamedColor(s); + return c; +} + +const char *qStringToC(const QCString &s) +{ + if (s.isEmpty()) + return ""; + return s.data(); +} + +QCString demarshal( QDataStream &stream, const QString &type ) +{ + QCString result; + + if ( type == "int" || type == "Q_INT32" ) + { + int i; + stream >> i; + result.setNum( i ); + } else if ( type == "uint" || type == "Q_UINT32" || type == "unsigned int" ) + { + uint i; + stream >> i; + result.setNum( i ); + } else if ( type == "long" || type == "long int" ) + { + long l; + stream >> l; + result.setNum( l ); + } else if ( type == "unsigned long" || type == "unsigned long int" ) + { + unsigned long l; + stream >> l; + result.setNum( l ); + } else if ( type == "float" ) + { + float f; + stream >> f; + result.setNum( f, 'f' ); + } else if ( type == "double" ) + { + double d; + stream >> d; + result.setNum( d, 'f' ); + } else if ( type == "Q_INT64" ) { + Q_INT64 i; + stream >> i; + result.sprintf( "%lld", i ); + } else if ( type == "Q_UINT64" ) { + Q_UINT64 i; + stream >> i; + result.sprintf( "%llu", i ); + } else if ( type == "bool" ) + { + bool b; + stream >> b; + result = b ? "true" : "false"; + } else if ( type == "QString" ) + { + QString s; + stream >> s; + result = s.local8Bit(); + } else if ( type == "QCString" ) + { + stream >> result; + } else if ( type == "QCStringList" ) + { + return demarshal( stream, "QValueList" ); + } else if ( type == "QStringList" ) + { + return demarshal( stream, "QValueList" ); + } else if ( type == "QColor" ) + { + QColor c; + stream >> c; + result = c.name().local8Bit(); + } else if ( type == "QSize" ) + { + QSize s; + stream >> s; + result.sprintf( "%dx%d", s.width(), s.height() ); + } else if ( type == "QPixmap" || type == "QImage" ) + { + QImage i; + stream >> i; + QByteArray ba; + QBuffer buf( ba ); + buf.open( IO_WriteOnly ); + i.save( &buf, "XPM" ); + result = ba; + } else if ( type == "QPoint" ) + { + QPoint p; + stream >> p; + result.sprintf( "+%d+%d", p.x(), p.y() ); + } else if ( type == "QRect" ) + { + QRect r; + stream >> r; + result.sprintf( "%dx%d+%d+%d", r.width(), r.height(), r.x(), r.y() ); + } else if ( type == "QVariant" ) + { + Q_INT32 type; + stream >> type; + return demarshal( stream, QVariant::typeToName( (QVariant::Type)type ) ); + } else if ( type == "DCOPRef" ) + { + DCOPRef r; + stream >> r; + result.sprintf( "DCOPRef(%s,%s)", qStringToC(r.app()), qStringToC(r.object()) ); + } else if ( type == "KURL" ) + { + KURL r; + stream >> r; + result = r.url().local8Bit(); + } else if ( type.left( 11 ) == "QValueList<" ) + { + if ( (uint)type.find( '>', 11 ) != type.length() - 1 ) + return result; + + QString nestedType = type.mid( 11, type.length() - 12 ); + + if ( nestedType.isEmpty() ) + return result; + + Q_UINT32 count; + stream >> count; + + Q_UINT32 i = 0; + for (; i < count; ++i ) + { + QCString arg = demarshal( stream, nestedType ); + result += arg; + + if ( i < count - 1 ) + result += '\n'; + } + } else if ( type.left( 5 ) == "QMap<" ) + { + int commaPos = type.find( ',', 5 ); + + if ( commaPos == -1 ) + return result; + + if ( (uint)type.find( '>', commaPos ) != type.length() - 1 ) + return result; + + QString keyType = type.mid( 5, commaPos - 5 ); + QString valueType = type.mid( commaPos + 1, type.length() - commaPos - 2 ); + + Q_UINT32 count; + stream >> count; + + Q_UINT32 i = 0; + for (; i < count; ++i ) + { + QCString key = demarshal( stream, keyType ); + + if ( key.isEmpty() ) + continue; + + QCString value = demarshal( stream, valueType ); + + if ( value.isEmpty() ) + continue; + + result += key + "->" + value; + + if ( i < count - 1 ) + result += '\n'; + } + } + else + { + result.sprintf( "<%s>", type.latin1()); + } + + return result; + +} + +void marshall( QDataStream &arg, QCStringList args, uint &i, QString type ) +{ + if( i >= args.count() ) + { + qWarning("Not enough arguments (expected %d, got %d).", i, args.count()); + exit(1); + } + QString s = QString::fromLocal8Bit( args[ i ] ); + + if (type == "QStringList") + type = "QValueList"; + if (type == "QCStringList") + type = "QValueList"; + + if ( type == "int" ) + arg << s.toInt(); + else if ( type == "uint" ) + arg << s.toUInt(); + else if ( type == "unsigned" ) + arg << s.toUInt(); + else if ( type == "unsigned int" ) + arg << s.toUInt(); + else if ( type == "Q_INT32" ) + arg << s.toInt(); + else if ( type == "Q_INT64" ) { + QVariant qv = QVariant( s ); + arg << qv.toLongLong(); + } + else if ( type == "Q_UINT32" ) + arg << s.toUInt(); + else if ( type == "Q_UINT64" ) { + QVariant qv = QVariant( s ); + arg << qv.toULongLong(); + } + else if ( type == "long" ) + arg << s.toLong(); + else if ( type == "long int" ) + arg << s.toLong(); + else if ( type == "unsigned long" ) + arg << s.toULong(); + else if ( type == "unsigned long int" ) + arg << s.toULong(); + else if ( type == "float" ) + arg << s.toFloat(); + else if ( type == "double" ) + arg << s.toDouble(); + else if ( type == "bool" ) + arg << mkBool( s ); + else if ( type == "QString" ) + arg << s; + else if ( type == "QCString" ) + arg << QCString( args[ i ] ); + else if ( type == "QColor" ) + arg << mkColor( s ); + else if ( type == "QPoint" ) + arg << mkPoint( s ); + else if ( type == "QSize" ) + arg << mkSize( s ); + else if ( type == "QRect" ) + arg << mkRect( s ); + else if ( type == "KURL" ) + arg << KURL( s ); + else if ( type == "QVariant" ) { + if ( s == "true" || s == "false" ) + arg << QVariant( mkBool( s ), 42 ); + else if ( s.left( 4 ) == "int(" ) + arg << QVariant( s.mid(4, s.length()-5).toInt() ); + else if ( s.left( 7 ) == "QPoint(" ) + arg << QVariant( mkPoint( s.mid(7, s.length()-8) ) ); + else if ( s.left( 6 ) == "QSize(" ) + arg << QVariant( mkSize( s.mid(6, s.length()-7) ) ); + else if ( s.left( 6 ) == "QRect(" ) + arg << QVariant( mkRect( s.mid(6, s.length()-7) ) ); + else if ( s.left( 7 ) == "QColor(" ) + arg << QVariant( mkColor( s.mid(7, s.length()-8) ) ); + else + arg << QVariant( s ); + } else if ( type.startsWith("QValueList<") || + type == "KURL::List" ) { + if ( type == "KURL::List" ) + type = "KURL"; + else + type = type.mid(11, type.length() - 12); + QStringList list; + QString delim = s; + if (delim == "[") + delim = "]"; + if (delim == "(") + delim = ")"; + i++; + QByteArray dummy_data; + QDataStream dummy_arg(dummy_data, IO_WriteOnly); + + uint j = i; + uint count = 0; + // Parse list to get the count + while (true) { + if( j > args.count() ) + { + qWarning("List end-delimiter '%s' not found.", delim.latin1()); + exit(1); + } + if( QString::fromLocal8Bit( args[ j ] ) == delim ) + break; + marshall( dummy_arg, args, j, type ); + count++; + } + arg << (Q_UINT32) count; + // Parse the list for real + while (true) { + if( i > args.count() ) + { + qWarning("List end-delimiter '%s' not found.", delim.latin1()); + exit(1); + } + if( QString::fromLocal8Bit( args[ i ] ) == delim ) + break; + marshall( arg, args, i, type ); + } + } else { + qWarning( "cannot handle datatype '%s'", type.latin1() ); + exit(1); + } + i++; +} + +// vim: set noet ts=8 sts=4 sw=4: + -- cgit v1.2.1