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 <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.