00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <ctype.h>
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026
00027 #include <qcolor.h>
00028 #include <qdir.h>
00029 #include <qfile.h>
00030 #include <qfileinfo.h>
00031 #include <qmap.h>
00032 #include <qstringlist.h>
00033 #include <qtextstream.h>
00034 #include <qvariant.h>
00035
00036
00037
00038 #include <config.h>
00039
00040 #include "../dcopclient.h"
00041 #include "../dcopref.h"
00042 #include "../kdatastream.h"
00043
00044 #include "marshall.cpp"
00045
00046 typedef QMap<QString, QString> UserList;
00047
00048 static DCOPClient* dcop = 0;
00049
00050 static QTextStream cin_ ( stdin, IO_ReadOnly );
00051 static QTextStream cout_( stdout, IO_WriteOnly );
00052 static QTextStream cerr_( stderr, IO_WriteOnly );
00053
00063 enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
00064
00065 bool startsWith(const QCString &id, const char *str, int n)
00066 {
00067 return !n || (strncmp(id.data(), str, n) == 0);
00068 }
00069
00070 bool endsWith(QCString &id, char c)
00071 {
00072 if (id.length() && (id[id.length()-1] == c))
00073 {
00074 id.truncate(id.length()-1);
00075 return true;
00076 }
00077 return false;
00078 }
00079
00080 void queryApplications(const QCString &filter)
00081 {
00082 int filterLen = filter.length();
00083 QCStringList apps = dcop->registeredApplications();
00084 for ( QCStringList::Iterator it = apps.begin(); it != apps.end(); ++it )
00085 {
00086 QCString &clientId = *it;
00087 if ( (clientId != dcop->appId()) &&
00088 !startsWith(clientId, "anonymous",9) &&
00089 startsWith(clientId, filter, filterLen)
00090 )
00091 printf( "%s\n", clientId.data() );
00092 }
00093
00094 if ( !dcop->isAttached() )
00095 {
00096 qWarning( "server not accessible" );
00097 exit(1);
00098 }
00099 }
00100
00101 void queryObjects( const QCString &app, const QCString &filter )
00102 {
00103 int filterLen = filter.length();
00104 bool ok = false;
00105 bool isDefault = false;
00106 QCStringList objs = dcop->remoteObjects( app, &ok );
00107 for ( QCStringList::Iterator it = objs.begin(); it != objs.end(); ++it )
00108 {
00109 QCString &objId = *it;
00110
00111 if (objId == "default")
00112 {
00113 isDefault = true;
00114 continue;
00115 }
00116
00117 if (startsWith(objId, filter, filterLen))
00118 {
00119 if (isDefault)
00120 printf( "%s (default)\n", objId.data() );
00121 else
00122 printf( "%s\n", objId.data() );
00123 }
00124 isDefault = false;
00125 }
00126 if ( !ok )
00127 {
00128 if (!dcop->isApplicationRegistered(app))
00129 qWarning( "No such application: '%s'", app.data());
00130 else
00131 qWarning( "Application '%s' not accessible", app.data() );
00132 exit(1);
00133 }
00134 }
00135
00136 void queryFunctions( const char* app, const char* obj )
00137 {
00138 bool ok = false;
00139 QCStringList funcs = dcop->remoteFunctions( app, obj, &ok );
00140 for ( QCStringList::Iterator it = funcs.begin(); it != funcs.end(); ++it ) {
00141 printf( "%s\n", (*it).data() );
00142 }
00143 if ( !ok )
00144 {
00145 qWarning( "object '%s' in application '%s' not accessible", obj, app );
00146 exit( 1 );
00147 }
00148 }
00149
00150 int callFunction( const char* app, const char* obj, const char* func, const QCStringList args )
00151 {
00152 QString f = func;
00153 int left = f.find( '(' );
00154 int right = f.find( ')' );
00155
00156 if ( right < left )
00157 {
00158 qWarning( "parentheses do not match" );
00159 return( 1 );
00160 }
00161
00162 if ( left < 0 ) {
00163
00164 bool ok = false;
00165 QCStringList funcs = dcop->remoteFunctions( app, obj, &ok );
00166 QCString realfunc;
00167 if ( !ok && args.isEmpty() )
00168 goto doit;
00169 if ( !ok )
00170 {
00171 qWarning( "object not accessible" );
00172 return( 1 );
00173 }
00174 for ( QCStringList::Iterator it = funcs.begin(); it != funcs.end(); ++it ) {
00175 int l = (*it).find( '(' );
00176 int s = (*it).find( ' ');
00177 if ( s < 0 )
00178 s = 0;
00179 else
00180 s++;
00181
00182 if ( l > 0 && (*it).mid( s, l - s ) == func ) {
00183 realfunc = (*it).mid( s );
00184 uint a = (*it).contains(',');
00185 if ( ( a == 0 && args.isEmpty() ) || ( a > 0 && a + 1 == args.count() ) )
00186 break;
00187 }
00188 }
00189 if ( realfunc.isEmpty() )
00190 {
00191 qWarning("no such function");
00192 return( 1 );
00193 }
00194 f = realfunc;
00195 left = f.find( '(' );
00196 right = f.find( ')' );
00197 }
00198
00199 doit:
00200 if ( left < 0 )
00201 f += "()";
00202
00203
00204
00205
00206
00207 QStringList intTypes;
00208 intTypes << "int" << "unsigned" << "long" << "bool" ;
00209
00210 QStringList types;
00211 if ( left >0 && left + 1 < right - 1) {
00212 types = QStringList::split( ',', f.mid( left + 1, right - left - 1) );
00213 for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
00214 QString lt = (*it).simplifyWhiteSpace();
00215
00216 int s = lt.find(' ');
00217
00218
00219
00220
00221
00222
00223
00224 if ( s > 0 )
00225 {
00226 QStringList partl = QStringList::split(' ' , lt);
00227
00228
00229
00230
00231
00232
00233
00234 s=1;
00235
00236 while (s < static_cast<int>(partl.count()) && intTypes.contains(partl[s]))
00237 {
00238 s++;
00239 }
00240
00241 if ( s < static_cast<int>(partl.count())-1)
00242 {
00243 qWarning("The argument `%s' seems syntactically wrong.",
00244 lt.latin1());
00245 }
00246 if ( s == static_cast<int>(partl.count())-1)
00247 {
00248 partl.remove(partl.at(s));
00249 }
00250
00251 lt = partl.join(" ");
00252 lt = lt.simplifyWhiteSpace();
00253 }
00254
00255 (*it) = lt;
00256 }
00257 QString fc = f.left( left );
00258 fc += '(';
00259 bool first = TRUE;
00260 for ( QStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
00261 if ( !first )
00262 fc +=",";
00263 first = FALSE;
00264 fc += *it;
00265 }
00266 fc += ')';
00267 f = fc;
00268 }
00269
00270 QByteArray data, replyData;
00271 QCString replyType;
00272 QDataStream arg(data, IO_WriteOnly);
00273
00274 uint i = 0;
00275 for( QStringList::Iterator it = types.begin(); it != types.end(); ++it )
00276 marshall( arg, args, i, *it );
00277
00278 if ( i != args.count() )
00279 {
00280 qWarning( "arguments do not match" );
00281 return( 1 );
00282 }
00283
00284 if ( !dcop->call( app, obj, f.latin1(), data, replyType, replyData) ) {
00285 qWarning( "call failed");
00286 return( 1 );
00287 } else {
00288 QDataStream reply(replyData, IO_ReadOnly);
00289
00290 if ( replyType != "void" && replyType != "ASYNC" )
00291 {
00292 QCString replyString = demarshal( reply, replyType );
00293 if ( !replyString.isEmpty() )
00294 printf( "%s\n", replyString.data() );
00295 else
00296 printf("\n");
00297 }
00298 }
00299 return 0;
00300 }
00301
00305 void showHelp( int exitCode = 0 )
00306 {
00307 cout_ << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl
00308 << "" << endl
00309 << "Console DCOP client" << endl
00310 << "" << endl
00311 << "Generic options:" << endl
00312 << " --help Show help about options" << endl
00313 << "" << endl
00314 << "Options:" << endl
00315 << " --pipe Call DCOP for each line read from stdin" << endl
00316 << " This is roughly equivalent to calling" << endl
00317 << " 'while read line ; do dcop $line ; done'" << endl
00318 << " but because no new dcop instance has to be started for" << endl
00319 << " each line this is generally much faster, especially" << endl
00320 << " for the slower GNU dynamic linkers." << endl
00321 << " --user <user> Connect to the given user's DCOP server. This option will" << endl
00322 << " ignore the values of the environment vars $DCOPSERVER and" << endl
00323 << " $ICEAUTHORITY, even if they are set." << endl
00324 << " If the user has more than one open session, you must also" << endl
00325 << " use one of the --list-sessions, --session or --all-sessions" << endl
00326 << " command-line options." << endl
00327 << " --all-users Send the same DCOP call to all users with a running DCOP" << endl
00328 << " server. Only failed calls to existing DCOP servers will" << endl
00329 << " generate an error message. If no DCOP server is available" << endl
00330 << " at all, no error will be generated." << endl
00331 << " --session <ses> Send to the given KDE session. This option can only be" << endl
00332 << " used in combination with the --user option." << endl
00333 << " --all-sessions Send to all sessions found. Only works with the --user" << endl
00334 << " and --all-users options." << endl
00335 << " --list-sessions List all active KDE session for a user or all users." << endl
00336 << endl;
00337
00338 exit( exitCode );
00339 }
00340
00345 static UserList userList()
00346 {
00347 UserList result;
00348
00349 QFile f( "/etc/passwd" );
00350
00351 if( !f.open( IO_ReadOnly ) )
00352 {
00353 cerr_ << "Can't open /etc/passwd for reading!" << endl;
00354 return result;
00355 }
00356
00357 QStringList l( QStringList::split( '\n', f.readAll() ) );
00358
00359 for( QStringList::ConstIterator it( l.begin() ); it != l.end(); ++it )
00360 {
00361 QStringList userInfo( QStringList::split( ':', *it, true ) );
00362 result[ userInfo[ 0 ] ] = userInfo[ 5 ];
00363 }
00364
00365 return result;
00366 }
00367
00372 QStringList dcopSessionList( const QString &user, const QString &home )
00373 {
00374 if( home.isEmpty() )
00375 {
00376 cerr_ << "WARNING: Cannot determine home directory for user "
00377 << user << "!" << endl
00378 << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
00379 << "calling dcop." << endl;
00380 return QStringList();
00381 }
00382
00383 QStringList result;
00384 QFileInfo dirInfo( home );
00385 if( !dirInfo.exists() || !dirInfo.isReadable() )
00386 return result;
00387
00388 QDir d( home );
00389 d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
00390 d.setNameFilter( ".DCOPserver*" );
00391
00392 const QFileInfoList *list = d.entryInfoList();
00393 if( !list )
00394 return result;
00395
00396 QFileInfoListIterator it( *list );
00397 QFileInfo *fi;
00398
00399 while ( ( fi = it.current() ) != 0 )
00400 {
00401 if( fi->isReadable() )
00402 result.append( fi->fileName() );
00403 ++it;
00404 }
00405 return result;
00406 }
00407
00411 int runDCOP( QCStringList args, UserList users, Session session,
00412 const QString sessionName, bool readStdin )
00413 {
00414 bool DCOPrefmode=false;
00415 QCString app;
00416 QCString objid;
00417 QCString function;
00418 QCStringList params;
00419 DCOPClient *client = 0L;
00420 int retval = 0;
00421 if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 )
00422 {
00423 int delimPos = args[ 0 ].findRev( ',' );
00424 if( delimPos == -1 )
00425 {
00426 cerr_ << "Error: '" << args[ 0 ]
00427 << "' is not a valid DCOP reference." << endl;
00428 exit( -1 );
00429 }
00430 app = args[ 0 ].mid( 8, delimPos-8 );
00431 delimPos++;
00432 objid = args[ 0 ].mid( delimPos, args[ 0 ].length()-delimPos-1 );
00433 if( args.count() > 1 )
00434 function = args[ 1 ];
00435 if( args.count() > 2 )
00436 {
00437 params = args;
00438 params.remove( params.begin() );
00439 params.remove( params.begin() );
00440 }
00441 DCOPrefmode=true;
00442 }
00443 else
00444 {
00445 if( !args.isEmpty() )
00446 app = args[ 0 ];
00447 if( args.count() > 1 )
00448 objid = args[ 1 ];
00449 if( args.count() > 2 )
00450 function = args[ 2 ];
00451 if( args.count() > 3)
00452 {
00453 params = args;
00454 params.remove( params.begin() );
00455 params.remove( params.begin() );
00456 params.remove( params.begin() );
00457 }
00458 }
00459
00460 bool firstRun = true;
00461 UserList::Iterator it;
00462 QStringList sessions;
00463 bool presetDCOPServer = false;
00464
00465 QString dcopServer;
00466
00467 for( it = users.begin(); it != users.end() || firstRun; it++ )
00468 {
00469 firstRun = false;
00470
00471
00472
00473 if( session == QuerySessions )
00474 {
00475 QStringList sessions = dcopSessionList( it.key(), it.data() );
00476 if( sessions.isEmpty() )
00477 {
00478 if( users.count() <= 1 )
00479 {
00480 cout_ << "No active sessions";
00481 if( !( *it ).isEmpty() )
00482 cout_ << " for user " << *it;
00483 cout_ << endl;
00484 }
00485 }
00486 else
00487 {
00488 cout_ << "Active sessions ";
00489 if( !( *it ).isEmpty() )
00490 cout_ << "for user " << *it << " ";
00491 cout_ << ":" << endl;
00492
00493 QStringList::Iterator sIt;
00494 for( sIt = sessions.begin(); sIt != sessions.end(); sIt++ )
00495 cout_ << " " << *sIt << endl;
00496
00497 cout_ << endl;
00498 }
00499 continue;
00500 }
00501
00502 if( getenv( "DCOPSERVER" ) )
00503 {
00504 sessions.append( getenv( "DCOPSERVER" ) );
00505 presetDCOPServer = true;
00506 }
00507
00508 if( users.count() > 1 || ( users.count() == 1 &&
00509 ( getenv( "DCOPSERVER" ) == 0 ) ) )
00510 {
00511 sessions = dcopSessionList( it.key(), it.data() );
00512 if( sessions.isEmpty() )
00513 {
00514 if( users.count() > 1 )
00515 continue;
00516 else
00517 {
00518 cerr_ << "ERROR: No active KDE sessions!" << endl
00519 << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
00520 << "before calling dcop." << endl;
00521 exit( -1 );
00522 }
00523 }
00524 else if( !sessionName.isEmpty() )
00525 {
00526 if( sessions.contains( sessionName ) )
00527 {
00528 sessions.clear();
00529 sessions.append( sessionName );
00530 }
00531 else
00532 {
00533 cerr_ << "ERROR: The specified session doesn't exist!" << endl;
00534 exit( -1 );
00535 }
00536 }
00537 else if( sessions.count() > 1 && session != AllSessions )
00538 {
00539 cerr_ << "ERROR: Multiple available KDE sessions!" << endl
00540 << "Please specify the correct session to use with --session or use the" << endl
00541 << "--all-sessions option to broadcast to all sessions." << endl;
00542 exit( -1 );
00543 }
00544 }
00545
00546 if( users.count() > 1 || ( users.count() == 1 &&
00547 ( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) )
00548 {
00549
00550 QString home = it.data();
00551 QString iceFile = it.data() + "/.ICEauthority";
00552 QFileInfo fi( iceFile );
00553 if( iceFile.isEmpty() )
00554 {
00555 cerr_ << "WARNING: Cannot determine home directory for user "
00556 << it.key() << "!" << endl
00557 << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
00558 << "calling dcop." << endl;
00559 }
00560 else if( fi.exists() )
00561 {
00562 if( fi.isReadable() )
00563 {
00564 char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() );
00565 putenv( envStr );
00566
00567 }
00568 else
00569 {
00570 cerr_ << "WARNING: ICE authority file " << iceFile
00571 << "is not readable by you!" << endl
00572 << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
00573 << "calling dcop." << endl;
00574 }
00575 }
00576 else
00577 {
00578 if( users.count() > 1 )
00579 continue;
00580 else
00581 {
00582 cerr_ << "WARNING: Cannot find ICE authority file "
00583 << iceFile << "!" << endl
00584 << "Please check permissions or set the $ICEAUTHORITY"
00585 << " variable manually before" << endl
00586 << "calling dcop." << endl;
00587 }
00588 }
00589 }
00590
00591
00592
00593
00594
00595 QStringList::Iterator sIt = sessions.begin();
00596 for( ; sIt != sessions.end() || users.isEmpty(); sIt++ )
00597 {
00598 if( !presetDCOPServer && !users.isEmpty() )
00599 {
00600 QString dcopFile = it.data() + "/" + *sIt;
00601 QFile f( dcopFile );
00602 if( !f.open( IO_ReadOnly ) )
00603 {
00604 cerr_ << "Can't open " << dcopFile << " for reading!" << endl;
00605 exit( -1 );
00606 }
00607
00608 QStringList l( QStringList::split( '\n', f.readAll() ) );
00609 dcopServer = l.first();
00610
00611 if( dcopServer.isEmpty() )
00612 {
00613 cerr_ << "WARNING: Unable to determine DCOP server for session "
00614 << *sIt << "!" << endl
00615 << "Please check permissions or set the $DCOPSERVER variable manually before" << endl
00616 << "calling dcop." << endl;
00617 exit( -1 );
00618 }
00619 }
00620
00621 delete client;
00622 client = new DCOPClient;
00623 if( !dcopServer.isEmpty() )
00624 client->setServerAddress( dcopServer.ascii() );
00625 bool success = client->attach();
00626 if( !success )
00627 {
00628 cerr_ << "ERROR: Couldn't attach to DCOP server!" << endl;
00629 retval = QMAX( retval, 1 );
00630 if( users.isEmpty() )
00631 break;
00632 else
00633 continue;
00634 }
00635 dcop = client;
00636
00637 int argscount = args.count();
00638 if ( DCOPrefmode )
00639 argscount++;
00640 switch ( argscount )
00641 {
00642 case 0:
00643 queryApplications("");
00644 break;
00645 case 1:
00646 if (endsWith(app, '*'))
00647 queryApplications(app);
00648 else
00649 queryObjects( app, "" );
00650 break;
00651 case 2:
00652 if (endsWith(objid, '*'))
00653 queryObjects(app, objid);
00654 else
00655 queryFunctions( app, objid );
00656 break;
00657 case 3:
00658 default:
00659 if( readStdin )
00660 {
00661 QCStringList::Iterator replaceArg = params.end();
00662
00663 QCStringList::Iterator it;
00664 for( it = params.begin(); it != params.end(); it++ )
00665 if( *it == "%1" )
00666 replaceArg = it;
00667
00668
00669
00670 while ( !cin_.atEnd() )
00671 {
00672 QString buf = cin_.readLine();
00673
00674 if( replaceArg != params.end() )
00675 *replaceArg = buf.local8Bit();
00676
00677 if( !buf.isNull() )
00678 {
00679 int res = callFunction( app, objid, function, params );
00680 retval = QMAX( retval, res );
00681 }
00682 }
00683 }
00684 else
00685 {
00686
00687
00688 int res = callFunction( app, objid, function, params );
00689 retval = QMAX( retval, res );
00690 }
00691 break;
00692 }
00693
00694 if( users.isEmpty() )
00695 break;
00696 }
00697
00698
00699 if( it == users.end() )
00700 break;
00701 }
00702
00703 return retval;
00704 }
00705
00706
00707 int main( int argc, char** argv )
00708 {
00709 bool readStdin = false;
00710 int numOptions = 0;
00711 QString user;
00712 Session session = DefaultSession;
00713 QString sessionName;
00714
00715 cin_.setEncoding( QTextStream::Locale );
00716
00717
00718 for( int pos = 1 ; pos <= argc - 1 ; pos++ )
00719 {
00720 if( strcmp( argv[ pos ], "--help" ) == 0 )
00721 showHelp( 0 );
00722 else if( strcmp( argv[ pos ], "--pipe" ) == 0 )
00723 {
00724 readStdin = true;
00725 numOptions++;
00726 }
00727 else if( strcmp( argv[ pos ], "--user" ) == 0 )
00728 {
00729 if( pos <= argc - 2 )
00730 {
00731 user = QString::fromLocal8Bit( argv[ pos + 1] );
00732 numOptions +=2;
00733 pos++;
00734 }
00735 else
00736 {
00737 cerr_ << "Missing username for '--user' option!" << endl << endl;
00738 showHelp( -1 );
00739 }
00740 }
00741 else if( strcmp( argv[ pos ], "--session" ) == 0 )
00742 {
00743 if( session == AllSessions )
00744 {
00745 cerr_ << "ERROR: --session cannot be mixed with --all-sessions!" << endl << endl;
00746 showHelp( -1 );
00747 }
00748 else if( pos <= argc - 2 )
00749 {
00750 sessionName = QString::fromLocal8Bit( argv[ pos + 1] );
00751 numOptions +=2;
00752 pos++;
00753 }
00754 else
00755 {
00756 cerr_ << "Missing session name for '--session' option!" << endl << endl;
00757 showHelp( -1 );
00758 }
00759 }
00760 else if( strcmp( argv[ pos ], "--all-users" ) == 0 )
00761 {
00762 user = "*";
00763 numOptions ++;
00764 }
00765 else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 )
00766 {
00767 session = QuerySessions;
00768 numOptions ++;
00769 }
00770 else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 )
00771 {
00772 if( !sessionName.isEmpty() )
00773 {
00774 cerr_ << "ERROR: --session cannot be mixed with --all-sessions!" << endl << endl;
00775 showHelp( -1 );
00776 }
00777 session = AllSessions;
00778 numOptions ++;
00779 }
00780 else if( argv[ pos ][ 0 ] == '-' )
00781 {
00782 cerr_ << "Unknown command-line option '" << argv[ pos ]
00783 << "'." << endl << endl;
00784 showHelp( -1 );
00785 }
00786 else
00787 break;
00788 }
00789
00790 argc -= numOptions;
00791
00792 QCStringList args;
00793 for( int i = numOptions; i < argc + numOptions - 1; i++ )
00794 args.append( argv[ i + 1 ] );
00795
00796 if( readStdin && args.count() < 3 )
00797 {
00798 cerr_ << "--pipe option only supported for function calls!" << endl << endl;
00799 showHelp( -1 );
00800 }
00801
00802 if( user == "*" && args.count() < 3 && session != QuerySessions )
00803 {
00804 cerr_ << "ERROR: The --all-users option is only supported for function calls!" << endl << endl;
00805 showHelp( -1 );
00806 }
00807
00808 if( session == QuerySessions && !args.isEmpty() )
00809 {
00810 cerr_ << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl;
00811 showHelp( -1 );
00812 }
00813
00814 if( session == QuerySessions && user.isEmpty() )
00815 {
00816 cerr_ << "ERROR: The --list-sessions option can only be used with the --user or" << endl
00817 << "--all-users options!" << endl << endl;
00818 showHelp( -1 );
00819 }
00820
00821 if( session != DefaultSession && session != QuerySessions &&
00822 args.count() < 3 )
00823 {
00824 cerr_ << "ERROR: The --session and --all-sessions options are only supported for function" << endl
00825 << "calls!" << endl << endl;
00826 showHelp( -1 );
00827 }
00828
00829 UserList users;
00830 if( user == "*" )
00831 users = userList();
00832 else if( !user.isEmpty() )
00833 users[ user ] = userList()[ user ];
00834
00835 int retval = runDCOP( args, users, session, sessionName, readStdin );
00836
00837 return retval;
00838 }
00839
00840
00841