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

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
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for dcop by doxygen 1.6.3
This website is maintained by Timothy Pearson.