• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

dcop

dcopclient.cpp

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

dcop

Skip menu "dcop"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal