Index: client/dcop.cpp =================================================================== RCS file: /home/kde/tdelibs/dcop/client/dcop.cpp,v retrieving revision 1.26 diff -n -r1.26 dcop.cpp d23 1 a23 4 #include #include #include d25 1 a25 12 #include #include #include #include #include #include #include // putenv() is not available on all platforms, so make sure the emulation // wrapper is available in those cases by loading config.h! #include d28 3 a30 1 #include "../kdatastream.h" a33 2 typedef QMap UserList; a35 14 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 }; d121 1 a121 1 void callFunction( const char* app, const char* obj, const char* func, const QCStringList args ) d123 1 d139 1 a139 1 if ( !ok && args.isEmpty() ) d156 2 a157 2 uint a = (*it).contains(','); if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) ) d164 1 a164 2 // exit(1); return; d246 5 a250 6 uint i = 0; for( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) marshall( arg, args, i, *it ); if ( i != args.count() ) { a268 27 /** * Show command-line help and exit */ void showHelp( int exitCode = 0 ) { cout << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl << "" << 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" << 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 --als-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" << " generate an error message. If no DCOP server is available" << endl << " at all, no error will be generated." << endl; exit( exitCode ); } d270 2 a271 5 /** * 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() a272 9 UserList result; QFile f( "/etc/passwd" ); if( !f.open( IO_ReadOnly ) ) { cerr << "Can't open /etc/passwd for reading!" << endl; return result; } d274 3 a276 6 QStringList l( QStringList::split( '\n', f.readAll() ) ); for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it ) { QStringList userInfo( QStringList::split( ':', *it, true ) ); result[ userInfo[ 0 ] ] = userInfo[ 5 ]; d279 3 a281 42 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; } a282 6 /** * Do the actual DCOP call */ void runDCOP( QCStringList args, UserList users, Session session, const QString sessionName, bool readStdin ) { d286 2 a287 3 QCStringList params; DCOPClient *client = 0L; if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 ) d289 16 a304 24 // WARNING: This part (until the closing '}') could very // well be broken now. As I don't know how to trigger and test // dcoprefs this code is *not* tested. It compiles and it looks // ok to me, but that's all I can say - Martijn (2001/12/24) int delimPos = args[ 0 ].findRev( ',' ); if( delimPos == -1 ) { cerr << "Error: '" << args[ 0 ] << "' is not a valid DCOP reference." << endl; exit( -1 ); } args[ 0 ][ delimPos ] = 0; app = args[ 0 ].mid( 8 ); delimPos++; args[ 0 ][ args[ 0 ].length() - 1 ] = 0; objid = args[ 0 ].mid( delimPos ); if( args.count() > 1 ) function = args[ 1 ]; if( args.count() > 2 ) { params = args; params.remove( params.begin() ); params.remove( params.begin() ); } d308 31 a338 84 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() ) { 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; for( sIt = sessions.begin(); 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( 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 ); } } a339 143 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; continue; } dcop = client; switch ( args.count() ) { 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( readStdin ) { QCStringList::Iterator replaceArg = args.end(); QCStringList::Iterator it; for( it = args.begin(); it != args.end(); it++ ) if( *it == "%1" ) replaceArg = it; // Read from stdin until EOF and call function for each line read char *buf = new char[ 1000 ]; while ( !feof( stdin ) ) { fgets( buf, 1000, stdin ); if( replaceArg != args.end() ) *replaceArg = buf; callFunction( app, objid, function, params ); } } else { // Just call function // cout << "call " << app << ", " << objid << ", " << function << ", (params)" << endl; callFunction( app, objid, function, params ); } break; } // Another sIt++ would make the loop infinite... if( users.isEmpty() ) break; } // Another it++ would make the loop infinite... if( it == users.end() ) break; a340 106 } int main( int argc, char** argv ) { bool readStdin = false; int numOptions = 0; QString user; Session session = DefaultSession; QString sessionName; // 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 ], "--all-users" ) == 0 ) { user = "*"; numOptions ++; } else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 ) { session = QuerySessions; numOptions ++; } else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 ) { session = AllSessions; 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; for( int i = numOptions; i < argc + numOptions - 1; i++ ) args.append( argv[ i + 1 ] ); 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 ]; runDCOP( args, users, session, sessionName, readStdin ); Index: client/dcopfind.cpp =================================================================== RCS file: /home/kde/tdelibs/dcop/client/dcopfind.cpp,v retrieving revision 1.2 diff -n -r1.2 dcopfind.cpp d39 1 a39 1 bool findObject( const char* app, const char* obj, const char* func, QCStringList args ) d121 1 a121 1 if ( types.count() != args.count() ) { d131 1 a131 1 marshall(arg, args, i, *it); d133 1 a133 1 if ( (uint) i != args.count() ) { d224 1 a224 5 QCStringList params; for( int i = 0; i < argc; i++ ) params.append( args[ i ] ); findObject( app, objid, function, params ); Index: client/marshall.cpp =================================================================== RCS file: /home/kde/tdelibs/dcop/client/marshall.cpp,v retrieving revision 1.3 diff -n -r1.3 marshall.cpp d245 1 a245 1 void marshall( QDataStream &arg, QCStringList args, uint &i, QString type ) d247 71 a317 10 if (type == "TQStringList") type = "QValueList"; if (type == "QCStringList") type = "QValueList"; if( i > args.count() ) { tqWarning("Not enough arguments."); exit(1); } QString s = QString::fromLocal8Bit( args[ i ] ); d319 28 a346 57 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 == "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 == "TQString" ) arg << s; else if ( type == "QCString" ) arg << QCString( args[ i ] ); else if ( type == "QColor" ) arg << mkColor( s ); else if ( type == "TQPoint" ) arg << mkPoint( s ); else if ( type == "QSize" ) arg << mkSize( s ); else if ( type == "QRect" ) arg << mkRect( 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 = type.mid(11, type.length() - 12); QStringList list; QString delim = s; if (delim == "[") delim = "]"; if (delim == "(") delim = ")"; a347 34 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() ) { tqWarning("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() ) { tqWarning("List end-delimiter '%s' not found.", delim.latin1()); exit(1); } if( QString::fromLocal8Bit( args[ i ] ) == delim ) break; marshall( arg, args, i, type ); } } else { tqWarning( "cannot handle datatype '%s'", type.latin1() ); exit(1); } i++;