• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • dcop
 

dcop

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

dcop

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

dcop

Skip menu "dcop"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for dcop by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |