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