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