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