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