dcop.cpp
00001 /***************************************************************** 00002 Copyright (c) 2000 Matthias Ettrich <ettrich@kde.org> 00003 00004 Permission is hereby granted, free of charge, to any person obtaining a copy 00005 of this software and associated documentation files (the "Software"), to deal 00006 in the Software without restriction, including without limitation the rights 00007 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00008 copies of the Software, and to permit persons to whom the Software is 00009 furnished to do so, subject to the following conditions: 00010 00011 The above copyright notice and this permission notice shall be included in 00012 all copies or substantial portions of the Software. 00013 00014 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00015 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00016 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00017 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 00018 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00019 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00020 00021 ******************************************************************/ 00022 00023 // putenv() is not available on all platforms, so make sure the emulation 00024 // wrapper is available in those cases by loading config.h! 00025 #include <config.h> 00026 00027 #include <sys/types.h> 00028 #include <pwd.h> 00029 #include <ctype.h> 00030 #include <stdio.h> 00031 #include <stdlib.h> 00032 00033 #include <tqbuffer.h> 00034 #include <tqcolor.h> 00035 #include <tqdir.h> 00036 #include <tqfile.h> 00037 #include <tqfileinfo.h> 00038 #include <tqimage.h> 00039 #include <tqmap.h> 00040 #include <tqstringlist.h> 00041 #include <tqtextstream.h> 00042 #include <tqvariant.h> 00043 00044 #include "../dcopclient.h" 00045 #include "../dcopref.h" 00046 #include "../kdatastream.h" 00047 00048 #include "marshall.cpp" 00049 00050 #if defined Q_WS_X11 00051 #include <X11/Xlib.h> 00052 #include <X11/Xatom.h> 00053 #endif 00054 00055 typedef TQMap<TQString, TQString> UserList; 00056 00057 static DCOPClient* dcop = 0; 00058 00059 static TQTextStream cin_ ( stdin, IO_ReadOnly ); 00060 static TQTextStream cout_( stdout, IO_WriteOnly ); 00061 static TQTextStream cerr_( stderr, IO_WriteOnly ); 00062 00072 enum Session { DefaultSession = 0, AllSessions, QuerySessions, CustomSession }; 00073 00074 bool startsWith(const TQCString &id, const char *str, int n) 00075 { 00076 return !n || (strncmp(id.data(), str, n) == 0); 00077 } 00078 00079 bool endsWith(TQCString &id, char c) 00080 { 00081 if (id.length() && (id[id.length()-1] == c)) 00082 { 00083 id.truncate(id.length()-1); 00084 return true; 00085 } 00086 return false; 00087 } 00088 00089 void queryApplications(const TQCString &filter) 00090 { 00091 int filterLen = filter.length(); 00092 QCStringList apps = dcop->registeredApplications(); 00093 for ( QCStringList::Iterator it = apps.begin(); it != apps.end(); ++it ) 00094 { 00095 TQCString &clientId = *it; 00096 if ( (clientId != dcop->appId()) && 00097 !startsWith(clientId, "anonymous",9) && 00098 startsWith(clientId, filter, filterLen) 00099 ) 00100 printf( "%s\n", clientId.data() ); 00101 } 00102 00103 if ( !dcop->isAttached() ) 00104 { 00105 qWarning( "server not accessible" ); 00106 exit(1); 00107 } 00108 } 00109 00110 void queryObjects( const TQCString &app, const TQCString &filter ) 00111 { 00112 int filterLen = filter.length(); 00113 bool ok = false; 00114 bool isDefault = false; 00115 QCStringList objs = dcop->remoteObjects( app, &ok ); 00116 for ( QCStringList::Iterator it = objs.begin(); it != objs.end(); ++it ) 00117 { 00118 TQCString &objId = *it; 00119 00120 if (objId == "default") 00121 { 00122 isDefault = true; 00123 continue; 00124 } 00125 00126 if (startsWith(objId, filter, filterLen)) 00127 { 00128 if (isDefault) 00129 printf( "%s (default)\n", objId.data() ); 00130 else 00131 printf( "%s\n", objId.data() ); 00132 } 00133 isDefault = false; 00134 } 00135 if ( !ok ) 00136 { 00137 if (!dcop->isApplicationRegistered(app)) 00138 qWarning( "No such application: '%s'", app.data()); 00139 else 00140 qWarning( "Application '%s' not accessible", app.data() ); 00141 exit(1); 00142 } 00143 } 00144 00145 void queryFunctions( const char* app, const char* obj ) 00146 { 00147 bool ok = false; 00148 QCStringList funcs = dcop->remoteFunctions( app, obj, &ok ); 00149 for ( QCStringList::Iterator it = funcs.begin(); it != funcs.end(); ++it ) { 00150 printf( "%s\n", (*it).data() ); 00151 } 00152 if ( !ok ) 00153 { 00154 qWarning( "object '%s' in application '%s' not accessible", obj, app ); 00155 exit( 1 ); 00156 } 00157 } 00158 00159 int callFunction( const char* app, const char* obj, const char* func, const QCStringList args ) 00160 { 00161 TQString f = func; // Qt is better with unicode strings, so use one. 00162 int left = f.find( '(' ); 00163 int right = f.find( ')' ); 00164 00165 if ( right < left ) 00166 { 00167 qWarning( "parentheses do not match" ); 00168 return( 1 ); 00169 } 00170 00171 if ( left < 0 ) { 00172 // try to get the interface from the server 00173 bool ok = false; 00174 QCStringList funcs = dcop->remoteFunctions( app, obj, &ok ); 00175 TQCString realfunc; 00176 if ( !ok && args.isEmpty() ) 00177 goto doit; 00178 if ( !ok ) 00179 { 00180 qWarning( "object not accessible" ); 00181 return( 1 ); 00182 } 00183 for ( QCStringList::Iterator it = funcs.begin(); it != funcs.end(); ++it ) { 00184 int l = (*it).find( '(' ); 00185 int s; 00186 if (l > 0) 00187 s = (*it).findRev( ' ', l); 00188 else 00189 s = (*it).find( ' ' ); 00190 00191 if ( s < 0 ) 00192 s = 0; 00193 else 00194 s++; 00195 00196 if ( l > 0 && (*it).mid( s, l - s ) == func ) { 00197 realfunc = (*it).mid( s ); 00198 const TQString arguments = (*it).mid(l+1,(*it).find( ')' )-l-1); 00199 uint a = arguments.contains(','); 00200 if ( (a==0 && !arguments.isEmpty()) || a>0) 00201 a++; 00202 if ( a == args.count() ) 00203 break; 00204 } 00205 } 00206 if ( realfunc.isEmpty() ) 00207 { 00208 qWarning("no such function"); 00209 return( 1 ); 00210 } 00211 f = realfunc; 00212 left = f.find( '(' ); 00213 right = f.find( ')' ); 00214 } 00215 00216 doit: 00217 if ( left < 0 ) 00218 f += "()"; 00219 00220 // This may seem expensive but is done only once per invocation 00221 // of dcop, so it should be OK. 00222 // 00223 // 00224 TQStringList intTypes; 00225 intTypes << "int" << "unsigned" << "long" << "bool" ; 00226 00227 TQStringList types; 00228 if ( left >0 && left + 1 < right - 1) { 00229 types = TQStringList::split( ',', f.mid( left + 1, right - left - 1) ); 00230 for ( TQStringList::Iterator it = types.begin(); it != types.end(); ++it ) { 00231 TQString lt = (*it).simplifyWhiteSpace(); 00232 00233 int s = lt.find(' '); 00234 00235 // If there are spaces in the name, there may be two 00236 // reasons: the parameter name is still there, ie. 00237 // "TQString URL" or it's a complicated int type, ie. 00238 // "unsigned long long int bool". 00239 // 00240 // 00241 if ( s > 0 ) 00242 { 00243 TQStringList partl = TQStringList::split(' ' , lt); 00244 00245 // The zero'th part is -- at the very least -- a 00246 // type part. Any trailing parts *might* be extra 00247 // int-type keywords, or at most one may be the 00248 // parameter name. 00249 // 00250 // 00251 s=1; 00252 00253 while (s < static_cast<int>(partl.count()) && intTypes.contains(partl[s])) 00254 { 00255 s++; 00256 } 00257 00258 if ( s < static_cast<int>(partl.count())-1) 00259 { 00260 qWarning("The argument `%s' seems syntactically wrong.", 00261 lt.latin1()); 00262 } 00263 if ( s == static_cast<int>(partl.count())-1) 00264 { 00265 partl.remove(partl.at(s)); 00266 } 00267 00268 lt = partl.join(" "); 00269 lt = lt.simplifyWhiteSpace(); 00270 } 00271 00272 (*it) = lt; 00273 } 00274 TQString fc = f.left( left ); 00275 fc += '('; 00276 bool first = true; 00277 for ( TQStringList::Iterator it = types.begin(); it != types.end(); ++it ) { 00278 if ( !first ) 00279 fc +=","; 00280 first = false; 00281 fc += *it; 00282 } 00283 fc += ')'; 00284 f = fc; 00285 } 00286 00287 TQByteArray data, replyData; 00288 TQCString replyType; 00289 TQDataStream arg(data, IO_WriteOnly); 00290 00291 uint i = 0; 00292 for( TQStringList::Iterator it = types.begin(); it != types.end(); ++it ) { 00293 marshall( arg, args, i, *it ); 00294 } 00295 00296 if ( i != args.count() ) 00297 { 00298 qWarning( "arguments do not match" ); 00299 return( 1 ); 00300 } 00301 00302 if ( !dcop->call( app, obj, f.latin1(), data, replyType, replyData) ) { 00303 qWarning( "call failed"); 00304 return( 1 ); 00305 } else { 00306 TQDataStream reply(replyData, IO_ReadOnly); 00307 00308 if ( replyType != "void" && replyType != "ASYNC" ) 00309 { 00310 TQCString replyString = demarshal( reply, replyType ); 00311 if ( !replyString.isEmpty() ) 00312 printf( "%s\n", replyString.data() ); 00313 else 00314 printf("\n"); 00315 } 00316 } 00317 return 0; 00318 } 00319 00323 void showHelp( int exitCode = 0 ) 00324 { 00325 #ifdef DCOPQUIT 00326 cout_ << "Usage: dcopquit [options] [application]" << endl 00327 #else 00328 cout_ << "Usage: dcop [options] [application [object [function [arg1] [arg2] ... ] ] ]" << endl 00329 #endif 00330 << "" << endl 00331 << "Console DCOP client" << endl 00332 << "" << endl 00333 << "Generic options:" << endl 00334 << " --help Show help about options" << endl 00335 << "" << endl 00336 << "Options:" << endl 00337 << " --pipe Call DCOP for each line read from stdin. The string '%1'" << endl 00338 << " will be used in the argument list as a placeholder for" << endl 00339 << " the substituted line." << endl 00340 << " For example," << endl 00341 << " dcop --pipe konqueror html-widget1 evalJS %1" << endl 00342 << " is equivalent to calling" << endl 00343 << " while read line ; do" << endl 00344 << " dcop konqueror html-widget1 evalJS \"$line\"" << endl 00345 << " done" << endl 00346 << " in bash, but because no new dcop instance has to be started" << endl 00347 << " for each line this is generally much faster, especially for" << endl 00348 << " the slower GNU dynamic linkers." << endl 00349 << " The '%1' placeholder cannot be used to replace e.g. the" << endl 00350 << " program, object or method name." << endl 00351 << " --user <user> Connect to the given user's DCOP server. This option will" << endl 00352 << " ignore the values of the environment vars $DCOPSERVER and" << endl 00353 << " $ICEAUTHORITY, even if they are set." << endl 00354 << " If the user has more than one open session, you must also" << endl 00355 << " use one of the --list-sessions, --session or --all-sessions" << endl 00356 << " command-line options." << endl 00357 << " --all-users Send the same DCOP call to all users with a running DCOP" << endl 00358 << " server. Only failed calls to existing DCOP servers will" << endl 00359 << " generate an error message. If no DCOP server is available" << endl 00360 << " at all, no error will be generated." << endl 00361 << " --session <ses> Send to the given KDE session. This option can only be" << endl 00362 << " used in combination with the --user option." << endl 00363 << " --all-sessions Send to all sessions found. Only works with the --user" << endl 00364 << " and --all-users options." << endl 00365 << " --list-sessions List all active KDE session for a user or all users." << endl 00366 << " --no-user-time Don't update the user activity timestamp in the called" << endl 00367 << " application (for usage in scripts running" << endl 00368 << " in the background)." << endl 00369 << endl; 00370 00371 exit( exitCode ); 00372 } 00373 00378 static UserList userList() 00379 { 00380 UserList result; 00381 00382 while( passwd* pstruct = getpwent() ) 00383 { 00384 result[ TQString::fromLocal8Bit(pstruct->pw_name) ] = TQFile::decodeName(pstruct->pw_dir); 00385 } 00386 00387 return result; 00388 } 00389 00394 TQStringList dcopSessionList( const TQString &user, const TQString &home ) 00395 { 00396 if( home.isEmpty() ) 00397 { 00398 cerr_ << "WARNING: Cannot determine home directory for user " 00399 << user << "!" << endl 00400 << "Please check permissions or set the $DCOPSERVER variable manually before" << endl 00401 << "calling dcop." << endl; 00402 return TQStringList(); 00403 } 00404 00405 TQStringList result; 00406 TQFileInfo dirInfo( home ); 00407 if( !dirInfo.exists() || !dirInfo.isReadable() ) 00408 return result; 00409 00410 TQDir d( home ); 00411 d.setFilter( TQDir::Files | TQDir::Hidden | TQDir::NoSymLinks ); 00412 d.setNameFilter( ".DCOPserver*" ); 00413 00414 const TQFileInfoList *list = d.entryInfoList(); 00415 if( !list ) 00416 return result; 00417 00418 TQFileInfoListIterator it( *list ); 00419 TQFileInfo *fi; 00420 00421 while ( ( fi = it.current() ) != 0 ) 00422 { 00423 if( fi->isReadable() ) 00424 result.append( fi->fileName() ); 00425 ++it; 00426 } 00427 return result; 00428 } 00429 00430 void sendUserTime( const char* app ) 00431 { 00432 #if defined Q_WS_X11 00433 static unsigned long time = 0; 00434 if( time == 0 ) 00435 { 00436 Display* dpy = XOpenDisplay( NULL ); 00437 if( dpy != NULL ) 00438 { 00439 Window w = XCreateSimpleWindow( dpy, DefaultRootWindow( dpy ), 0, 0, 1, 1, 0, 0, 0 ); 00440 XSelectInput( dpy, w, PropertyChangeMask ); 00441 unsigned char data[ 1 ]; 00442 XChangeProperty( dpy, w, XA_ATOM, XA_ATOM, 8, PropModeAppend, data, 1 ); 00443 XEvent ev; 00444 XWindowEvent( dpy, w, PropertyChangeMask, &ev ); 00445 time = ev.xproperty.time; 00446 XDestroyWindow( dpy, w ); 00447 } 00448 } 00449 DCOPRef( app, "MainApplication-Interface" ).call( "updateUserTimestamp", time ); 00450 #else 00451 // ... 00452 #endif 00453 } 00454 00458 int runDCOP( QCStringList args, UserList users, Session session, 00459 const TQString sessionName, bool readStdin, bool updateUserTime ) 00460 { 00461 bool DCOPrefmode=false; 00462 TQCString app; 00463 TQCString objid; 00464 TQCString function; 00465 QCStringList params; 00466 DCOPClient *client = 0L; 00467 int retval = 0; 00468 if ( !args.isEmpty() && args[ 0 ].find( "DCOPRef(" ) == 0 ) 00469 { 00470 int delimPos = args[ 0 ].findRev( ',' ); 00471 if( delimPos == -1 ) 00472 { 00473 cerr_ << "Error: '" << args[ 0 ] 00474 << "' is not a valid DCOP reference." << endl; 00475 exit( -1 ); 00476 } 00477 app = args[ 0 ].mid( 8, delimPos-8 ); 00478 delimPos++; 00479 objid = args[ 0 ].mid( delimPos, args[ 0 ].length()-delimPos-1 ); 00480 if( args.count() > 1 ) 00481 function = args[ 1 ]; 00482 if( args.count() > 2 ) 00483 { 00484 params = args; 00485 params.remove( params.begin() ); 00486 params.remove( params.begin() ); 00487 } 00488 DCOPrefmode=true; 00489 } 00490 else 00491 { 00492 if( !args.isEmpty() ) 00493 app = args[ 0 ]; 00494 if( args.count() > 1 ) 00495 objid = args[ 1 ]; 00496 if( args.count() > 2 ) 00497 function = args[ 2 ]; 00498 if( args.count() > 3) 00499 { 00500 params = args; 00501 params.remove( params.begin() ); 00502 params.remove( params.begin() ); 00503 params.remove( params.begin() ); 00504 } 00505 } 00506 00507 bool firstRun = true; 00508 UserList::Iterator it; 00509 TQStringList sessions; 00510 bool presetDCOPServer = false; 00511 // char *dcopStr = 0L; 00512 TQString dcopServer; 00513 00514 for( it = users.begin(); it != users.end() || firstRun; ++it ) 00515 { 00516 firstRun = false; 00517 00518 //cout_ << "Iterating '" << it.key() << "'" << endl; 00519 00520 if( session == QuerySessions ) 00521 { 00522 TQStringList sessions = dcopSessionList( it.key(), it.data() ); 00523 if( sessions.isEmpty() ) 00524 { 00525 if( users.count() <= 1 ) 00526 { 00527 cout_ << "No active sessions"; 00528 if( !( *it ).isEmpty() ) 00529 cout_ << " for user " << *it; 00530 cout_ << endl; 00531 } 00532 } 00533 else 00534 { 00535 cout_ << "Active sessions "; 00536 if( !( *it ).isEmpty() ) 00537 cout_ << "for user " << *it << " "; 00538 cout_ << ":" << endl; 00539 00540 TQStringList::Iterator sIt = sessions.begin(); 00541 for( ; sIt != sessions.end(); ++sIt ) 00542 cout_ << " " << *sIt << endl; 00543 00544 cout_ << endl; 00545 } 00546 continue; 00547 } 00548 00549 if( getenv( "DCOPSERVER" ) ) 00550 { 00551 sessions.append( getenv( "DCOPSERVER" ) ); 00552 presetDCOPServer = true; 00553 } 00554 00555 if( users.count() > 1 || ( users.count() == 1 && 00556 ( getenv( "DCOPSERVER" ) == 0 /*&& getenv( "DISPLAY" ) == 0*/ ) ) ) 00557 { 00558 sessions = dcopSessionList( it.key(), it.data() ); 00559 if( sessions.isEmpty() ) 00560 { 00561 if( users.count() > 1 ) 00562 continue; 00563 else 00564 { 00565 cerr_ << "ERROR: No active KDE sessions!" << endl 00566 << "If you are sure there is one, please set the $DCOPSERVER variable manually" << endl 00567 << "before calling dcop." << endl; 00568 exit( -1 ); 00569 } 00570 } 00571 else if( !sessionName.isEmpty() ) 00572 { 00573 if( sessions.contains( sessionName ) ) 00574 { 00575 sessions.clear(); 00576 sessions.append( sessionName ); 00577 } 00578 else 00579 { 00580 cerr_ << "ERROR: The specified session doesn't exist!" << endl; 00581 exit( -1 ); 00582 } 00583 } 00584 else if( sessions.count() > 1 && session != AllSessions ) 00585 { 00586 cerr_ << "ERROR: Multiple available KDE sessions!" << endl 00587 << "Please specify the correct session to use with --session or use the" << endl 00588 << "--all-sessions option to broadcast to all sessions." << endl; 00589 exit( -1 ); 00590 } 00591 } 00592 00593 if( users.count() > 1 || ( users.count() == 1 && 00594 ( getenv( "ICEAUTHORITY" ) == 0 || getenv( "DISPLAY" ) == 0 ) ) ) 00595 { 00596 // Check for ICE authority file and if the file can be read by us 00597 TQString iceFileBase = "ICEauthority"; 00598 TQString iceFile; 00599 TQFileInfo fi; 00600 00601 if (getenv("XDG_RUNTIME_DIR") != 0 ) 00602 { 00603 TQFileInfo xdgRuntime(getenv("XDG_RUNTIME_DIR")); 00604 passwd* pstruct = getpwnam(it.key().local8Bit()); 00605 if (pstruct) 00606 { 00607 iceFile = TQString("%1/%2/%3").arg(xdgRuntime.dirPath()).arg(pstruct->pw_uid).arg(iceFileBase); 00608 fi.setFile(iceFile); 00609 } 00610 if (!pstruct || !fi.exists()) 00611 { 00612 iceFile = TQString::null; 00613 } 00614 } 00615 if (iceFile.isEmpty()) 00616 { 00617 iceFile = TQString("%1/.%2").arg(it.data()).arg(iceFileBase); 00618 fi.setFile(iceFile); 00619 } 00620 if( iceFile.isEmpty() ) 00621 { 00622 cerr_ << "WARNING: Cannot determine home directory for user " 00623 << it.key() << "!" << endl 00624 << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl 00625 << "calling dcop." << endl; 00626 } 00627 else if( fi.exists() ) 00628 { 00629 if( fi.isReadable() ) 00630 { 00631 char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() ); 00632 putenv( envStr ); 00633 //cerr_ << "ice: " << envStr << endl; 00634 } 00635 else 00636 { 00637 cerr_ << "WARNING: ICE authority file " << iceFile 00638 << "is not readable by you!" << endl 00639 << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl 00640 << "calling dcop." << endl; 00641 } 00642 } 00643 else 00644 { 00645 if( users.count() > 1 ) 00646 continue; 00647 else 00648 { 00649 cerr_ << "WARNING: Cannot find ICE authority file " 00650 << iceFile << "!" << endl 00651 << "Please check permissions or set the $ICEAUTHORITY" 00652 << " variable manually before" << endl 00653 << "calling dcop." << endl; 00654 } 00655 } 00656 } 00657 00658 // Main loop 00659 // If users is an empty list we're calling for the currently logged 00660 // in user. In this case we don't have a session, but still want 00661 // to iterate the loop once. 00662 TQStringList::Iterator sIt = sessions.begin(); 00663 for( ; sIt != sessions.end() || users.isEmpty(); ++sIt ) 00664 { 00665 if( !presetDCOPServer && !users.isEmpty() ) 00666 { 00667 TQString dcopFile = it.data() + "/" + *sIt; 00668 TQFile f( dcopFile ); 00669 if( !f.open( IO_ReadOnly ) ) 00670 { 00671 cerr_ << "Can't open " << dcopFile << " for reading!" << endl; 00672 exit( -1 ); 00673 } 00674 00675 TQStringList l( TQStringList::split( '\n', f.readAll() ) ); 00676 dcopServer = l.first(); 00677 00678 if( dcopServer.isEmpty() ) 00679 { 00680 cerr_ << "WARNING: Unable to determine DCOP server for session " 00681 << *sIt << "!" << endl 00682 << "Please check permissions or set the $DCOPSERVER variable manually before" << endl 00683 << "calling dcop." << endl; 00684 exit( -1 ); 00685 } 00686 } 00687 00688 delete client; 00689 client = new DCOPClient; 00690 if( !dcopServer.isEmpty() ) 00691 client->setServerAddress( dcopServer.ascii() ); 00692 bool success = client->attach(); 00693 if( !success ) 00694 { 00695 cerr_ << "ERROR: Couldn't attach to DCOP server!" << endl; 00696 retval = QMAX( retval, 1 ); 00697 if( users.isEmpty() ) 00698 break; 00699 else 00700 continue; 00701 } 00702 dcop = client; 00703 00704 int argscount = args.count(); 00705 if ( DCOPrefmode ) 00706 argscount++; 00707 switch ( argscount ) 00708 { 00709 case 0: 00710 queryApplications(""); 00711 break; 00712 case 1: 00713 if (endsWith(app, '*')) 00714 queryApplications(app); 00715 else 00716 queryObjects( app, "" ); 00717 break; 00718 case 2: 00719 if (endsWith(objid, '*')) 00720 queryObjects(app, objid); 00721 else 00722 queryFunctions( app, objid ); 00723 break; 00724 case 3: 00725 default: 00726 if( updateUserTime ) 00727 sendUserTime( app ); 00728 if( readStdin ) 00729 { 00730 QCStringList::Iterator replaceArg = params.end(); 00731 00732 QCStringList::Iterator it = params.begin(); 00733 for( ; it != params.end(); ++it ) 00734 if( *it == "%1" ) 00735 replaceArg = it; 00736 00737 // Read from stdin until EOF and call function for each 00738 // read line 00739 while ( !cin_.atEnd() ) 00740 { 00741 TQString buf = cin_.readLine(); 00742 00743 if( replaceArg != params.end() ) 00744 *replaceArg = buf.local8Bit(); 00745 00746 if( !buf.isNull() ) 00747 { 00748 int res = callFunction( app, objid, function, params ); 00749 retval = QMAX( retval, res ); 00750 } 00751 } 00752 } 00753 else 00754 { 00755 // Just call function 00756 // cout_ << "call " << app << ", " << objid << ", " << function << ", (params)" << endl; 00757 int res = callFunction( app, objid, function, params ); 00758 retval = QMAX( retval, res ); 00759 } 00760 break; 00761 } 00762 // Another sIt++ would make the loop infinite... 00763 if( users.isEmpty() ) 00764 break; 00765 } 00766 00767 // Another it++ would make the loop infinite... 00768 if( it == users.end() ) 00769 break; 00770 } 00771 00772 return retval; 00773 } 00774 00775 #ifdef Q_OS_WIN 00776 # define main kdemain 00777 #endif 00778 00779 int main( int argc, char** argv ) 00780 { 00781 bool readStdin = false; 00782 int numOptions = 0; 00783 TQString user; 00784 Session session = DefaultSession; 00785 TQString sessionName; 00786 bool updateUserTime = true; 00787 00788 cin_.setEncoding( TQTextStream::Locale ); 00789 00790 // Scan for command-line options first 00791 for( int pos = 1 ; pos <= argc - 1 ; pos++ ) 00792 { 00793 if( strcmp( argv[ pos ], "--help" ) == 0 ) 00794 showHelp( 0 ); 00795 else if( strcmp( argv[ pos ], "--pipe" ) == 0 ) 00796 { 00797 readStdin = true; 00798 numOptions++; 00799 } 00800 else if( strcmp( argv[ pos ], "--user" ) == 0 ) 00801 { 00802 if( pos <= argc - 2 ) 00803 { 00804 user = TQString::fromLocal8Bit( argv[ pos + 1] ); 00805 numOptions +=2; 00806 pos++; 00807 } 00808 else 00809 { 00810 cerr_ << "Missing username for '--user' option!" << endl << endl; 00811 showHelp( -1 ); 00812 } 00813 } 00814 else if( strcmp( argv[ pos ], "--session" ) == 0 ) 00815 { 00816 if( session == AllSessions ) 00817 { 00818 cerr_ << "ERROR: --session cannot be mixed with --all-sessions!" << endl << endl; 00819 showHelp( -1 ); 00820 } 00821 else if( pos <= argc - 2 ) 00822 { 00823 sessionName = TQString::fromLocal8Bit( argv[ pos + 1] ); 00824 numOptions +=2; 00825 pos++; 00826 } 00827 else 00828 { 00829 cerr_ << "Missing session name for '--session' option!" << endl << endl; 00830 showHelp( -1 ); 00831 } 00832 } 00833 else if( strcmp( argv[ pos ], "--all-users" ) == 0 ) 00834 { 00835 user = "*"; 00836 numOptions ++; 00837 } 00838 else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 ) 00839 { 00840 session = QuerySessions; 00841 numOptions ++; 00842 } 00843 else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 ) 00844 { 00845 if( !sessionName.isEmpty() ) 00846 { 00847 cerr_ << "ERROR: --session cannot be mixed with --all-sessions!" << endl << endl; 00848 showHelp( -1 ); 00849 } 00850 session = AllSessions; 00851 numOptions ++; 00852 } 00853 else if( strcmp( argv[ pos ], "--no-user-time" ) == 0 ) 00854 { 00855 updateUserTime = false; 00856 numOptions ++; 00857 } 00858 else if( argv[ pos ][ 0 ] == '-' ) 00859 { 00860 cerr_ << "Unknown command-line option '" << argv[ pos ] 00861 << "'." << endl << endl; 00862 showHelp( -1 ); 00863 } 00864 else 00865 break; // End of options 00866 } 00867 00868 argc -= numOptions; 00869 00870 QCStringList args; 00871 00872 #ifdef DCOPQUIT 00873 if (argc > 1) 00874 { 00875 TQCString prog = argv[ numOptions + 1 ]; 00876 00877 if (!prog.isEmpty()) 00878 { 00879 args.append( prog ); 00880 00881 // Pass as-is if it ends with a wildcard 00882 if (prog[prog.length()-1] != '*') 00883 { 00884 // Strip a trailing -<PID> part. 00885 int i = prog.findRev('-'); 00886 if ((i >= 0) && prog.mid(i+1).toLong()) 00887 { 00888 prog = prog.left(i); 00889 } 00890 args.append( "qt/"+prog ); 00891 args.append( "quit()" ); 00892 } 00893 } 00894 } 00895 #else 00896 for( int i = numOptions; i < argc + numOptions - 1; i++ ) 00897 args.append( argv[ i + 1 ] ); 00898 #endif 00899 00900 if( readStdin && args.count() < 3 ) 00901 { 00902 cerr_ << "--pipe option only supported for function calls!" << endl << endl; 00903 showHelp( -1 ); 00904 } 00905 00906 if( user == "*" && args.count() < 3 && session != QuerySessions ) 00907 { 00908 cerr_ << "ERROR: The --all-users option is only supported for function calls!" << endl << endl; 00909 showHelp( -1 ); 00910 } 00911 00912 if( session == QuerySessions && !args.isEmpty() ) 00913 { 00914 cerr_ << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl; 00915 showHelp( -1 ); 00916 } 00917 00918 if( session == QuerySessions && user.isEmpty() ) 00919 { 00920 cerr_ << "ERROR: The --list-sessions option can only be used with the --user or" << endl 00921 << "--all-users options!" << endl << endl; 00922 showHelp( -1 ); 00923 } 00924 00925 if( session != DefaultSession && session != QuerySessions && 00926 args.count() < 3 ) 00927 { 00928 cerr_ << "ERROR: The --session and --all-sessions options are only supported for function" << endl 00929 << "calls!" << endl << endl; 00930 showHelp( -1 ); 00931 } 00932 00933 UserList users; 00934 if( user == "*" ) 00935 users = userList(); 00936 else if( !user.isEmpty() ) 00937 users[ user ] = userList()[ user ]; 00938 00939 int retval = runDCOP( args, users, session, sessionName, readStdin, updateUserTime ); 00940 00941 return retval; 00942 } 00943 00944 // vim: set ts=8 sts=4 sw=4 noet: 00945