dcop Library API Documentation

dcopclient.cpp

00001 /*****************************************************************
00002 
00003 Copyright (c) 1999 Preston Brown <pbrown@kde.org>
00004 Copyright (c) 1999 Matthias Ettrich <ettrich@kde.org>
00005 
00006 Permission is hereby granted, free of charge, to any person obtaining a copy
00007 of this software and associated documentation files (the "Software"), to deal
00008 in the Software without restriction, including without limitation the rights
00009 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00010 copies of the Software, and to permit persons to whom the Software is
00011 furnished to do so, subject to the following conditions:
00012 
00013 The above copyright notice and this permission notice shall be included in
00014 all copies or substantial portions of the Software.
00015 
00016 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00019 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00020 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00021 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00022 
00023 ******************************************************************/
00024 
00025 // qt <-> dcop integration
00026 #include <qobjectlist.h>
00027 #include <qmetaobject.h>
00028 #include <qvariant.h>
00029 #include <qtimer.h>
00030 // end of qt <-> dcop integration
00031 
00032 #include <config.h>
00033 #include <dcopref.h>
00034 
00035 #include <sys/types.h>
00036 #include <sys/stat.h>
00037 #include <sys/file.h>
00038 #include <sys/socket.h>
00039 
00040 #include <ctype.h>
00041 #include <unistd.h>
00042 #include <stdlib.h>
00043 #include <assert.h>
00044 #include <string.h>
00045 
00046 #ifndef QT_CLEAN_NAMESPACE
00047 #define QT_CLEAN_NAMESPACE
00048 #endif
00049 #include <qtextstream.h>
00050 #include <qfile.h>
00051 #include <qapplication.h>
00052 #include <qsocketnotifier.h>
00053 #include <qregexp.h>
00054 
00055 #include <private/qucomextra_p.h>
00056 
00057 #include <dcopglobal.h>
00058 #include <dcopclient.h>
00059 #include <dcopobject.h>
00060 
00061 #ifdef Q_WS_X11
00062 #include <X11/Xmd.h>
00063 #endif
00064 extern "C" {
00065 #include <KDE-ICE/ICElib.h>
00066 #include <KDE-ICE/ICEutil.h>
00067 #include <KDE-ICE/ICEmsg.h>
00068 #include <KDE-ICE/ICEproto.h>
00069 
00070 
00071 #include <sys/time.h>
00072 #include <sys/types.h>
00073 #include <unistd.h>
00074 }
00075 
00076 extern QMap<QCString, DCOPObject *> *dcopObjMap; // defined in dcopobject.cpp
00077 
00078 /*********************************************
00079  * Keep track of local clients
00080  *********************************************/
00081 typedef QAsciiDict<DCOPClient> client_map_t;
00082 static client_map_t *DCOPClient_CliMap = 0;
00083 
00084 static
00085 client_map_t *cliMap()
00086 {
00087     if (!DCOPClient_CliMap)
00088        DCOPClient_CliMap = new client_map_t;
00089     return DCOPClient_CliMap;
00090 }
00091 
00092 static
00093 DCOPClient *findLocalClient( const QCString &_appId )
00094 {
00095     return cliMap()->find(_appId.data());
00096 }
00097 
00098 static
00099 void registerLocalClient( const QCString &_appId, DCOPClient *client )
00100 {
00101     cliMap()->replace(_appId.data(), client);
00102 }
00103 
00104 static
00105 void unregisterLocalClient( const QCString &_appId )
00106 {
00107     client_map_t *map = cliMap();
00108     map->remove(_appId.data());
00109 }
00111 
00112 template class QPtrList<DCOPObjectProxy>;
00113 template class QPtrList<DCOPClientTransaction>;
00114 template class QPtrList<_IceConn>;
00115 
00116 struct DCOPClientMessage
00117 {
00118     int opcode;
00119     CARD32 key;
00120     QByteArray data;
00121 };
00122 
00123 class DCOPClientPrivate
00124 {
00125 public:
00126     DCOPClient *parent;
00127     QCString appId;
00128     IceConn iceConn;
00129     int majorOpcode; // major opcode negotiated w/server and used to tag all comms.
00130 
00131     int majorVersion, minorVersion; // protocol versions negotiated w/server
00132 
00133     static const char* serverAddr; // location of server in ICE-friendly format.
00134     QSocketNotifier *notifier;
00135     bool non_blocking_call_lock;
00136     bool registered;
00137     bool foreign_server;
00138     bool accept_calls;
00139     bool accept_calls_override; // If true, user has specified policy.
00140     bool qt_bridge_enabled;
00141 
00142     QCString senderId;
00143     QCString objId;
00144     QCString function;
00145 
00146     QCString defaultObject;
00147     QPtrList<DCOPClientTransaction> *transactionList;
00148     bool transaction;
00149     Q_INT32 transactionId;
00150     int opcode;
00151 
00152     CARD32 key;
00153     CARD32 currentKey;
00154 
00155     QTimer postMessageTimer;
00156     QPtrList<DCOPClientMessage> messages;
00157 };
00158 
00159 class DCOPClientTransaction
00160 {
00161 public:
00162     Q_INT32 id;
00163     CARD32 key;
00164     QCString senderId;
00165 };
00166 
00167 struct ReplyStruct
00168 {
00169 
00170     enum ReplyStatus { Pending, Ok, Failed };
00171     ReplyStruct() {
00172     status = Pending;
00173     replyType = 0;
00174     replyData = 0;
00175     replyId = 0;
00176     }
00177     ReplyStatus status;
00178     QCString* replyType;
00179     QByteArray* replyData;
00180     Q_INT32 replyId;
00181 };
00182 
00183 static QCString dcopServerFile(const QCString &hostname, bool old)
00184 {
00185    QCString fName = ::getenv("DCOPAUTHORITY");
00186    if (!old && !fName.isEmpty())
00187         return fName;
00188 
00189    fName = ::getenv("HOME");
00190    if (fName.isEmpty())
00191    {
00192       fprintf(stderr, "Aborting. $HOME is not set.\n");
00193       exit(1);
00194    }
00195 #ifdef Q_WS_X11
00196    QCString disp = getenv("DISPLAY");
00197 #elif defined(Q_WS_QWS)
00198    QCString disp = getenv("QWS_DISPLAY");
00199 #endif
00200    if (disp.isEmpty())
00201       disp = "NODISPLAY";
00202 
00203    int i;
00204    if((i = disp.findRev('.')) > disp.findRev(':') && i >= 0)
00205        disp.truncate(i);
00206 
00207    if (!old)
00208    {
00209       while( (i = disp.find(':')) >= 0)
00210          disp[i] = '_';
00211    }
00212 
00213    fName += "/.DCOPserver_";
00214    if (hostname.isEmpty())
00215    {
00216       char hostName[256];
00217       if (gethostname(hostName, 255))
00218          fName += "localhost";
00219       else
00220          fName += hostName;
00221    }
00222    else
00223    {
00224       fName += hostname;
00225    }
00226    fName += "_"+disp;
00227    return fName;
00228 }
00229 
00230 
00231 // static
00232 QCString DCOPClient::dcopServerFile(const QCString &hostname)
00233 {
00234    return ::dcopServerFile(hostname, false);
00235 }
00236 
00237 
00238 // static
00239 QCString DCOPClient::dcopServerFileOld(const QCString &hostname)
00240 {
00241    return ::dcopServerFile(hostname, true);
00242 }
00243 
00244 
00245 const char* DCOPClientPrivate::serverAddr = 0;
00246 
00247 static void DCOPProcessInternal( DCOPClientPrivate *d, int opcode, CARD32 key, const QByteArray& dataReceived, bool canPost  );
00248 
00252 static void DCOPProcessMessage(IceConn iceConn, IcePointer clientObject,
00253             int opcode, unsigned long length, Bool /*swap*/,
00254             IceReplyWaitInfo *replyWait,
00255             Bool *replyWaitRet)
00256 {
00257     DCOPMsg *pMsg = 0;
00258     DCOPClientPrivate *d = static_cast<DCOPClientPrivate *>(clientObject);
00259 
00260     IceReadMessageHeader(iceConn, sizeof(DCOPMsg), DCOPMsg, pMsg);
00261     CARD32 key = pMsg->key;
00262     if ( d->key == 0 )
00263     d->key = key; // received a key from the server
00264 
00265     QByteArray dataReceived( length );
00266     IceReadData(iceConn, length, dataReceived.data() );
00267 
00268     d->opcode = opcode;
00269     switch (opcode ) {
00270 
00271     case DCOPReplyFailed:
00272     if ( replyWait ) {
00273         static_cast<ReplyStruct*>(replyWait->reply)->status = ReplyStruct::Failed;
00274         *replyWaitRet = True;
00275         return;
00276     } else {
00277         qWarning("Very strange! got a DCOPReplyFailed opcode, but we were not waiting for a reply!");
00278         return;
00279     }
00280     case DCOPReply:
00281     if ( replyWait ) {
00282         QByteArray* b = static_cast<ReplyStruct*>(replyWait->reply)->replyData;
00283         QCString* t =  static_cast<ReplyStruct*>(replyWait->reply)->replyType;
00284         static_cast<ReplyStruct*>(replyWait->reply)->status = ReplyStruct::Ok;
00285 
00286         QCString calledApp, app;
00287         QDataStream ds( dataReceived, IO_ReadOnly );
00288         ds >> calledApp >> app >> *t >> *b;
00289 
00290         *replyWaitRet = True;
00291         return;
00292     } else {
00293         qWarning("Very strange! got a DCOPReply opcode, but we were not waiting for a reply!");
00294         return;
00295     }
00296     case DCOPReplyWait:
00297     if ( replyWait ) {
00298         QCString calledApp, app;
00299         Q_INT32 id;
00300         QDataStream ds( dataReceived, IO_ReadOnly );
00301         ds >> calledApp >> app >> id;
00302         static_cast<ReplyStruct*>(replyWait->reply)->replyId = id;
00303         return;
00304     } else {
00305         qWarning("Very strange! got a DCOPReplyWait opcode, but we were not waiting for a reply!");
00306         return;
00307     }
00308     case DCOPReplyDelayed:
00309     if ( replyWait ) {
00310         QByteArray* b = static_cast<ReplyStruct*>(replyWait->reply)->replyData;
00311         static_cast<ReplyStruct*>(replyWait->reply)->status = ReplyStruct::Ok;
00312         QCString* t =  static_cast<ReplyStruct*>(replyWait->reply)->replyType;
00313 
00314         QDataStream ds( dataReceived, IO_ReadOnly );
00315         QCString calledApp, app;
00316         Q_INT32 id;
00317 
00318         ds >> calledApp >> app >> id >> *t >> *b;
00319         if (id != static_cast<ReplyStruct*>(replyWait->reply)->replyId) {
00320         static_cast<ReplyStruct*>(replyWait->reply)->status = ReplyStruct::Failed;
00321         qWarning("Very strange! DCOPReplyDelayed got wrong sequence id!");
00322         }
00323 
00324         *replyWaitRet = True;
00325     } else {
00326         qWarning("Very strange! got a DCOPReplyDelayed opcode, but we were not waiting for a reply!");
00327     }
00328     return;
00329     case DCOPCall:
00330     case DCOPFind:
00331     case DCOPSend:
00332     DCOPProcessInternal( d, opcode, key, dataReceived, TRUE );
00333     }
00334 }
00335 
00336 
00337 void DCOPClient::processPostedMessagesInternal()
00338 {
00339     if ( d->messages.isEmpty() )
00340     return;
00341     QPtrListIterator<DCOPClientMessage> it (d->messages );
00342     DCOPClientMessage* msg ;
00343     while ( ( msg = it.current() ) ) {
00344     ++it;
00345     if ( d->currentKey && msg->key != d->currentKey )
00346         continue;
00347     d->messages.removeRef( msg );
00348         d->opcode = msg->opcode;
00349     DCOPProcessInternal( d, msg->opcode, msg->key, msg->data, FALSE );
00350     delete msg;
00351     }
00352     if ( !d->messages.isEmpty() )
00353     d->postMessageTimer.start( 0, TRUE );
00354 }
00355 
00359 void DCOPProcessInternal( DCOPClientPrivate *d, int opcode, CARD32 key, const QByteArray& dataReceived, bool canPost  )
00360 {
00361     if (!d->accept_calls && (opcode == DCOPSend))
00362         return;
00363 
00364     IceConn iceConn = d->iceConn;
00365     DCOPMsg *pMsg = 0;
00366     DCOPClient *c = d->parent;
00367     QDataStream ds( dataReceived, IO_ReadOnly );
00368 
00369     QCString fromApp;
00370     ds >> fromApp;
00371 
00372     if (!d->accept_calls)
00373     {
00374         QByteArray reply;
00375         QDataStream replyStream( reply, IO_WriteOnly );
00376     // Call rejected.
00377     replyStream << d->appId << fromApp;
00378     IceGetHeader( iceConn, d->majorOpcode, DCOPReplyFailed,
00379               sizeof(DCOPMsg), DCOPMsg, pMsg );
00380     int datalen = reply.size();
00381     pMsg->key = key;
00382     pMsg->length += datalen;
00383     IceSendData( iceConn, datalen, const_cast<char *>(reply.data()));
00384     return;
00385     }
00386 
00387     QCString app, objId, fun;
00388     QByteArray data;
00389     ds >> app >> objId >> fun >> data;
00390     d->senderId = fromApp;
00391     d->objId = objId;
00392     d->function = fun;
00393 
00394     if ( canPost && d->currentKey && key != d->currentKey ) {
00395     DCOPClientMessage* msg = new DCOPClientMessage;
00396     msg->opcode = opcode;
00397     msg->key = key;
00398     msg->data = dataReceived;
00399     d->messages.append( msg );
00400     d->postMessageTimer.start( 0, TRUE );
00401     return;
00402     }
00403 
00404     d->objId = objId;
00405     d->function = fun;
00406 
00407     QCString replyType;
00408     QByteArray replyData;
00409     bool b;
00410     CARD32 oldCurrentKey = d->currentKey;
00411     if ( opcode != DCOPSend ) // DCOPSend doesn't change the current key
00412     d->currentKey = key;
00413 
00414     if ( opcode == DCOPFind )
00415     b = c->find(app, objId, fun, data, replyType, replyData );
00416     else
00417     b = c->receive( app, objId, fun, data, replyType, replyData );
00418     // set notifier back to previous state
00419 
00420     if ( opcode == DCOPSend )
00421     return;
00422 
00423     d->currentKey = oldCurrentKey;
00424 
00425     QByteArray reply;
00426     QDataStream replyStream( reply, IO_WriteOnly );
00427 
00428     Q_INT32 id = c->transactionId();
00429     if (id) {
00430     // Call delayed. Send back the transaction ID.
00431     replyStream << d->appId << fromApp << id;
00432 
00433     IceGetHeader( iceConn, d->majorOpcode, DCOPReplyWait,
00434               sizeof(DCOPMsg), DCOPMsg, pMsg );
00435     pMsg->key = key;
00436     pMsg->length += reply.size();
00437     IceSendData( iceConn, reply.size(), const_cast<char *>(reply.data()));
00438     return;
00439     }
00440 
00441     if ( !b )   {
00442     // Call failed. No data send back.
00443 
00444     replyStream << d->appId << fromApp;
00445     IceGetHeader( iceConn, d->majorOpcode, DCOPReplyFailed,
00446               sizeof(DCOPMsg), DCOPMsg, pMsg );
00447     int datalen = reply.size();
00448     pMsg->key = key;
00449     pMsg->length += datalen;
00450     IceSendData( iceConn, datalen, const_cast<char *>(reply.data()));
00451     return;
00452     }
00453 
00454     // Call successfull. Send back replyType and replyData.
00455     replyStream << d->appId << fromApp << replyType << replyData.size();
00456 
00457 
00458     // we are calling, so we need to set up reply data
00459     IceGetHeader( iceConn, d->majorOpcode, DCOPReply,
00460           sizeof(DCOPMsg), DCOPMsg, pMsg );
00461     int datalen = reply.size() + replyData.size();
00462     pMsg->key = key;
00463     pMsg->length += datalen;
00464     // use IceSendData not IceWriteData to avoid a copy.  Output buffer
00465     // shouldn't need to be flushed.
00466     IceSendData( iceConn, reply.size(), const_cast<char *>(reply.data()));
00467     IceSendData( iceConn, replyData.size(), const_cast<char *>(replyData.data()));
00468 }
00469 
00470 
00471 
00472 static IcePoVersionRec DCOPClientVersions[] = {
00473     { DCOPVersionMajor, DCOPVersionMinor,  DCOPProcessMessage }
00474 };
00475 
00476 
00477 static DCOPClient* dcop_main_client = 0;
00478 
00479 DCOPClient* DCOPClient::mainClient()
00480 {
00481     return dcop_main_client;
00482 }
00483 
00484 void DCOPClient::setMainClient( DCOPClient* client )
00485 {
00486     dcop_main_client = client;
00487 }
00488 
00489 
00490 DCOPClient::DCOPClient()
00491 {
00492     d = new DCOPClientPrivate;
00493     d->parent = this;
00494     d->iceConn = 0L;
00495     d->majorOpcode = 0;
00496     d->key = 0;
00497     d->currentKey = 0;
00498     d->appId = 0;
00499     d->notifier = 0L;
00500     d->non_blocking_call_lock = false;
00501     d->registered = false;
00502     d->foreign_server = true;
00503     d->accept_calls = true;
00504     d->accept_calls_override = false;
00505     d->qt_bridge_enabled = true;
00506     d->transactionList = 0L;
00507     d->transactionId = 0;
00508     QObject::connect( &d->postMessageTimer, SIGNAL( timeout() ), this, SLOT( processPostedMessagesInternal() ) );
00509 
00510     if ( !mainClient() )
00511     setMainClient( this );
00512 }
00513 
00514 DCOPClient::~DCOPClient()
00515 {
00516     if (d->iceConn)
00517     if (IceConnectionStatus(d->iceConn) == IceConnectAccepted)
00518         detach();
00519 
00520     if (d->registered)
00521        unregisterLocalClient( d->appId );
00522 
00523     delete d->notifier;
00524     delete d->transactionList;
00525     delete d;
00526 
00527     if ( mainClient() == this )
00528     setMainClient( 0 );
00529 }
00530 
00531 void DCOPClient::setServerAddress(const QCString &addr)
00532 {
00533     QCString env = "DCOPSERVER=" + addr;
00534     putenv(strdup(env.data()));
00535     delete [] DCOPClientPrivate::serverAddr;
00536     DCOPClientPrivate::serverAddr = qstrdup( addr.data() );
00537 }
00538 
00539 bool DCOPClient::attach()
00540 {
00541     if (!attachInternal( true ))
00542        if (!attachInternal( true ))
00543           return false; // Try two times!
00544     return true;
00545 }
00546 
00547 void DCOPClient::bindToApp()
00548 {
00549     // check if we have a qApp instantiated.  If we do,
00550     // we can create a QSocketNotifier and use it for receiving data.
00551     if (qApp) {
00552     if ( d->notifier )
00553         delete d->notifier;
00554     d->notifier = new QSocketNotifier(socket(),
00555                       QSocketNotifier::Read, 0, 0);
00556     QObject::connect(d->notifier, SIGNAL(activated(int)),
00557         SLOT(processSocketData(int)));
00558     }
00559 }
00560 
00561 void DCOPClient::suspend()
00562 {
00563   assert(d->notifier); // Suspending makes no sense if we didn't had a qApp yet
00564   d->notifier->setEnabled(false);
00565 }
00566 
00567 void DCOPClient::resume()
00568 {
00569   assert(d->notifier); // Should never happen
00570   d->notifier->setEnabled(true);
00571 }
00572 
00573 bool DCOPClient::isSuspended() const
00574 {
00575   return !d->notifier->isEnabled();
00576 }
00577 
00578 #ifdef SO_PEERCRED
00579 // Check whether the remote end is owned by the same user.
00580 static bool peerIsUs(int sockfd)
00581 {
00582     struct ucred cred;
00583     socklen_t siz = sizeof(cred);
00584     if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &siz) != 0)
00585        return false;
00586     return (cred.uid == getuid());
00587 }
00588 #else
00589 // Check whether the socket is owned by the same user.
00590 static bool isServerSocketOwnedByUser(const char*server)
00591 {
00592    if (strncmp(server, "local/", 6) != 0)
00593       return false; // Not a local socket -> foreign.
00594    const char *path = strchr(server, ':');
00595    if (!path)
00596       return false;
00597    path++;
00598 
00599    struct stat stat_buf;
00600    if (stat(path, &stat_buf) != 0)
00601       return false;
00602 
00603    return (stat_buf.st_uid == getuid());
00604 }
00605 #endif
00606 
00607 
00608 bool DCOPClient::attachInternal( bool registerAsAnonymous )
00609 {
00610     char errBuf[1024];
00611 
00612     if ( isAttached() )
00613     detach();
00614 
00615     extern int _KDE_IceLastMajorOpcode; // from libICE
00616     if (_KDE_IceLastMajorOpcode < 1 )
00617         IceRegisterForProtocolSetup(const_cast<char *>("DUMMY"),
00618                     const_cast<char *>("DUMMY"),
00619                     const_cast<char *>("DUMMY"),
00620                     1, DCOPClientVersions,
00621                     DCOPAuthCount, const_cast<char **>(DCOPAuthNames),
00622                     DCOPClientAuthProcs, 0);
00623     if (_KDE_IceLastMajorOpcode < 1 )
00624     qWarning("DCOPClient Error: incorrect major opcode!");
00625 
00626     if ((d->majorOpcode = IceRegisterForProtocolSetup(const_cast<char *>("DCOP"),
00627                               const_cast<char *>(DCOPVendorString),
00628                               const_cast<char *>(DCOPReleaseString),
00629                               1, DCOPClientVersions,
00630                               DCOPAuthCount,
00631                               const_cast<char **>(DCOPAuthNames),
00632                               DCOPClientAuthProcs, 0L)) < 0) {
00633     emit attachFailed(QString::fromLatin1( "Communications could not be established." ));
00634     return false;
00635     }
00636 
00637     bool bClearServerAddr = false;
00638     // first, check if serverAddr was ever set.
00639     if (!d->serverAddr) {
00640     // here, we obtain the list of possible DCOP connections,
00641     // and attach to them.
00642     QString dcopSrv;
00643     dcopSrv = ::getenv("DCOPSERVER");
00644     if (dcopSrv.isEmpty()) {
00645         QString fName = dcopServerFile();
00646         QFile f(fName);
00647         if (!f.open(IO_ReadOnly)) {
00648         emit attachFailed(QString::fromLatin1( "Could not read network connection list.\n" )+fName);
00649         return false;
00650         }
00651             int size = QMIN( 1024, f.size() ); // protection against a huge file
00652             QCString contents( size+1 );
00653             if ( f.readBlock( contents.data(), size ) != size )
00654             {
00655                qDebug("Error reading from %s, didn't read the expected %d bytes", fName.latin1(), size);
00656                // Should we abort ?
00657             }
00658             contents[size] = '\0';
00659             int pos = contents.find('\n');
00660             if ( pos == -1 ) // Shouldn't happen
00661             {
00662                 qDebug("Only one line in dcopserver file !: %s", contents.data());
00663                 dcopSrv = QString::fromLatin1(contents);
00664             }
00665             else
00666             {
00667                 dcopSrv = QString::fromLatin1(contents.left( pos ));
00668 //#ifndef NDEBUG
00669 //                qDebug("dcopserver address: %s", dcopSrv.latin1());
00670 //#endif
00671             }
00672     }
00673     d->serverAddr = qstrdup( const_cast<char *>(dcopSrv.latin1()) );
00674         bClearServerAddr = true;
00675     }
00676 
00677     if ((d->iceConn = IceOpenConnection(const_cast<char*>(d->serverAddr),
00678                     static_cast<IcePointer>(this), False, d->majorOpcode,
00679                     sizeof(errBuf), errBuf)) == 0L) {
00680         qDebug("DCOPClient::attachInternal. Attach failed %s", errBuf ? errBuf : "");
00681     d->iceConn = 0;
00682         if (bClearServerAddr) {
00683            delete [] d->serverAddr;
00684            d->serverAddr = 0;
00685         }
00686     emit attachFailed(QString::fromLatin1( errBuf ));
00687     return false;
00688     }
00689 
00690     IceSetShutdownNegotiation(d->iceConn, False);
00691 
00692     int setupstat;
00693     char* vendor = 0;
00694     char* release = 0;
00695     setupstat = IceProtocolSetup(d->iceConn, d->majorOpcode,
00696                  static_cast<IcePointer>(d),
00697                  False, /* must authenticate */
00698                  &(d->majorVersion), &(d->minorVersion),
00699                  &vendor, &release, 1024, errBuf);
00700 
00701     if (vendor) free(vendor);
00702     if (release) free(release);
00703 
00704 
00705     if (setupstat == IceProtocolSetupFailure ||
00706     setupstat == IceProtocolSetupIOError) {
00707     IceCloseConnection(d->iceConn);
00708         d->iceConn = 0;
00709         if (bClearServerAddr) {
00710            delete [] d->serverAddr;
00711            d->serverAddr = 0;
00712         }
00713     emit attachFailed(QString::fromLatin1( errBuf ));
00714     return false;
00715     } else if (setupstat == IceProtocolAlreadyActive) {
00716         if (bClearServerAddr) {
00717            delete [] d->serverAddr;
00718            d->serverAddr = 0;
00719         }
00720     /* should not happen because 3rd arg to IceOpenConnection was 0. */
00721     emit attachFailed(QString::fromLatin1( "internal error in IceOpenConnection" ));
00722     return false;
00723     }
00724 
00725 
00726     if (IceConnectionStatus(d->iceConn) != IceConnectAccepted) {
00727         if (bClearServerAddr) {
00728            delete [] d->serverAddr;
00729            d->serverAddr = 0;
00730         }
00731     emit attachFailed(QString::fromLatin1( "DCOP server did not accept the connection." ));
00732     return false;
00733     }
00734 
00735 #ifdef SO_PEERCRED
00736     d->foreign_server = !peerIsUs(socket());
00737 #else
00738     d->foreign_server = !isServerSocketOwnedByUser(d->serverAddr);
00739 #endif
00740     if (!d->accept_calls_override)
00741        d->accept_calls = !d->foreign_server;
00742 
00743     bindToApp();
00744 
00745     if ( registerAsAnonymous )
00746     registerAs( "anonymous", true );
00747 
00748     return true;
00749 }
00750 
00751 
00752 bool DCOPClient::detach()
00753 {
00754     int status;
00755 
00756     if (d->iceConn) {
00757     IceProtocolShutdown(d->iceConn, d->majorOpcode);
00758     status = IceCloseConnection(d->iceConn);
00759     if (status != IceClosedNow)
00760         return false;
00761     else
00762         d->iceConn = 0L;
00763     }
00764 
00765     if (d->registered)
00766        unregisterLocalClient(d->appId);
00767 
00768     delete d->notifier;
00769     d->notifier = 0L;
00770     d->registered = false;
00771     d->foreign_server = true;
00772     return true;
00773 }
00774 
00775 bool DCOPClient::isAttached() const
00776 {
00777     if (!d->iceConn)
00778     return false;
00779 
00780     return (IceConnectionStatus(d->iceConn) == IceConnectAccepted);
00781 }
00782 
00783 bool DCOPClient::isAttachedToForeignServer() const
00784 {
00785     return isAttached() && d->foreign_server;
00786 }
00787 
00788 bool DCOPClient::acceptCalls() const
00789 {
00790     return isAttached() && d->accept_calls;
00791 }
00792 
00793 void DCOPClient::setAcceptCalls(bool b)
00794 {
00795     d->accept_calls = b;
00796     d->accept_calls_override = true;
00797 }
00798 
00799 bool DCOPClient::qtBridgeEnabled()
00800 {
00801     return d->qt_bridge_enabled;
00802 }
00803 
00804 void DCOPClient::setQtBridgeEnabled(bool b)
00805 {
00806     d->qt_bridge_enabled = b;
00807 }
00808 
00809 QCString DCOPClient::registerAs( const QCString &appId, bool addPID )
00810 {
00811     QCString result;
00812 
00813     QCString _appId = appId;
00814 
00815     if (addPID) {
00816     QCString pid;
00817     pid.sprintf("-%d", getpid());
00818     _appId = _appId + pid;
00819     }
00820 
00821     if( d->appId == _appId )
00822         return d->appId;
00823 
00824 #if 0 // no need to detach, dcopserver can handle renaming
00825     // Detach before reregistering.
00826     if ( isRegistered() ) {
00827     detach();
00828     }
00829 #endif
00830 
00831     if ( !isAttached() ) {
00832         if (!attachInternal( false ))
00833             if (!attachInternal( false ))
00834                 return result; // Try two times
00835     }
00836 
00837     // register the application identifier with the server
00838     QCString replyType;
00839     QByteArray data, replyData;
00840     QDataStream arg( data, IO_WriteOnly );
00841     arg << _appId;
00842     if ( call( "DCOPServer", "", "registerAs(QCString)", data, replyType, replyData ) ) {
00843     QDataStream reply( replyData, IO_ReadOnly );
00844     reply >> result;
00845     }
00846 
00847     d->appId = result;
00848     d->registered = !result.isNull();
00849 
00850     if (d->registered)
00851        registerLocalClient( d->appId, this );
00852 
00853     return result;
00854 }
00855 
00856 bool DCOPClient::isRegistered() const
00857 {
00858     return d->registered;
00859 }
00860 
00861 
00862 QCString DCOPClient::appId() const
00863 {
00864     return d->appId;
00865 }
00866 
00867 
00868 int DCOPClient::socket() const
00869 {
00870     if (d->iceConn)
00871     return IceConnectionNumber(d->iceConn);
00872     else
00873     return 0;
00874 }
00875 
00876 static inline bool isIdentChar( char x )
00877 {                       // Avoid bug in isalnum
00878     return x == '_' || (x >= '0' && x <= '9') ||
00879      (x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z');
00880 }
00881 
00882 QCString DCOPClient::normalizeFunctionSignature( const QCString& fun ) {
00883     if ( fun.isEmpty() )                // nothing to do
00884     return fun.copy();
00885     QCString result( fun.size() );
00886     char *from  = fun.data();
00887     char *to    = result.data();
00888     char *first = to;
00889     char last = 0;
00890     while ( true ) {
00891     while ( *from && isspace(*from) )
00892         from++;
00893     if ( last && isIdentChar( last ) && isIdentChar( *from ) )
00894         *to++ = 0x20;
00895     while ( *from && !isspace(*from) ) {
00896         last = *from++;
00897         *to++ = last;
00898     }
00899     if ( !*from )
00900         break;
00901     }
00902     if ( to > first && *(to-1) == 0x20 )
00903     to--;
00904     *to = '\0';
00905     result.resize( (int)((long)to - (long)result.data()) + 1 );
00906     return result;
00907 }
00908 
00909 
00910 QCString DCOPClient::senderId() const
00911 {
00912     return d->senderId;
00913 }
00914 
00915 
00916 bool DCOPClient::send(const QCString &remApp, const QCString &remObjId,
00917               const QCString &remFun, const QByteArray &data)
00918 {
00919     if (remApp.isEmpty())
00920        return false;
00921     DCOPClient *localClient = findLocalClient( remApp );
00922 
00923     if ( localClient  ) {
00924     QCString replyType;
00925     QByteArray replyData;
00926     (void) localClient->receive(  remApp, remObjId, remFun, data, replyType, replyData );
00927 
00928     // send() returns TRUE if the data could be send to the DCOPServer,
00929     // regardles of receiving the data on the other application.
00930     // So we assume the data is successfully send to the (virtual) server
00931     // and return TRUE in any case.
00932     return true;
00933     }
00934 
00935     if ( !isAttached() )
00936     return false;
00937 
00938 
00939     DCOPMsg *pMsg;
00940 
00941     QByteArray ba;
00942     QDataStream ds(ba, IO_WriteOnly);
00943     ds << d->appId << remApp << remObjId << normalizeFunctionSignature(remFun) << data.size();
00944 
00945     IceGetHeader(d->iceConn, d->majorOpcode, DCOPSend,
00946          sizeof(DCOPMsg), DCOPMsg, pMsg);
00947 
00948     pMsg->key = 1; // DCOPSend always uses the magic key 1
00949     int datalen = ba.size() + data.size();
00950     pMsg->length += datalen;
00951 
00952     IceSendData( d->iceConn, ba.size(), const_cast<char *>(ba.data()) );
00953     IceSendData( d->iceConn, data.size(), const_cast<char *>(data.data()) );
00954 
00955     //IceFlush(d->iceConn);
00956 
00957     if (IceConnectionStatus(d->iceConn) != IceConnectAccepted)
00958     return false;
00959     else
00960     return true;
00961 }
00962 
00963 bool DCOPClient::send(const QCString &remApp, const QCString &remObjId,
00964               const QCString &remFun, const QString &data)
00965 {
00966     QByteArray ba;
00967     QDataStream ds(ba, IO_WriteOnly);
00968     ds << data;
00969     return send(remApp, remObjId, remFun, ba);
00970 }
00971 
00972 bool DCOPClient::findObject(const QCString &remApp, const QCString &remObj,
00973                             const QCString &remFun, const QByteArray &data,
00974                             QCString &foundApp, QCString &foundObj,
00975                             bool useEventLoop)
00976 {
00977     QCStringList appList;
00978     QCString app = remApp;
00979     if (app.isEmpty())
00980        app = "*";
00981 
00982     foundApp = 0;
00983     foundObj = 0;
00984 
00985     if (app[app.length()-1] == '*')
00986     {
00987        // Find all apps that match 'app'.
00988        // NOTE: It would be more efficient to do the filtering in
00989        // the dcopserver itself.
00990        int len = app.length()-1;
00991        QCStringList apps=registeredApplications();
00992        for( QCStringList::ConstIterator it = apps.begin();
00993             it != apps.end();
00994             ++it)
00995        {
00996           if ( strncmp( (*it).data(), app.data(), len) == 0)
00997              appList.append(*it);
00998        }
00999     }
01000     else
01001     {
01002        appList.append(app);
01003     }
01004 
01005     for( QCStringList::ConstIterator it = appList.begin();
01006          it != appList.end();
01007          ++it)
01008     {
01009         QCString replyType;
01010         QByteArray replyData;
01011         if (callInternal((*it), remObj, remFun, data,
01012                      replyType, replyData, useEventLoop, DCOPFind))
01013         {
01014            if (replyType == "DCOPRef")
01015            {
01016               DCOPRef ref;
01017               QDataStream reply( replyData, IO_ReadOnly );
01018               reply >> ref;
01019 
01020               if (ref.app() == (*it)) // Consistency check
01021               {
01022                  // replyType contains objId.
01023                  foundApp = ref.app();
01024                  foundObj = ref.object();
01025                  return true;
01026               }
01027            }
01028         }
01029     }
01030     return false;
01031 }
01032 
01033 bool DCOPClient::process(const QCString &, const QByteArray &,
01034              QCString&, QByteArray &)
01035 {
01036     return false;
01037 }
01038 
01039 bool DCOPClient::isApplicationRegistered( const QCString& remApp)
01040 {
01041     QCString replyType;
01042     QByteArray data, replyData;
01043     QDataStream arg( data, IO_WriteOnly );
01044     arg << remApp;
01045     int result = false;
01046     if ( call( "DCOPServer", "", "isApplicationRegistered(QCString)", data, replyType, replyData ) ) {
01047     QDataStream reply( replyData, IO_ReadOnly );
01048     reply >> result;
01049     }
01050     return result;
01051 }
01052 
01053 QCStringList DCOPClient::registeredApplications()
01054 {
01055     QCString replyType;
01056     QByteArray data, replyData;
01057     QCStringList result;
01058     if ( call( "DCOPServer", "", "registeredApplications()", data, replyType, replyData ) ) {
01059     QDataStream reply( replyData, IO_ReadOnly );
01060     reply >> result;
01061     }
01062     return result;
01063 }
01064 
01065 QCStringList DCOPClient::remoteObjects( const QCString& remApp, bool *ok )
01066 {
01067     QCString replyType;
01068     QByteArray data, replyData;
01069     QCStringList result;
01070     if ( ok )
01071     *ok = FALSE;
01072     if ( call( remApp, "DCOPClient", "objects()", data, replyType, replyData ) ) {
01073     QDataStream reply( replyData, IO_ReadOnly );
01074     reply >> result;
01075     if ( ok )
01076         *ok = TRUE;
01077     }
01078     return result;
01079 }
01080 
01081 QCStringList DCOPClient::remoteInterfaces( const QCString& remApp, const QCString& remObj, bool *ok  )
01082 {
01083     QCString replyType;
01084     QByteArray data, replyData;
01085     QCStringList result;
01086     if ( ok )
01087     *ok = FALSE;
01088     if ( call( remApp, remObj, "interfaces()", data, replyType, replyData ) && replyType == "QCStringList") {
01089     QDataStream reply( replyData, IO_ReadOnly );
01090     reply >> result;
01091     if ( ok )
01092         *ok = TRUE;
01093     }
01094     return result;
01095 }
01096 
01097 QCStringList DCOPClient::remoteFunctions( const QCString& remApp, const QCString& remObj, bool *ok  )
01098 {
01099     QCString replyType;
01100     QByteArray data, replyData;
01101     QCStringList result;
01102     if ( ok )
01103     *ok = FALSE;
01104     if ( call( remApp, remObj, "functions()", data, replyType, replyData ) && replyType == "QCStringList") {
01105     QDataStream reply( replyData, IO_ReadOnly );
01106     reply >> result;
01107     if ( ok )
01108         *ok = TRUE;
01109     }
01110     return result;
01111 }
01112 
01113 void DCOPClient::setNotifications(bool enabled)
01114 {
01115     QByteArray data;
01116     QDataStream ds(data, IO_WriteOnly);
01117     ds << static_cast<Q_INT8>(enabled);
01118 
01119     QCString replyType;
01120     QByteArray reply;
01121     if (!call("DCOPServer", "", "setNotifications( bool )", data, replyType, reply))
01122     qWarning("I couldn't enable notifications at the dcopserver!");
01123 }
01124 
01125 void DCOPClient::setDaemonMode( bool daemonMode )
01126 {
01127     QByteArray data;
01128     QDataStream ds(data, IO_WriteOnly);
01129     ds << static_cast<Q_INT8>( daemonMode );
01130 
01131     QCString replyType;
01132     QByteArray reply;
01133     if (!call("DCOPServer", "", "setDaemonMode(bool)", data, replyType, reply))
01134     qWarning("I couldn't enable daemon mode at the dcopserver!");
01135 }
01136 
01137 
01138 
01139 /*
01140   DCOP <-> Qt bridge
01141 
01142   ********************************************************************************
01143  */
01144 static void fillQtObjects( QCStringList& l, QObject* o, QCString path )
01145 {
01146     if ( !path.isEmpty() )
01147     path += '/';
01148 
01149     int unnamed = 0;
01150     const QObjectList *list = o ? o->children() : QObject::objectTrees();
01151     if ( list ) {
01152     QObjectListIt it( *list );
01153     QObject *obj;
01154     while ( (obj=it.current()) ) {
01155         ++it;
01156         QCString n = obj->name();
01157         if ( n == "unnamed" || n.isEmpty() )
01158         {
01159             n.sprintf("%p", (void *) obj);
01160             n = QString("unnamed%1(%2, %3)").arg(++unnamed).arg(obj->className()).arg(n).latin1();
01161         }
01162         QCString fn = path + n;
01163         l.append( fn );
01164         if ( obj->children() )
01165         fillQtObjects( l, obj, fn );
01166     }
01167     }
01168 }
01169 
01170 struct O
01171 {
01172     O(): o(0) {}
01173     O ( const QCString& str, QObject* obj ):s(str), o(obj){}
01174     QCString s;
01175     QObject* o;
01176 };
01177 
01178 static void fillQtObjectsEx( QValueList<O>& l, QObject* o, QCString path )
01179 {
01180     if ( !path.isEmpty() )
01181     path += '/';
01182 
01183     int unnamed = 0;
01184     const QObjectList *list = o ? o->children() : QObject::objectTrees();
01185     if ( list ) {
01186     QObjectListIt it( *list );
01187     QObject *obj;
01188     while ( (obj=it.current()) ) {
01189         ++it;
01190         QCString n = obj->name();
01191         if ( n == "unnamed" || n.isEmpty() )
01192         {
01193             n.sprintf("%p", (void *) obj);
01194             n = QString("unnamed%1(%2, %3)").arg(++unnamed).arg(obj->className()).arg(n).latin1();
01195         }
01196         QCString fn = path + n;
01197         l.append( O( fn, obj ) );
01198         if ( obj->children() )
01199         fillQtObjectsEx( l, obj, fn );
01200     }
01201     }
01202 }
01203 
01204 
01205 static QObject* findQtObject( QCString id )
01206 {
01207     QRegExp expr( id );
01208     QValueList<O> l;
01209     fillQtObjectsEx( l, 0, "qt" );
01210     // Prefer an exact match, but fall-back on the first that contains the substring
01211     QObject* firstContains = 0L;
01212     for ( QValueList<O>::ConstIterator it = l.begin(); it != l.end(); ++it ) {
01213     if ( (*it).s == id ) // exact match
01214         return (*it).o;
01215     if ( !firstContains && (*it).s.contains( expr ) ) {
01216         firstContains = (*it).o;
01217     }
01218     }
01219     return firstContains;
01220 }
01221 
01222 static QCStringList  findQtObjects( QCString id )
01223 {
01224     QRegExp expr( id );
01225     QValueList<O> l;
01226     fillQtObjectsEx( l, 0, "qt" );
01227     QCStringList result;
01228     for ( QValueList<O>::ConstIterator it = l.begin(); it != l.end(); ++it ) {
01229     if ( (*it).s.contains( expr ) )
01230         result << (*it).s;
01231     }
01232     return result;
01233 }
01234 
01235 static bool receiveQtObject( const QCString &objId, const QCString &fun, const QByteArray &data,
01236                 QCString& replyType, QByteArray &replyData)
01237 {
01238     if  ( objId == "qt" ) {
01239     if ( fun == "interfaces()" ) {
01240         replyType = "QCStringList";
01241         QDataStream reply( replyData, IO_WriteOnly );
01242         QCStringList l;
01243         l << "DCOPObject";
01244         l << "Qt";
01245         reply << l;
01246         return true;
01247     } else if ( fun == "functions()" ) {
01248         replyType = "QCStringList";
01249         QDataStream reply( replyData, IO_WriteOnly );
01250         QCStringList l;
01251         l << "QCStringList functions()";
01252         l << "QCStringList interfaces()";
01253         l << "QCStringList objects()";
01254         l << "QCStringList find(QCString)";
01255         reply << l;
01256         return true;
01257     } else if ( fun == "objects()" ) {
01258         replyType = "QCStringList";
01259         QDataStream reply( replyData, IO_WriteOnly );
01260         QCStringList l;
01261         fillQtObjects( l, 0, "qt" );
01262         reply << l;
01263         return true;
01264     } else if ( fun == "find(QCString)" ) {
01265         QDataStream ds( data, IO_ReadOnly );
01266         QCString id;
01267         ds >> id ;
01268         replyType = "QCStringList";
01269         QDataStream reply( replyData, IO_WriteOnly );
01270         reply << findQtObjects( id ) ;
01271         return true;
01272     }
01273     } else if ( objId.left(3) == "qt/" ) {
01274     QObject* o = findQtObject( objId );
01275     if ( !o )
01276         return false;
01277     if ( fun == "functions()" ) {
01278         replyType = "QCStringList";
01279         QDataStream reply( replyData, IO_WriteOnly );
01280         QCStringList l;
01281         l << "QCStringList functions()";
01282         l << "QCStringList interfaces()";
01283         l << "QCStringList properties()";
01284         l << "bool setProperty(QCString,QVariant)";
01285         l << "QVariant property(QCString)";
01286         QStrList lst = o->metaObject()->slotNames( true );
01287         int i = 0;
01288         for ( QPtrListIterator<char> it( lst ); it.current(); ++it ) {
01289         if ( o->metaObject()->slot( i++, true )->access != QMetaData::Public )
01290             continue;
01291         QCString slot = it.current();
01292         if ( slot.contains( "()" ) ) {
01293             slot.prepend("void ");
01294             l <<  slot;
01295         }
01296         }
01297         reply << l;
01298         return true;
01299     } else if ( fun == "interfaces()" ) {
01300         replyType = "QCStringList";
01301         QDataStream reply( replyData, IO_WriteOnly );
01302         QCStringList l;
01303         QMetaObject *meta = o->metaObject();
01304         while ( meta ) {
01305         l.prepend( meta->className() );
01306         meta = meta->superClass();
01307         }
01308         reply << l;
01309         return true;
01310     } else if ( fun == "properties()" ) {
01311         replyType = "QCStringList";
01312         QDataStream reply( replyData, IO_WriteOnly );
01313         QCStringList l;
01314         QStrList lst = o->metaObject()->propertyNames( true );
01315         for ( QPtrListIterator<char> it( lst ); it.current(); ++it ) {
01316         QMetaObject *mo = o->metaObject();
01317         const QMetaProperty* p = mo->property( mo->findProperty( it.current(), true ), true );
01318         if ( !p )
01319             continue;
01320         QCString prop = p->type();
01321         prop += ' ';
01322         prop += p->name();
01323         if ( !p->writable() )
01324             prop += " readonly";
01325         l << prop;
01326         }
01327         reply << l;
01328         return true;
01329     } else if ( fun == "property(QCString)" ) {
01330         replyType = "QVariant";
01331         QDataStream ds( data, IO_ReadOnly );
01332         QCString name;
01333         ds >> name ;
01334         QVariant result = o->property(  name );
01335         QDataStream reply( replyData, IO_WriteOnly );
01336         reply << result;
01337         return true;
01338     } else if ( fun == "setProperty(QCString,QVariant)" ) {
01339         QDataStream ds( data, IO_ReadOnly );
01340         QCString name;
01341         QVariant value;
01342         ds >> name >> value;
01343         replyType = "bool";
01344         QDataStream reply( replyData, IO_WriteOnly );
01345         reply << (Q_INT8) o->setProperty( name, value );
01346         return true;
01347     } else {
01348         int slot = o->metaObject()->findSlot( fun, true );
01349         if ( slot != -1 ) {
01350         replyType = "void";
01351         QUObject uo[ 1 ];
01352         o->qt_invoke( slot, uo );
01353         return true;
01354         }
01355     }
01356 
01357 
01358     }
01359     return false;
01360 }
01361 
01362 
01363 /*
01364   ********************************************************************************
01365   End of DCOP <-> Qt bridge
01366  */
01367 
01368 
01369 bool DCOPClient::receive(const QCString &/*app*/, const QCString &objId,
01370              const QCString &fun, const QByteArray &data,
01371              QCString& replyType, QByteArray &replyData)
01372 {
01373     d->transaction = false; // Assume no transaction.
01374     if ( objId == "DCOPClient" ) {
01375     if ( fun == "objects()" ) {
01376         replyType = "QCStringList";
01377         QDataStream reply( replyData, IO_WriteOnly );
01378         QCStringList l;
01379         if (d->qt_bridge_enabled)
01380         {
01381            l << "qt"; // the Qt bridge object
01382         }
01383         if ( dcopObjMap ) {
01384         QMap<QCString, DCOPObject *>::ConstIterator it( dcopObjMap->begin());
01385         for (; it != dcopObjMap->end(); ++it) {
01386             if ( !it.key().isEmpty() ) {
01387             if ( it.key() == d->defaultObject )
01388                 l << "default";
01389             l << it.key();
01390             }
01391         }
01392         }
01393         reply << l;
01394         return true;
01395     }
01396     }
01397 
01398     if ( objId.isEmpty() || objId == "DCOPClient" ) {
01399     if ( fun == "applicationRegistered(QCString)" ) {
01400         QDataStream ds( data, IO_ReadOnly );
01401         QCString r;
01402         ds >> r;
01403         emit applicationRegistered( r );
01404         return true;
01405     } else if ( fun == "applicationRemoved(QCString)" ) {
01406         QDataStream ds( data, IO_ReadOnly );
01407         QCString r;
01408         ds >> r;
01409         emit applicationRemoved( r );
01410         return true;
01411     }
01412 
01413     if ( process( fun, data, replyType, replyData ) )
01414         return true;
01415     // fall through and send to defaultObject if available
01416 
01417     } else if (d->qt_bridge_enabled &&
01418                (objId == "qt" || objId.left(3) == "qt/") ) { // dcop <-> qt bridge
01419     return receiveQtObject( objId, fun, data, replyType, replyData );
01420     }
01421 
01422     if ( objId.isEmpty() || objId == "default" ) {
01423     if ( !d->defaultObject.isEmpty() && DCOPObject::hasObject( d->defaultObject ) ) {
01424         DCOPObject *objPtr = DCOPObject::find( d->defaultObject );
01425         objPtr->setCallingDcopClient(this);
01426         if (objPtr->process(fun, data, replyType, replyData))
01427         return true;
01428     }
01429 
01430     // fall through and send to object proxies
01431     }
01432 
01433     if (!objId.isEmpty() && objId[objId.length()-1] == '*') {
01434     // handle a multicast to several objects.
01435     // doesn't handle proxies currently.  should it?
01436     QPtrList<DCOPObject> matchList =
01437         DCOPObject::match(objId.left(objId.length()-1));
01438     for (DCOPObject *objPtr = matchList.first();
01439          objPtr != 0L; objPtr = matchList.next()) {
01440         objPtr->setCallingDcopClient(this);
01441         if (!objPtr->process(fun, data, replyType, replyData))
01442         return false;
01443     }
01444     return true;
01445     } else if (!DCOPObject::hasObject(objId)) {
01446     if ( DCOPObjectProxy::proxies ) {
01447         for ( QPtrListIterator<DCOPObjectProxy> it( *DCOPObjectProxy::proxies ); it.current();  ++it ) {
01448             // TODO: it.current()->setCallingDcopClient(this);
01449         if ( it.current()->process( objId, fun, data, replyType, replyData ) )
01450             return true;
01451         }
01452     }
01453     return false;
01454 
01455     } else {
01456     DCOPObject *objPtr = DCOPObject::find(objId);
01457     objPtr->setCallingDcopClient(this);
01458     if (!objPtr->process(fun, data, replyType, replyData)) {
01459         // obj doesn't understand function or some other error.
01460         return false;
01461     }
01462     }
01463 
01464     return true;
01465 }
01466 
01467 // Check if the function result is a bool with the value "true"
01468 // If so set the function result to DCOPRef pointing to (app,objId) and
01469 // return true. Return false otherwise.
01470 static bool findResultOk(QCString &replyType, QByteArray &replyData)
01471 {
01472     Q_INT8 success; // Tsk.. why is there no operator>>(bool)?
01473     if (replyType != "bool") return false;
01474 
01475     QDataStream reply( replyData, IO_ReadOnly );
01476     reply >> success;
01477 
01478     if (!success) return false;
01479     return true;
01480 }
01481 
01482 // set the function result to DCOPRef pointing to (app,objId) and
01483 // return true.
01484 static bool findSuccess(const QCString &app, const QCString objId, QCString &replyType, QByteArray &replyData)
01485 {
01486     DCOPRef ref(app, objId);
01487     replyType = "DCOPRef";
01488 
01489     replyData = QByteArray();
01490     QDataStream final_reply( replyData, IO_WriteOnly );
01491     final_reply << ref;
01492     return true;
01493 }
01494 
01495 
01496 bool DCOPClient::find(const QCString &app, const QCString &objId,
01497               const QCString &fun, const QByteArray &data,
01498                       QCString& replyType, QByteArray &replyData)
01499 {
01500     d->transaction = false; // Transactions are not allowed.
01501     if ( !app.isEmpty() && app != d->appId && app[app.length()-1] != '*') {
01502     qWarning("WEIRD! we somehow received a DCOP message w/a different appId");
01503     return false;
01504     }
01505 
01506     if (objId.isEmpty() || objId[objId.length()-1] != '*')
01507     {
01508         if (fun.isEmpty())
01509         {
01510             if (objId.isEmpty() || DCOPObject::hasObject(objId))
01511                return findSuccess(app, objId, replyType, replyData);
01512             return false;
01513         }
01514         // Message to application or single object...
01515         if (receive(app, objId, fun, data, replyType, replyData))
01516         {
01517             if (findResultOk(replyType, replyData))
01518                 return findSuccess(app, objId, replyType, replyData);
01519         }
01520     }
01521     else {
01522     // handle a multicast to several objects.
01523     // doesn't handle proxies currently.  should it?
01524     QPtrList<DCOPObject> matchList =
01525         DCOPObject::match(objId.left(objId.length()-1));
01526     for (DCOPObject *objPtr = matchList.first();
01527          objPtr != 0L; objPtr = matchList.next())
01528         {
01529             replyType = 0;
01530             replyData = QByteArray();
01531             if (fun.isEmpty())
01532                 return findSuccess(app, objPtr->objId(), replyType, replyData);
01533             objPtr->setCallingDcopClient(this);
01534         if (objPtr->process(fun, data, replyType, replyData))
01535         if (findResultOk(replyType, replyData))
01536                     return findSuccess(app, objPtr->objId(), replyType, replyData);
01537     }
01538     }
01539     return false;
01540 }
01541 
01542 
01543 bool DCOPClient::call(const QCString &remApp, const QCString &remObjId,
01544               const QCString &remFun, const QByteArray &data,
01545               QCString& replyType, QByteArray &replyData,
01546                       bool useEventLoop)
01547 {
01548     if (remApp.isEmpty())
01549        return false;
01550     DCOPClient *localClient = findLocalClient( remApp );
01551 
01552     if ( localClient ) {
01553     bool b = localClient->receive(  remApp, remObjId, remFun, data, replyType, replyData );
01554     return b;
01555     }
01556 
01557     return callInternal(remApp, remObjId, remFun, data,
01558                          replyType, replyData, useEventLoop, DCOPCall);
01559 }
01560 
01561 bool DCOPClient::callInternal(const QCString &remApp, const QCString &remObjId,
01562               const QCString &remFun, const QByteArray &data,
01563               QCString& replyType, QByteArray &replyData,
01564                       bool useEventLoop, int minor_opcode)
01565 {
01566     if ( !isAttached() )
01567     return false;
01568 
01569     DCOPMsg *pMsg;
01570 
01571     CARD32 oldCurrentKey = d->currentKey;
01572     if ( !d->currentKey )
01573     d->currentKey = d->key; // no key yet, initiate new call
01574 
01575     QByteArray ba;
01576     QDataStream ds(ba, IO_WriteOnly);
01577     ds << d->appId << remApp << remObjId << normalizeFunctionSignature(remFun) << data.size();
01578 
01579     IceGetHeader(d->iceConn, d->majorOpcode, minor_opcode,
01580          sizeof(DCOPMsg), DCOPMsg, pMsg);
01581 
01582     pMsg->key = d->currentKey;
01583     int datalen = ba.size() + data.size();
01584     pMsg->length += datalen;
01585 
01586     IceSendData(d->iceConn, ba.size(), const_cast<char *>(ba.data()));
01587     IceSendData(d->iceConn, data.size(), const_cast<char *>(data.data()));
01588 
01589 
01590     if (IceConnectionStatus(d->iceConn) != IceConnectAccepted)
01591     return false;
01592 
01593     IceFlush (d->iceConn);
01594 
01595     IceReplyWaitInfo waitInfo;
01596     waitInfo.sequence_of_request = IceLastSentSequenceNumber(d->iceConn);
01597     waitInfo.major_opcode_of_request = d->majorOpcode;
01598     waitInfo.minor_opcode_of_request = minor_opcode;
01599     ReplyStruct replyStruct;
01600     replyStruct.replyType = &replyType;
01601     replyStruct.replyData = &replyData;
01602     waitInfo.reply = static_cast<IcePointer>(&replyStruct);
01603 
01604     Bool readyRet = False;
01605     IceProcessMessagesStatus s;
01606 
01607     do {
01608     if ( useEventLoop && d->notifier ) { // we have a socket notifier and a qApp
01609 
01610         int msecs = 100; // timeout for the GUI refresh
01611         fd_set fds;
01612         struct timeval tv;
01613         FD_ZERO( &fds );
01614         FD_SET( socket(), &fds );
01615         tv.tv_sec = msecs / 1000;
01616         tv.tv_usec = (msecs % 1000) * 1000;
01617         if ( select( socket() + 1, &fds, 0, 0, &tv ) <= 0 ) {
01618         // nothing was available, we got a timeout. Reactivate
01619         // the GUI in blocked state.
01620         bool old_lock = d->non_blocking_call_lock;
01621         if ( !old_lock ) {
01622             d->non_blocking_call_lock = true;
01623             emit blockUserInput( true );
01624         }
01625         qApp->enter_loop();
01626         if ( !old_lock ) {
01627             d->non_blocking_call_lock = false;
01628             emit blockUserInput( false );
01629         }
01630         }
01631     }
01632         if (!d->iceConn)
01633             return false;
01634 
01635     // something is available
01636     s = IceProcessMessages(d->iceConn, &waitInfo,
01637                    &readyRet);
01638     if (s == IceProcessMessagesIOError) {
01639             detach();
01640         d->currentKey = oldCurrentKey;
01641         return false;
01642     }
01643 
01644     } while (!readyRet);
01645 
01646     d->currentKey = oldCurrentKey;
01647     return replyStruct.status == ReplyStruct::Ok;
01648 }
01649 
01650 void DCOPClient::processSocketData(int fd)
01651 {
01652     // Make sure there is data to read!
01653     fd_set fds;
01654     timeval timeout;
01655     timeout.tv_sec = 0;
01656     timeout.tv_usec = 0;
01657     FD_ZERO(&fds);
01658     FD_SET(fd, &fds);
01659     int result = select(fd+1, &fds, 0, 0, &timeout);
01660     if (result == 0)
01661         return;
01662 
01663     if ( d->non_blocking_call_lock ) {
01664     qApp->exit_loop();
01665     return;
01666     }
01667 
01668     if (!d->iceConn) {
01669     d->notifier->deleteLater();
01670     d->notifier = 0;
01671     qWarning("received an error processing data from the DCOP server!");
01672         return;
01673     }
01674 
01675     IceProcessMessagesStatus s =  IceProcessMessages(d->iceConn, 0, 0);
01676 
01677     if (s == IceProcessMessagesIOError) {
01678         detach();
01679     qWarning("received an error processing data from the DCOP server!");
01680     return;
01681     }
01682 }
01683 
01684 void DCOPClient::setDefaultObject( const QCString& objId )
01685 {
01686     d->defaultObject = objId;
01687 }
01688 
01689 
01690 QCString DCOPClient::defaultObject() const
01691 {
01692     return d->defaultObject;
01693 }
01694 
01695 DCOPClientTransaction *
01696 DCOPClient::beginTransaction()
01697 {
01698     if (d->opcode == DCOPSend)
01699        return 0;
01700     if (!d->transactionList)
01701     d->transactionList = new QPtrList<DCOPClientTransaction>;
01702 
01703     d->transaction = true;
01704     DCOPClientTransaction *trans = new DCOPClientTransaction();
01705     trans->senderId = d->senderId;
01706     if (!d->transactionId)  // transactionId should not be 0!
01707     d->transactionId++;
01708     trans->id = ++(d->transactionId);
01709     trans->key = d->currentKey;
01710 
01711     d->transactionList->append( trans );
01712     return trans;
01713 }
01714 
01715 Q_INT32
01716 DCOPClient::transactionId() const
01717 {
01718     if (d->transaction)
01719     return d->transactionId;
01720     else
01721     return 0;
01722 }
01723 
01724 void
01725 DCOPClient::endTransaction( DCOPClientTransaction *trans, QCString& replyType,
01726                 QByteArray &replyData)
01727 {
01728     if ( !trans )
01729         return;
01730 
01731     if ( !isAttached() )
01732     return;
01733 
01734     if ( !d->transactionList) {
01735     qWarning("Transaction unknown: No pending transactions!");
01736     return; // No pending transactions!
01737     }
01738 
01739     if ( !d->transactionList->removeRef( trans ) ) {
01740     qWarning("Transaction unknown: Not on list of pending transactions!");
01741     return; // Transaction
01742     }
01743 
01744     DCOPMsg *pMsg;
01745 
01746     QByteArray ba;
01747     QDataStream ds(ba, IO_WriteOnly);
01748     ds << d->appId << trans->senderId << trans->id << replyType << replyData;
01749 
01750     IceGetHeader(d->iceConn, d->majorOpcode, DCOPReplyDelayed,
01751          sizeof(DCOPMsg), DCOPMsg, pMsg);
01752 
01753     pMsg->key = trans->key;
01754     pMsg->length += ba.size();
01755 
01756     IceSendData( d->iceConn, ba.size(), const_cast<char *>(ba.data()) );
01757 
01758     delete trans;
01759 }
01760 
01761 void
01762 DCOPClient::emitDCOPSignal( const QCString &object, const QCString &signal, const QByteArray &data)
01763 {
01764     // We hack the sending object name into the signal name
01765     send("DCOPServer", "emit", object+"#"+normalizeFunctionSignature(signal), data);
01766 }
01767 
01768 void
01769 DCOPClient::emitDCOPSignal( const QCString &signal, const QByteArray &data)
01770 {
01771     emitDCOPSignal(0, signal, data);
01772 }
01773 
01774 bool
01775 DCOPClient::connectDCOPSignal( const QCString &sender, const QCString &senderObj,
01776   const QCString &signal,
01777   const QCString &receiverObj, const QCString &slot, bool Volatile)
01778 {
01779   QCString replyType;
01780   QByteArray data, replyData;
01781   Q_INT8 iVolatile = Volatile ? 1 : 0;
01782 
01783   QDataStream args(data, IO_WriteOnly );
01784   args << sender << senderObj << normalizeFunctionSignature(signal) << receiverObj << normalizeFunctionSignature(slot) << iVolatile;
01785 
01786   if (!call("DCOPServer", 0,
01787     "connectSignal(QCString,QCString,QCString,QCString,QCString,bool)",
01788     data, replyType, replyData))
01789      return false;
01790 
01791   if (replyType != "bool")
01792      return false;
01793 
01794   QDataStream reply(replyData, IO_ReadOnly );
01795   Q_INT8 result;
01796   reply >> result;
01797   return (result != 0);
01798 }
01799 
01800 bool
01801 DCOPClient::connectDCOPSignal( const QCString &sender, const QCString &signal,
01802   const QCString &receiverObj, const QCString &slot, bool Volatile)
01803 {
01804    return connectDCOPSignal( sender, 0, signal, receiverObj, slot, Volatile);
01805 }
01806 
01807 bool
01808 DCOPClient::disconnectDCOPSignal( const QCString &sender, const QCString &senderObj,
01809   const QCString &signal,
01810   const QCString &receiverObj, const QCString &slot)
01811 {
01812   QCString replyType;
01813   QByteArray data, replyData;
01814 
01815   QDataStream args(data, IO_WriteOnly );
01816   args << sender << senderObj << normalizeFunctionSignature(signal) << receiverObj << normalizeFunctionSignature(slot);
01817 
01818   if (!call("DCOPServer", 0,
01819     "disconnectSignal(QCString,QCString,QCString,QCString,QCString)",
01820     data, replyType, replyData))
01821      return false;
01822 
01823   if (replyType != "bool")
01824      return false;
01825 
01826   QDataStream reply(replyData, IO_ReadOnly );
01827   Q_INT8 result;
01828   reply >> result;
01829   return (result != 0);
01830 }
01831 
01832 bool
01833 DCOPClient::disconnectDCOPSignal( const QCString &sender, const QCString &signal,
01834   const QCString &receiverObj, const QCString &slot)
01835 {
01836   return disconnectDCOPSignal( sender, 0, signal, receiverObj, slot);
01837 }
01838 
01839 void
01840 DCOPClient::emergencyClose()
01841 {
01842     QPtrList<DCOPClient> list;
01843     client_map_t *map = DCOPClient_CliMap;
01844     if (!map) return;
01845     QAsciiDictIterator<DCOPClient> it(*map);
01846     while(it.current()) {
01847        list.removeRef(it.current());
01848        list.append(it.current());
01849        ++it;
01850     }
01851     for(DCOPClient *cl = list.first(); cl; cl = list.next())
01852     {
01853         if (cl->d->iceConn) {
01854             IceProtocolShutdown(cl->d->iceConn, cl->d->majorOpcode);
01855             IceCloseConnection(cl->d->iceConn);
01856             cl->d->iceConn = 0L;
01857         }
01858     }
01859 }
01860 
01861 const char *
01862 DCOPClient::postMortemSender()
01863 {
01864    if (!dcop_main_client)
01865       return "";
01866    return dcop_main_client->d->senderId.data();
01867 }
01868 
01869 const char *
01870 DCOPClient::postMortemObject()
01871 {
01872    if (!dcop_main_client)
01873       return "";
01874    return dcop_main_client->d->objId.data();
01875 }
01876 const char *
01877 DCOPClient::postMortemFunction()
01878 {
01879    if (!dcop_main_client)
01880       return "";
01881    return dcop_main_client->d->function.data();
01882 }
01883 
01884 void DCOPClient::virtual_hook( int, void* )
01885 { /*BASE::virtual_hook( id, data );*/ }
01886 
01887 #include <dcopclient.moc>
01888 
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:14:33 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001