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