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