dcopclient.cpp Source File (dcop Library)

| # dcop Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# 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

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:42:41 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001