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