dcop Library: dcopclient.cpp Source File (dcop Library)

| # dcop Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# dcopclient.cpp

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

This file is part of the documentation for dcop Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:16:55 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003