00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <qobjectlist.h>
00027 #include <qmetaobject.h>
00028 #include <qvariant.h>
00029 #include <qtimer.h>
00030 #include <qintdict.h>
00031 #include <qeventloop.h>
00032
00033
00034 #include "config.h"
00035
00036 #include <config.h>
00037 #include <dcopref.h>
00038
00039 #include <sys/types.h>
00040 #include <sys/stat.h>
00041 #include <sys/file.h>
00042 #include <sys/socket.h>
00043
00044 #include <ctype.h>
00045 #include <unistd.h>
00046 #include <stdlib.h>
00047 #include <assert.h>
00048 #include <string.h>
00049
00050 #ifndef QT_CLEAN_NAMESPACE
00051 #define QT_CLEAN_NAMESPACE
00052 #endif
00053 #include <qguardedptr.h>
00054 #include <qtextstream.h>
00055 #include <qfile.h>
00056 #include <qapplication.h>
00057 #include <qsocketnotifier.h>
00058 #include <qregexp.h>
00059
00060 #include <private/qucomextra_p.h>
00061
00062 #include <dcopglobal.h>
00063 #include <dcopclient.h>
00064 #include <dcopobject.h>
00065
00066 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00067 #include <X11/Xmd.h>
00068 #endif
00069 extern "C" {
00070 #include <KDE-ICE/ICElib.h>
00071 #include <KDE-ICE/ICEutil.h>
00072 #include <KDE-ICE/ICEmsg.h>
00073 #include <KDE-ICE/ICEproto.h>
00074
00075
00076 #include <sys/time.h>
00077 #include <sys/types.h>
00078 #include <unistd.h>
00079 }
00080
00081 extern QMap<QCString, DCOPObject *> * kde_dcopObjMap;
00082
00083
00084
00085
00086 typedef QAsciiDict<DCOPClient> client_map_t;
00087 static client_map_t *DCOPClient_CliMap = 0;
00088
00089 static
00090 client_map_t *cliMap()
00091 {
00092 if (!DCOPClient_CliMap)
00093 DCOPClient_CliMap = new client_map_t;
00094 return DCOPClient_CliMap;
00095 }
00096
00097 DCOPClient *DCOPClient::findLocalClient( const QCString &_appId )
00098 {
00099 return cliMap()->find(_appId.data());
00100 }
00101
00102 static
00103 void registerLocalClient( const QCString &_appId, DCOPClient *client )
00104 {
00105 cliMap()->replace(_appId.data(), client);
00106 }
00107
00108 static
00109 void unregisterLocalClient( const QCString &_appId )
00110 {
00111 client_map_t *map = cliMap();
00112 map->remove(_appId.data());
00113 }
00115
00116 template class QPtrList<DCOPObjectProxy>;
00117 template class QPtrList<DCOPClientTransaction>;
00118 template class QPtrList<_IceConn>;
00119
00120 struct DCOPClientMessage
00121 {
00122 int opcode;
00123 CARD32 key;
00124 QByteArray data;
00125 };
00126
00127 class DCOPClient::ReplyStruct
00128 {
00129 public:
00130 enum ReplyStatus { Pending, Ok, Failed };
00131 ReplyStruct() {
00132 status = Pending;
00133 replyType = 0;
00134 replyData = 0;
00135 replyId = -1;
00136 transactionId = -1;
00137 replyObject = 0;
00138 }
00139 ReplyStatus status;
00140 QCString* replyType;
00141 QByteArray* replyData;
00142 int replyId;
00143 Q_INT32 transactionId;
00144 QCString calledApp;
00145 QGuardedPtr<QObject> replyObject;
00146 QCString replySlot;
00147 };
00148
00149 class DCOPClientPrivate
00150 {
00151 public:
00152 DCOPClient *parent;
00153 QCString appId;
00154 IceConn iceConn;
00155 int majorOpcode;
00156
00157 int majorVersion, minorVersion;
00158
00159 static const char* serverAddr;
00160 QSocketNotifier *notifier;
00161 bool non_blocking_call_lock;
00162 bool registered;
00163 bool foreign_server;
00164 bool accept_calls;
00165 bool accept_calls_override;
00166 bool qt_bridge_enabled;
00167
00168 QCString senderId;
00169 QCString objId;
00170 QCString function;
00171
00172 QCString defaultObject;
00173 QPtrList<DCOPClientTransaction> *transactionList;
00174 bool transaction;
00175 Q_INT32 transactionId;
00176 int opcode;
00177
00178
00179
00180
00181
00182
00183 CARD32 key;
00184 CARD32 currentKey;
00185 CARD32 currentKeySaved;
00186
00187 QTimer postMessageTimer;
00188 QPtrList<DCOPClientMessage> messages;
00189
00190 QPtrList<DCOPClient::ReplyStruct> pendingReplies;
00191 QPtrList<DCOPClient::ReplyStruct> asyncReplyQueue;
00192
00193 struct LocalTransactionResult
00194 {
00195 QCString replyType;
00196 QByteArray replyData;
00197 };
00198
00199 QIntDict<LocalTransactionResult> localTransActionList;
00200 };
00201
00202 class DCOPClientTransaction
00203 {
00204 public:
00205 Q_INT32 id;
00206 CARD32 key;
00207 QCString senderId;
00208 };
00209
00210 QCString DCOPClient::iceauthPath()
00211 {
00212 QCString path = ::getenv("PATH");
00213 if (path.isEmpty())
00214 path = "/bin:/usr/bin";
00215 path += ":/usr/bin/X11:/usr/X11/bin:/usr/X11R6/bin";
00216 QCString fPath = strtok(path.data(), ":\b");
00217 while (!fPath.isNull())
00218 {
00219 fPath += "/iceauth";
00220 if (access(fPath.data(), X_OK) == 0)
00221 {
00222 return fPath;
00223 }
00224
00225 fPath = strtok(NULL, ":\b");
00226 }
00227 return 0;
00228 }
00229
00230 static QCString dcopServerFile(const QCString &hostname, bool old)
00231 {
00232 QCString fName = ::getenv("DCOPAUTHORITY");
00233 if (!old && !fName.isEmpty())
00234 return fName;
00235
00236 fName = ::getenv("HOME");
00237 if (fName.isEmpty())
00238 {
00239 fprintf(stderr, "Aborting. $HOME is not set.\n");
00240 exit(1);
00241 }
00242 #ifdef Q_WS_X11
00243 QCString disp = getenv("DISPLAY");
00244 #elif defined(Q_WS_QWS)
00245 QCString disp = getenv("QWS_DISPLAY");
00246 #else
00247 QCString disp;
00248 #endif
00249 if (disp.isEmpty())
00250 disp = "NODISPLAY";
00251
00252 int i;
00253 if((i = disp.findRev('.')) > disp.findRev(':') && i >= 0)
00254 disp.truncate(i);
00255
00256 if (!old)
00257 {
00258 while( (i = disp.find(':')) >= 0)
00259 disp[i] = '_';
00260 }
00261
00262 fName += "/.DCOPserver_";
00263 if (hostname.isEmpty())
00264 {
00265 char hostName[256];
00266 hostName[0] = '\0';
00267 if (gethostname(hostName, sizeof(hostName)))
00268 {
00269 fName += "localhost";
00270 }
00271 else
00272 {
00273 hostName[sizeof(hostName)-1] = '\0';
00274 fName += hostName;
00275 }
00276 }
00277 else
00278 {
00279 fName += hostname;
00280 }
00281 fName += "_"+disp;
00282 return fName;
00283 }
00284
00285
00286
00287 QCString DCOPClient::dcopServerFile(const QCString &hostname)
00288 {
00289 return ::dcopServerFile(hostname, false);
00290 }
00291
00292
00293
00294 QCString DCOPClient::dcopServerFileOld(const QCString &hostname)
00295 {
00296 return ::dcopServerFile(hostname, true);
00297 }
00298
00299
00300 const char* DCOPClientPrivate::serverAddr = 0;
00301
00302 static void DCOPProcessInternal( DCOPClientPrivate *d, int opcode, CARD32 key, const QByteArray& dataReceived, bool canPost );
00303
00304 void DCOPClient::handleAsyncReply(ReplyStruct *replyStruct)
00305 {
00306 if (replyStruct->replyObject)
00307 {
00308 QObject::connect(this, SIGNAL(callBack(int, const QCString&, const QByteArray &)),
00309 replyStruct->replyObject, replyStruct->replySlot);
00310 emit callBack(replyStruct->replyId, *(replyStruct->replyType), *(replyStruct->replyData));
00311 QObject::disconnect(this, SIGNAL(callBack(int, const QCString&, const QByteArray &)),
00312 replyStruct->replyObject, replyStruct->replySlot);
00313 }
00314 delete replyStruct;
00315 }
00316
00320 static void DCOPProcessMessage(IceConn iceConn, IcePointer clientObject,
00321 int opcode, unsigned long length, Bool ,
00322 IceReplyWaitInfo *replyWait,
00323 Bool *replyWaitRet)
00324 {
00325 DCOPMsg *pMsg = 0;
00326 DCOPClientPrivate *d = static_cast<DCOPClientPrivate *>(clientObject);
00327 DCOPClient::ReplyStruct *replyStruct = replyWait ? static_cast<DCOPClient::ReplyStruct*>(replyWait->reply) : 0;
00328
00329 IceReadMessageHeader(iceConn, sizeof(DCOPMsg), DCOPMsg, pMsg);
00330 CARD32 key = pMsg->key;
00331 if ( d->key == 0 )
00332 d->key = key;
00333
00334 QByteArray dataReceived( length );
00335 IceReadData(iceConn, length, dataReceived.data() );
00336
00337 d->opcode = opcode;
00338 switch (opcode ) {
00339
00340 case DCOPReplyFailed:
00341 if ( replyStruct ) {
00342 replyStruct->status = DCOPClient::ReplyStruct::Failed;
00343 replyStruct->transactionId = 0;
00344 *replyWaitRet = True;
00345 return;
00346 } else {
00347 qWarning("Very strange! got a DCOPReplyFailed opcode, but we were not waiting for a reply!");
00348 return;
00349 }
00350 case DCOPReply:
00351 if ( replyStruct ) {
00352 QByteArray* b = replyStruct->replyData;
00353 QCString* t = replyStruct->replyType;
00354 replyStruct->status = DCOPClient::ReplyStruct::Ok;
00355 replyStruct->transactionId = 0;
00356
00357 QCString calledApp, app;
00358 QDataStream ds( dataReceived, IO_ReadOnly );
00359 ds >> calledApp >> app >> *t >> *b;
00360
00361 *replyWaitRet = True;
00362 return;
00363 } else {
00364 qWarning("Very strange! got a DCOPReply opcode, but we were not waiting for a reply!");
00365 return;
00366 }
00367 case DCOPReplyWait:
00368 if ( replyStruct ) {
00369 QCString calledApp, app;
00370 Q_INT32 id;
00371 QDataStream ds( dataReceived, IO_ReadOnly );
00372 ds >> calledApp >> app >> id;
00373 replyStruct->transactionId = id;
00374 replyStruct->calledApp = calledApp;
00375 d->pendingReplies.append(replyStruct);
00376 *replyWaitRet = True;
00377 return;
00378 } else {
00379 qWarning("Very strange! got a DCOPReplyWait opcode, but we were not waiting for a reply!");
00380 return;
00381 }
00382 case DCOPReplyDelayed:
00383 {
00384 QDataStream ds( dataReceived, IO_ReadOnly );
00385 QCString calledApp, app;
00386 Q_INT32 id;
00387
00388 ds >> calledApp >> app >> id;
00389 if (replyStruct && (id == replyStruct->transactionId) && (calledApp = replyStruct->calledApp))
00390 {
00391 *replyWaitRet = True;
00392 }
00393
00394 for(DCOPClient::ReplyStruct *rs = d->pendingReplies.first(); rs;
00395 rs = d->pendingReplies.next())
00396 {
00397 if ((rs->transactionId == id) && (rs->calledApp == calledApp))
00398 {
00399 d->pendingReplies.remove();
00400 QByteArray* b = rs->replyData;
00401 QCString* t = rs->replyType;
00402 ds >> *t >> *b;
00403
00404 rs->status = DCOPClient::ReplyStruct::Ok;
00405 rs->transactionId = 0;
00406 if (!rs->replySlot.isEmpty())
00407 {
00408 d->parent->handleAsyncReply(rs);
00409 }
00410 return;
00411 }
00412 }
00413 }
00414 qWarning("Very strange! got a DCOPReplyDelayed opcode, but we were not waiting for a reply!");
00415 return;
00416 case DCOPCall:
00417 case DCOPFind:
00418 case DCOPSend:
00419 DCOPProcessInternal( d, opcode, key, dataReceived, true );
00420 }
00421 }
00422
00423
00424 void DCOPClient::processPostedMessagesInternal()
00425 {
00426 if ( d->messages.isEmpty() )
00427 return;
00428 QPtrListIterator<DCOPClientMessage> it (d->messages );
00429 DCOPClientMessage* msg ;
00430 while ( ( msg = it.current() ) ) {
00431 ++it;
00432 if ( d->currentKey && msg->key != d->currentKey )
00433 continue;
00434 d->messages.removeRef( msg );
00435 d->opcode = msg->opcode;
00436 DCOPProcessInternal( d, msg->opcode, msg->key, msg->data, false );
00437 delete msg;
00438 }
00439 if ( !d->messages.isEmpty() )
00440 d->postMessageTimer.start( 100, true );
00441 }
00442
00446 void DCOPProcessInternal( DCOPClientPrivate *d, int opcode, CARD32 key, const QByteArray& dataReceived, bool canPost )
00447 {
00448 if (!d->accept_calls && (opcode == DCOPSend))
00449 return;
00450
00451 IceConn iceConn = d->iceConn;
00452 DCOPMsg *pMsg = 0;
00453 DCOPClient *c = d->parent;
00454 QDataStream ds( dataReceived, IO_ReadOnly );
00455
00456 QCString fromApp;
00457 ds >> fromApp;
00458 if (fromApp.isEmpty())
00459 return;
00460
00461 if (!d->accept_calls)
00462 {
00463 QByteArray reply;
00464 QDataStream replyStream( reply, IO_WriteOnly );
00465
00466 replyStream << d->appId << fromApp;
00467 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyFailed,
00468 sizeof(DCOPMsg), DCOPMsg, pMsg );
00469 int datalen = reply.size();
00470 pMsg->key = key;
00471 pMsg->length += datalen;
00472 IceSendData( iceConn, datalen, const_cast<char *>(reply.data()));
00473 return;
00474 }
00475
00476 QCString app, objId, fun;
00477 QByteArray data;
00478 ds >> app >> objId >> fun >> data;
00479 d->senderId = fromApp;
00480 d->objId = objId;
00481 d->function = fun;
00482
00483
00484
00485 if ( canPost && d->currentKey && key != d->currentKey ) {
00486 DCOPClientMessage* msg = new DCOPClientMessage;
00487 msg->opcode = opcode;
00488 msg->key = key;
00489 msg->data = dataReceived;
00490 d->messages.append( msg );
00491 d->postMessageTimer.start( 0, true );
00492 return;
00493 }
00494
00495 d->objId = objId;
00496 d->function = fun;
00497
00498 QCString replyType;
00499 QByteArray replyData;
00500 bool b;
00501 CARD32 oldCurrentKey = d->currentKey;
00502 if ( opcode != DCOPSend )
00503 d->currentKey = key;
00504
00505 if ( opcode == DCOPFind )
00506 b = c->find(app, objId, fun, data, replyType, replyData );
00507 else
00508 b = c->receive( app, objId, fun, data, replyType, replyData );
00509
00510
00511 if ( opcode == DCOPSend )
00512 return;
00513
00514 if ((d->currentKey == key) || (oldCurrentKey != 2))
00515 d->currentKey = oldCurrentKey;
00516
00517 QByteArray reply;
00518 QDataStream replyStream( reply, IO_WriteOnly );
00519
00520 Q_INT32 id = c->transactionId();
00521 if (id) {
00522
00523 replyStream << d->appId << fromApp << id;
00524
00525 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyWait,
00526 sizeof(DCOPMsg), DCOPMsg, pMsg );
00527 pMsg->key = key;
00528 pMsg->length += reply.size();
00529 IceSendData( iceConn, reply.size(), const_cast<char *>(reply.data()));
00530 return;
00531 }
00532
00533 if ( !b ) {
00534
00535
00536 replyStream << d->appId << fromApp;
00537 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyFailed,
00538 sizeof(DCOPMsg), DCOPMsg, pMsg );
00539 int datalen = reply.size();
00540 pMsg->key = key;
00541 pMsg->length += datalen;
00542 IceSendData( iceConn, datalen, const_cast<char *>(reply.data()));
00543 return;
00544 }
00545
00546
00547 replyStream << d->appId << fromApp << replyType << replyData.size();
00548
00549
00550
00551 IceGetHeader( iceConn, d->majorOpcode, DCOPReply,
00552 sizeof(DCOPMsg), DCOPMsg, pMsg );
00553 int datalen = reply.size() + replyData.size();
00554 pMsg->key = key;
00555 pMsg->length += datalen;
00556
00557
00558 IceSendData( iceConn, reply.size(), const_cast<char *>(reply.data()));
00559 IceSendData( iceConn, replyData.size(), const_cast<char *>(replyData.data()));
00560 }
00561
00562
00563
00564 static IcePoVersionRec DCOPClientVersions[] = {
00565 { DCOPVersionMajor, DCOPVersionMinor, DCOPProcessMessage }
00566 };
00567
00568
00569 static DCOPClient* dcop_main_client = 0;
00570
00571 DCOPClient* DCOPClient::mainClient()
00572 {
00573 return dcop_main_client;
00574 }
00575
00576 void DCOPClient::setMainClient( DCOPClient* client )
00577 {
00578 dcop_main_client = client;
00579 }
00580
00581
00582 DCOPClient::DCOPClient()
00583 {
00584 d = new DCOPClientPrivate;
00585 d->parent = this;
00586 d->iceConn = 0L;
00587 d->majorOpcode = 0;
00588 d->key = 0;
00589 d->currentKey = 0;
00590 d->appId = 0;
00591 d->notifier = 0L;
00592 d->non_blocking_call_lock = false;
00593 d->registered = false;
00594 d->foreign_server = true;
00595 d->accept_calls = true;
00596 d->accept_calls_override = false;
00597 d->qt_bridge_enabled = true;
00598 d->transactionList = 0L;
00599 d->transactionId = 0;
00600 QObject::connect( &d->postMessageTimer, SIGNAL( timeout() ), this, SLOT( processPostedMessagesInternal() ) );
00601
00602 if ( !mainClient() )
00603 setMainClient( this );
00604 }
00605
00606 DCOPClient::~DCOPClient()
00607 {
00608 if (d->iceConn)
00609 if (IceConnectionStatus(d->iceConn) == IceConnectAccepted)
00610 detach();
00611
00612 if (d->registered)
00613 unregisterLocalClient( d->appId );
00614
00615 delete d->notifier;
00616 delete d->transactionList;
00617 delete d;
00618
00619 if ( mainClient() == this )
00620 setMainClient( 0 );
00621 }
00622
00623 void DCOPClient::setServerAddress(const QCString &addr)
00624 {
00625 QCString env = "DCOPSERVER=" + addr;
00626 putenv(strdup(env.data()));
00627 delete [] DCOPClientPrivate::serverAddr;
00628 DCOPClientPrivate::serverAddr = qstrdup( addr.data() );
00629 }
00630
00631 bool DCOPClient::attach()
00632 {
00633 if (!attachInternal( true ))
00634 if (!attachInternal( true ))
00635 return false;
00636 return true;
00637 }
00638
00639 void DCOPClient::bindToApp()
00640 {
00641
00642
00643 if (qApp) {
00644 if ( d->notifier )
00645 delete d->notifier;
00646 d->notifier = new QSocketNotifier(socket(),
00647 QSocketNotifier::Read, 0, 0);
00648 QObject::connect(d->notifier, SIGNAL(activated(int)),
00649 SLOT(processSocketData(int)));
00650 }
00651 }
00652
00653 void DCOPClient::suspend()
00654 {
00655 assert(d->notifier);
00656 d->notifier->setEnabled(false);
00657 }
00658
00659 void DCOPClient::resume()
00660 {
00661 assert(d->notifier);
00662 d->notifier->setEnabled(true);
00663 }
00664
00665 bool DCOPClient::isSuspended() const
00666 {
00667 return !d->notifier->isEnabled();
00668 }
00669
00670 #ifdef SO_PEERCRED
00671
00672 static bool peerIsUs(int sockfd)
00673 {
00674 struct ucred cred;
00675 socklen_t siz = sizeof(cred);
00676 if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &siz) != 0)
00677 return false;
00678 return (cred.uid == getuid());
00679 }
00680 #else
00681
00682 static bool isServerSocketOwnedByUser(const char*server)
00683 {
00684 if (strncmp(server, "local/", 6) != 0)
00685 return false;
00686 const char *path = strchr(server, ':');
00687 if (!path)
00688 return false;
00689 path++;
00690
00691 struct stat stat_buf;
00692 if (stat(path, &stat_buf) != 0)
00693 return false;
00694
00695 return (stat_buf.st_uid == getuid());
00696 }
00697 #endif
00698
00699
00700 bool DCOPClient::attachInternal( bool registerAsAnonymous )
00701 {
00702 char errBuf[1024];
00703
00704 if ( isAttached() )
00705 detach();
00706
00707 extern int _kde_IceLastMajorOpcode;
00708 if (_kde_IceLastMajorOpcode < 1 )
00709 IceRegisterForProtocolSetup(const_cast<char *>("DUMMY"),
00710 const_cast<char *>("DUMMY"),
00711 const_cast<char *>("DUMMY"),
00712 1, DCOPClientVersions,
00713 DCOPAuthCount, const_cast<char **>(DCOPAuthNames),
00714 DCOPClientAuthProcs, 0);
00715 if (_kde_IceLastMajorOpcode < 1 )
00716 qWarning("DCOPClient Error: incorrect major opcode!");
00717
00718 if ((d->majorOpcode = IceRegisterForProtocolSetup(const_cast<char *>("DCOP"),
00719 const_cast<char *>(DCOPVendorString),
00720 const_cast<char *>(DCOPReleaseString),
00721 1, DCOPClientVersions,
00722 DCOPAuthCount,
00723 const_cast<char **>(DCOPAuthNames),
00724 DCOPClientAuthProcs, 0L)) < 0) {
00725 emit attachFailed(QString::fromLatin1( "Communications could not be established." ));
00726 return false;
00727 }
00728
00729 bool bClearServerAddr = false;
00730
00731 if (!d->serverAddr) {
00732
00733
00734 QString dcopSrv;
00735 dcopSrv = ::getenv("DCOPSERVER");
00736 if (dcopSrv.isEmpty()) {
00737 QString fName = dcopServerFile();
00738 QFile f(fName);
00739 if (!f.open(IO_ReadOnly)) {
00740 emit attachFailed(QString::fromLatin1( "Could not read network connection list.\n" )+fName);
00741 return false;
00742 }
00743 int size = QMIN( 1024, f.size() );
00744 QCString contents( size+1 );
00745 if ( f.readBlock( contents.data(), size ) != size )
00746 {
00747 qDebug("Error reading from %s, didn't read the expected %d bytes", fName.latin1(), size);
00748
00749 }
00750 contents[size] = '\0';
00751 int pos = contents.find('\n');
00752 if ( pos == -1 )
00753 {
00754 qDebug("Only one line in dcopserver file !: %s", contents.data());
00755 dcopSrv = QString::fromLatin1(contents);
00756 }
00757 else
00758 {
00759 dcopSrv = QString::fromLatin1(contents.left( pos ));
00760
00761
00762
00763 }
00764 }
00765 d->serverAddr = qstrdup( const_cast<char *>(dcopSrv.latin1()) );
00766 bClearServerAddr = true;
00767 }
00768
00769 if ((d->iceConn = IceOpenConnection(const_cast<char*>(d->serverAddr),
00770 static_cast<IcePointer>(this), False, d->majorOpcode,
00771 sizeof(errBuf), errBuf)) == 0L) {
00772 qDebug("DCOPClient::attachInternal. Attach failed %s", errBuf ? errBuf : "");
00773 d->iceConn = 0;
00774 if (bClearServerAddr) {
00775 delete [] d->serverAddr;
00776 d->serverAddr = 0;
00777 }
00778 emit attachFailed(QString::fromLatin1( errBuf ));
00779 return false;
00780 }
00781
00782 IceSetShutdownNegotiation(d->iceConn, False);
00783
00784 int setupstat;
00785 char* vendor = 0;
00786 char* release = 0;
00787 setupstat = IceProtocolSetup(d->iceConn, d->majorOpcode,
00788 static_cast<IcePointer>(d),
00789 False,
00790 &(d->majorVersion), &(d->minorVersion),
00791 &(vendor), &(release), 1024, errBuf);
00792 if (vendor) free(vendor);
00793 if (release) free(release);
00794
00795 if (setupstat == IceProtocolSetupFailure ||
00796 setupstat == IceProtocolSetupIOError) {
00797 IceCloseConnection(d->iceConn);
00798 d->iceConn = 0;
00799 if (bClearServerAddr) {
00800 delete [] d->serverAddr;
00801 d->serverAddr = 0;
00802 }
00803 emit attachFailed(QString::fromLatin1( errBuf ));
00804 return false;
00805 } else if (setupstat == IceProtocolAlreadyActive) {
00806 if (bClearServerAddr) {
00807 delete [] d->serverAddr;
00808 d->serverAddr = 0;
00809 }
00810
00811 emit attachFailed(QString::fromLatin1( "internal error in IceOpenConnection" ));
00812 return false;
00813 }
00814
00815
00816 if (IceConnectionStatus(d->iceConn) != IceConnectAccepted) {
00817 if (bClearServerAddr) {
00818 delete [] d->serverAddr;
00819 d->serverAddr = 0;
00820 }
00821 emit attachFailed(QString::fromLatin1( "DCOP server did not accept the connection." ));
00822 return false;
00823 }
00824
00825 #ifdef SO_PEERCRED
00826 d->foreign_server = !peerIsUs(socket());
00827 #else
00828 d->foreign_server = !isServerSocketOwnedByUser(d->serverAddr);
00829 #endif
00830 if (!d->accept_calls_override)
00831 d->accept_calls = !d->foreign_server;
00832
00833 bindToApp();
00834
00835 if ( registerAsAnonymous )
00836 registerAs( "anonymous", true );
00837
00838 return true;
00839 }
00840
00841
00842 bool DCOPClient::detach()
00843 {
00844 int status;
00845
00846 if (d->iceConn) {
00847 IceProtocolShutdown(d->iceConn, d->majorOpcode);
00848 status = IceCloseConnection(d->iceConn);
00849 if (status != IceClosedNow)
00850 return false;
00851 else
00852 d->iceConn = 0L;
00853 }
00854
00855 if (d->registered)
00856 unregisterLocalClient(d->appId);
00857
00858 delete d->notifier;
00859 d->notifier = 0L;
00860 d->registered = false;
00861 d->foreign_server = true;
00862 return true;
00863 }
00864
00865 bool DCOPClient::isAttached() const
00866 {
00867 if (!d->iceConn)
00868 return false;
00869
00870 return (IceConnectionStatus(d->iceConn) == IceConnectAccepted);
00871 }
00872
00873 bool DCOPClient::isAttachedToForeignServer() const
00874 {
00875 return isAttached() && d->foreign_server;
00876 }
00877
00878 bool DCOPClient::acceptCalls() const
00879 {
00880 return isAttached() && d->accept_calls;
00881 }
00882
00883 void DCOPClient::setAcceptCalls(bool b)
00884 {
00885 d->accept_calls = b;
00886 d->accept_calls_override = true;
00887 }
00888
00889 bool DCOPClient::qtBridgeEnabled()
00890 {
00891 return d->qt_bridge_enabled;
00892 }
00893
00894 void DCOPClient::setQtBridgeEnabled(bool b)
00895 {
00896 d->qt_bridge_enabled = b;
00897 }
00898
00899 QCString DCOPClient::registerAs( const QCString &appId, bool addPID )
00900 {
00901 QCString result;
00902
00903 QCString _appId = appId;
00904
00905 if (addPID) {
00906 QCString pid;
00907 pid.sprintf("-%d", getpid());
00908 _appId = _appId + pid;
00909 }
00910
00911 if( d->appId == _appId )
00912 return d->appId;
00913
00914 #if 0 // no need to detach, dcopserver can handle renaming
00915
00916 if ( isRegistered() ) {
00917 detach();
00918 }
00919 #endif
00920
00921 if ( !isAttached() ) {
00922 if (!attachInternal( false ))
00923 if (!attachInternal( false ))
00924 return result;
00925 }
00926
00927
00928 QCString replyType;
00929 QByteArray data, replyData;
00930 QDataStream arg( data, IO_WriteOnly );
00931 arg << _appId;
00932 if ( call( "DCOPServer", "", "registerAs(QCString)", data, replyType, replyData ) ) {
00933 QDataStream reply( replyData, IO_ReadOnly );
00934 reply >> result;
00935 }
00936
00937 d->appId = result;
00938 d->registered = !result.isNull();
00939
00940 if (d->registered)
00941 registerLocalClient( d->appId, this );
00942
00943 return result;
00944 }
00945
00946 bool DCOPClient::isRegistered() const
00947 {
00948 return d->registered;
00949 }
00950
00951
00952 QCString DCOPClient::appId() const
00953 {
00954 return d->appId;
00955 }
00956
00957
00958 int DCOPClient::socket() const
00959 {
00960 if (d->iceConn)
00961 return IceConnectionNumber(d->iceConn);
00962 else
00963 return 0;
00964 }
00965
00966 static inline bool isIdentChar( char x )
00967 {
00968 return x == '_' || (x >= '0' && x <= '9') ||
00969 (x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z');
00970 }
00971
00972 QCString DCOPClient::normalizeFunctionSignature( const QCString& fun ) {
00973 if ( fun.isEmpty() )
00974 return fun.copy();
00975 QCString result( fun.size() );
00976 char *from = fun.data();
00977 char *to = result.data();
00978 char *first = to;
00979 char last = 0;
00980 while ( true ) {
00981 while ( *from && isspace(*from) )
00982 from++;
00983 if ( last && isIdentChar( last ) && isIdentChar( *from ) )
00984 *to++ = 0x20;
00985 while ( *from && !isspace(*from) ) {
00986 last = *from++;
00987 *to++ = last;
00988 }
00989 if ( !*from )
00990 break;
00991 }
00992 if ( to > first && *(to-1) == 0x20 )
00993 to--;
00994 *to = '\0';
00995 result.resize( (int)((long)to - (long)result.data()) + 1 );
00996 return result;
00997 }
00998
00999
01000 QCString DCOPClient::senderId() const
01001 {
01002 return d->senderId;
01003 }
01004
01005
01006 bool DCOPClient::send(const QCString &remApp, const QCString &remObjId,
01007 const QCString &remFun, const QByteArray &data)
01008 {
01009 if (remApp.isEmpty())
01010 return false;
01011 DCOPClient *localClient = findLocalClient( remApp );
01012
01013 if ( localClient ) {
01014 bool saveTransaction = d->transaction;
01015 Q_INT32 saveTransactionId = d->transactionId;
01016 QCString saveSenderId = d->senderId;
01017
01018 d->senderId = 0;
01019 QCString replyType;
01020 QByteArray replyData;
01021 (void) localClient->receive( remApp, remObjId, remFun, data, replyType, replyData );
01022
01023 d->transaction = saveTransaction;
01024 d->transactionId = saveTransactionId;
01025 d->senderId = saveSenderId;
01026
01027
01028
01029
01030 return true;
01031 }
01032
01033 if ( !isAttached() )
01034 return false;
01035
01036
01037 DCOPMsg *pMsg;
01038
01039 QByteArray ba;
01040 QDataStream ds(ba, IO_WriteOnly);
01041 ds << d->appId << remApp << remObjId << normalizeFunctionSignature(remFun) << data.size();
01042
01043 IceGetHeader(d->iceConn, d->majorOpcode, DCOPSend,
01044 sizeof(DCOPMsg), DCOPMsg, pMsg);
01045
01046 pMsg->key = 1;
01047 int datalen = ba.size() + data.size();
01048 pMsg->length += datalen;
01049
01050 IceSendData( d->iceConn, ba.size(), const_cast<char *>(ba.data()) );
01051 IceSendData( d->iceConn, data.size(), const_cast<char *>(data.data()) );
01052
01053
01054
01055 if (IceConnectionStatus(d->iceConn) != IceConnectAccepted)
01056 return false;
01057 else
01058 return true;
01059 }
01060
01061 bool DCOPClient::send(const QCString &remApp, const QCString &remObjId,
01062 const QCString &remFun, const QString &data)
01063 {
01064 QByteArray ba;
01065 QDataStream ds(ba, IO_WriteOnly);
01066 ds << data;
01067 return send(remApp, remObjId, remFun, ba);
01068 }
01069
01070 bool DCOPClient::findObject(const QCString &remApp, const QCString &remObj,
01071 const QCString &remFun, const QByteArray &data,
01072 QCString &foundApp, QCString &foundObj,
01073 bool useEventLoop)
01074 {
01075 return findObject( remApp, remObj, remFun, data, foundApp, foundObj, useEventLoop, -1 );
01076 }
01077
01078 bool DCOPClient::findObject(const QCString &remApp, const QCString &remObj,
01079 const QCString &remFun, const QByteArray &data,
01080 QCString &foundApp, QCString &foundObj,
01081 bool useEventLoop, int timeout)
01082 {
01083 QCStringList appList;
01084 QCString app = remApp;
01085 if (app.isEmpty())
01086 app = "*";
01087
01088 foundApp = 0;
01089 foundObj = 0;
01090
01091 if (app[app.length()-1] == '*')
01092 {
01093
01094
01095
01096 int len = app.length()-1;
01097 QCStringList apps=registeredApplications();
01098 for( QCStringList::ConstIterator it = apps.begin();
01099 it != apps.end();
01100 ++it)
01101 {
01102 if ( strncmp( (*it).data(), app.data(), len) == 0)
01103 appList.append(*it);
01104 }
01105 }
01106 else
01107 {
01108 appList.append(app);
01109 }
01110
01111
01112 for(int phase=1; phase <= 2; phase++)
01113 {
01114 for( QCStringList::ConstIterator it = appList.begin();
01115 it != appList.end();
01116 ++it)
01117 {
01118 QCString remApp = *it;
01119 QCString replyType;
01120 QByteArray replyData;
01121 bool result;
01122 DCOPClient *localClient = findLocalClient( remApp );
01123
01124 if ( (phase == 1) && localClient ) {
01125
01126 bool saveTransaction = d->transaction;
01127 Q_INT32 saveTransactionId = d->transactionId;
01128 QCString saveSenderId = d->senderId;
01129
01130 d->senderId = 0;
01131 result = localClient->find( remApp, remObj, remFun, data, replyType, replyData );
01132
01133 Q_INT32 id = localClient->transactionId();
01134 if (id) {
01135
01136 do {
01137 QApplication::eventLoop()->processEvents( QEventLoop::WaitForMore);
01138 } while( !localClient->isLocalTransactionFinished(id, replyType, replyData));
01139 result = true;
01140 }
01141 d->transaction = saveTransaction;
01142 d->transactionId = saveTransactionId;
01143 d->senderId = saveSenderId;
01144 }
01145 else if ((phase == 2) && !localClient)
01146 {
01147
01148 result = callInternal(remApp, remObj, remFun, data,
01149 replyType, replyData, useEventLoop, timeout, DCOPFind);
01150 }
01151
01152 if (result)
01153 {
01154 if (replyType == "DCOPRef")
01155 {
01156 DCOPRef ref;
01157 QDataStream reply( replyData, IO_ReadOnly );
01158 reply >> ref;
01159
01160 if (ref.app() == remApp)
01161 {
01162
01163 foundApp = ref.app();
01164 foundObj = ref.object();
01165 return true;
01166 }
01167 }
01168 }
01169 }
01170 }
01171 return false;
01172 }
01173
01174 bool DCOPClient::process(const QCString &, const QByteArray &,
01175 QCString&, QByteArray &)
01176 {
01177 return false;
01178 }
01179
01180 bool DCOPClient::isApplicationRegistered( const QCString& remApp)
01181 {
01182 QCString replyType;
01183 QByteArray data, replyData;
01184 QDataStream arg( data, IO_WriteOnly );
01185 arg << remApp;
01186 int result = false;
01187 if ( call( "DCOPServer", "", "isApplicationRegistered(QCString)", data, replyType, replyData ) ) {
01188 QDataStream reply( replyData, IO_ReadOnly );
01189 reply >> result;
01190 }
01191 return result;
01192 }
01193
01194 QCStringList DCOPClient::registeredApplications()
01195 {
01196 QCString replyType;
01197 QByteArray data, replyData;
01198 QCStringList result;
01199 if ( call( "DCOPServer", "", "registeredApplications()", data, replyType, replyData ) ) {
01200 QDataStream reply( replyData, IO_ReadOnly );
01201 reply >> result;
01202 }
01203 return result;
01204 }
01205
01206 QCStringList DCOPClient::remoteObjects( const QCString& remApp, bool *ok )
01207 {
01208 QCString replyType;
01209 QByteArray data, replyData;
01210 QCStringList result;
01211 if ( ok )
01212 *ok = false;
01213 if ( call( remApp, "DCOPClient", "objects()", data, replyType, replyData ) ) {
01214 QDataStream reply( replyData, IO_ReadOnly );
01215 reply >> result;
01216 if ( ok )
01217 *ok = true;
01218 }
01219 return result;
01220 }
01221
01222 QCStringList DCOPClient::remoteInterfaces( const QCString& remApp, const QCString& remObj, bool *ok )
01223 {
01224 QCString replyType;
01225 QByteArray data, replyData;
01226 QCStringList result;
01227 if ( ok )
01228 *ok = false;
01229 if ( call( remApp, remObj, "interfaces()", data, replyType, replyData ) && replyType == "QCStringList") {
01230 QDataStream reply( replyData, IO_ReadOnly );
01231 reply >> result;
01232 if ( ok )
01233 *ok = true;
01234 }
01235 return result;
01236 }
01237
01238 QCStringList DCOPClient::remoteFunctions( const QCString& remApp, const QCString& remObj, bool *ok )
01239 {
01240 QCString replyType;
01241 QByteArray data, replyData;
01242 QCStringList result;
01243 if ( ok )
01244 *ok = false;
01245 if ( call( remApp, remObj, "functions()", data, replyType, replyData ) && replyType == "QCStringList") {
01246 QDataStream reply( replyData, IO_ReadOnly );
01247 reply >> result;
01248 if ( ok )
01249 *ok = true;
01250 }
01251 return result;
01252 }
01253
01254 void DCOPClient::setNotifications(bool enabled)
01255 {
01256 QByteArray data;
01257 QDataStream ds(data, IO_WriteOnly);
01258 ds << static_cast<Q_INT8>(enabled);
01259
01260 QCString replyType;
01261 QByteArray reply;
01262 if (!call("DCOPServer", "", "setNotifications( bool )", data, replyType, reply))
01263 qWarning("I couldn't enable notifications at the dcopserver!");
01264 }
01265
01266 void DCOPClient::setDaemonMode( bool daemonMode )
01267 {
01268 QByteArray data;
01269 QDataStream ds(data, IO_WriteOnly);
01270 ds << static_cast<Q_INT8>( daemonMode );
01271
01272 QCString replyType;
01273 QByteArray reply;
01274 if (!call("DCOPServer", "", "setDaemonMode(bool)", data, replyType, reply))
01275 qWarning("I couldn't enable daemon mode at the dcopserver!");
01276 }
01277
01278
01279
01280
01281
01282
01283
01284
01285 static void fillQtObjects( QCStringList& l, QObject* o, QCString path )
01286 {
01287 if ( !path.isEmpty() )
01288 path += '/';
01289
01290 int unnamed = 0;
01291 const QObjectList *list = o ? o->children() : QObject::objectTrees();
01292 if ( list ) {
01293 QObjectListIt it( *list );
01294 QObject *obj;
01295 while ( (obj=it.current()) ) {
01296 ++it;
01297 QCString n = obj->name();
01298 if ( n == "unnamed" || n.isEmpty() )
01299 {
01300 n.sprintf("%p", (void *) obj);
01301 n = QString("unnamed%1(%2, %3)").arg(++unnamed).arg(obj->className()).arg(n).latin1();
01302 }
01303 QCString fn = path + n;
01304 l.append( fn );
01305 if ( obj->children() )
01306 fillQtObjects( l, obj, fn );
01307 }
01308 }
01309 }
01310
01311 namespace
01312 {
01313 struct O
01314 {
01315 O(): o(0) {}
01316 O ( const QCString& str, QObject* obj ):s(str), o(obj){}
01317 QCString s;
01318 QObject* o;
01319 };
01320 }
01321
01322 static void fillQtObjectsEx( QValueList<O>& l, QObject* o, QCString path )
01323 {
01324 if ( !path.isEmpty() )
01325 path += '/';
01326
01327 int unnamed = 0;
01328 const QObjectList *list = o ? o->children() : QObject::objectTrees();
01329 if ( list ) {
01330 QObjectListIt it( *list );
01331 QObject *obj;
01332 while ( (obj=it.current()) ) {
01333 ++it;
01334 QCString n = obj->name();
01335 if ( n == "unnamed" || n.isEmpty() )
01336 {
01337 n.sprintf("%p", (void *) obj);
01338 n = QString("unnamed%1(%2, %3)").arg(++unnamed).arg(obj->className()).arg(n).latin1();
01339 }
01340 QCString fn = path + n;
01341 l.append( O( fn, obj ) );
01342 if ( obj->children() )
01343 fillQtObjectsEx( l, obj, fn );
01344 }
01345 }
01346 }
01347
01348
01349 static QObject* findQtObject( QCString id )
01350 {
01351 QRegExp expr( id );
01352 QValueList<O> l;
01353 fillQtObjectsEx( l, 0, "qt" );
01354
01355 QObject* firstContains = 0L;
01356 for ( QValueList<O>::ConstIterator it = l.begin(); it != l.end(); ++it ) {
01357 if ( (*it).s == id )
01358 return (*it).o;
01359 if ( !firstContains && (*it).s.contains( expr ) ) {
01360 firstContains = (*it).o;
01361 }
01362 }
01363 return firstContains;
01364 }
01365
01366 static QCStringList findQtObjects( QCString id )
01367 {
01368 QRegExp expr( id );
01369 QValueList<O> l;
01370 fillQtObjectsEx( l, 0, "qt" );
01371 QCStringList result;
01372 for ( QValueList<O>::ConstIterator it = l.begin(); it != l.end(); ++it ) {
01373 if ( (*it).s.contains( expr ) )
01374 result << (*it).s;
01375 }
01376 return result;
01377 }
01378
01379 static bool receiveQtObject( const QCString &objId, const QCString &fun, const QByteArray &data,
01380 QCString& replyType, QByteArray &replyData)
01381 {
01382 if ( objId == "qt" ) {
01383 if ( fun == "interfaces()" ) {
01384 replyType = "QCStringList";
01385 QDataStream reply( replyData, IO_WriteOnly );
01386 QCStringList l;
01387 l << "DCOPObject";
01388 l << "Qt";
01389 reply << l;
01390 return true;
01391 } else if ( fun == "functions()" ) {
01392 replyType = "QCStringList";
01393 QDataStream reply( replyData, IO_WriteOnly );
01394 QCStringList l;
01395 l << "QCStringList functions()";
01396 l << "QCStringList interfaces()";
01397 l << "QCStringList objects()";
01398 l << "QCStringList find(QCString)";
01399 reply << l;
01400 return true;
01401 } else if ( fun == "objects()" ) {
01402 replyType = "QCStringList";
01403 QDataStream reply( replyData, IO_WriteOnly );
01404 QCStringList l;
01405 fillQtObjects( l, 0, "qt" );
01406 reply << l;
01407 return true;
01408 } else if ( fun == "find(QCString)" ) {
01409 QDataStream ds( data, IO_ReadOnly );
01410 QCString id;
01411 ds >> id ;
01412 replyType = "QCStringList";
01413 QDataStream reply( replyData, IO_WriteOnly );
01414 reply << findQtObjects( id ) ;
01415 return true;
01416 }
01417 } else if ( objId.left(3) == "qt/" ) {
01418 QObject* o = findQtObject( objId );
01419 if ( !o )
01420 return false;
01421 if ( fun == "functions()" ) {
01422 replyType = "QCStringList";
01423 QDataStream reply( replyData, IO_WriteOnly );
01424 QCStringList l;
01425 l << "QCStringList functions()";
01426 l << "QCStringList interfaces()";
01427 l << "QCStringList properties()";
01428 l << "bool setProperty(QCString,QVariant)";
01429 l << "QVariant property(QCString)";
01430 QStrList lst = o->metaObject()->slotNames( true );
01431 int i = 0;
01432 for ( QPtrListIterator<char> it( lst ); it.current(); ++it ) {
01433 if ( o->metaObject()->slot( i++, true )->access != QMetaData::Public )
01434 continue;
01435 QCString slot = it.current();
01436 if ( slot.contains( "()" ) ) {
01437 slot.prepend("void ");
01438 l << slot;
01439 }
01440 }
01441 reply << l;
01442 return true;
01443 } else if ( fun == "interfaces()" ) {
01444 replyType = "QCStringList";
01445 QDataStream reply( replyData, IO_WriteOnly );
01446 QCStringList l;
01447 QMetaObject *meta = o->metaObject();
01448 while ( meta ) {
01449 l.prepend( meta->className() );
01450 meta = meta->superClass();
01451 }
01452 reply << l;
01453 return true;
01454 } else if ( fun == "properties()" ) {
01455 replyType = "QCStringList";
01456 QDataStream reply( replyData, IO_WriteOnly );
01457 QCStringList l;
01458 QStrList lst = o->metaObject()->propertyNames( true );
01459 for ( QPtrListIterator<char> it( lst ); it.current(); ++it ) {
01460 QMetaObject *mo = o->