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