dcop Library API Documentation

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