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 )
432 #if defined TQ_WS_X11 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 TQString xdgRuntimeDir = TQString::fromLocal8Bit(getenv(
"XDG_RUNTIME_DIR"));
602 if (xdgRuntimeDir.isEmpty())
604 xdgRuntimeDir =
"/run/user/<uid>";
606 if (!xdgRuntimeDir.isEmpty())
608 TQFileInfo xdgRuntime(xdgRuntimeDir);
609 passwd* pstruct = getpwnam(it.key().local8Bit());
612 iceFile = TQString(
"%1/%2/%3").arg(xdgRuntime.dirPath()).arg(pstruct->pw_uid).arg(iceFileBase);
615 if (!pstruct || !fi.exists())
617 iceFile = TQString::null;
620 if (iceFile.isEmpty())
622 iceFile = TQString(
"%1/.%2").arg(it.data()).arg(iceFileBase);
625 if (iceFile.isEmpty())
627 cerr_ <<
"WARNING: Cannot determine home directory for user " 628 << it.key() <<
"!" << endl
629 <<
"Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
630 <<
"calling dcop." <<
endl;
632 else if (fi.exists())
636 char *envStr = strdup((
"ICEAUTHORITY=" + iceFile).local8Bit());
642 cerr_ <<
"WARNING: ICE authority file " << iceFile
643 <<
"is not readable by you!" << endl
644 <<
"Please check permissions or set the $ICEAUTHORITY variable manually before" << endl
645 <<
"calling dcop." <<
endl;
650 if (users.count() > 1)
656 cerr_ <<
"WARNING: Cannot find ICE authority file " 657 << iceFile <<
"!" << endl
658 <<
"Please check permissions or set the $ICEAUTHORITY" 659 <<
" variable manually before" << endl
660 <<
"calling dcop." <<
endl;
669 TQStringList::Iterator sIt = sessions.begin();
670 for( ; sIt != sessions.end() || users.isEmpty(); ++sIt )
672 if( !presetDCOPServer && !users.isEmpty() )
674 TQString dcopFile = it.data() +
"/" + *sIt;
675 TQFile f( dcopFile );
676 if( !f.open( IO_ReadOnly ) )
678 cerr_ <<
"Can't open " << dcopFile <<
" for reading!" <<
endl;
682 TQStringList l( TQStringList::split(
'\n', f.readAll() ) );
683 dcopServer = l.first();
685 if( dcopServer.isEmpty() )
687 cerr_ <<
"WARNING: Unable to determine DCOP server for session " 688 << *sIt <<
"!" << endl
689 <<
"Please check permissions or set the $DCOPSERVER variable manually before" << endl
690 <<
"calling dcop." <<
endl;
697 if( !dcopServer.isEmpty() )
699 bool success = client->
attach();
702 cerr_ <<
"ERROR: Couldn't attach to DCOP server!" <<
endl;
703 retval = TQMAX( retval, 1 );
704 if( users.isEmpty() )
711 int argscount = args.count();
717 queryApplications(
"");
720 if (endsWith(app,
'*'))
721 queryApplications(app);
723 queryObjects( app,
"" );
726 if (endsWith(objid,
'*'))
727 queryObjects(app, objid);
729 queryFunctions( app, objid );
737 QCStringList::Iterator replaceArg = params.end();
739 QCStringList::Iterator it = params.begin();
740 for( ; it != params.end(); ++it )
746 while ( !cin_.atEnd() )
748 TQString buf = cin_.readLine();
750 if( replaceArg != params.end() )
751 *replaceArg = buf.local8Bit();
755 int res = callFunction( app, objid,
function, params );
756 retval = TQMAX( retval, res );
764 int res = callFunction( app, objid,
function, params );
765 retval = TQMAX( retval, res );
770 if( users.isEmpty() )
775 if( it == users.end() )
783 # define main kdemain 786 int main(
int argc,
char** argv )
788 bool readStdin =
false;
791 Session session = DefaultSession;
792 TQString sessionName;
793 bool updateUserTime =
true;
795 cin_.setEncoding( TQTextStream::Locale );
798 for(
int pos = 1 ; pos <= argc - 1 ; pos++ )
800 if( strcmp( argv[ pos ],
"--help" ) == 0 )
802 else if( strcmp( argv[ pos ],
"--pipe" ) == 0 )
807 else if( strcmp( argv[ pos ],
"--user" ) == 0 )
809 if( pos <= argc - 2 )
811 user = TQString::fromLocal8Bit( argv[ pos + 1] );
817 cerr_ <<
"Missing username for '--user' option!" << endl <<
endl;
821 else if( strcmp( argv[ pos ],
"--session" ) == 0 )
823 if( session == AllSessions )
825 cerr_ <<
"ERROR: --session cannot be mixed with --all-sessions!" << endl <<
endl;
828 else if( pos <= argc - 2 )
830 sessionName = TQString::fromLocal8Bit( argv[ pos + 1] );
836 cerr_ <<
"Missing session name for '--session' option!" << endl <<
endl;
840 else if( strcmp( argv[ pos ],
"--all-users" ) == 0 )
845 else if( strcmp( argv[ pos ],
"--list-sessions" ) == 0 )
847 session = QuerySessions;
850 else if( strcmp( argv[ pos ],
"--all-sessions" ) == 0 )
852 if( !sessionName.isEmpty() )
854 cerr_ <<
"ERROR: --session cannot be mixed with --all-sessions!" << endl <<
endl;
857 session = AllSessions;
860 else if( strcmp( argv[ pos ],
"--no-user-time" ) == 0 )
862 updateUserTime =
false;
865 else if( argv[ pos ][ 0 ] ==
'-' )
867 cerr_ <<
"Unknown command-line option '" << argv[ pos ]
868 <<
"'." << endl <<
endl;
882 TQCString prog = argv[ numOptions + 1 ];
889 if (prog[prog.length()-1] !=
'*')
892 int i = prog.findRev(
'-');
893 if ((i >= 0) && prog.mid(i+1).toLong())
897 args.append(
"qt/"+prog );
898 args.append(
"quit()" );
903 for(
int i = numOptions; i < argc + numOptions - 1; i++ )
904 args.append( argv[ i + 1 ] );
907 if( readStdin && args.count() < 3 )
909 cerr_ <<
"--pipe option only supported for function calls!" << endl <<
endl;
913 if( user ==
"*" && args.count() < 3 && session != QuerySessions )
915 cerr_ <<
"ERROR: The --all-users option is only supported for function calls!" << endl <<
endl;
919 if( session == QuerySessions && !args.isEmpty() )
921 cerr_ <<
"ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl <<
endl;
925 if( session == QuerySessions && user.isEmpty() )
927 cerr_ <<
"ERROR: The --list-sessions option can only be used with the --user or" << endl
928 <<
"--all-users options!" << endl <<
endl;
932 if( session != DefaultSession && session != QuerySessions &&
935 cerr_ <<
"ERROR: The --session and --all-sessions options are only supported for function" << endl
936 <<
"calls!" << endl <<
endl;
943 else if( !user.isEmpty() )
944 users[ user ] = userList()[ user ];
946 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.