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

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.7.1
This website is maintained by Timothy Pearson.