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