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