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