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