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