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