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