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