Index: client/dcop.cpp
===================================================================
RCS file: /home/kde/tdelibs/dcop/client/dcop.cpp,v
retrieving revision 1.26
diff -e -r1.26 dcop.cpp
343a

// vim: set ts=8 sts=4 sw=4 noet:

.
340a
}


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 );
.
339a
	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;
.
308,338c
        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 );
	    }
	}
.
289,304c
	// 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() );
	}
.
286,287c
    QCStringList params;
    DCOPClient *client = 0L;
    if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
.
282a
/**
 * Do the actual DCOP call
 */
void runDCOP( QCStringList args, UserList users, Session session,
              const QString sessionName, bool readStdin )
{
.
279,281c
    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;
}
.
274,276c
    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 ];
.
272a
    UserList result;
    
    QFile f( "/etc/passwd" );

    if( !f.open( IO_ReadOnly ) )
    {
	cerr << "Can't open /etc/passwd for reading!" << endl;
	return result;
    }
.
270,271c
/**
 * 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()
.
268a
/**
 * 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 <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 );
}
.
246,250c
    uint i = 0;
    for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
        marshall( arg, args, i, *it );

    if ( i != args.count() )
    {
.
164c
//            exit(1);
	    return;
.
156,157c
		uint a = (*it).contains(',');
		if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
.
139c
	if ( !ok && args.isEmpty() )
.
123d
121c
void callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
.
35a
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 };

.
33a
typedef QMap<QString, QString> UserList;

.
28,30c
#include "../kdatastream.h"
.
25c
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qmap.h>
#include <qstringlist.h>
#include <qtextstream.h>
#include <qvariant.h>

// putenv() is not available on all platforms, so make sure the emulation
// wrapper is available in those cases by loading config.h!
#include <config.h>

.
23c
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>

.
Index: client/dcopfind.cpp
===================================================================
RCS file: /home/kde/tdelibs/dcop/client/dcopfind.cpp,v
retrieving revision 1.2
diff -e -r1.2 dcopfind.cpp
224c
    QCStringList params;
    for( int i = 0; i < argc; i++ )
	    params.append( args[ i ] );
    
    findObject( app, objid, function, params );
.
133c
    if ( (uint) i != args.count() ) {
.
131c
        marshall(arg, args, i, *it);
.
121c
    if ( types.count() != args.count() ) {
.
39c
bool findObject( const char* app, const char* obj, const char* func, QCStringList args )
.
Index: client/marshall.cpp
===================================================================
RCS file: /home/kde/tdelibs/dcop/client/marshall.cpp,v
retrieving revision 1.3
diff -e -r1.3 marshall.cpp
347a
	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++;
.
319,346c
    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_OBJECT_NAME_STRING )
	arg << s;
    else if ( type == "QCString" )
	arg << QCString( args[ i ] );
    else if ( type == "QColor" )
	arg << mkColor( s );
    else if ( type == TQPOINT_OBJECT_NAME_STRING )
	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 = ")";
.
247,317c
    if (type == TQSTRINGLIST_OBJECT_NAME_STRING)
       type = "QValueList<QString>";
    if (type == "QCStringList")
       type = "QValueList<QCString>";
    if( i > args.count() )
    {
	tqWarning("Not enough arguments.");
	exit(1);
    }       
    QString s = QString::fromLocal8Bit( args[ i ] );
.
245c
void marshall( QDataStream &arg, QCStringList args, uint &i, QString type )
.
