dcop Library API Documentation

dcopclient.cpp

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