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