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 iceFileBase =
"ICEauthority";
601 if (getenv(
"XDG_RUNTIME_DIR") != 0 )
603 TQFileInfo xdgRuntime(getenv(
"XDG_RUNTIME_DIR"));
604 passwd* pstruct = getpwnam(it.key().local8Bit());
607 iceFile = TQString(
"%1/%2/%3").arg(xdgRuntime.dirPath()).arg(pstruct->pw_uid).arg(iceFileBase);
610 if (!pstruct || !fi.exists())
612 iceFile = TQString::null;
615 if (iceFile.isEmpty())
617 iceFile = TQString(
"%1/.%2").arg(it.data()).arg(iceFileBase);
620 if( iceFile.isEmpty() )
622 cerr_ <<
"WARNING: Cannot determine home directory for user "
623 << it.key() <<
"!" << endl
624 <<
"Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
625 <<
"calling dcop." <<
endl;
627 else if( fi.exists() )
629 if( fi.isReadable() )
631 char *envStr = strdup( (
"ICEAUTHORITY=" + iceFile ).ascii() );
637 cerr_ <<
"WARNING: ICE authority file " << iceFile
638 <<
"is not readable by you!" << endl
639 <<
"Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
640 <<
"calling dcop." <<
endl;
645 if( users.count() > 1 )
649 cerr_ <<
"WARNING: Cannot find ICE authority file "
650 << iceFile <<
"!" << endl
651 <<
"Please check permissions or set the $ICEAUTHORITY"
652 <<
" variable manually before" << endl
653 <<
"calling dcop." <<
endl;
662 TQStringList::Iterator sIt = sessions.begin();
663 for( ; sIt != sessions.end() || users.isEmpty(); ++sIt )
665 if( !presetDCOPServer && !users.isEmpty() )
667 TQString dcopFile = it.data() +
"/" + *sIt;
668 TQFile f( dcopFile );
669 if( !f.open( IO_ReadOnly ) )
671 cerr_ <<
"Can't open " << dcopFile <<
" for reading!" <<
endl;
675 TQStringList l( TQStringList::split(
'\n', f.readAll() ) );
676 dcopServer = l.first();
678 if( dcopServer.isEmpty() )
680 cerr_ <<
"WARNING: Unable to determine DCOP server for session "
681 << *sIt <<
"!" << endl
682 <<
"Please check permissions or set the $DCOPSERVER variable manually before" << endl
683 <<
"calling dcop." <<
endl;
690 if( !dcopServer.isEmpty() )
692 bool success = client->
attach();
695 cerr_ <<
"ERROR: Couldn't attach to DCOP server!" <<
endl;
696 retval = TQMAX( retval, 1 );
697 if( users.isEmpty() )
704 int argscount = args.count();
710 queryApplications(
"");
713 if (endsWith(app,
'*'))
714 queryApplications(app);
716 queryObjects( app,
"" );
719 if (endsWith(objid,
'*'))
720 queryObjects(app, objid);
722 queryFunctions( app, objid );
730 QCStringList::Iterator replaceArg = params.end();
732 QCStringList::Iterator it = params.begin();
733 for( ; it != params.end(); ++it )
739 while ( !cin_.atEnd() )
741 TQString buf = cin_.readLine();
743 if( replaceArg != params.end() )
744 *replaceArg = buf.local8Bit();
748 int res = callFunction( app, objid,
function, params );
749 retval = TQMAX( retval, res );
757 int res = callFunction( app, objid,
function, params );
758 retval = TQMAX( retval, res );
763 if( users.isEmpty() )
768 if( it == users.end() )
776 # define main kdemain
779 int main(
int argc,
char** argv )
781 bool readStdin =
false;
784 Session session = DefaultSession;
785 TQString sessionName;
786 bool updateUserTime =
true;
788 cin_.setEncoding( TQTextStream::Locale );
791 for(
int pos = 1 ; pos <= argc - 1 ; pos++ )
793 if( strcmp( argv[ pos ],
"--help" ) == 0 )
795 else if( strcmp( argv[ pos ],
"--pipe" ) == 0 )
800 else if( strcmp( argv[ pos ],
"--user" ) == 0 )
802 if( pos <= argc - 2 )
804 user = TQString::fromLocal8Bit( argv[ pos + 1] );
810 cerr_ <<
"Missing username for '--user' option!" << endl <<
endl;
814 else if( strcmp( argv[ pos ],
"--session" ) == 0 )
816 if( session == AllSessions )
818 cerr_ <<
"ERROR: --session cannot be mixed with --all-sessions!" << endl <<
endl;
821 else if( pos <= argc - 2 )
823 sessionName = TQString::fromLocal8Bit( argv[ pos + 1] );
829 cerr_ <<
"Missing session name for '--session' option!" << endl <<
endl;
833 else if( strcmp( argv[ pos ],
"--all-users" ) == 0 )
838 else if( strcmp( argv[ pos ],
"--list-sessions" ) == 0 )
840 session = QuerySessions;
843 else if( strcmp( argv[ pos ],
"--all-sessions" ) == 0 )
845 if( !sessionName.isEmpty() )
847 cerr_ <<
"ERROR: --session cannot be mixed with --all-sessions!" << endl <<
endl;
850 session = AllSessions;
853 else if( strcmp( argv[ pos ],
"--no-user-time" ) == 0 )
855 updateUserTime =
false;
858 else if( argv[ pos ][ 0 ] ==
'-' )
860 cerr_ <<
"Unknown command-line option '" << argv[ pos ]
861 <<
"'." << endl <<
endl;
875 TQCString prog = argv[ numOptions + 1 ];
882 if (prog[prog.length()-1] !=
'*')
885 int i = prog.findRev(
'-');
886 if ((i >= 0) && prog.mid(i+1).toLong())
890 args.append(
"qt/"+prog );
891 args.append(
"quit()" );
896 for(
int i = numOptions; i < argc + numOptions - 1; i++ )
897 args.append( argv[ i + 1 ] );
900 if( readStdin && args.count() < 3 )
902 cerr_ <<
"--pipe option only supported for function calls!" << endl <<
endl;
906 if( user ==
"*" && args.count() < 3 && session != QuerySessions )
908 cerr_ <<
"ERROR: The --all-users option is only supported for function calls!" << endl <<
endl;
912 if( session == QuerySessions && !args.isEmpty() )
914 cerr_ <<
"ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl <<
endl;
918 if( session == QuerySessions && user.isEmpty() )
920 cerr_ <<
"ERROR: The --list-sessions option can only be used with the --user or" << endl
921 <<
"--all-users options!" << endl <<
endl;
925 if( session != DefaultSession && session != QuerySessions &&
928 cerr_ <<
"ERROR: The --session and --all-sessions options are only supported for function" << endl
929 <<
"calls!" << endl <<
endl;
936 else if( !user.isEmpty() )
937 users[ user ] = userList()[ user ];
939 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
where type is optional...
Inter-process communication and remote procedure calls for KDE applications.
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.
TQCString appId() const
Returns the current app id or a null string if the application hasn't yet been registered.
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.
bool isAttached() const
Returns whether or not the client is attached to the server.
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.