27 #include <sys/types.h> 37 #include <tqfileinfo.h> 40 #include <tqstringlist.h> 41 #include <tqtextstream.h> 42 #include <tqvariant.h> 44 #include "../dcopclient.h" 45 #include "../dcopref.h" 46 #include "../kdatastream.h" 48 #include "marshall.cpp" 52 #include <X11/Xatom.h> 55 typedef TQMap<TQString, TQString> UserList;
59 static TQTextStream cin_ ( stdin, IO_ReadOnly );
60 static TQTextStream cout_( stdout, IO_WriteOnly );
61 static TQTextStream cerr_( stderr, IO_WriteOnly );
72 enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession };
74 bool startsWith(
const TQCString &
id,
const char *str,
int n)
76 return !n || (strncmp(
id.data(), str, n) == 0);
79 bool endsWith(TQCString &
id,
char c)
81 if (
id.length() && (
id[
id.length()-1] == c))
83 id.truncate(
id.length()-1);
89 void queryApplications(
const TQCString &filter)
91 int filterLen = filter.length();
93 for ( QCStringList::Iterator it = apps.begin(); it != apps.end(); ++it )
95 TQCString &clientId = *it;
96 if ( (clientId != dcop->
appId()) &&
97 !startsWith(clientId,
"anonymous",9) &&
98 startsWith(clientId, filter, filterLen)
100 printf(
"%s\n", clientId.data() );
105 tqWarning(
"server not accessible" );
110 void queryObjects(
const TQCString &app,
const TQCString &filter )
112 int filterLen = filter.length();
114 bool isDefault =
false;
116 for ( QCStringList::Iterator it = objs.begin(); it != objs.end(); ++it )
118 TQCString &objId = *it;
120 if (objId ==
"default")
126 if (startsWith(objId, filter, filterLen))
129 printf(
"%s (default)\n", objId.data() );
131 printf(
"%s\n", objId.data() );
138 tqWarning(
"No such application: '%s'", app.data());
140 tqWarning(
"Application '%s' not accessible", app.data() );
145 void queryFunctions(
const char* app,
const char* obj )
149 for ( QCStringList::Iterator it = funcs.begin(); it != funcs.end(); ++it ) {
150 printf(
"%s\n", (*it).data() );
154 tqWarning(
"object '%s' in application '%s' not accessible", obj, app );
159 int callFunction(
const char* app,
const char* obj,
const char* func,
const QCStringList args )
162 int left = f.find(
'(' );
163 int right = f.find(
')' );
167 tqWarning(
"parentheses do not match" );
176 if ( !ok && args.isEmpty() )
180 tqWarning(
"object not accessible" );
183 for ( QCStringList::Iterator it = funcs.begin(); it != funcs.end(); ++it ) {
184 int l = (*it).find(
'(' );
187 s = (*it).findRev(
' ', l);
189 s = (*it).find(
' ' );
196 if ( l > 0 && (*it).mid( s, l - s ) == func ) {
197 realfunc = (*it).mid( s );
198 const TQString arguments = (*it).mid(l+1,(*it).find(
')' )-l-1);
199 uint a = arguments.contains(
',');
200 if ( (a==0 && !arguments.isEmpty()) || a>0)
202 if ( a == args.count() )
206 if ( realfunc.isEmpty() )
208 tqWarning(
"no such function");
212 left = f.find(
'(' );
213 right = f.find(
')' );
224 TQStringList intTypes;
225 intTypes <<
"int" <<
"unsigned" <<
"long" <<
"bool" ;
228 if ( left >0 && left + 1 < right - 1) {
229 types = TQStringList::split(
',', f.mid( left + 1, right - left - 1) );
230 for ( TQStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
231 TQString lt = (*it).simplifyWhiteSpace();
233 int s = lt.find(
' ');
243 TQStringList partl = TQStringList::split(
' ' , lt);
253 while (s < static_cast<int>(partl.count()) && intTypes.contains(partl[s]))
258 if ( s < static_cast<int>(partl.count())-1)
260 tqWarning(
"The argument `%s' seems syntactically wrong.",
263 if ( s == static_cast<int>(partl.count())-1)
265 partl.remove(partl.at(s));
268 lt = partl.join(
" ");
269 lt = lt.simplifyWhiteSpace();
274 TQString fc = f.left( left );
277 for ( TQStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
287 TQByteArray data, replyData;
289 TQDataStream arg(data, IO_WriteOnly);
292 for( TQStringList::Iterator it = types.begin(); it != types.end(); ++it ) {
293 marshall( arg, args, i, *it );
296 if ( i != args.count() )
298 tqWarning(
"arguments do not match" );
302 if ( !dcop->
call( app, obj, f.latin1(), data, replyType, replyData) ) {
303 tqWarning(
"call failed");
306 TQDataStream reply(replyData, IO_ReadOnly);
308 if ( replyType !=
"void" && replyType !=
"ASYNC" )
310 TQCString replyString = demarshal( reply, replyType );
311 if ( !replyString.isEmpty() )
312 printf(
"%s\n", replyString.data() );
323 void showHelp(
int exitCode = 0 )
326 cout_ <<
"Usage: dcopquit [options] [application]" <<
endl 328 cout_ <<
"Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" <<
endl 331 <<
"Console DCOP client" <<
endl 333 <<
"Generic options:" <<
endl 334 <<
" --help Show help about options" <<
endl 336 <<
"Options:" <<
endl 337 <<
" --pipe Call DCOP for each line read from stdin. The string '%1'" <<
endl 338 <<
" will be used in the argument list as a placeholder for" <<
endl 339 <<
" the substituted line." <<
endl 340 <<
" For example," <<
endl 341 <<
" dcop --pipe konqueror html-widget1 evalJS %1" <<
endl 342 <<
" is equivalent to calling" <<
endl 343 <<
" while read line ; do" <<
endl 344 <<
" dcop konqueror html-widget1 evalJS \"$line\"" <<
endl 346 <<
" in bash, but because no new dcop instance has to be started" <<
endl 347 <<
" for each line this is generally much faster, especially for" <<
endl 348 <<
" the slower GNU dynamic linkers." <<
endl 349 <<
" The '%1' placeholder cannot be used to replace e.g. the" <<
endl 350 <<
" program, object or method name." <<
endl 351 <<
" --user <user> Connect to the given user's DCOP server. This option will" <<
endl 352 <<
" ignore the values of the environment vars $DCOPSERVER and" <<
endl 353 <<
" $ICEAUTHORITY, even if they are set." <<
endl 354 <<
" If the user has more than one open session, you must also" <<
endl 355 <<
" use one of the --list-sessions, --session or --all-sessions" <<
endl 356 <<
" command-line options." <<
endl 357 <<
" --all-users Send the same DCOP call to all users with a running DCOP" <<
endl 358 <<
" server. Only failed calls to existing DCOP servers will" <<
endl 359 <<
" generate an error message. If no DCOP server is available" <<
endl 360 <<
" at all, no error will be generated." <<
endl 361 <<
" --session <ses> Send to the given TDE session. This option can only be" <<
endl 362 <<
" used in combination with the --user option." <<
endl 363 <<
" --all-sessions Send to all sessions found. Only works with the --user" <<
endl 364 <<
" and --all-users options." <<
endl 365 <<
" --list-sessions List all active TDE session for a user or all users." <<
endl 366 <<
" --no-user-time Don't update the user activity timestamp in the called" <<
endl 367 <<
" application (for usage in scripts running" <<
endl 368 <<
" in the background)." <<
endl 378 static UserList userList()
382 while( passwd* pstruct = getpwent() )
384 result[ TQString::fromLocal8Bit(pstruct->pw_name) ] = TQFile::decodeName(pstruct->pw_dir);
394 TQStringList dcopSessionList(
const TQString &user,
const TQString &home )
398 cerr_ <<
"WARNING: Cannot determine home directory for user " 399 << user <<
"!" <<
endl 400 <<
"Please check permissions or set the $DCOPSERVER variable manually before" <<
endl 401 <<
"calling dcop." <<
endl;
402 return TQStringList();
406 TQFileInfo dirInfo( home );
407 if( !dirInfo.exists() || !dirInfo.isReadable() )
411 d.setFilter( TQDir::Files | TQDir::Hidden | TQDir::NoSymLinks );
412 d.setNameFilter(
".DCOPserver*" );
414 const TQFileInfoList *list = d.entryInfoList();
418 TQFileInfoListIterator it( *list );
421 while ( ( fi = it.current() ) != 0 )
423 if( fi->isReadable() )
424 result.append( fi->fileName() );
430 void sendUserTime(
const char* app )
433 static unsigned long time = 0;
436 Display* dpy = XOpenDisplay( NULL );
439 Window w = XCreateSimpleWindow( dpy, DefaultRootWindow( dpy ), 0, 0, 1, 1, 0, 0, 0 );
440 XSelectInput( dpy, w, PropertyChangeMask );
441 unsigned char data[ 1 ];
442 XChangeProperty( dpy, w, XA_ATOM, XA_ATOM, 8, PropModeAppend, data, 1 );
444 XWindowEvent( dpy, w, PropertyChangeMask, &ev );
445 time = ev.xproperty.time;
446 XDestroyWindow( dpy, w );
449 DCOPRef( app,
"MainApplication-Interface" ).
call(
"updateUserTimestamp", time );
458 int runDCOP( QCStringList args, UserList users, Session session,
459 const TQString sessionName,
bool readStdin,
bool updateUserTime )
461 bool DCOPrefmode=
false;
468 if ( !args.isEmpty() && args[ 0 ].find(
"DCOPRef(" ) == 0 )
470 int delimPos = args[ 0 ].findRev(
',' );
473 cerr_ <<
"Error: '" << args[ 0 ]
474 <<
"' is not a valid DCOP reference." <<
endl;
477 app = args[ 0 ].mid( 8, delimPos-8 );
479 objid = args[ 0 ].mid( delimPos, args[ 0 ].length()-delimPos-1 );
480 if( args.count() > 1 )
481 function = args[ 1 ];
482 if( args.count() > 2 )
485 params.remove( params.begin() );
486 params.remove( params.begin() );
492 if( !args.isEmpty() )
494 if( args.count() > 1 )
496 if( args.count() > 2 )
497 function = args[ 2 ];
498 if( args.count() > 3)
501 params.remove( params.begin() );
502 params.remove( params.begin() );
503 params.remove( params.begin() );
507 bool firstRun =
true;
508 UserList::Iterator it;
509 TQStringList sessions;
510 bool presetDCOPServer =
false;
514 for( it = users.begin(); it != users.end() || firstRun; ++it )
520 if( session == QuerySessions )
522 TQStringList sessions = dcopSessionList( it.key(), it.data() );
523 if( sessions.isEmpty() )
525 if( users.count() <= 1 )
527 cout_ <<
"No active sessions";
528 if( !( *it ).isEmpty() )
529 cout_ <<
" for user " << *it;
535 cout_ <<
"Active sessions ";
536 if( !( *it ).isEmpty() )
537 cout_ <<
"for user " << *it <<
" ";
538 cout_ <<
":" <<
endl;
540 TQStringList::Iterator sIt = sessions.begin();
541 for( ; sIt != sessions.end(); ++sIt )
542 cout_ <<
" " << *sIt << endl;
549 if( getenv(
"DCOPSERVER" ) )
551 sessions.append( getenv(
"DCOPSERVER" ) );
552 presetDCOPServer =
true;
555 if( users.count() > 1 || ( users.count() == 1 &&
556 ( getenv(
"DCOPSERVER" ) == 0 ) ) )
558 sessions = dcopSessionList( it.key(), it.data() );
559 if( sessions.isEmpty() )
561 if( users.count() > 1 )
565 cerr_ <<
"ERROR: No active TDE sessions!" << endl
566 <<
"If you are sure there is one, please set the $DCOPSERVER variable manually" << endl
567 <<
"before calling dcop." <<
endl;
571 else if( !sessionName.isEmpty() )
573 if( sessions.contains( sessionName ) )
576 sessions.append( sessionName );
580 cerr_ <<
"ERROR: The specified session doesn't exist!" <<
endl;
584 else if( sessions.count() > 1 && session != AllSessions )
586 cerr_ <<
"ERROR: Multiple available TDE sessions!" << endl
587 <<
"Please specify the correct session to use with --session or use the" << endl
588 <<
"--all-sessions option to broadcast to all sessions." <<
endl;
593 if( users.count() > 1 || ( users.count() == 1 &&
594 ( getenv(
"ICEAUTHORITY" ) == 0 || getenv(
"DISPLAY" ) == 0 ) ) )
597 TQString home = it.data();
598 TQString iceFile = it.data() +
"/.ICEauthority";
599 TQFileInfo fi( iceFile );
600 if( iceFile.isEmpty() )
602 cerr_ <<
"WARNING: Cannot determine home directory for user " 603 << it.key() <<
"!" << endl
604 <<
"Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
605 <<
"calling dcop." <<
endl;
607 else if( fi.exists() )
609 if( fi.isReadable() )
611 char *envStr = strdup( (
"ICEAUTHORITY=" + iceFile ).ascii() );
617 cerr_ <<
"WARNING: ICE authority file " << iceFile
618 <<
"is not readable by you!" << endl
619 <<
"Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
620 <<
"calling dcop." <<
endl;
625 if( users.count() > 1 )
629 cerr_ <<
"WARNING: Cannot find ICE authority file " 630 << iceFile <<
"!" << endl
631 <<
"Please check permissions or set the $ICEAUTHORITY" 632 <<
" variable manually before" << endl
633 <<
"calling dcop." <<
endl;
642 TQStringList::Iterator sIt = sessions.begin();
643 for( ; sIt != sessions.end() || users.isEmpty(); ++sIt )
645 if( !presetDCOPServer && !users.isEmpty() )
647 TQString dcopFile = it.data() +
"/" + *sIt;
648 TQFile f( dcopFile );
649 if( !f.open( IO_ReadOnly ) )
651 cerr_ <<
"Can't open " << dcopFile <<
" for reading!" <<
endl;
655 TQStringList l( TQStringList::split(
'\n', f.readAll() ) );
656 dcopServer = l.first();
658 if( dcopServer.isEmpty() )
660 cerr_ <<
"WARNING: Unable to determine DCOP server for session " 661 << *sIt <<
"!" << endl
662 <<
"Please check permissions or set the $DCOPSERVER variable manually before" << endl
663 <<
"calling dcop." <<
endl;
670 if( !dcopServer.isEmpty() )
672 bool success = client->
attach();
675 cerr_ <<
"ERROR: Couldn't attach to DCOP server!" <<
endl;
676 retval = TQMAX( retval, 1 );
677 if( users.isEmpty() )
684 int argscount = args.count();
690 queryApplications(
"");
693 if (endsWith(app,
'*'))
694 queryApplications(app);
696 queryObjects( app,
"" );
699 if (endsWith(objid,
'*'))
700 queryObjects(app, objid);
702 queryFunctions( app, objid );
710 QCStringList::Iterator replaceArg = params.end();
712 QCStringList::Iterator it = params.begin();
713 for( ; it != params.end(); ++it )
719 while ( !cin_.atEnd() )
721 TQString buf = cin_.readLine();
723 if( replaceArg != params.end() )
724 *replaceArg = buf.local8Bit();
728 int res = callFunction( app, objid,
function, params );
729 retval = TQMAX( retval, res );
737 int res = callFunction( app, objid,
function, params );
738 retval = TQMAX( retval, res );
743 if( users.isEmpty() )
748 if( it == users.end() )
756 # define main kdemain 759 int main(
int argc,
char** argv )
761 bool readStdin =
false;
764 Session session = DefaultSession;
765 TQString sessionName;
766 bool updateUserTime =
true;
768 cin_.setEncoding( TQTextStream::Locale );
771 for(
int pos = 1 ; pos <= argc - 1 ; pos++ )
773 if( strcmp( argv[ pos ],
"--help" ) == 0 )
775 else if( strcmp( argv[ pos ],
"--pipe" ) == 0 )
780 else if( strcmp( argv[ pos ],
"--user" ) == 0 )
782 if( pos <= argc - 2 )
784 user = TQString::fromLocal8Bit( argv[ pos + 1] );
790 cerr_ <<
"Missing username for '--user' option!" << endl <<
endl;
794 else if( strcmp( argv[ pos ],
"--session" ) == 0 )
796 if( session == AllSessions )
798 cerr_ <<
"ERROR: --session cannot be mixed with --all-sessions!" << endl <<
endl;
801 else if( pos <= argc - 2 )
803 sessionName = TQString::fromLocal8Bit( argv[ pos + 1] );
809 cerr_ <<
"Missing session name for '--session' option!" << endl <<
endl;
813 else if( strcmp( argv[ pos ],
"--all-users" ) == 0 )
818 else if( strcmp( argv[ pos ],
"--list-sessions" ) == 0 )
820 session = QuerySessions;
823 else if( strcmp( argv[ pos ],
"--all-sessions" ) == 0 )
825 if( !sessionName.isEmpty() )
827 cerr_ <<
"ERROR: --session cannot be mixed with --all-sessions!" << endl <<
endl;
830 session = AllSessions;
833 else if( strcmp( argv[ pos ],
"--no-user-time" ) == 0 )
835 updateUserTime =
false;
838 else if( argv[ pos ][ 0 ] ==
'-' )
840 cerr_ <<
"Unknown command-line option '" << argv[ pos ]
841 <<
"'." << endl <<
endl;
855 TQCString prog = argv[ numOptions + 1 ];
862 if (prog[prog.length()-1] !=
'*')
865 int i = prog.findRev(
'-');
866 if ((i >= 0) && prog.mid(i+1).toLong())
870 args.append(
"qt/"+prog );
871 args.append(
"quit()" );
876 for(
int i = numOptions; i < argc + numOptions - 1; i++ )
877 args.append( argv[ i + 1 ] );
880 if( readStdin && args.count() < 3 )
882 cerr_ <<
"--pipe option only supported for function calls!" << endl <<
endl;
886 if( user ==
"*" && args.count() < 3 && session != QuerySessions )
888 cerr_ <<
"ERROR: The --all-users option is only supported for function calls!" << endl <<
endl;
892 if( session == QuerySessions && !args.isEmpty() )
894 cerr_ <<
"ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl <<
endl;
898 if( session == QuerySessions && user.isEmpty() )
900 cerr_ <<
"ERROR: The --list-sessions option can only be used with the --user or" << endl
901 <<
"--all-users options!" << endl <<
endl;
905 if( session != DefaultSession && session != QuerySessions &&
908 cerr_ <<
"ERROR: The --session and --all-sessions options are only supported for function" << endl
909 <<
"calls!" << endl <<
endl;
916 else if( !user.isEmpty() )
917 users[ user ] = userList()[ user ];
919 int retval = runDCOP( args, users, session, sessionName, readStdin, updateUserTime );
static void setServerAddress(const TQCString &addr)
Sets the address of a server to use upon attaching.
bool isApplicationRegistered(const TQCString &remApp)
Checks whether remApp is registered with the DCOP server.
bool attach()
Attaches to the DCOP server.
A DCOPRef(erence) encapsulates a remote DCOP object as a triple <app,obj,type> where type is optional...
Inter-process communication and remote procedure calls for KDE applications.
bool isAttached() const
Returns whether or not the client is attached to the server.
TQCString appId() const
Returns the current app id or a null string if the application hasn't yet been registered.
QCStringList registeredApplications()
Retrieves the list of all currently registered applications from dcopserver.
DCOPReply call(const TQCString &fun)
Calls the function fun on the object referenced by this reference.
QCStringList remoteFunctions(const TQCString &remApp, const TQCString &remObj, bool *ok=0)
Retrieves the list of functions of the remote object remObj of application remApp.
QCStringList remoteObjects(const TQCString &remApp, bool *ok=0)
Retrieves the list of objects of the remote application remApp.
kndbgstream & endl(kndbgstream &s)
bool call(const TQCString &remApp, const TQCString &remObj, const TQCString &remFun, const TQByteArray &data, TQCString &replyType, TQByteArray &replyData, bool useEventLoop, int timeout, bool forceRemote)
Performs a synchronous send and receive.