dcopclient.cpp
00001 /***************************************************************** 00002 00003 Copyright (c) 1999 Preston Brown <pbrown@kde.org> 00004 Copyright (c) 1999 Matthias Ettrich <ettrich@kde.org> 00005 00006 Permission is hereby granted, free of charge, to any person obtaining a copy 00007 of this software and associated documentation files (the "Software"), to deal 00008 in the Software without restriction, including without limitation the rights 00009 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00010 copies of the Software, and to permit persons to whom the Software is 00011 furnished to do so, subject to the following conditions: 00012 00013 The above copyright notice and this permission notice shall be included in 00014 all copies or substantial portions of the Software. 00015 00016 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00017 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00018 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00019 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 00020 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00021 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00022 00023 ******************************************************************/ 00024 00025 // qt <-> dcop integration 00026 #include <tqobjectlist.h> 00027 #include <tqmetaobject.h> 00028 #include <tqvariant.h> 00029 #include <tqtimer.h> 00030 #include <tqintdict.h> 00031 #include <tqeventloop.h> 00032 // end of qt <-> dcop integration 00033 00034 #include "config.h" 00035 00036 #include <config.h> 00037 #include <dcopref.h> 00038 00039 #include <sys/time.h> 00040 #include <sys/types.h> 00041 #include <sys/stat.h> 00042 #include <sys/file.h> 00043 #include <sys/socket.h> 00044 #include <sys/un.h> 00045 #include <fcntl.h> 00046 #include <unistd.h> 00047 00048 #include <ctype.h> 00049 #include <unistd.h> 00050 #include <stdlib.h> 00051 #include <assert.h> 00052 #include <string.h> 00053 00054 #ifndef QT_CLEAN_NAMESPACE 00055 #define QT_CLEAN_NAMESPACE 00056 #endif 00057 #include <tqguardedptr.h> 00058 #include <tqtextstream.h> 00059 #include <tqfile.h> 00060 #include <tqdir.h> 00061 #include <tqapplication.h> 00062 #include <tqsocketnotifier.h> 00063 #include <tqregexp.h> 00064 00065 #include <tqucomextra_p.h> 00066 00067 #include <dcopglobal.h> 00068 #include <dcopclient.h> 00069 #include <dcopobject.h> 00070 00071 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 00072 #include <X11/Xmd.h> 00073 #endif 00074 extern "C" { 00075 #include <KDE-ICE/ICElib.h> 00076 #include <KDE-ICE/ICEutil.h> 00077 #include <KDE-ICE/ICEmsg.h> 00078 #include <KDE-ICE/ICEproto.h> 00079 } 00080 00081 // #define DCOPCLIENT_DEBUG 1 00082 00083 extern TQMap<TQCString, DCOPObject *> * kde_dcopObjMap; // defined in dcopobject.cpp 00084 00085 /********************************************* 00086 * Keep track of local clients 00087 *********************************************/ 00088 typedef TQAsciiDict<DCOPClient> client_map_t; 00089 static client_map_t *DCOPClient_CliMap = 0; 00090 00091 static 00092 client_map_t *cliMap() 00093 { 00094 if (!DCOPClient_CliMap) 00095 DCOPClient_CliMap = new client_map_t; 00096 return DCOPClient_CliMap; 00097 } 00098 00099 DCOPClient *DCOPClient::findLocalClient( const TQCString &_appId ) 00100 { 00101 return cliMap()->find(_appId.data()); 00102 } 00103 00104 static 00105 void registerLocalClient( const TQCString &_appId, DCOPClient *client ) 00106 { 00107 cliMap()->replace(_appId.data(), client); 00108 } 00109 00110 static 00111 void unregisterLocalClient( const TQCString &_appId ) 00112 { 00113 client_map_t *map = cliMap(); 00114 map->remove(_appId.data()); 00115 } 00117 00118 template class TQPtrList<DCOPObjectProxy>; 00119 template class TQPtrList<DCOPClientTransaction>; 00120 template class TQPtrList<_IceConn>; 00121 00122 struct DCOPClientMessage 00123 { 00124 int opcode; 00125 CARD32 key; 00126 TQByteArray data; 00127 }; 00128 00129 class DCOPClient::ReplyStruct 00130 { 00131 public: 00132 enum ReplyStatus { Pending, Ok, Failed }; 00133 ReplyStruct() { 00134 status = Pending; 00135 replyType = 0; 00136 replyData = 0; 00137 replyId = -1; 00138 transactionId = -1; 00139 replyObject = 0; 00140 } 00141 ReplyStatus status; 00142 TQCString* replyType; 00143 TQByteArray* replyData; 00144 int replyId; 00145 TQ_INT32 transactionId; 00146 TQCString calledApp; 00147 TQGuardedPtr<TQObject> replyObject; 00148 TQCString replySlot; 00149 }; 00150 00151 class DCOPClientPrivate 00152 { 00153 public: 00154 DCOPClient *parent; 00155 TQCString appId; 00156 IceConn iceConn; 00157 int majorOpcode; // major opcode negotiated w/server and used to tag all comms. 00158 00159 int majorVersion, minorVersion; // protocol versions negotiated w/server 00160 00161 static const char* serverAddr; // location of server in ICE-friendly format. 00162 TQSocketNotifier *notifier; 00163 bool non_blocking_call_lock; 00164 bool registered; 00165 bool foreign_server; 00166 bool accept_calls; 00167 bool accept_calls_override; // If true, user has specified policy. 00168 bool qt_bridge_enabled; 00169 00170 TQCString senderId; 00171 TQCString objId; 00172 TQCString function; 00173 00174 TQCString defaultObject; 00175 TQPtrList<DCOPClientTransaction> *transactionList; 00176 bool transaction; 00177 TQ_INT32 transactionId; 00178 int opcode; 00179 00180 // Special key values: 00181 // 0 : Not specified 00182 // 1 : DCOPSend 00183 // 2 : Priority 00184 // >= 42: Normal 00185 CARD32 key; 00186 CARD32 currentKey; 00187 CARD32 currentKeySaved; 00188 00189 TQTimer postMessageTimer; 00190 TQPtrList<DCOPClientMessage> messages; 00191 00192 TQPtrList<DCOPClient::ReplyStruct> pendingReplies; 00193 TQPtrList<DCOPClient::ReplyStruct> asyncReplyQueue; 00194 00195 struct LocalTransactionResult 00196 { 00197 TQCString replyType; 00198 TQByteArray replyData; 00199 }; 00200 00201 TQIntDict<LocalTransactionResult> localTransActionList; 00202 00203 TQTimer eventLoopTimer; 00204 }; 00205 00206 class DCOPClientTransaction 00207 { 00208 public: 00209 TQ_INT32 id; 00210 CARD32 key; 00211 TQCString senderId; 00212 }; 00213 00214 TQCString DCOPClient::iceauthPath() 00215 { 00216 #if defined(ICEAUTH_PATH) 00217 if ( 00218 # if defined(Q_WS_WIN) 00219 access(ICEAUTH_PATH, 0) == 0 00220 # else 00221 access(ICEAUTH_PATH, X_OK) == 0 00222 # endif 00223 ) 00224 { 00225 return TQCString(ICEAUTH_PATH); 00226 } 00227 00228 #elif defined(Q_OS_WIN32) 00229 char szPath[512]; 00230 char * pszFilePart; 00231 int ret; 00232 ret = SearchPathA(NULL,"iceauth.exe",NULL,sizeof(szPath)/sizeof(szPath[0]),szPath,&pszFilePart); 00233 if(ret != 0) 00234 return TQCString(szPath); 00235 00236 #else 00237 TQCString path = ::getenv("PATH"); 00238 if (path.isEmpty()) 00239 path = "/bin:/usr/bin"; 00240 path += ":/usr/bin/X11:/usr/X11/bin:/usr/X11R6/bin"; 00241 TQCString fPath = strtok(path.data(), ":\b"); 00242 while (!fPath.isNull()) 00243 { 00244 fPath += "/iceauth"; 00245 if (access(fPath.data(), X_OK) == 0) 00246 { 00247 return fPath; 00248 } 00249 fPath = strtok(NULL, ":\b"); 00250 } 00251 00252 #endif 00253 return 0; 00254 } 00255 00256 static TQCString dcopServerFile(const TQCString &hostname, bool old) 00257 { 00258 TQCString fName = ::getenv("DCOPAUTHORITY"); 00259 if (!old && !fName.isEmpty()) 00260 return fName; 00261 00262 fName = TQFile::encodeName( TQDir::homeDirPath() ); 00263 // fName = ::getenv("HOME"); 00264 if (fName.isEmpty()) 00265 { 00266 fprintf(stderr, "Aborting. $HOME is not set.\n"); 00267 exit(1); 00268 } 00269 #ifdef Q_WS_X11 00270 TQCString disp = getenv("DISPLAY"); 00271 #elif defined(Q_WS_QWS) 00272 TQCString disp = getenv("QWS_DISPLAY"); 00273 #else 00274 TQCString disp; 00275 #endif 00276 if (disp.isEmpty()) 00277 disp = "NODISPLAY"; 00278 00279 int i; 00280 if((i = disp.findRev('.')) > disp.findRev(KPATH_SEPARATOR) && i >= 0) 00281 disp.truncate(i); 00282 00283 if (!old) 00284 { 00285 while( (i = disp.find(KPATH_SEPARATOR)) >= 0) 00286 disp[i] = '_'; 00287 } 00288 00289 fName += "/.DCOPserver_"; 00290 if (hostname.isEmpty()) 00291 { 00292 char hostName[256]; 00293 hostName[0] = '\0'; 00294 if (getenv("XAUTHLOCALHOSTNAME")) 00295 fName += getenv("XAUTHLOCALHOSTNAME"); 00296 else if (gethostname(hostName, sizeof(hostName))) 00297 { 00298 fName += "localhost"; 00299 } 00300 else 00301 { 00302 hostName[sizeof(hostName)-1] = '\0'; 00303 fName += hostName; 00304 } 00305 } 00306 else 00307 { 00308 fName += hostname; 00309 } 00310 fName += "_"+disp; 00311 return fName; 00312 } 00313 00314 00315 // static 00316 TQCString DCOPClient::dcopServerFile(const TQCString &hostname) 00317 { 00318 return ::dcopServerFile(hostname, false); 00319 } 00320 00321 00322 // static 00323 TQCString DCOPClient::dcopServerFileOld(const TQCString &hostname) 00324 { 00325 return ::dcopServerFile(hostname, true); 00326 } 00327 00328 00329 const char* DCOPClientPrivate::serverAddr = 0; 00330 00331 static void DCOPProcessInternal( DCOPClientPrivate *d, int opcode, CARD32 key, const TQByteArray& dataReceived, bool canPost ); 00332 00333 void DCOPClient::handleAsyncReply(ReplyStruct *replyStruct) 00334 { 00335 if (replyStruct->replyObject) 00336 { 00337 TQObject::connect(this, TQT_SIGNAL(callBack(int, const TQCString&, const TQByteArray &)), 00338 replyStruct->replyObject, replyStruct->replySlot); 00339 emit callBack(replyStruct->replyId, *(replyStruct->replyType), *(replyStruct->replyData)); 00340 TQObject::disconnect(this, TQT_SIGNAL(callBack(int, const TQCString&, const TQByteArray &)), 00341 replyStruct->replyObject, replyStruct->replySlot); 00342 } 00343 delete replyStruct; 00344 } 00345 00349 static void DCOPProcessMessage(IceConn iceConn, IcePointer clientObject, 00350 int opcode, unsigned long length, Bool /*swap*/, 00351 IceReplyWaitInfo *replyWait, 00352 Bool *replyWaitRet) 00353 { 00354 DCOPMsg *pMsg = 0; 00355 DCOPClientPrivate *d = static_cast<DCOPClientPrivate *>(clientObject); 00356 DCOPClient::ReplyStruct *replyStruct = replyWait ? static_cast<DCOPClient::ReplyStruct*>(replyWait->reply) : 0; 00357 00358 IceReadMessageHeader(iceConn, sizeof(DCOPMsg), DCOPMsg, pMsg); 00359 CARD32 key = pMsg->key; 00360 if ( d->key == 0 ) 00361 d->key = key; // received a key from the server 00362 00363 TQByteArray dataReceived( length ); 00364 IceReadData(iceConn, length, dataReceived.data() ); 00365 00366 d->opcode = opcode; 00367 switch (opcode ) { 00368 00369 case DCOPReplyFailed: 00370 if ( replyStruct ) { 00371 replyStruct->status = DCOPClient::ReplyStruct::Failed; 00372 replyStruct->transactionId = 0; 00373 *replyWaitRet = True; 00374 return; 00375 } else { 00376 qWarning("Very strange! got a DCOPReplyFailed opcode, but we were not waiting for a reply!"); 00377 return; 00378 } 00379 case DCOPReply: 00380 if ( replyStruct ) { 00381 TQByteArray* b = replyStruct->replyData; 00382 TQCString* t = replyStruct->replyType; 00383 replyStruct->status = DCOPClient::ReplyStruct::Ok; 00384 replyStruct->transactionId = 0; 00385 00386 TQCString calledApp, app; 00387 TQDataStream ds( dataReceived, IO_ReadOnly ); 00388 ds >> calledApp >> app >> *t >> *b; 00389 00390 *replyWaitRet = True; 00391 return; 00392 } else { 00393 qWarning("Very strange! got a DCOPReply opcode, but we were not waiting for a reply!"); 00394 return; 00395 } 00396 case DCOPReplyWait: 00397 if ( replyStruct ) { 00398 TQCString calledApp, app; 00399 TQ_INT32 id; 00400 TQDataStream ds( dataReceived, IO_ReadOnly ); 00401 ds >> calledApp >> app >> id; 00402 replyStruct->transactionId = id; 00403 replyStruct->calledApp = calledApp; 00404 d->pendingReplies.append(replyStruct); 00405 *replyWaitRet = True; 00406 return; 00407 } else { 00408 qWarning("Very strange! got a DCOPReplyWait opcode, but we were not waiting for a reply!"); 00409 return; 00410 } 00411 case DCOPReplyDelayed: 00412 { 00413 TQDataStream ds( dataReceived, IO_ReadOnly ); 00414 TQCString calledApp, app; 00415 TQ_INT32 id; 00416 00417 ds >> calledApp >> app >> id; 00418 if (replyStruct && (id == replyStruct->transactionId) && (calledApp == replyStruct->calledApp)) 00419 { 00420 *replyWaitRet = True; 00421 } 00422 00423 for(DCOPClient::ReplyStruct *rs = d->pendingReplies.first(); rs; 00424 rs = d->pendingReplies.next()) 00425 { 00426 if ((rs->transactionId == id) && (rs->calledApp == calledApp)) 00427 { 00428 d->pendingReplies.remove(); 00429 TQByteArray* b = rs->replyData; 00430 TQCString* t = rs->replyType; 00431 ds >> *t >> *b; 00432 00433 rs->status = DCOPClient::ReplyStruct::Ok; 00434 rs->transactionId = 0; 00435 if (!rs->replySlot.isEmpty()) 00436 { 00437 d->parent->handleAsyncReply(rs); 00438 } 00439 return; 00440 } 00441 } 00442 } 00443 qWarning("Very strange! got a DCOPReplyDelayed opcode, but we were not waiting for a reply!"); 00444 return; 00445 case DCOPCall: 00446 case DCOPFind: 00447 case DCOPSend: 00448 DCOPProcessInternal( d, opcode, key, dataReceived, true ); 00449 } 00450 } 00451 00452 void DCOPClient::processPostedMessagesInternal() 00453 { 00454 if ( d->messages.isEmpty() ) 00455 return; 00456 TQPtrListIterator<DCOPClientMessage> it (d->messages ); 00457 DCOPClientMessage* msg ; 00458 while ( ( msg = it.current() ) ) { 00459 ++it; 00460 if ( d->currentKey && msg->key != d->currentKey ) 00461 continue; 00462 d->messages.removeRef( msg ); 00463 d->opcode = msg->opcode; 00464 DCOPProcessInternal( d, msg->opcode, msg->key, msg->data, false ); 00465 delete msg; 00466 } 00467 if ( !d->messages.isEmpty() ) 00468 d->postMessageTimer.start( 100, true ); 00469 } 00470 00474 void DCOPProcessInternal( DCOPClientPrivate *d, int opcode, CARD32 key, const TQByteArray& dataReceived, bool canPost ) 00475 { 00476 if (!d->accept_calls && (opcode == DCOPSend)) 00477 return; 00478 00479 IceConn iceConn = d->iceConn; 00480 DCOPMsg *pMsg = 0; 00481 DCOPClient *c = d->parent; 00482 TQDataStream ds( dataReceived, IO_ReadOnly ); 00483 00484 TQCString fromApp; 00485 ds >> fromApp; 00486 if (fromApp.isEmpty()) 00487 return; // Reserved for local calls 00488 00489 if (!d->accept_calls) 00490 { 00491 TQByteArray reply; 00492 TQDataStream replyStream( reply, IO_WriteOnly ); 00493 // Call rejected. 00494 replyStream << d->appId << fromApp; 00495 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyFailed, 00496 sizeof(DCOPMsg), DCOPMsg, pMsg ); 00497 int datalen = reply.size(); 00498 pMsg->key = key; 00499 pMsg->length += datalen; 00500 IceSendData( iceConn, datalen, reply.data()); 00501 return; 00502 } 00503 00504 TQCString app, objId, fun; 00505 TQByteArray data; 00506 ds >> app >> objId >> fun >> data; 00507 d->senderId = fromApp; 00508 d->objId = objId; 00509 d->function = fun; 00510 00511 // qWarning("DCOP: %s got call: %s:%s:%s key = %d currentKey = %d", d->appId.data(), app.data(), objId.data(), fun.data(), key, d->currentKey); 00512 00513 if ( canPost && d->currentKey && key != d->currentKey ) { 00514 DCOPClientMessage* msg = new DCOPClientMessage; 00515 msg->opcode = opcode; 00516 msg->key = key; 00517 msg->data = dataReceived; 00518 d->messages.append( msg ); 00519 d->postMessageTimer.start( 0, true ); 00520 return; 00521 } 00522 00523 d->objId = objId; 00524 d->function = fun; 00525 00526 TQCString replyType; 00527 TQByteArray replyData; 00528 bool b; 00529 CARD32 oldCurrentKey = d->currentKey; 00530 if ( opcode != DCOPSend ) // DCOPSend doesn't change the current key 00531 d->currentKey = key; 00532 00533 if ( opcode == DCOPFind ) 00534 b = c->find(app, objId, fun, data, replyType, replyData ); 00535 else 00536 b = c->receive( app, objId, fun, data, replyType, replyData ); 00537 // set notifier back to previous state 00538 00539 if ( opcode == DCOPSend ) 00540 return; 00541 00542 if ((d->currentKey == key) || (oldCurrentKey != 2)) 00543 d->currentKey = oldCurrentKey; 00544 00545 TQByteArray reply; 00546 TQDataStream replyStream( reply, IO_WriteOnly ); 00547 00548 TQ_INT32 id = c->transactionId(); 00549 if (id) { 00550 // Call delayed. Send back the transaction ID. 00551 replyStream << d->appId << fromApp << id; 00552 00553 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyWait, 00554 sizeof(DCOPMsg), DCOPMsg, pMsg ); 00555 pMsg->key = key; 00556 pMsg->length += reply.size(); 00557 IceSendData( iceConn, reply.size(), const_cast<char *>(reply.data())); 00558 return; 00559 } 00560 00561 if ( !b ) { 00562 // Call failed. No data send back. 00563 00564 replyStream << d->appId << fromApp; 00565 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyFailed, 00566 sizeof(DCOPMsg), DCOPMsg, pMsg ); 00567 int datalen = reply.size(); 00568 pMsg->key = key; 00569 pMsg->length += datalen; 00570 IceSendData( iceConn, datalen, const_cast<char *>(reply.data())); 00571 return; 00572 } 00573 00574 // Call successful. Send back replyType and replyData. 00575 replyStream << d->appId << fromApp << replyType << replyData.size(); 00576 00577 00578 // we are calling, so we need to set up reply data 00579 IceGetHeader( iceConn, d->majorOpcode, DCOPReply, 00580 sizeof(DCOPMsg), DCOPMsg, pMsg ); 00581 int datalen = reply.size() + replyData.size(); 00582 pMsg->key = key; 00583 pMsg->length += datalen; 00584 // use IceSendData not IceWriteData to avoid a copy. Output buffer 00585 // shouldn't need to be flushed. 00586 IceSendData( iceConn, reply.size(), const_cast<char *>(reply.data())); 00587 IceSendData( iceConn, replyData.size(), const_cast<char *>(replyData.data())); 00588 } 00589 00590 00591 00592 static IcePoVersionRec DCOPClientVersions[] = { 00593 { DCOPVersionMajor, DCOPVersionMinor, DCOPProcessMessage } 00594 }; 00595 00596 00597 static DCOPClient* dcop_main_client = 0; 00598 00599 DCOPClient* DCOPClient::mainClient() 00600 { 00601 return dcop_main_client; 00602 } 00603 00604 void DCOPClient::setMainClient( DCOPClient* client ) 00605 { 00606 dcop_main_client = client; 00607 } 00608 00609 00610 DCOPClient::DCOPClient() 00611 { 00612 d = new DCOPClientPrivate; 00613 d->parent = this; 00614 d->iceConn = 0L; 00615 d->key = 0; 00616 d->currentKey = 0; 00617 d->majorOpcode = 0; 00618 d->appId = 0; 00619 d->notifier = 0L; 00620 d->non_blocking_call_lock = false; 00621 d->registered = false; 00622 d->foreign_server = true; 00623 d->accept_calls = true; 00624 d->accept_calls_override = false; 00625 d->qt_bridge_enabled = true; 00626 d->transactionList = 0L; 00627 d->transactionId = 0; 00628 TQObject::connect( &d->postMessageTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( processPostedMessagesInternal() ) ); 00629 TQObject::connect( &d->eventLoopTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( eventLoopTimeout() ) ); 00630 00631 if ( !mainClient() ) 00632 setMainClient( this ); 00633 } 00634 00635 DCOPClient::~DCOPClient() 00636 { 00637 #ifdef DCOPCLIENT_DEBUG 00638 qWarning("d->messages.count() = %d", d->messages.count()); 00639 TQPtrListIterator<DCOPClientMessage> it (d->messages ); 00640 DCOPClientMessage* msg ; 00641 while ( ( msg = it.current() ) ) { 00642 ++it; 00643 d->messages.removeRef( msg ); 00644 qWarning("DROPPING UNHANDLED DCOP MESSAGE:"); 00645 qWarning(" opcode = %d key = %d", msg->opcode, msg->key); 00646 TQDataStream ds( msg->data, IO_ReadOnly ); 00647 00648 TQCString fromApp, app, objId, fun; 00649 ds >> fromApp >> app >> objId >> fun; 00650 qWarning(" from = %s", fromApp.data()); 00651 qWarning(" to = %s / %s / %s", app.data(), objId.data(), fun.data()); 00652 delete msg; 00653 } 00654 #endif 00655 if (d->iceConn) 00656 if (IceConnectionStatus(d->iceConn) == IceConnectAccepted) 00657 detach(); 00658 00659 if (d->registered) 00660 unregisterLocalClient( d->appId ); 00661 00662 delete d->notifier; 00663 delete d->transactionList; 00664 d->messages.setAutoDelete(true); 00665 delete d; 00666 00667 if ( mainClient() == this ) 00668 setMainClient( 0 ); 00669 } 00670 00671 void DCOPClient::setServerAddress(const TQCString &addr) 00672 { 00673 TQCString env = "DCOPSERVER=" + addr; 00674 putenv(strdup(env.data())); 00675 delete [] DCOPClientPrivate::serverAddr; 00676 DCOPClientPrivate::serverAddr = qstrdup( addr.data() ); 00677 } 00678 00679 bool DCOPClient::attach() 00680 { 00681 if (!attachInternal( true )) 00682 if (!attachInternal( true )) 00683 return false; // Try two times! 00684 return true; 00685 } 00686 00687 void DCOPClient::bindToApp() 00688 { 00689 // check if we have a tqApp instantiated. If we do, 00690 // we can create a TQSocketNotifier and use it for receiving data. 00691 if (tqApp) { 00692 if ( d->notifier ) 00693 delete d->notifier; 00694 d->notifier = new TQSocketNotifier(socket(), 00695 TQSocketNotifier::Read, 0, 0); 00696 TQObject::connect(d->notifier, TQT_SIGNAL(activated(int)), 00697 TQT_SLOT(processSocketData(int))); 00698 } 00699 } 00700 00701 void DCOPClient::suspend() 00702 { 00703 #ifdef Q_WS_WIN //TODO: remove (win32 ports sometimes do not create notifiers) 00704 if (!d->notifier) 00705 return; 00706 #endif 00707 assert(d->notifier); // Suspending makes no sense if we didn't had a tqApp yet 00708 d->notifier->setEnabled(false); 00709 } 00710 00711 void DCOPClient::resume() 00712 { 00713 #ifdef Q_WS_WIN //TODO: remove 00714 if (!d->notifier) 00715 return; 00716 #endif 00717 assert(d->notifier); // Should never happen 00718 d->notifier->setEnabled(true); 00719 } 00720 00721 bool DCOPClient::isSuspended() const 00722 { 00723 #if defined(Q_WS_WIN) || defined(Q_WS_MAC) //TODO: REMOVE 00724 if (!d->notifier) 00725 return false; 00726 #endif 00727 return !d->notifier->isEnabled(); 00728 } 00729 00730 #if defined(SO_PEERCRED) || defined(LOCAL_PEEREID) 00731 #define USE_PEER_IS_US 00732 // Check whether the remote end is owned by the same user. 00733 static bool peerIsUs(int sockfd) 00734 { 00735 #ifdef SO_PEERCRED 00736 #if defined(__OpenBSD__) 00737 struct sockpeercred cred; 00738 #else 00739 struct ucred cred; 00740 #endif 00741 socklen_t siz = sizeof(cred); 00742 if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &siz) != 0) 00743 return false; 00744 return (cred.uid == getuid()); 00745 #elif defined LOCAL_PEEREID 00746 struct unpcbid cred; 00747 socklen_t siz = sizeof(cred); 00748 if (getsockopt(sockfd, 0, LOCAL_PEEREID, &cred, &siz) != 0 || siz != sizeof(cred)) 00749 return false; 00750 return (cred.unp_euid == geteuid()); 00751 #endif 00752 } 00753 #else 00754 // Check whether the socket is owned by the same user. 00755 static bool isServerSocketOwnedByUser(const char*server) 00756 { 00757 #ifdef Q_OS_WIN 00758 if (strncmp(server, "tcp/", 4) != 0) 00759 return false; // Not a local socket -> foreign. 00760 else 00761 return true; 00762 #else 00763 if (strncmp(server, "local/", 6) != 0) 00764 return false; // Not a local socket -> foreign. 00765 const char *path = strchr(server, KPATH_SEPARATOR); 00766 if (!path) 00767 return false; 00768 path++; 00769 00770 struct stat stat_buf; 00771 if (stat(path, &stat_buf) != 0) 00772 return false; 00773 00774 return (stat_buf.st_uid == getuid()); 00775 #endif 00776 } 00777 #endif 00778 00779 00780 bool DCOPClient::attachInternal( bool registerAsAnonymous ) 00781 { 00782 char errBuf[1024]; 00783 00784 if ( isAttached() ) 00785 detach(); 00786 00787 if ((d->majorOpcode = IceRegisterForProtocolSetup(const_cast<char *>("DCOP"), 00788 const_cast<char *>(DCOPVendorString), 00789 const_cast<char *>(DCOPReleaseString), 00790 1, DCOPClientVersions, 00791 DCOPAuthCount, 00792 const_cast<char **>(DCOPAuthNames), 00793 DCOPClientAuthProcs, 0L)) < 0) { 00794 emit attachFailed(TQString::fromLatin1( "Communications could not be established." )); 00795 return false; 00796 } 00797 00798 bool bClearServerAddr = false; 00799 // first, check if serverAddr was ever set. 00800 if (!d->serverAddr) { 00801 // here, we obtain the list of possible DCOP connections, 00802 // and attach to them. 00803 TQCString dcopSrv; 00804 dcopSrv = ::getenv("DCOPSERVER"); 00805 if (dcopSrv.isEmpty()) { 00806 TQCString fName = dcopServerFile(); 00807 TQFile f(TQFile::decodeName(fName)); 00808 if (!f.open(IO_ReadOnly)) { 00809 emit attachFailed(TQString::fromLatin1( "Could not read network connection list.\n" )+TQFile::decodeName(fName)); 00810 return false; 00811 } 00812 int size = QMIN( (qint64)1024, f.size() ); // protection against a huge file 00813 TQCString contents( size+1 ); 00814 if ( f.readBlock( contents.data(), size ) != size ) 00815 { 00816 qDebug("Error reading from %s, didn't read the expected %d bytes", fName.data(), size); 00817 // Should we abort ? 00818 } 00819 contents[size] = '\0'; 00820 int pos = contents.find('\n'); 00821 if ( pos == -1 ) // Shouldn't happen 00822 { 00823 qDebug("Only one line in dcopserver file !: %s", contents.data()); 00824 dcopSrv = contents; 00825 } 00826 else 00827 { 00828 if(contents[pos - 1] == '\r') // check for windows end of line 00829 pos--; 00830 dcopSrv = contents.left( pos ); 00831 //#ifndef NDEBUG 00832 // qDebug("dcopserver address: %s", dcopSrv.data()); 00833 //#endif 00834 } 00835 } 00836 d->serverAddr = qstrdup( const_cast<char *>(dcopSrv.data()) ); 00837 bClearServerAddr = true; 00838 } 00839 00840 if ((d->iceConn = IceOpenConnection(const_cast<char*>(d->serverAddr), 00841 static_cast<IcePointer>(this), False, d->majorOpcode, 00842 sizeof(errBuf), errBuf)) == 0L) { 00843 qDebug("DCOPClient::attachInternal. Attach failed %s", errBuf); 00844 d->iceConn = 0; 00845 if (bClearServerAddr) { 00846 delete [] d->serverAddr; 00847 d->serverAddr = 0; 00848 } 00849 emit attachFailed(TQString::fromLatin1( errBuf )); 00850 return false; 00851 } 00852 fcntl(socket(), F_SETFL, FD_CLOEXEC); 00853 00854 IceSetShutdownNegotiation(d->iceConn, False); 00855 00856 int setupstat; 00857 char* vendor = 0; 00858 char* release = 0; 00859 setupstat = IceProtocolSetup(d->iceConn, d->majorOpcode, 00860 static_cast<IcePointer>(d), 00861 False, /* must authenticate */ 00862 &(d->majorVersion), &(d->minorVersion), 00863 &(vendor), &(release), 1024, errBuf); 00864 if (vendor) free(vendor); 00865 if (release) free(release); 00866 00867 if (setupstat == IceProtocolSetupFailure || 00868 setupstat == IceProtocolSetupIOError) { 00869 IceCloseConnection(d->iceConn); 00870 d->iceConn = 0; 00871 if (bClearServerAddr) { 00872 delete [] d->serverAddr; 00873 d->serverAddr = 0; 00874 } 00875 emit attachFailed(TQString::fromLatin1( errBuf )); 00876 return false; 00877 } else if (setupstat == IceProtocolAlreadyActive) { 00878 if (bClearServerAddr) { 00879 delete [] d->serverAddr; 00880 d->serverAddr = 0; 00881 } 00882 /* should not happen because 3rd arg to IceOpenConnection was 0. */ 00883 emit attachFailed(TQString::fromLatin1( "internal error in IceOpenConnection" )); 00884 return false; 00885 } 00886 00887 00888 if (IceConnectionStatus(d->iceConn) != IceConnectAccepted) { 00889 if (bClearServerAddr) { 00890 delete [] d->serverAddr; 00891 d->serverAddr = 0; 00892 } 00893 emit attachFailed(TQString::fromLatin1( "DCOP server did not accept the connection." )); 00894 return false; 00895 } 00896 00897 #ifdef USE_PEER_IS_US 00898 d->foreign_server = !peerIsUs(socket()); 00899 #else 00900 d->foreign_server = !isServerSocketOwnedByUser(d->serverAddr); 00901 #endif 00902 if (!d->accept_calls_override) 00903 d->accept_calls = !d->foreign_server; 00904 00905 bindToApp(); 00906 00907 if ( registerAsAnonymous ) 00908 registerAs( "anonymous", true ); 00909 00910 return true; 00911 } 00912 00913 00914 bool DCOPClient::detach() 00915 { 00916 int status; 00917 00918 if (d->iceConn) { 00919 IceProtocolShutdown(d->iceConn, d->majorOpcode); 00920 status = IceCloseConnection(d->iceConn); 00921 if (status != IceClosedNow) 00922 return false; 00923 else 00924 d->iceConn = 0L; 00925 } 00926 00927 if (d->registered) 00928 unregisterLocalClient(d->appId); 00929 00930 delete d->notifier; 00931 d->notifier = 0L; 00932 d->registered = false; 00933 d->foreign_server = true; 00934 return true; 00935 } 00936 00937 bool DCOPClient::isAttached() const 00938 { 00939 if (!d->iceConn) 00940 return false; 00941 00942 return (IceConnectionStatus(d->iceConn) == IceConnectAccepted); 00943 } 00944 00945 bool DCOPClient::isAttachedToForeignServer() const 00946 { 00947 return isAttached() && d->foreign_server; 00948 } 00949 00950 bool DCOPClient::acceptCalls() const 00951 { 00952 return isAttached() && d->accept_calls; 00953 } 00954 00955 void DCOPClient::setAcceptCalls(bool b) 00956 { 00957 d->accept_calls = b; 00958 d->accept_calls_override = true; 00959 } 00960 00961 bool DCOPClient::qtBridgeEnabled() 00962 { 00963 return d->qt_bridge_enabled; 00964 } 00965 00966 void DCOPClient::setQtBridgeEnabled(bool b) 00967 { 00968 d->qt_bridge_enabled = b; 00969 } 00970 00971 TQCString DCOPClient::registerAs( const TQCString &appId, bool addPID ) 00972 { 00973 TQCString result; 00974 00975 TQCString _appId = appId; 00976 00977 if (addPID) { 00978 TQCString pid; 00979 pid.sprintf("-%d", getpid()); 00980 _appId = _appId + pid; 00981 } 00982 00983 if( d->appId == _appId ) 00984 return d->appId; 00985 00986 #if 0 // no need to detach, dcopserver can handle renaming 00987 // Detach before reregistering. 00988 if ( isRegistered() ) { 00989 detach(); 00990 } 00991 #endif 00992 00993 if ( !isAttached() ) { 00994 if (!attachInternal( false )) 00995 if (!attachInternal( false )) 00996 return result; // Try two times 00997 } 00998 00999 // register the application identifier with the server 01000 TQCString replyType; 01001 TQByteArray data, replyData; 01002 TQDataStream arg( data, IO_WriteOnly ); 01003 arg << _appId; 01004 if ( call( "DCOPServer", "", "registerAs(TQCString)", data, replyType, replyData ) ) { 01005 TQDataStream reply( replyData, IO_ReadOnly ); 01006 reply >> result; 01007 } 01008 01009 d->appId = result; 01010 d->registered = !result.isNull(); 01011 01012 if (d->registered) 01013 registerLocalClient( d->appId, this ); 01014 01015 return result; 01016 } 01017 01018 bool DCOPClient::isRegistered() const 01019 { 01020 return d->registered; 01021 } 01022 01023 01024 TQCString DCOPClient::appId() const 01025 { 01026 return d->appId; 01027 } 01028 01029 01030 int DCOPClient::socket() const 01031 { 01032 if (d->iceConn) 01033 return IceConnectionNumber(d->iceConn); 01034 return 0; 01035 } 01036 01037 static inline bool isIdentChar( char x ) 01038 { // Avoid bug in isalnum 01039 return x == '_' || (x >= '0' && x <= '9') || 01040 (x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z'); 01041 } 01042 01043 TQCString DCOPClient::normalizeFunctionSignature( const TQCString& fun ) { 01044 if ( fun.isEmpty() ) // nothing to do 01045 return fun.copy(); 01046 TQCString result( fun.size() ); 01047 char *from = const_cast<TQCString&>(fun).data(); 01048 char *to = result.data(); 01049 char *first = to; 01050 char last = 0; 01051 while ( true ) { 01052 while ( *from && isspace(*from) ) 01053 from++; 01054 if ( last && isIdentChar( last ) && isIdentChar( *from ) ) 01055 *to++ = 0x20; 01056 while ( *from && !isspace(*from) ) { 01057 last = *from++; 01058 *to++ = last; 01059 } 01060 if ( !*from ) 01061 break; 01062 } 01063 if ( to > first && *(to-1) == 0x20 ) 01064 to--; 01065 *to = '\0'; 01066 result.resize( (int)((long)to - (long)result.data()) + 1 ); 01067 return result; 01068 } 01069 01070 01071 TQCString DCOPClient::senderId() const 01072 { 01073 return d->senderId; 01074 } 01075 01076 01077 bool DCOPClient::send(const TQCString &remApp, const TQCString &remObjId, 01078 const TQCString &remFun, const TQByteArray &data) 01079 { 01080 if (remApp.isEmpty()) 01081 return false; 01082 DCOPClient *localClient = findLocalClient( remApp ); 01083 01084 if ( localClient ) { 01085 bool saveTransaction = d->transaction; 01086 TQ_INT32 saveTransactionId = d->transactionId; 01087 TQCString saveSenderId = d->senderId; 01088 01089 d->senderId = 0; // Local call 01090 TQCString replyType; 01091 TQByteArray replyData; 01092 (void) localClient->receive( remApp, remObjId, remFun, data, replyType, replyData ); 01093 01094 d->transaction = saveTransaction; 01095 d->transactionId = saveTransactionId; 01096 d->senderId = saveSenderId; 01097 // send() returns true if the data could be send to the DCOPServer, 01098 // regardles of receiving the data on the other application. 01099 // So we assume the data is successfully send to the (virtual) server 01100 // and return true in any case. 01101 return true; 01102 } 01103 01104 if ( !isAttached() ) 01105 return false; 01106 01107 01108 DCOPMsg *pMsg; 01109 01110 TQByteArray ba; 01111 TQDataStream ds(ba, IO_WriteOnly); 01112 ds << d->appId << remApp << remObjId << normalizeFunctionSignature(remFun) << data.size(); 01113 01114 IceGetHeader(d->iceConn, d->majorOpcode, DCOPSend, 01115 sizeof(DCOPMsg), DCOPMsg, pMsg); 01116 01117 pMsg->key = 1; // DCOPSend always uses the magic key 1 01118 int datalen = ba.size() + data.size(); 01119 pMsg->length += datalen; 01120 01121 IceSendData( d->iceConn, ba.size(), const_cast<char *>(ba.data()) ); 01122 IceSendData( d->iceConn, data.size(), const_cast<char *>(data.data()) ); 01123 01124 //IceFlush(d->iceConn); 01125 01126 if (IceConnectionStatus(d->iceConn) == IceConnectAccepted) 01127 return true; 01128 return false; 01129 } 01130 01131 bool DCOPClient::send(const TQCString &remApp, const TQCString &remObjId, 01132 const TQCString &remFun, const TQString &data) 01133 { 01134 TQByteArray ba; 01135 TQDataStream ds(ba, IO_WriteOnly); 01136 ds << data; 01137 return send(remApp, remObjId, remFun, ba); 01138 } 01139 01140 bool DCOPClient::findObject(const TQCString &remApp, const TQCString &remObj, 01141 const TQCString &remFun, const TQByteArray &data, 01142 TQCString &foundApp, TQCString &foundObj, 01143 bool useEventLoop) 01144 { 01145 return findObject( remApp, remObj, remFun, data, foundApp, foundObj, useEventLoop, -1 ); 01146 } 01147 01148 bool DCOPClient::findObject(const TQCString &remApp, const TQCString &remObj, 01149 const TQCString &remFun, const TQByteArray &data, 01150 TQCString &foundApp, TQCString &foundObj, 01151 bool useEventLoop, int timeout) 01152 { 01153 QCStringList appList; 01154 TQCString app = remApp; 01155 if (app.isEmpty()) 01156 app = "*"; 01157 01158 foundApp = 0; 01159 foundObj = 0; 01160 01161 if (app[app.length()-1] == '*') 01162 { 01163 // Find all apps that match 'app'. 01164 // NOTE: It would be more efficient to do the filtering in 01165 // the dcopserver itself. 01166 int len = app.length()-1; 01167 QCStringList apps=registeredApplications(); 01168 for( QCStringList::ConstIterator it = apps.begin(); 01169 it != apps.end(); 01170 ++it) 01171 { 01172 if ( strncmp( (*it).data(), app.data(), len) == 0) 01173 appList.append(*it); 01174 } 01175 } 01176 else 01177 { 01178 appList.append(app); 01179 } 01180 01181 // We do all the local clients in phase1 and the rest in phase2 01182 for(int phase=1; phase <= 2; phase++) 01183 { 01184 for( QCStringList::ConstIterator it = appList.begin(); 01185 it != appList.end(); 01186 ++it) 01187 { 01188 TQCString remApp = *it; 01189 TQCString replyType; 01190 TQByteArray replyData; 01191 bool result = false; 01192 DCOPClient *localClient = findLocalClient( remApp ); 01193 01194 if ( (phase == 1) && localClient ) { 01195 // In phase 1 we do all local clients 01196 bool saveTransaction = d->transaction; 01197 TQ_INT32 saveTransactionId = d->transactionId; 01198 TQCString saveSenderId = d->senderId; 01199 01200 d->senderId = 0; // Local call 01201 result = localClient->find( remApp, remObj, remFun, data, replyType, replyData ); 01202 01203 TQ_INT32 id = localClient->transactionId(); 01204 if (id) { 01205 // Call delayed. We have to wait till it has been processed. 01206 do { 01207 TQApplication::eventLoop()->processEvents( TQEventLoop::WaitForMore); 01208 } while( !localClient->isLocalTransactionFinished(id, replyType, replyData)); 01209 result = true; 01210 } 01211 d->transaction = saveTransaction; 01212 d->transactionId = saveTransactionId; 01213 d->senderId = saveSenderId; 01214 } 01215 else if ((phase == 2) && !localClient) 01216 { 01217 // In phase 2 we do the other clients 01218 result = callInternal(remApp, remObj, remFun, data, 01219 replyType, replyData, useEventLoop, timeout, DCOPFind); 01220 } 01221 01222 if (result) 01223 { 01224 if (replyType == "DCOPRef") 01225 { 01226 DCOPRef ref; 01227 TQDataStream reply( replyData, IO_ReadOnly ); 01228 reply >> ref; 01229 01230 if (ref.app() == remApp) // Consistency check 01231 { 01232 // replyType contains objId. 01233 foundApp = ref.app(); 01234 foundObj = ref.object(); 01235 return true; 01236 } 01237 } 01238 } 01239 } 01240 } 01241 return false; 01242 } 01243 01244 bool DCOPClient::process(const TQCString &, const TQByteArray &, 01245 TQCString&, TQByteArray &) 01246 { 01247 return false; 01248 } 01249 01250 bool DCOPClient::isApplicationRegistered( const TQCString& remApp) 01251 { 01252 TQCString replyType; 01253 TQByteArray data, replyData; 01254 TQDataStream arg( data, IO_WriteOnly ); 01255 arg << remApp; 01256 int result = false; 01257 if ( call( "DCOPServer", "", "isApplicationRegistered(TQCString)", data, replyType, replyData ) ) { 01258 TQDataStream reply( replyData, IO_ReadOnly ); 01259 reply >> result; 01260 } 01261 return result; 01262 } 01263 01264 QCStringList DCOPClient::registeredApplications() 01265 { 01266 TQCString replyType; 01267 TQByteArray data, replyData; 01268 QCStringList result; 01269 if ( call( "DCOPServer", "", "registeredApplications()", data, replyType, replyData ) ) { 01270 TQDataStream reply( replyData, IO_ReadOnly ); 01271 reply >> result; 01272 } 01273 return result; 01274 } 01275 01276 QCStringList DCOPClient::remoteObjects( const TQCString& remApp, bool *ok ) 01277 { 01278 TQCString replyType; 01279 TQByteArray data, replyData; 01280 QCStringList result; 01281 if ( ok ) 01282 *ok = false; 01283 if ( call( remApp, "DCOPClient", "objects()", data, replyType, replyData ) ) { 01284 TQDataStream reply( replyData, IO_ReadOnly ); 01285 reply >> result; 01286 if ( ok ) 01287 *ok = true; 01288 } 01289 return result; 01290 } 01291 01292 QCStringList DCOPClient::remoteInterfaces( const TQCString& remApp, const TQCString& remObj, bool *ok ) 01293 { 01294 TQCString replyType; 01295 TQByteArray data, replyData; 01296 QCStringList result; 01297 if ( ok ) 01298 *ok = false; 01299 if ( call( remApp, remObj, "interfaces()", data, replyType, replyData ) && replyType == "QCStringList") { 01300 TQDataStream reply( replyData, IO_ReadOnly ); 01301 reply >> result; 01302 if ( ok ) 01303 *ok = true; 01304 } 01305 return result; 01306 } 01307 01308 QCStringList DCOPClient::remoteFunctions( const TQCString& remApp, const TQCString& remObj, bool *ok ) 01309 { 01310 TQCString replyType; 01311 TQByteArray data, replyData; 01312 QCStringList result; 01313 if ( ok ) 01314 *ok = false; 01315 if ( call( remApp, remObj, "functions()", data, replyType, replyData ) && replyType == "QCStringList") { 01316 TQDataStream reply( replyData, IO_ReadOnly ); 01317 reply >> result; 01318 if ( ok ) 01319 *ok = true; 01320 } 01321 return result; 01322 } 01323 01324 void DCOPClient::setNotifications(bool enabled) 01325 { 01326 TQByteArray data; 01327 TQDataStream ds(data, IO_WriteOnly); 01328 ds << static_cast<TQ_INT8>(enabled); 01329 01330 TQCString replyType; 01331 TQByteArray reply; 01332 if (!call("DCOPServer", "", "setNotifications( bool )", data, replyType, reply)) 01333 qWarning("I couldn't enable notifications at the dcopserver!"); 01334 } 01335 01336 void DCOPClient::setDaemonMode( bool daemonMode ) 01337 { 01338 TQByteArray data; 01339 TQDataStream ds(data, IO_WriteOnly); 01340 ds << static_cast<TQ_INT8>( daemonMode ); 01341 01342 TQCString replyType; 01343 TQByteArray reply; 01344 if (!call("DCOPServer", "", "setDaemonMode(bool)", data, replyType, reply)) 01345 qWarning("I couldn't enable daemon mode at the dcopserver!"); 01346 } 01347 01348 01349 01350 /* 01351 DCOP <-> Qt bridge 01352 01353 ******************************************************************************** 01354 */ 01355 static void fillQtObjects( QCStringList& l, TQObject* o, TQCString path ) 01356 { 01357 if ( !path.isEmpty() ) 01358 path += '/'; 01359 01360 int unnamed = 0; 01361 const TQObjectList list = o ? o->childrenListObject() : TQObject::objectTreesListObject(); 01362 if ( !list.isEmpty() ) { 01363 TQObjectListIt it( list ); 01364 TQObject *obj; 01365 while ( (obj=it.current()) ) { 01366 ++it; 01367 TQCString n = obj->name(); 01368 if ( n == "unnamed" || n.isEmpty() ) 01369 { 01370 n.sprintf("%p", (void *) obj); 01371 n = TQString(TQString("unnamed%1(%2, %3)").arg(++unnamed).arg(obj->className()).arg(TQString(n))).latin1(); 01372 } 01373 TQCString fn = path + n; 01374 l.append( fn ); 01375 if ( !obj->childrenListObject().isEmpty() ) 01376 fillQtObjects( l, obj, fn ); 01377 } 01378 } 01379 } 01380 01381 namespace 01382 { 01383 struct O 01384 { 01385 O(): o(0) {} 01386 O ( const TQCString& str, TQObject* obj ):s(str), o(obj){} 01387 TQCString s; 01388 TQObject* o; 01389 }; 01390 } // namespace 01391 01392 static void fillQtObjectsEx( TQValueList<O>& l, TQObject* o, TQCString path ) 01393 { 01394 if ( !path.isEmpty() ) 01395 path += '/'; 01396 01397 int unnamed = 0; 01398 const TQObjectList list = o ? o->childrenListObject() : TQObject::objectTreesListObject(); 01399 if ( !list.isEmpty() ) { 01400 TQObjectListIt it( list ); 01401 TQObject *obj; 01402 while ( (obj=it.current()) ) { 01403 ++it; 01404 TQCString n = obj->name(); 01405 if ( n == "unnamed" || n.isEmpty() ) 01406 { 01407 n.sprintf("%p", (void *) obj); 01408 n = TQString(TQString("unnamed%1(%2, %3)").arg(++unnamed).arg(obj->className()).arg(TQString(n))).latin1(); 01409 } 01410 TQCString fn = path + n; 01411 l.append( O( fn, obj ) ); 01412 if ( !obj->childrenListObject().isEmpty() ) 01413 fillQtObjectsEx( l, obj, fn ); 01414 } 01415 } 01416 } 01417 01418 01419 static TQObject* findQtObject( TQCString id ) 01420 { 01421 TQRegExp expr( id ); 01422 TQValueList<O> l; 01423 fillQtObjectsEx( l, 0, "qt" ); 01424 // Prefer an exact match, but fall-back on the first that contains the substring 01425 TQObject* firstContains = 0L; 01426 for ( TQValueList<O>::ConstIterator it = l.begin(); it != l.end(); ++it ) { 01427 if ( (*it).s == id ) // exact match 01428 return (*it).o; 01429 if ( !firstContains && (*it).s.contains( expr ) ) { 01430 firstContains = (*it).o; 01431 } 01432 } 01433 return firstContains; 01434 } 01435 01436 static QCStringList findQtObjects( TQCString id ) 01437 { 01438 TQRegExp expr( id ); 01439 TQValueList<O> l; 01440 fillQtObjectsEx( l, 0, "qt" ); 01441 QCStringList result; 01442 for ( TQValueList<O>::ConstIterator it = l.begin(); it != l.end(); ++it ) { 01443 if ( (*it).s.contains( expr ) ) 01444 result << (*it).s; 01445 } 01446 return result; 01447 } 01448 01449 static bool receiveQtObject( const TQCString &objId, const TQCString &fun, const TQByteArray &data, 01450 TQCString& replyType, TQByteArray &replyData) 01451 { 01452 if ( objId == "qt" ) { 01453 if ( fun == "interfaces()" ) { 01454 replyType = "QCStringList"; 01455 TQDataStream reply( replyData, IO_WriteOnly ); 01456 QCStringList l; 01457 l << "DCOPObject"; 01458 l << "Qt"; 01459 reply << l; 01460 return true; 01461 } else if ( fun == "functions()" ) { 01462 replyType = "QCStringList"; 01463 TQDataStream reply( replyData, IO_WriteOnly ); 01464 QCStringList l; 01465 l << "QCStringList functions()"; 01466 l << "QCStringList interfaces()"; 01467 l << "QCStringList objects()"; 01468 l << "QCStringList find(TQCString)"; 01469 reply << l; 01470 return true; 01471 } else if ( fun == "objects()" ) { 01472 replyType = "QCStringList"; 01473 TQDataStream reply( replyData, IO_WriteOnly ); 01474 QCStringList l; 01475 fillQtObjects( l, 0, "qt" ); 01476 reply << l; 01477 return true; 01478 } else if ( fun == "find(TQCString)" ) { 01479 TQDataStream ds( data, IO_ReadOnly ); 01480 TQCString id; 01481 ds >> id ; 01482 replyType = "QCStringList"; 01483 TQDataStream reply( replyData, IO_WriteOnly ); 01484 reply << findQtObjects( id ) ; 01485 return true; 01486 } 01487 } else if ( objId.left(3) == "qt/" ) { 01488 TQObject* o = findQtObject( objId ); 01489 if ( !o ) 01490 return false; 01491 if ( fun == "functions()" ) { 01492 replyType = "QCStringList"; 01493 TQDataStream reply( replyData, IO_WriteOnly ); 01494 QCStringList l; 01495 l << "QCStringList functions()"; 01496 l << "QCStringList interfaces()"; 01497 l << "QCStringList properties()"; 01498 l << "bool setProperty(TQCString,TQVariant)"; 01499 l << "TQVariant property(TQCString)"; 01500 TQStrList lst = o->metaObject()->slotNames( true ); 01501 int i = 0; 01502 for ( TQPtrListIterator<char> it( lst ); it.current(); ++it ) { 01503 if ( o->metaObject()->slot( i++, true )->tqt_mo_access != TQMetaData::Public ) 01504 continue; 01505 TQCString slot = it.current(); 01506 if ( slot.contains( "()" ) ) { 01507 slot.prepend("void "); 01508 l << slot; 01509 } 01510 } 01511 reply << l; 01512 return true; 01513 } else if ( fun == "interfaces()" ) { 01514 replyType = "QCStringList"; 01515 TQDataStream reply( replyData, IO_WriteOnly ); 01516 QCStringList l; 01517 TQMetaObject *meta = o->metaObject(); 01518 while ( meta ) { 01519 l.prepend( meta->className() ); 01520 meta = meta->superClass(); 01521 } 01522 reply << l; 01523 return true; 01524 } else if ( fun == "properties()" ) { 01525 replyType = "QCStringList"; 01526 TQDataStream reply( replyData, IO_WriteOnly ); 01527 QCStringList l; 01528 TQStrList lst = o->metaObject()->propertyNames( true ); 01529 for ( TQPtrListIterator<char> it( lst ); it.current(); ++it ) { 01530 TQMetaObject *mo = o->metaObject(); 01531 const TQMetaProperty* p = mo->property( mo->findProperty( it.current(), true ), true ); 01532 if ( !p ) 01533 continue; 01534 TQCString prop = p->type(); 01535 prop += ' '; 01536 prop += p->name(); 01537 if ( !p->writable() ) 01538 prop += " readonly"; 01539 l << prop; 01540 } 01541 reply << l; 01542 return true; 01543 } else if ( fun == "property(TQCString)" ) { 01544 replyType = "TQVariant"; 01545 TQDataStream ds( data, IO_ReadOnly ); 01546 TQCString name; 01547 ds >> name ; 01548 TQVariant result = o->property( name ); 01549 TQDataStream reply( replyData, IO_WriteOnly ); 01550 reply << result; 01551 return true; 01552 } else if ( fun == "setProperty(TQCString,TQVariant)" ) { 01553 TQDataStream ds( data, IO_ReadOnly ); 01554 TQCString name; 01555 TQVariant value; 01556 ds >> name >> value; 01557 replyType = "bool"; 01558 TQDataStream reply( replyData, IO_WriteOnly ); 01559 reply << (TQ_INT8) o->setProperty( name, value ); 01560 return true; 01561 } else { 01562 int slot = o->metaObject()->findSlot( fun, true ); 01563 if ( slot != -1 ) { 01564 replyType = "void"; 01565 TQUObject uo[ 1 ]; 01566 o->qt_invoke( slot, uo ); 01567 return true; 01568 } 01569 } 01570 01571 01572 } 01573 return false; 01574 } 01575 01576 01577 /* 01578 ******************************************************************************** 01579 End of DCOP <-> Qt bridge 01580 */ 01581 01582 01583 bool DCOPClient::receive(const TQCString &/*app*/, const TQCString &objId, 01584 const TQCString &fun, const TQByteArray &data, 01585 TQCString& replyType, TQByteArray &replyData) 01586 { 01587 d->transaction = false; // Assume no transaction. 01588 if ( objId == "DCOPClient" ) { 01589 if ( fun == "objects()" ) { 01590 replyType = "QCStringList"; 01591 TQDataStream reply( replyData, IO_WriteOnly ); 01592 QCStringList l; 01593 if (d->qt_bridge_enabled) 01594 { 01595 l << "qt"; // the Qt bridge object 01596 } 01597 if ( kde_dcopObjMap ) { 01598 TQMap<TQCString, DCOPObject *>::ConstIterator it( kde_dcopObjMap->begin()); 01599 for (; it != kde_dcopObjMap->end(); ++it) { 01600 if ( !it.key().isEmpty() ) { 01601 if ( it.key() == d->defaultObject ) 01602 l << "default"; 01603 l << it.key(); 01604 } 01605 } 01606 } 01607 reply << l; 01608 return true; 01609 } 01610 } 01611 01612 if ( objId.isEmpty() || objId == "DCOPClient" ) { 01613 if ( fun == "applicationRegistered(TQCString)" ) { 01614 TQDataStream ds( data, IO_ReadOnly ); 01615 TQCString r; 01616 ds >> r; 01617 emit applicationRegistered( r ); 01618 return true; 01619 } else if ( fun == "applicationRemoved(TQCString)" ) { 01620 TQDataStream ds( data, IO_ReadOnly ); 01621 TQCString r; 01622 ds >> r; 01623 emit applicationRemoved( r ); 01624 return true; 01625 } 01626 01627 if ( process( fun, data, replyType, replyData ) ) 01628 return true; 01629 // fall through and send to defaultObject if available 01630 01631 } else if (d->qt_bridge_enabled && 01632 (objId == "qt" || objId.left(3) == "qt/") ) { // dcop <-> qt bridge 01633 return receiveQtObject( objId, fun, data, replyType, replyData ); 01634 } 01635 01636 if ( objId.isEmpty() || objId == "default" ) { 01637 if ( !d->defaultObject.isEmpty() && DCOPObject::hasObject( d->defaultObject ) ) { 01638 DCOPObject *objPtr = DCOPObject::find( d->defaultObject ); 01639 objPtr->setCallingDcopClient(this); 01640 if (objPtr->process(fun, data, replyType, replyData)) 01641 return true; 01642 } 01643 01644 // fall through and send to object proxies 01645 } 01646 01647 // if (!objId.isEmpty() && objId[objId.length()-1] == '*') { 01648 if (!objId.isEmpty() && ((objId.length()>0)?(objId[objId.length()-1] == '*'):0)) { 01649 // handle a multicast to several objects. 01650 // doesn't handle proxies currently. should it? 01651 TQPtrList<DCOPObject> matchList = 01652 DCOPObject::match(objId.left(objId.length()-1)); 01653 for (DCOPObject *objPtr = matchList.first(); 01654 objPtr != 0L; objPtr = matchList.next()) { 01655 objPtr->setCallingDcopClient(this); 01656 if (!objPtr->process(fun, data, replyType, replyData)) 01657 return false; 01658 } 01659 return true; 01660 } else if (!DCOPObject::hasObject(objId)) { 01661 if ( DCOPObjectProxy::proxies ) { 01662 for ( TQPtrListIterator<DCOPObjectProxy> it( *DCOPObjectProxy::proxies ); it.current(); ++it ) { 01663 // TODO: it.current()->setCallingDcopClient(this); 01664 if ( it.current()->process( objId, fun, data, replyType, replyData ) ) 01665 return true; 01666 } 01667 } 01668 return false; 01669 01670 } else { 01671 DCOPObject *objPtr = DCOPObject::find(objId); 01672 objPtr->setCallingDcopClient(this); 01673 if (!objPtr->process(fun, data, replyType, replyData)) { 01674 // obj doesn't understand function or some other error. 01675 return false; 01676 } 01677 } 01678 01679 return true; 01680 } 01681 01682 // Check if the function result is a bool with the value "true" 01683 // If so set the function result to DCOPRef pointing to (app,objId) and 01684 // return true. Return false otherwise. 01685 static bool findResultOk(TQCString &replyType, TQByteArray &replyData) 01686 { 01687 TQ_INT8 success; // Tsk.. why is there no operator>>(bool)? 01688 if (replyType != "bool") return false; 01689 01690 TQDataStream reply( replyData, IO_ReadOnly ); 01691 reply >> success; 01692 01693 if (!success) return false; 01694 return true; 01695 } 01696 01697 // set the function result to DCOPRef pointing to (app,objId) and 01698 // return true. 01699 static bool findSuccess(const TQCString &app, const TQCString objId, TQCString &replyType, TQByteArray &replyData) 01700 { 01701 DCOPRef ref(app, objId); 01702 replyType = "DCOPRef"; 01703 01704 replyData = TQByteArray(); 01705 TQDataStream final_reply( replyData, IO_WriteOnly ); 01706 final_reply << ref; 01707 return true; 01708 } 01709 01710 01711 bool DCOPClient::find(const TQCString &app, const TQCString &objId, 01712 const TQCString &fun, const TQByteArray &data, 01713 TQCString& replyType, TQByteArray &replyData) 01714 { 01715 d->transaction = false; // Transactions are not allowed. 01716 if ( !app.isEmpty() && app != d->appId && app[app.length()-1] != '*') { 01717 qWarning("WEIRD! we somehow received a DCOP message w/a different appId"); 01718 return false; 01719 } 01720 01721 if (objId.isEmpty() || objId[objId.length()-1] != '*') 01722 { 01723 if (fun.isEmpty()) 01724 { 01725 if (objId.isEmpty() || DCOPObject::hasObject(objId)) 01726 return findSuccess(app, objId, replyType, replyData); 01727 return false; 01728 } 01729 // Message to application or single object... 01730 if (receive(app, objId, fun, data, replyType, replyData)) 01731 { 01732 if (findResultOk(replyType, replyData)) 01733 return findSuccess(app, objId, replyType, replyData); 01734 } 01735 } 01736 else { 01737 // handle a multicast to several objects. 01738 // doesn't handle proxies currently. should it? 01739 TQPtrList<DCOPObject> matchList = 01740 DCOPObject::match(objId.left(objId.length()-1)); 01741 for (DCOPObject *objPtr = matchList.first(); 01742 objPtr != 0L; objPtr = matchList.next()) 01743 { 01744 replyType = 0; 01745 replyData = TQByteArray(); 01746 if (fun.isEmpty()) 01747 return findSuccess(app, objPtr->objId(), replyType, replyData); 01748 objPtr->setCallingDcopClient(this); 01749 if (objPtr->process(fun, data, replyType, replyData)) 01750 if (findResultOk(replyType, replyData)) 01751 return findSuccess(app, objPtr->objId(), replyType, replyData); 01752 } 01753 } 01754 return false; 01755 } 01756 01757 01758 bool DCOPClient::call(const TQCString &remApp, const TQCString &remObjId, 01759 const TQCString &remFun, const TQByteArray &data, 01760 TQCString& replyType, TQByteArray &replyData, 01761 bool useEventLoop) 01762 { 01763 return call( remApp, remObjId, remFun, data, replyType, replyData, useEventLoop, -1 ); 01764 } 01765 01766 bool DCOPClient::call(const TQCString &remApp, const TQCString &remObjId, 01767 const TQCString &remFun, const TQByteArray &data, 01768 TQCString& replyType, TQByteArray &replyData, 01769 bool useEventLoop, int timeout) 01770 { 01771 if (remApp.isEmpty()) 01772 return false; 01773 DCOPClient *localClient = findLocalClient( remApp ); 01774 01775 if ( localClient ) { 01776 bool saveTransaction = d->transaction; 01777 TQ_INT32 saveTransactionId = d->transactionId; 01778 TQCString saveSenderId = d->senderId; 01779 01780 d->senderId = 0; // Local call 01781 bool b = localClient->receive( remApp, remObjId, remFun, data, replyType, replyData ); 01782 01783 TQ_INT32 id = localClient->transactionId(); 01784 if (id) { 01785 // Call delayed. We have to wait till it has been processed. 01786 do { 01787 TQApplication::eventLoop()->processEvents( TQEventLoop::WaitForMore); 01788 } while( !localClient->isLocalTransactionFinished(id, replyType, replyData)); 01789 b = true; 01790 } 01791 d->transaction = saveTransaction; 01792 d->transactionId = saveTransactionId; 01793 d->senderId = saveSenderId; 01794 return b; 01795 } 01796 01797 return callInternal(remApp, remObjId, remFun, data, 01798 replyType, replyData, useEventLoop, timeout, DCOPCall); 01799 } 01800 01801 void DCOPClient::asyncReplyReady() 01802 { 01803 while( d->asyncReplyQueue.count() ) 01804 { 01805 ReplyStruct *replyStruct = d->asyncReplyQueue.take(0); 01806 handleAsyncReply(replyStruct); 01807 } 01808 } 01809 01810 int DCOPClient::callAsync(const TQCString &remApp, const TQCString &remObjId, 01811 const TQCString &remFun, const TQByteArray &data, 01812 TQObject *callBackObj, const char *callBackSlot) 01813 { 01814 TQCString replyType; 01815 TQByteArray replyData; 01816 01817 ReplyStruct *replyStruct = new ReplyStruct; 01818 replyStruct->replyType = new TQCString; 01819 replyStruct->replyData = new TQByteArray; 01820 replyStruct->replyObject = callBackObj; 01821 replyStruct->replySlot = callBackSlot; 01822 replyStruct->replyId = ++d->transactionId; 01823 if (d->transactionId < 0) // Ensure that ids > 0 01824 d->transactionId = 0; 01825 01826 bool b = callInternal(remApp, remObjId, remFun, data, 01827 replyStruct, false, -1, DCOPCall); 01828 if (!b) 01829 { 01830 delete replyStruct->replyType; 01831 delete replyStruct->replyData; 01832 delete replyStruct; 01833 return 0; 01834 } 01835 01836 if (replyStruct->transactionId == 0) 01837 { 01838 // Call is finished already 01839 TQTimer::singleShot(0, this, TQT_SLOT(asyncReplyReady())); 01840 d->asyncReplyQueue.append(replyStruct); 01841 } 01842 01843 return replyStruct->replyId; 01844 } 01845 01846 bool DCOPClient::callInternal(const TQCString &remApp, const TQCString &remObjId, 01847 const TQCString &remFun, const TQByteArray &data, 01848 TQCString& replyType, TQByteArray &replyData, 01849 bool useEventLoop, int timeout, int minor_opcode) 01850 { 01851 ReplyStruct replyStruct; 01852 replyStruct.replyType = &replyType; 01853 replyStruct.replyData = &replyData; 01854 return callInternal(remApp, remObjId, remFun, data, &replyStruct, useEventLoop, timeout, minor_opcode); 01855 } 01856 01857 bool DCOPClient::callInternal(const TQCString &remApp, const TQCString &remObjId, 01858 const TQCString &remFun, const TQByteArray &data, 01859 ReplyStruct *replyStruct, 01860 bool useEventLoop, int timeout, int minor_opcode) 01861 { 01862 if ( !isAttached() ) 01863 return false; 01864 01865 DCOPMsg *pMsg; 01866 01867 CARD32 oldCurrentKey = d->currentKey; 01868 if ( !d->currentKey ) 01869 d->currentKey = d->key; // no key yet, initiate new call 01870 01871 TQByteArray ba; 01872 TQDataStream ds(ba, IO_WriteOnly); 01873 ds << d->appId << remApp << remObjId << normalizeFunctionSignature(remFun) << data.size(); 01874 01875 IceGetHeader(d->iceConn, d->majorOpcode, minor_opcode, 01876 sizeof(DCOPMsg), DCOPMsg, pMsg); 01877 01878 pMsg->key = d->currentKey; 01879 int datalen = ba.size() + data.size(); 01880 pMsg->length += datalen; 01881 01882 // qWarning("DCOP: %s made call %s:%s:%s key = %d", d->appId.data(), remApp.data(), remObjId.data(), remFun.data(), pMsg->key); 01883 01884 IceSendData(d->iceConn, ba.size(), const_cast<char *>(ba.data())); 01885 IceSendData(d->iceConn, data.size(), const_cast<char *>(data.data())); 01886 01887 if (IceConnectionStatus(d->iceConn) != IceConnectAccepted) 01888 return false; 01889 01890 IceFlush (d->iceConn); 01891 01892 IceReplyWaitInfo waitInfo; 01893 waitInfo.sequence_of_request = IceLastSentSequenceNumber(d->iceConn); 01894 waitInfo.major_opcode_of_request = d->majorOpcode; 01895 waitInfo.minor_opcode_of_request = minor_opcode; 01896 01897 replyStruct->transactionId = -1; 01898 waitInfo.reply = static_cast<IcePointer>(replyStruct); 01899 01900 Bool readyRet = False; 01901 IceProcessMessagesStatus s; 01902 01903 timeval time_start; 01904 int time_left = -1; 01905 if( timeout >= 0 ) 01906 { 01907 gettimeofday( &time_start, NULL ); 01908 time_left = timeout; 01909 } 01910 for(;;) { 01911 bool checkMessages = true; 01912 if ( useEventLoop 01913 ? d->notifier != NULL // useEventLoop needs a socket notifier and a tqApp 01914 : timeout >= 0 ) { // !useEventLoop doesn't block only for timeout >= 0 01915 const int guiTimeout = 100; 01916 checkMessages = false; 01917 01918 int msecs = useEventLoop 01919 ? guiTimeout // timeout for the GUI refresh 01920 : time_left; // time remaining for the whole call 01921 fd_set fds; 01922 struct timeval tv; 01923 FD_ZERO( &fds ); 01924 FD_SET( socket(), &fds ); 01925 tv.tv_sec = msecs / 1000; 01926 tv.tv_usec = (msecs % 1000) * 1000; 01927 if ( select( socket() + 1, &fds, 0, 0, &tv ) <= 0 ) { 01928 if( useEventLoop && (timeout < 0 || time_left > guiTimeout)) { 01929 // nothing was available, we got a timeout. Reactivate 01930 // the GUI in blocked state. 01931 bool old_lock = d->non_blocking_call_lock; 01932 if ( !old_lock ) { 01933 d->non_blocking_call_lock = true; 01934 emit blockUserInput( true ); 01935 } 01936 if( timeout >= 0 ) 01937 d->eventLoopTimer.start(time_left - guiTimeout, true); 01938 tqApp->enter_loop(); 01939 d->eventLoopTimer.stop(); 01940 if ( !old_lock ) { 01941 d->non_blocking_call_lock = false; 01942 emit blockUserInput( false ); 01943 } 01944 } 01945 } 01946 else 01947 { 01948 checkMessages = true; 01949 } 01950 } 01951 if (!d->iceConn) 01952 return false; 01953 01954 if( replyStruct->transactionId != -1 ) 01955 { 01956 if (replyStruct->transactionId == 0) 01957 break; // Call complete 01958 if (!replyStruct->replySlot.isEmpty()) 01959 break; // Async call 01960 } 01961 01962 if( checkMessages ) { // something is available 01963 s = IceProcessMessages(d->iceConn, &waitInfo, 01964 &readyRet); 01965 if (s == IceProcessMessagesIOError) { 01966 detach(); 01967 d->currentKey = oldCurrentKey; 01968 return false; 01969 } 01970 } 01971 01972 if( replyStruct->transactionId != -1 ) 01973 { 01974 if (replyStruct->transactionId == 0) 01975 break; // Call complete 01976 if (!replyStruct->replySlot.isEmpty()) 01977 break; // Async call 01978 } 01979 01980 if( timeout < 0 ) 01981 continue; 01982 timeval time_now; 01983 gettimeofday( &time_now, NULL ); 01984 time_left = timeout - 01985 ((time_now.tv_sec - time_start.tv_sec) * 1000) - 01986 ((time_now.tv_usec - time_start.tv_usec) / 1000); 01987 if( time_left <= 0) 01988 { 01989 if (useEventLoop) 01990 { 01991 // Before we fail, check one more time if something is available 01992 time_left = 0; 01993 useEventLoop = false; 01994 continue; 01995 } 01996 *(replyStruct->replyType) = TQCString(); 01997 *(replyStruct->replyData) = TQByteArray(); 01998 replyStruct->status = ReplyStruct::Failed; 01999 break; 02000 } 02001 } 02002 02003 // Wake up parent call, maybe it's reply is available already. 02004 if ( d->non_blocking_call_lock ) { 02005 tqApp->exit_loop(); 02006 } 02007 02008 d->currentKey = oldCurrentKey; 02009 return replyStruct->status != ReplyStruct::Failed; 02010 } 02011 02012 void DCOPClient::eventLoopTimeout() 02013 { 02014 tqApp->exit_loop(); 02015 } 02016 02017 void DCOPClient::processSocketData(int fd) 02018 { 02019 // Make sure there is data to read! 02020 fd_set fds; 02021 timeval timeout; 02022 timeout.tv_sec = 0; 02023 timeout.tv_usec = 0; 02024 FD_ZERO(&fds); 02025 FD_SET(fd, &fds); 02026 int result = select(fd+1, &fds, 0, 0, &timeout); 02027 if (result == 0) 02028 return; 02029 02030 if ( d->non_blocking_call_lock ) { 02031 if( tqApp ) 02032 tqApp->exit_loop(); 02033 return; 02034 } 02035 02036 if (!d->iceConn) { 02037 if( d->notifier ) 02038 d->notifier->deleteLater(); 02039 d->notifier = 0; 02040 qWarning("received an error processing data from the DCOP server!"); 02041 return; 02042 } 02043 02044 IceProcessMessagesStatus s = IceProcessMessages(d->iceConn, 0, 0); 02045 02046 if (s == IceProcessMessagesIOError) { 02047 detach(); 02048 qWarning("received an error processing data from the DCOP server!"); 02049 return; 02050 } 02051 } 02052 02053 void DCOPClient::setDefaultObject( const TQCString& objId ) 02054 { 02055 d->defaultObject = objId; 02056 } 02057 02058 02059 TQCString DCOPClient::defaultObject() const 02060 { 02061 return d->defaultObject; 02062 } 02063 02064 bool 02065 DCOPClient::isLocalTransactionFinished(TQ_INT32 id, TQCString &replyType, TQByteArray &replyData) 02066 { 02067 DCOPClientPrivate::LocalTransactionResult *result = d->localTransActionList.take(id); 02068 if (!result) 02069 return false; 02070 02071 replyType = result->replyType; 02072 replyData = result->replyData; 02073 delete result; 02074 02075 return true; 02076 } 02077 02078 DCOPClientTransaction * 02079 DCOPClient::beginTransaction() 02080 { 02081 if (d->opcode == DCOPSend) 02082 return 0; 02083 if (!d->transactionList) 02084 d->transactionList = new TQPtrList<DCOPClientTransaction>; 02085 02086 d->transaction = true; 02087 DCOPClientTransaction *trans = new DCOPClientTransaction(); 02088 trans->senderId = d->senderId; 02089 trans->id = ++d->transactionId; 02090 if (d->transactionId < 0) // Ensure that ids > 0 02091 d->transactionId = 0; 02092 trans->key = d->currentKey; 02093 02094 d->transactionList->append( trans ); 02095 02096 return trans; 02097 } 02098 02099 TQ_INT32 02100 DCOPClient::transactionId() const 02101 { 02102 if (d->transaction) 02103 return d->transactionId; 02104 else 02105 return 0; 02106 } 02107 02108 void 02109 DCOPClient::endTransaction( DCOPClientTransaction *trans, TQCString& replyType, 02110 TQByteArray &replyData) 02111 { 02112 if ( !trans ) 02113 return; 02114 02115 if ( !isAttached() ) 02116 return; 02117 02118 if ( !d->transactionList) { 02119 qWarning("Transaction unknown: No pending transactions!"); 02120 return; // No pending transactions! 02121 } 02122 02123 if ( !d->transactionList->removeRef( trans ) ) { 02124 qWarning("Transaction unknown: Not on list of pending transactions!"); 02125 return; // Transaction 02126 } 02127 02128 if (trans->senderId.isEmpty()) 02129 { 02130 // Local transaction 02131 DCOPClientPrivate::LocalTransactionResult *result = new DCOPClientPrivate::LocalTransactionResult(); 02132 result->replyType = replyType; 02133 result->replyData = replyData; 02134 02135 d->localTransActionList.insert(trans->id, result); 02136 02137 delete trans; 02138 02139 return; 02140 } 02141 02142 DCOPMsg *pMsg; 02143 02144 TQByteArray ba; 02145 TQDataStream ds(ba, IO_WriteOnly); 02146 ds << d->appId << trans->senderId << trans->id << replyType << replyData; 02147 02148 IceGetHeader(d->iceConn, d->majorOpcode, DCOPReplyDelayed, 02149 sizeof(DCOPMsg), DCOPMsg, pMsg); 02150 pMsg->key = trans->key; 02151 pMsg->length += ba.size(); 02152 02153 IceSendData( d->iceConn, ba.size(), const_cast<char *>(ba.data()) ); 02154 02155 delete trans; 02156 } 02157 02158 void 02159 DCOPClient::emitDCOPSignal( const TQCString &object, const TQCString &signal, const TQByteArray &data) 02160 { 02161 // We hack the sending object name into the signal name 02162 send("DCOPServer", "emit", object+"#"+normalizeFunctionSignature(signal), data); 02163 } 02164 02165 void 02166 DCOPClient::emitDCOPSignal( const TQCString &signal, const TQByteArray &data) 02167 { 02168 emitDCOPSignal(0, signal, data); 02169 } 02170 02171 bool 02172 DCOPClient::connectDCOPSignal( const TQCString &sender, const TQCString &senderObj, 02173 const TQCString &signal, 02174 const TQCString &receiverObj, const TQCString &slot, bool Volatile) 02175 { 02176 TQCString replyType; 02177 TQByteArray data, replyData; 02178 TQ_INT8 iVolatile = Volatile ? 1 : 0; 02179 02180 TQDataStream args(data, IO_WriteOnly ); 02181 args << sender << senderObj << normalizeFunctionSignature(signal) << receiverObj << normalizeFunctionSignature(slot) << iVolatile; 02182 02183 if (!call("DCOPServer", 0, 02184 "connectSignal(TQCString,TQCString,TQCString,TQCString,TQCString,bool)", 02185 data, replyType, replyData)) 02186 { 02187 return false; 02188 } 02189 02190 if (replyType != "bool") 02191 return false; 02192 02193 TQDataStream reply(replyData, IO_ReadOnly ); 02194 TQ_INT8 result; 02195 reply >> result; 02196 return (result != 0); 02197 } 02198 02199 bool 02200 DCOPClient::connectDCOPSignal( const TQCString &sender, const TQCString &signal, 02201 const TQCString &receiverObj, const TQCString &slot, bool Volatile) 02202 { 02203 return connectDCOPSignal( sender, 0, signal, receiverObj, slot, Volatile); 02204 } 02205 02206 bool 02207 DCOPClient::disconnectDCOPSignal( const TQCString &sender, const TQCString &senderObj, 02208 const TQCString &signal, 02209 const TQCString &receiverObj, const TQCString &slot) 02210 { 02211 TQCString replyType; 02212 TQByteArray data, replyData; 02213 02214 TQDataStream args(data, IO_WriteOnly ); 02215 args << sender << senderObj << normalizeFunctionSignature(signal) << receiverObj << normalizeFunctionSignature(slot); 02216 02217 if (!call("DCOPServer", 0, 02218 "disconnectSignal(TQCString,TQCString,TQCString,TQCString,TQCString)", 02219 data, replyType, replyData)) 02220 { 02221 return false; 02222 } 02223 02224 if (replyType != "bool") 02225 return false; 02226 02227 TQDataStream reply(replyData, IO_ReadOnly ); 02228 TQ_INT8 result; 02229 reply >> result; 02230 return (result != 0); 02231 } 02232 02233 bool 02234 DCOPClient::disconnectDCOPSignal( const TQCString &sender, const TQCString &signal, 02235 const TQCString &receiverObj, const TQCString &slot) 02236 { 02237 return disconnectDCOPSignal( sender, 0, signal, receiverObj, slot); 02238 } 02239 02240 void 02241 DCOPClient::setPriorityCall(bool b) 02242 { 02243 if (b) 02244 { 02245 if (d->currentKey == 2) 02246 return; 02247 d->currentKeySaved = d->currentKey; 02248 d->currentKey = 2; 02249 } 02250 else 02251 { 02252 if (d->currentKey != 2) 02253 return; 02254 d->currentKey = d->currentKeySaved; 02255 if ( !d->messages.isEmpty() ) 02256 d->postMessageTimer.start( 0, true ); // Process queued messages 02257 } 02258 } 02259 02260 02261 02262 void 02263 DCOPClient::emergencyClose() 02264 { 02265 TQPtrList<DCOPClient> list; 02266 client_map_t *map = DCOPClient_CliMap; 02267 if (!map) return; 02268 TQAsciiDictIterator<DCOPClient> it(*map); 02269 while(it.current()) { 02270 list.removeRef(it.current()); 02271 list.append(it.current()); 02272 ++it; 02273 } 02274 for(DCOPClient *cl = list.first(); cl; cl = list.next()) 02275 { 02276 if (cl->d->iceConn) { 02277 IceProtocolShutdown(cl->d->iceConn, cl->d->majorOpcode); 02278 IceCloseConnection(cl->d->iceConn); 02279 cl->d->iceConn = 0L; 02280 } 02281 } 02282 } 02283 02284 const char * 02285 DCOPClient::postMortemSender() 02286 { 02287 if (!dcop_main_client) 02288 return ""; 02289 if (dcop_main_client->d->senderId.isEmpty()) 02290 return ""; 02291 return dcop_main_client->d->senderId.data(); 02292 } 02293 02294 const char * 02295 DCOPClient::postMortemObject() 02296 { 02297 if (!dcop_main_client) 02298 return ""; 02299 return dcop_main_client->d->objId.data(); 02300 } 02301 const char * 02302 DCOPClient::postMortemFunction() 02303 { 02304 if (!dcop_main_client) 02305 return ""; 02306 return dcop_main_client->d->function.data(); 02307 } 02308 02309 void DCOPClient::virtual_hook( int, void* ) 02310 { /*BASE::virtual_hook( id, data );*/ } 02311 02312 #include <dcopclient.moc> 02313