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 tqWarning( "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 tqWarning( "No such application: '%s'", app.data()); 00139 else 00140 tqWarning( "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 tqWarning( "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 tqWarning( "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 tqWarning( "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 tqWarning("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 tqWarning("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 tqWarning( "arguments do not match" ); 00299 return( 1 ); 00300 } 00301 00302 if ( !dcop->call( app, obj, f.latin1(), data, replyType, replyData) ) { 00303 tqWarning( "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 TDE 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 TDE 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 TDE 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 TDE 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 home = it.data(); 00598 TQString iceFile = it.data() + "/.ICEauthority"; 00599 TQFileInfo fi( iceFile ); 00600 if( iceFile.isEmpty() ) 00601 { 00602 cerr_ << "WARNING: Cannot determine home directory for user " 00603 << it.key() << "!" << endl 00604 << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl 00605 << "calling dcop." << endl; 00606 } 00607 else if( fi.exists() ) 00608 { 00609 if( fi.isReadable() ) 00610 { 00611 char *envStr = strdup( ( "ICEAUTHORITY=" + iceFile ).ascii() ); 00612 putenv( envStr ); 00613 //cerr_ << "ice: " << envStr << endl; 00614 } 00615 else 00616 { 00617 cerr_ << "WARNING: ICE authority file " << iceFile 00618 << "is not readable by you!" << endl 00619 << "Please check permissions or set the $ICEAUTHORITY variable manually before" << endl 00620 << "calling dcop." << endl; 00621 } 00622 } 00623 else 00624 { 00625 if( users.count() > 1 ) 00626 continue; 00627 else 00628 { 00629 cerr_ << "WARNING: Cannot find ICE authority file " 00630 << iceFile << "!" << endl 00631 << "Please check permissions or set the $ICEAUTHORITY" 00632 << " variable manually before" << endl 00633 << "calling dcop." << endl; 00634 } 00635 } 00636 } 00637 00638 // Main loop 00639 // If users is an empty list we're calling for the currently logged 00640 // in user. In this case we don't have a session, but still want 00641 // to iterate the loop once. 00642 TQStringList::Iterator sIt = sessions.begin(); 00643 for( ; sIt != sessions.end() || users.isEmpty(); ++sIt ) 00644 { 00645 if( !presetDCOPServer && !users.isEmpty() ) 00646 { 00647 TQString dcopFile = it.data() + "/" + *sIt; 00648 TQFile f( dcopFile ); 00649 if( !f.open( IO_ReadOnly ) ) 00650 { 00651 cerr_ << "Can't open " << dcopFile << " for reading!" << endl; 00652 exit( -1 ); 00653 } 00654 00655 TQStringList l( TQStringList::split( '\n', f.readAll() ) ); 00656 dcopServer = l.first(); 00657 00658 if( dcopServer.isEmpty() ) 00659 { 00660 cerr_ << "WARNING: Unable to determine DCOP server for session " 00661 << *sIt << "!" << endl 00662 << "Please check permissions or set the $DCOPSERVER variable manually before" << endl 00663 << "calling dcop." << endl; 00664 exit( -1 ); 00665 } 00666 } 00667 00668 delete client; 00669 client = new DCOPClient; 00670 if( !dcopServer.isEmpty() ) 00671 client->setServerAddress( dcopServer.ascii() ); 00672 bool success = client->attach(); 00673 if( !success ) 00674 { 00675 cerr_ << "ERROR: Couldn't attach to DCOP server!" << endl; 00676 retval = TQMAX( retval, 1 ); 00677 if( users.isEmpty() ) 00678 break; 00679 else 00680 continue; 00681 } 00682 dcop = client; 00683 00684 int argscount = args.count(); 00685 if ( DCOPrefmode ) 00686 argscount++; 00687 switch ( argscount ) 00688 { 00689 case 0: 00690 queryApplications(""); 00691 break; 00692 case 1: 00693 if (endsWith(app, '*')) 00694 queryApplications(app); 00695 else 00696 queryObjects( app, "" ); 00697 break; 00698 case 2: 00699 if (endsWith(objid, '*')) 00700 queryObjects(app, objid); 00701 else 00702 queryFunctions( app, objid ); 00703 break; 00704 case 3: 00705 default: 00706 if( updateUserTime ) 00707 sendUserTime( app ); 00708 if( readStdin ) 00709 { 00710 QCStringList::Iterator replaceArg = params.end(); 00711 00712 QCStringList::Iterator it = params.begin(); 00713 for( ; it != params.end(); ++it ) 00714 if( *it == "%1" ) 00715 replaceArg = it; 00716 00717 // Read from stdin until EOF and call function for each 00718 // read line 00719 while ( !cin_.atEnd() ) 00720 { 00721 TQString buf = cin_.readLine(); 00722 00723 if( replaceArg != params.end() ) 00724 *replaceArg = buf.local8Bit(); 00725 00726 if( !buf.isNull() ) 00727 { 00728 int res = callFunction( app, objid, function, params ); 00729 retval = TQMAX( retval, res ); 00730 } 00731 } 00732 } 00733 else 00734 { 00735 // Just call function 00736 // cout_ << "call " << app << ", " << objid << ", " << function << ", (params)" << endl; 00737 int res = callFunction( app, objid, function, params ); 00738 retval = TQMAX( retval, res ); 00739 } 00740 break; 00741 } 00742 // Another sIt++ would make the loop infinite... 00743 if( users.isEmpty() ) 00744 break; 00745 } 00746 00747 // Another it++ would make the loop infinite... 00748 if( it == users.end() ) 00749 break; 00750 } 00751 00752 return retval; 00753 } 00754 00755 #ifdef Q_OS_WIN 00756 # define main kdemain 00757 #endif 00758 00759 int main( int argc, char** argv ) 00760 { 00761 bool readStdin = false; 00762 int numOptions = 0; 00763 TQString user; 00764 Session session = DefaultSession; 00765 TQString sessionName; 00766 bool updateUserTime = true; 00767 00768 cin_.setEncoding( TQTextStream::Locale ); 00769 00770 // Scan for command-line options first 00771 for( int pos = 1 ; pos <= argc - 1 ; pos++ ) 00772 { 00773 if( strcmp( argv[ pos ], "--help" ) == 0 ) 00774 showHelp( 0 ); 00775 else if( strcmp( argv[ pos ], "--pipe" ) == 0 ) 00776 { 00777 readStdin = true; 00778 numOptions++; 00779 } 00780 else if( strcmp( argv[ pos ], "--user" ) == 0 ) 00781 { 00782 if( pos <= argc - 2 ) 00783 { 00784 user = TQString::fromLocal8Bit( argv[ pos + 1] ); 00785 numOptions +=2; 00786 pos++; 00787 } 00788 else 00789 { 00790 cerr_ << "Missing username for '--user' option!" << endl << endl; 00791 showHelp( -1 ); 00792 } 00793 } 00794 else if( strcmp( argv[ pos ], "--session" ) == 0 ) 00795 { 00796 if( session == AllSessions ) 00797 { 00798 cerr_ << "ERROR: --session cannot be mixed with --all-sessions!" << endl << endl; 00799 showHelp( -1 ); 00800 } 00801 else if( pos <= argc - 2 ) 00802 { 00803 sessionName = TQString::fromLocal8Bit( argv[ pos + 1] ); 00804 numOptions +=2; 00805 pos++; 00806 } 00807 else 00808 { 00809 cerr_ << "Missing session name for '--session' option!" << endl << endl; 00810 showHelp( -1 ); 00811 } 00812 } 00813 else if( strcmp( argv[ pos ], "--all-users" ) == 0 ) 00814 { 00815 user = "*"; 00816 numOptions ++; 00817 } 00818 else if( strcmp( argv[ pos ], "--list-sessions" ) == 0 ) 00819 { 00820 session = QuerySessions; 00821 numOptions ++; 00822 } 00823 else if( strcmp( argv[ pos ], "--all-sessions" ) == 0 ) 00824 { 00825 if( !sessionName.isEmpty() ) 00826 { 00827 cerr_ << "ERROR: --session cannot be mixed with --all-sessions!" << endl << endl; 00828 showHelp( -1 ); 00829 } 00830 session = AllSessions; 00831 numOptions ++; 00832 } 00833 else if( strcmp( argv[ pos ], "--no-user-time" ) == 0 ) 00834 { 00835 updateUserTime = false; 00836 numOptions ++; 00837 } 00838 else if( argv[ pos ][ 0 ] == '-' ) 00839 { 00840 cerr_ << "Unknown command-line option '" << argv[ pos ] 00841 << "'." << endl << endl; 00842 showHelp( -1 ); 00843 } 00844 else 00845 break; // End of options 00846 } 00847 00848 argc -= numOptions; 00849 00850 QCStringList args; 00851 00852 #ifdef DCOPQUIT 00853 if (argc > 1) 00854 { 00855 TQCString prog = argv[ numOptions + 1 ]; 00856 00857 if (!prog.isEmpty()) 00858 { 00859 args.append( prog ); 00860 00861 // Pass as-is if it ends with a wildcard 00862 if (prog[prog.length()-1] != '*') 00863 { 00864 // Strip a trailing -<PID> part. 00865 int i = prog.findRev('-'); 00866 if ((i >= 0) && prog.mid(i+1).toLong()) 00867 { 00868 prog = prog.left(i); 00869 } 00870 args.append( "qt/"+prog ); 00871 args.append( "quit()" ); 00872 } 00873 } 00874 } 00875 #else 00876 for( int i = numOptions; i < argc + numOptions - 1; i++ ) 00877 args.append( argv[ i + 1 ] ); 00878 #endif 00879 00880 if( readStdin && args.count() < 3 ) 00881 { 00882 cerr_ << "--pipe option only supported for function calls!" << endl << endl; 00883 showHelp( -1 ); 00884 } 00885 00886 if( user == "*" && args.count() < 3 && session != QuerySessions ) 00887 { 00888 cerr_ << "ERROR: The --all-users option is only supported for function calls!" << endl << endl; 00889 showHelp( -1 ); 00890 } 00891 00892 if( session == QuerySessions && !args.isEmpty() ) 00893 { 00894 cerr_ << "ERROR: The --list-sessions option cannot be used for actual DCOP calls!" << endl << endl; 00895 showHelp( -1 ); 00896 } 00897 00898 if( session == QuerySessions && user.isEmpty() ) 00899 { 00900 cerr_ << "ERROR: The --list-sessions option can only be used with the --user or" << endl 00901 << "--all-users options!" << endl << endl; 00902 showHelp( -1 ); 00903 } 00904 00905 if( session != DefaultSession && session != QuerySessions && 00906 args.count() < 3 ) 00907 { 00908 cerr_ << "ERROR: The --session and --all-sessions options are only supported for function" << endl 00909 << "calls!" << endl << endl; 00910 showHelp( -1 ); 00911 } 00912 00913 UserList users; 00914 if( user == "*" ) 00915 users = userList(); 00916 else if( !user.isEmpty() ) 00917 users[ user ] = userList()[ user ]; 00918 00919 int retval = runDCOP( args, users, session, sessionName, readStdin, updateUserTime ); 00920 00921 return retval; 00922 } 00923 00924 // vim: set ts=8 sts=4 sw=4 noet: 00925
Trinity API Reference