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