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