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 
00027 
00028 #include <config.h>
00029 
00030 #include <sys/types.h>
00031 #ifdef HAVE_SYS_STAT_H
00032 #include <sys/stat.h>
00033 #endif
00034 #ifdef HAVE_SYS_PARAM_H
00035 #include <sys/param.h>
00036 #endif
00037 #include <sys/resource.h>
00038                    
00039 #include <unistd.h>
00040 #include <stdlib.h>
00041 #include <signal.h>
00042 #include <unistd.h>
00043 #include <fcntl.h>
00044 #include <errno.h>
00045 #ifdef HAVE_LIMITS_H
00046 #include <limits.h>
00047 #endif
00048 
00049 #define QT_CLEAN_NAMESPACE 1
00050 #include <qfile.h>
00051 #include <qtextstream.h>
00052 #include <qdatastream.h>
00053 #include <qptrstack.h>
00054 #include <qtimer.h>
00055 
00056 #include <dcopserver.h>
00057 #include <dcopsignals.h>
00058 #include <dcopclient.h>
00059 #include <dcopglobal.h>
00060 #include "dcop-path.h"
00061 
00062 
00063 
00064 DCOPServer* the_server;
00065 
00066 template class QDict<DCOPConnection>;
00067 template class QPtrDict<DCOPConnection>;
00068 template class QPtrList<DCOPListener>;
00069 
00070 #define _DCOPIceSendBegin(x)    \
00071    int fd = IceConnectionNumber( x );       \
00072    long fd_fl = fcntl(fd, F_GETFL, 0);      \
00073    fcntl(fd, F_SETFL, fd_fl | O_NDELAY);
00074 #define _DCOPIceSendEnd()   \
00075    fcntl(fd, F_SETFL, fd_fl);
00076 
00077 static QCString findDcopserverShutdown()
00078 {
00079    QCString path = getenv("PATH");
00080    char *dir = strtok(path.data(), ":");
00081    while (dir)
00082    {
00083       QCString file = dir;
00084       file += "/dcopserver_shutdown";
00085       if (access(file.data(), X_OK) == 0)
00086          return file;
00087       dir = strtok(NULL, ":");
00088    }
00089    QCString file = DCOP_PATH;
00090    file += "/dcopserver_shutdown";
00091    if (access(file.data(), X_OK) == 0)
00092       return file;
00093 
00094    return QCString("dcopserver_shutdown");
00095 }
00096 
00097 static Bool HostBasedAuthProc ( char* )
00098 {
00099     return false; 
00100 }
00101 
00102 extern "C" {
00103 extern IceWriteHandler _kde_IceWriteHandler;
00104 extern IceIOErrorHandler _kde_IceIOErrorHandler;
00105 void DCOPIceWriteChar(register IceConn iceConn, unsigned long nbytes, char *ptr);
00106 }
00107 
00108 static QCString readQCString(QDataStream &ds)
00109 {
00110    QCString result;
00111    Q_UINT32 len;
00112    ds >> len;
00113    QIODevice *device = ds.device();
00114    int bytesLeft = device->size()-device->at();
00115    if ((bytesLeft < 0 ) || (len > (uint) bytesLeft))
00116    {
00117       qWarning("Corrupt data!\n");
00118       return result;
00119    }
00120    result.QByteArray::resize( (uint)len );
00121    if (len > 0)
00122       ds.readRawBytes( result.data(), (uint)len);
00123    return result;
00124 }
00125 
00126 static QByteArray readQByteArray(QDataStream &ds)
00127 {
00128    QByteArray result;
00129    Q_UINT32 len;
00130    ds >> len;
00131    QIODevice *device = ds.device();
00132    int bytesLeft = device->size()-device->at();
00133    if ((bytesLeft < 0 ) || (len > (uint) bytesLeft))
00134    {
00135       qWarning("Corrupt data!\n");
00136       return result;
00137    }
00138    result.resize( (uint)len );
00139    if (len > 0)
00140       ds.readRawBytes( result.data(), (uint)len);
00141    return result;
00142 }
00143 
00144 static unsigned long writeIceData(IceConn iceConn, unsigned long nbytes, char *ptr)
00145 {
00146     int fd = IceConnectionNumber(iceConn);
00147     unsigned long nleft = nbytes;
00148     while (nleft > 0)
00149     {
00150     int nwritten;
00151 
00152     if (iceConn->io_ok)
00153         nwritten = write(fd, ptr, (int) nleft);
00154     else
00155         return 0;
00156 
00157     if (nwritten <= 0)
00158     {
00159             if (errno == EINTR)
00160                continue;
00161 
00162             if (errno == EAGAIN)
00163                return nleft;
00164 
00165         
00166 
00167 
00168 
00169 
00170         iceConn->io_ok = False;
00171 
00172         if (iceConn->connection_status == IceConnectPending)
00173         {
00174         
00175 
00176 
00177 
00178 
00179         return 0;
00180         }
00181 
00182         if (iceConn->process_msg_info)
00183         {
00184         int i;
00185 
00186         for (i = iceConn->his_min_opcode;
00187              i <= iceConn->his_max_opcode; i++)
00188         {
00189             _IceProcessMsgInfo *process;
00190 
00191             process = &iceConn->process_msg_info[
00192             i - iceConn->his_min_opcode];
00193 
00194             if (process->in_use)
00195             {
00196             IceIOErrorProc IOErrProc = process->accept_flag ?
00197                 process->protocol->accept_client->io_error_proc :
00198                 process->protocol->orig_client->io_error_proc;
00199 
00200             if (IOErrProc)
00201                 (*IOErrProc) (iceConn);
00202             }
00203         }
00204         }
00205 
00206         (*_kde_IceIOErrorHandler) (iceConn);
00207         return 0;
00208     }
00209 
00210     nleft -= nwritten;
00211     ptr   += nwritten;
00212     }
00213     return 0;
00214 }
00215 
00216 void DCOPIceWriteChar(register IceConn iceConn, unsigned long nbytes, char *ptr)
00217 {
00218     DCOPConnection* conn = the_server->findConn( iceConn );
00219 #ifdef DCOP_DEBUG
00220 qWarning("DCOPServer: DCOPIceWriteChar() Writing %d bytes to %d [%s]", nbytes, fd, conn ? conn->appId.data() : "<unknown>");
00221 #endif
00222 
00223     if (conn)
00224     {
00225        if (conn->outputBlocked)
00226        {
00227           QByteArray _data(nbytes);
00228           memcpy(_data.data(), ptr, nbytes);
00229 #ifdef DCOP_DEBUG
00230 qWarning("DCOPServer: _IceWrite() outputBlocked. Queuing %d bytes.", _data.size());
00231 #endif
00232           conn->outputBuffer.append(_data);
00233           return;
00234        }
00235        
00236     }
00237 
00238     unsigned long nleft = writeIceData(iceConn, nbytes, ptr);
00239     if ((nleft > 0) && conn)
00240     {
00241         QByteArray _data(nleft);
00242         memcpy(_data.data(), ptr, nleft);
00243         conn->waitForOutputReady(_data, 0);
00244         return;
00245     }
00246 }
00247 
00248 static void DCOPIceWrite(IceConn iceConn, const QByteArray &_data)
00249 {
00250     DCOPConnection* conn = the_server->findConn( iceConn );
00251 #ifdef DCOP_DEBUG
00252 qWarning("DCOPServer: DCOPIceWrite() Writing %d bytes to %d [%s]", _data.size(), fd, conn ? conn->appId.data() : "<unknown>");
00253 #endif
00254     if (conn)
00255     {
00256        if (conn->outputBlocked)
00257        {
00258 #ifdef DCOP_DEBUG
00259 qWarning("DCOPServer: DCOPIceWrite() outputBlocked. Queuing %d bytes.", _data.size());
00260 #endif
00261           conn->outputBuffer.append(_data);
00262           return;
00263        }
00264        
00265     }
00266 
00267     unsigned long nleft = writeIceData(iceConn, _data.size(), _data.data());
00268     if ((nleft > 0) && conn)
00269     {
00270         conn->waitForOutputReady(_data, _data.size() - nleft);
00271         return;
00272     }
00273 }
00274 
00275 void DCOPConnection::waitForOutputReady(const QByteArray &_data, int start)
00276 {
00277 #ifdef DCOP_DEBUG
00278 qWarning("DCOPServer: waitForOutputReady fd = %d datasize = %d start = %d", socket(), _data.size(), start);
00279 #endif
00280    outputBlocked = true;
00281    outputBuffer.append(_data);
00282    outputBufferStart = start;
00283    if (!outputBufferNotifier)
00284    {
00285       outputBufferNotifier = new QSocketNotifier(socket(), Write);
00286       connect(outputBufferNotifier, SIGNAL(activated(int)),
00287               the_server, SLOT(slotOutputReady(int)));
00288    }
00289    outputBufferNotifier->setEnabled(true);
00290    return;
00291 }
00292 
00293 void DCOPServer::slotOutputReady(int socket)
00294 {
00295 #ifdef DCOP_DEBUG
00296 qWarning("DCOPServer: slotOutputReady fd = %d", socket);
00297 #endif
00298    
00299    DCOPConnection *conn = fd_clients.find(socket);
00300    
00301    
00302    
00303    
00304    conn->slotOutputReady();
00305 }
00306 
00307 
00308 void DCOPConnection::slotOutputReady()
00309 {
00310    
00311    
00312 
00313    QByteArray data = outputBuffer.first();
00314 
00315    int fd = socket();
00316 
00317    long fd_fl = fcntl(fd, F_GETFL, 0);
00318    fcntl(fd, F_SETFL, fd_fl | O_NDELAY);
00319    int nwritten = write(fd, data.data()+outputBufferStart, data.size()-outputBufferStart);
00320    int e = errno;
00321    fcntl(fd, F_SETFL, fd_fl);
00322 
00323 #ifdef DCOP_DEBUG
00324 qWarning("DCOPServer: slotOutputReady() %d bytes written", nwritten);
00325 #endif
00326 
00327    if (nwritten < 0)
00328    {
00329       if ((e == EINTR) || (e == EAGAIN))
00330          return;
00331       (*_kde_IceIOErrorHandler) (iceConn);
00332       return;
00333    }
00334    outputBufferStart += nwritten;
00335 
00336    if (outputBufferStart == data.size())
00337    {
00338       outputBufferStart = 0;
00339       outputBuffer.remove(outputBuffer.begin());
00340       if (outputBuffer.isEmpty())
00341       {
00342 #ifdef DCOP_DEBUG
00343 qWarning("DCOPServer: slotOutputRead() all data transmitted.");
00344 #endif
00345          outputBlocked = false;
00346          outputBufferNotifier->setEnabled(false);
00347       }
00348 #ifdef DCOP_DEBUG
00349 else
00350 {
00351 qWarning("DCOPServer: slotOutputRead() more data to send.");
00352 }
00353 #endif
00354    }
00355 }
00356 
00357 static void DCOPIceSendData(register IceConn _iceConn,
00358                             const QByteArray &_data)
00359 {
00360    if (_iceConn->outbufptr > _iceConn->outbuf)
00361    {
00362 #ifdef DCOP_DEBUG
00363 qWarning("DCOPServer: Flushing data, fd = %d", IceConnectionNumber(_iceConn));
00364 #endif
00365       IceFlush( _iceConn );
00366    }
00367    DCOPIceWrite(_iceConn, _data);
00368 }
00369 
00370 class DCOPListener : public QSocketNotifier
00371 {
00372 public:
00373     DCOPListener( IceListenObj obj )
00374     : QSocketNotifier( IceGetListenConnectionNumber( obj ),
00375                QSocketNotifier::Read, 0, 0)
00376 {
00377     listenObj = obj;
00378 }
00379 
00380     IceListenObj listenObj;
00381 };
00382 
00383 DCOPConnection::DCOPConnection( IceConn conn )
00384     : QSocketNotifier( IceConnectionNumber( conn ),
00385                QSocketNotifier::Read, 0, 0 )
00386 {
00387     iceConn = conn;
00388     notifyRegister = 0;
00389     _signalConnectionList = 0;
00390     daemon = false;
00391     outputBlocked = false;
00392     outputBufferNotifier = 0;
00393     outputBufferStart = 0;
00394 }
00395 
00396 DCOPConnection::~DCOPConnection()
00397 {
00398     delete _signalConnectionList;
00399     delete outputBufferNotifier;
00400 }
00401 
00402 DCOPSignalConnectionList *
00403 DCOPConnection::signalConnectionList()
00404 {
00405     if (!_signalConnectionList)
00406        _signalConnectionList = new DCOPSignalConnectionList;
00407     return _signalConnectionList;
00408 }
00409 
00410 static IceAuthDataEntry *authDataEntries;
00411 static char *addAuthFile;
00412 
00413 static IceListenObj *listenObjs;
00414 static int numTransports;
00415 static int ready[2];
00416 
00417 
00418 
00419 static void fprintfhex (FILE *fp, unsigned int len, char *cp)
00420 {
00421     static char hexchars[] = "0123456789abcdef";
00422 
00423     for (; len > 0; len--, cp++) {
00424     unsigned char s = *cp;
00425     putc(hexchars[s >> 4], fp);
00426     putc(hexchars[s & 0x0f], fp);
00427     }
00428 }
00429 
00430 
00431 
00432 
00433 
00434 static void
00435 write_iceauth (FILE *addfp, IceAuthDataEntry *entry)
00436 {
00437     fprintf (addfp,
00438          "add %s \"\" %s %s ",
00439          entry->protocol_name,
00440          entry->network_id,
00441          entry->auth_name);
00442     fprintfhex (addfp, entry->auth_data_length, entry->auth_data);
00443     fprintf (addfp, "\n");
00444 }
00445 
00446 
00447 #ifndef HAVE_MKSTEMP
00448 static char *unique_filename (const char *path, const char *prefix)
00449 #else
00450 static char *unique_filename (const char *path, const char *prefix, int *pFd)
00451 #endif
00452 {
00453 #ifndef HAVE_MKSTEMP
00454 #ifndef X_NOT_POSIX
00455     return ((char *) tempnam (path, prefix));
00456 #else
00457     char tempFile[PATH_MAX];
00458     char *tmp;
00459 
00460     snprintf (tempFile, PATH_MAX, "%s/%sXXXXXX", path, prefix);
00461     tmp = (char *) mktemp (tempFile);
00462     if (tmp)
00463     {
00464         char *ptr = (char *) malloc (strlen (tmp) + 1);
00465         if (ptr != NULL)
00466         {
00467             strcpy (ptr, tmp);
00468         }
00469         return (ptr);
00470     }
00471     else
00472     return (NULL);
00473 #endif
00474 #else
00475     char tempFile[PATH_MAX];
00476     char *ptr;
00477 
00478     snprintf (tempFile, PATH_MAX, "%s/%sXXXXXX", path, prefix);
00479     ptr = static_cast<char *>(malloc(strlen(tempFile) + 1));
00480     if (ptr != NULL)
00481     {
00482         strcpy(ptr, tempFile);
00483         *pFd =  mkstemp(ptr);
00484     }
00485     return ptr;
00486 #endif
00487 }
00488 
00489 #if 0
00490 Status SetAuthentication_local (int count, IceListenObj *listenObjs)
00491 {
00492     int i;
00493     for (i = 0; i < count; i ++) {
00494     char *prot = IceGetListenConnectionString(listenObjs[i]);
00495     if (!prot) continue;
00496     char *host = strchr(prot, '/');
00497     char *sock = 0;
00498     if (host) {
00499         *host=0;
00500         host++;
00501         sock = strchr(host, ':');
00502         if (sock) {
00503         *sock = 0;
00504         sock++;
00505         }
00506     }
00507 #ifndef NDEBUG
00508     qDebug("DCOPServer: SetAProc_loc: conn %d, prot=%s, file=%s",
00509         (unsigned)i, prot, sock);
00510 #endif
00511     if (sock && !strcmp(prot, "local")) {
00512         chmod(sock, 0700);
00513     }
00514     IceSetHostBasedAuthProc (listenObjs[i], HostBasedAuthProc);
00515     free(prot);
00516     }
00517     return 1;
00518 }
00519 #endif
00520 
00521 #define MAGIC_COOKIE_LEN 16
00522 
00523 Status
00524 SetAuthentication (int count, IceListenObj *_listenObjs,
00525            IceAuthDataEntry **_authDataEntries)
00526 {
00527     FILE        *addfp = NULL;
00528     const char  *path;
00529     int         original_umask;
00530     int         i;
00531     QCString command;    
00532 #ifdef HAVE_MKSTEMP
00533     int         fd;
00534 #endif
00535 
00536     original_umask = umask (0077);      
00537 
00538     path = getenv ("DCOP_SAVE_DIR");
00539     if (!path)
00540     path = "/tmp";
00541 #ifndef HAVE_MKSTEMP
00542     if ((addAuthFile = unique_filename (path, "dcop")) == NULL)
00543     goto bad;
00544 
00545     if (!(addfp = fopen (addAuthFile, "w")))
00546     goto bad;
00547 #else
00548     if ((addAuthFile = unique_filename (path, "dcop", &fd)) == NULL)
00549     goto bad;
00550 
00551     if (!(addfp = fdopen(fd, "wb")))
00552     goto bad;
00553 #endif
00554 
00555     if ((*_authDataEntries = static_cast<IceAuthDataEntry *>(malloc (count * 2 * sizeof (IceAuthDataEntry)))) == NULL)
00556     goto bad;
00557 
00558     for (i = 0; i < numTransports * 2; i += 2) {
00559     (*_authDataEntries)[i].network_id =
00560         IceGetListenConnectionString (_listenObjs[i/2]);
00561     (*_authDataEntries)[i].protocol_name = const_cast<char *>("ICE");
00562     (*_authDataEntries)[i].auth_name = const_cast<char *>("MIT-MAGIC-COOKIE-1");
00563 
00564     (*_authDataEntries)[i].auth_data =
00565         IceGenerateMagicCookie (MAGIC_COOKIE_LEN);
00566     (*_authDataEntries)[i].auth_data_length = MAGIC_COOKIE_LEN;
00567 
00568     (*_authDataEntries)[i+1].network_id =
00569         IceGetListenConnectionString (_listenObjs[i/2]);
00570     (*_authDataEntries)[i+1].protocol_name = const_cast<char *>("DCOP");
00571     (*_authDataEntries)[i+1].auth_name = const_cast<char *>("MIT-MAGIC-COOKIE-1");
00572 
00573     (*_authDataEntries)[i+1].auth_data =
00574         IceGenerateMagicCookie (MAGIC_COOKIE_LEN);
00575     (*_authDataEntries)[i+1].auth_data_length = MAGIC_COOKIE_LEN;
00576 
00577     write_iceauth (addfp, &(*_authDataEntries)[i]);
00578     write_iceauth (addfp, &(*_authDataEntries)[i+1]);
00579 
00580     IceSetPaAuthData (2, &(*_authDataEntries)[i]);
00581 
00582     IceSetHostBasedAuthProc (_listenObjs[i/2], HostBasedAuthProc);
00583     }
00584 
00585     fclose (addfp);
00586 
00587     umask (original_umask);
00588 
00589     command = DCOPClient::iceauthPath();
00590     
00591     if (command.isEmpty())
00592     {
00593        fprintf( stderr, "dcopserver: 'iceauth' not found in path, aborting.\n" );
00594        exit(1);
00595     }
00596     
00597     command += " source ";
00598     command += addAuthFile;
00599     system (command);
00600 
00601     unlink(addAuthFile);
00602 
00603     return (1);
00604 
00605  bad:
00606 
00607     if (addfp)
00608     fclose (addfp);
00609 
00610     if (addAuthFile) {
00611     unlink(addAuthFile);
00612     free(addAuthFile);
00613     }
00614 
00615     umask (original_umask);
00616 
00617     return (0);
00618 }
00619 
00620 
00621 
00622 
00623 void
00624 FreeAuthenticationData(int count, IceAuthDataEntry *_authDataEntries)
00625 {
00626     
00627     int i;
00628 
00629     for (i = 0; i < count * 2; i++) {
00630     free (_authDataEntries[i].network_id);
00631     free (_authDataEntries[i].auth_data);
00632     }
00633 
00634     free(_authDataEntries);
00635     free(addAuthFile);
00636 }
00637 
00638 void DCOPWatchProc ( IceConn iceConn, IcePointer client_data, Bool opening, IcePointer* watch_data)
00639 {
00640     DCOPServer* ds = static_cast<DCOPServer*>(client_data);
00641 
00642     if (opening) {
00643     *watch_data = static_cast<IcePointer>(ds->watchConnection( iceConn ));
00644     }
00645     else  {
00646     ds->removeConnection( static_cast<void*>(*watch_data) );
00647     }
00648 }
00649 
00650 void DCOPProcessMessage( IceConn iceConn, IcePointer ,
00651              int opcode, unsigned long length, Bool swap)
00652 {
00653     the_server->processMessage( iceConn, opcode, length, swap );
00654 }
00655 
00656 void DCOPServer::processMessage( IceConn iceConn, int opcode,
00657                  unsigned long length, Bool )
00658 {
00659     DCOPConnection* conn = clients.find( iceConn );
00660     if ( !conn ) {
00661     qWarning("DCOPServer::processMessage message from unknown connection. [opcode = %d]", opcode);
00662     return;
00663     }
00664     switch( opcode ) {
00665     case DCOPSend:
00666     case DCOPReplyDelayed:
00667     {
00668         DCOPMsg *pMsg = 0;
00669         IceReadMessageHeader(iceConn, sizeof(DCOPMsg), DCOPMsg, pMsg);
00670         CARD32 key = pMsg->key;
00671         QByteArray ba( length );
00672         IceReadData(iceConn, length, ba.data() );
00673         QDataStream ds( ba, IO_ReadOnly );
00674         QCString fromApp = readQCString(ds);
00675             QCString toApp = readQCString(ds);
00676 
00677         DCOPConnection* target = findApp( toApp );
00678         int datalen = ba.size();
00679         if ( opcode == DCOPReplyDelayed ) {
00680         if ( !target )
00681             qWarning("DCOPServer::DCOPReplyDelayed for unknown connection.");
00682         else if ( !conn )
00683             qWarning("DCOPServer::DCOPReplyDelayed from unknown connection.");
00684         else if (!conn->waitingForDelayedReply.removeRef( target->iceConn ))
00685             qWarning("DCOPServer::DCOPReplyDelayed from/to does not match. (#2)");
00686                 else if (!target->waitingOnReply.removeRef(iceConn))
00687                        qWarning("DCOPServer::DCOPReplyDelayed for client who wasn't waiting on one!");
00688         }
00689         if ( target ) {
00690 #ifdef DCOP_DEBUG
00691 if (opcode == DCOPSend)
00692 {
00693    QCString obj = readQCString(obj);
00694    QCString fun = readQCString(fun);
00695    qWarning("Sending %d bytes from %s to %s. DCOPSend %s", length, fromApp.data(), toApp.data(), fun.data());
00696 }
00697 #endif
00698         IceGetHeader( target->iceConn, majorOpcode, opcode,
00699                   sizeof(DCOPMsg), DCOPMsg, pMsg );
00700         pMsg->key = key;
00701         pMsg->length += datalen;
00702         _DCOPIceSendBegin( target->iceConn );
00703         DCOPIceSendData(target->iceConn, ba);
00704                 _DCOPIceSendEnd();
00705         } else if ( toApp == "DCOPServer" ) {
00706         QCString obj = readQCString(ds);
00707         QCString fun = readQCString(ds);
00708         QByteArray data = readQByteArray(ds);
00709 
00710         QCString replyType;
00711         QByteArray replyData;
00712         if ( !receive( toApp, obj, fun, data, replyType, replyData, iceConn ) ) {
00713             qWarning("%s failure: object '%s' has no function '%s'", toApp.data(), obj.data(), fun.data() );
00714         }
00715         } else if ( toApp[toApp.length()-1] == '*') {
00716 #ifdef DCOP_DEBUG
00717 if (opcode == DCOPSend)
00718 {
00719    QCString obj = readQCString(obj);
00720    QCString fun = readQCString(fun);
00721    qWarning("Sending %d bytes from %s to %s. DCOPSend %s", length, fromApp.data(), toApp.data(), fun.data());
00722 }
00723 #endif
00724         
00725         QAsciiDictIterator<DCOPConnection> aIt(appIds);
00726         int l = toApp.length()-1;
00727         for ( ; aIt.current(); ++aIt) {
00728             DCOPConnection *client = aIt.current();
00729             if (!l || (strncmp(client->appId.data(), toApp.data(), l) == 0))
00730             {
00731                 IceGetHeader(client->iceConn, majorOpcode, DCOPSend,
00732                      sizeof(DCOPMsg), DCOPMsg, pMsg);
00733                 pMsg->key = key;
00734                 pMsg->length += datalen;
00735                 _DCOPIceSendBegin( client->iceConn );
00736                 DCOPIceSendData(client->iceConn, ba);
00737                             _DCOPIceSendEnd();
00738             }
00739         }
00740         }
00741     }
00742     break;
00743     case DCOPCall:
00744     case DCOPFind:
00745     {
00746         DCOPMsg *pMsg = 0;
00747         IceReadMessageHeader(iceConn, sizeof(DCOPMsg), DCOPMsg, pMsg);
00748         CARD32 key = pMsg->key;
00749         QByteArray ba( length );
00750         IceReadData(iceConn, length, ba.data() );
00751         QDataStream ds( ba, IO_ReadOnly );
00752         QCString fromApp = readQCString(ds);
00753         QCString toApp = readQCString(ds);
00754         DCOPConnection* target = findApp( toApp );
00755         int datalen = ba.size();
00756 
00757         if ( target ) {
00758 #ifdef DCOP_DEBUG
00759 if (opcode == DCOPCall)
00760 {
00761    QCString obj = readQCString(obj);
00762    QCString fun = readQCString(fun);
00763    qWarning("Sending %d bytes from %s to %s. DCOPCall %s", length, fromApp.data(), toApp.data(), fun.data());
00764 }
00765 #endif
00766         target->waitingForReply.append( iceConn );
00767                 conn->waitingOnReply.append( target->iceConn);
00768 
00769         IceGetHeader( target->iceConn, majorOpcode, opcode,
00770                   sizeof(DCOPMsg), DCOPMsg, pMsg );
00771         pMsg->key = key;
00772         pMsg->length += datalen;
00773         _DCOPIceSendBegin( target->iceConn );
00774         DCOPIceSendData(target->iceConn, ba);
00775                 _DCOPIceSendEnd();
00776         } else {
00777         QCString replyType;
00778         QByteArray replyData;
00779         bool b = false;
00780         
00781         if ( (opcode == DCOPCall) && (toApp == "DCOPServer") ) {
00782             QCString obj = readQCString(ds);
00783             QCString fun = readQCString(ds);
00784             QByteArray data = readQByteArray(ds);
00785             b = receive( toApp, obj, fun, data, replyType, replyData, iceConn );
00786             if ( !b )
00787             qWarning("%s failure: object '%s' has no function '%s'", toApp.data(), obj.data(), fun.data() );
00788         }
00789 
00790         if (b) {
00791             QByteArray reply;
00792             QDataStream replyStream( reply, IO_WriteOnly );
00793             replyStream << toApp << fromApp << replyType << replyData.size();
00794             int replylen = reply.size() + replyData.size();
00795             IceGetHeader( iceConn, majorOpcode, DCOPReply,
00796                   sizeof(DCOPMsg), DCOPMsg, pMsg );
00797             if ( key != 0 )
00798             pMsg->key = key;
00799             else
00800             pMsg->key = serverKey++;
00801             pMsg->length += replylen;
00802                     _DCOPIceSendBegin( iceConn );
00803             DCOPIceSendData( iceConn, reply);
00804             DCOPIceSendData( iceConn, replyData);
00805                     _DCOPIceSendEnd();
00806         } else {
00807             QByteArray reply;
00808             QDataStream replyStream( reply, IO_WriteOnly );
00809             replyStream << toApp << fromApp;
00810             IceGetHeader( iceConn, majorOpcode, DCOPReplyFailed,
00811                   sizeof(DCOPMsg), DCOPMsg, pMsg );
00812             if ( key != 0 )
00813             pMsg->key = key;
00814             else
00815             pMsg->key = serverKey++;
00816             pMsg->length += reply.size();
00817                     _DCOPIceSendBegin( iceConn );
00818             DCOPIceSendData( iceConn, reply );
00819                     _DCOPIceSendEnd();
00820         }
00821         }
00822     }
00823     break;
00824     case DCOPReply:
00825     case DCOPReplyFailed:
00826     case DCOPReplyWait:
00827     {
00828         DCOPMsg *pMsg = 0;
00829         IceReadMessageHeader(iceConn, sizeof(DCOPMsg), DCOPMsg, pMsg);
00830         CARD32 key = pMsg->key;
00831         QByteArray ba( length );
00832         IceReadData(iceConn, length, ba.data() );
00833         QDataStream ds( ba, IO_ReadOnly );
00834             QCString fromApp = readQCString(ds);
00835             QCString toApp = readQCString(ds);
00836 
00837         DCOPConnection* connreply = findApp( toApp );
00838         int datalen = ba.size();
00839 
00840         if ( !connreply )
00841         qWarning("DCOPServer::DCOPReply for unknown connection.");
00842         else {
00843         conn->waitingForReply.removeRef( connreply->iceConn );
00844         if ( opcode == DCOPReplyWait )
00845                 {
00846             conn->waitingForDelayedReply.append( connreply->iceConn );
00847                 }
00848                 else
00849                 { 
00850                     if (!connreply->waitingOnReply.removeRef(iceConn))
00851                        qWarning("DCOPServer::DCOPReply for client who wasn't waiting on one!");
00852                 }
00853         IceGetHeader( connreply->iceConn, majorOpcode, opcode,
00854                   sizeof(DCOPMsg), DCOPMsg, pMsg );
00855         pMsg->key = key;
00856         pMsg->length += datalen;
00857                 _DCOPIceSendBegin( connreply->iceConn );
00858         DCOPIceSendData(connreply->iceConn, ba);
00859                 _DCOPIceSendEnd();
00860         }
00861     }
00862     break;
00863     default:
00864     qWarning("DCOPServer::processMessage unknown message");
00865     }
00866 }
00867 
00868 static const IcePaVersionRec DCOPServerVersions[] = {
00869     { DCOPVersionMajor, DCOPVersionMinor,  DCOPProcessMessage }
00870 };
00871 
00872 static const IcePoVersionRec DUMMYVersions[] = {
00873     { DCOPVersionMajor, DCOPVersionMinor, 0 }
00874 };
00875 
00876 typedef struct DCOPServerConnStruct *DCOPServerConn;
00877 
00878 struct DCOPServerConnStruct
00879 {
00880     
00881 
00882 
00883 
00884     IceConn     iceConn;
00885 
00886 
00887     
00888 
00889 
00890 
00891     int         proto_major_version;
00892     int         proto_minor_version;
00893 
00894 
00895     QCString clientId;
00896 };
00897 
00898 
00899 static Status DCOPServerProtocolSetupProc ( IceConn iceConn,
00900                         int majorVersion, int minorVersion,
00901                         char* vendor, char* release,
00902                         IcePointer *clientDataRet,
00903                         char **)
00904 {
00905     DCOPServerConn serverConn;
00906 
00907     
00908 
00909 
00910 
00911     if (vendor)
00912     free (vendor);
00913     if (release)
00914     free (release);
00915 
00916 
00917     
00918 
00919 
00920 
00921     serverConn = new DCOPServerConnStruct;
00922 
00923     serverConn->iceConn = iceConn;
00924     serverConn->proto_major_version = majorVersion;
00925     serverConn->proto_minor_version = minorVersion;
00926     
00927 
00928     *clientDataRet = static_cast<IcePointer>(serverConn);
00929 
00930 
00931     return 1;
00932 }
00933 
00934 
00935 static void sighandler(int sig)
00936 {
00937     if (sig == SIGHUP) {
00938     signal(SIGHUP, sighandler);
00939     return;
00940     }
00941 
00942     qApp->quit();
00943     
00944 }
00945 
00946 DCOPServer::DCOPServer(bool _suicide)
00947     : QObject(0,0), currentClientNumber(0), appIds(263), clients(263)
00948 {
00949     serverKey = 42;
00950 
00951     suicide = _suicide;
00952 
00953     dcopSignals = new DCOPSignals;
00954 
00955     extern int _kde_IceLastMajorOpcode; 
00956     if (_kde_IceLastMajorOpcode < 1 )
00957         IceRegisterForProtocolSetup(const_cast<char *>("DUMMY"),
00958                     const_cast<char *>("DUMMY"),
00959                     const_cast<char *>("DUMMY"),
00960                     1, const_cast<IcePoVersionRec *>(DUMMYVersions),
00961                     DCOPAuthCount, const_cast<char **>(DCOPAuthNames),
00962                     DCOPClientAuthProcs, 0);
00963     if (_kde_IceLastMajorOpcode < 1 )
00964     qWarning("DCOPServer Error: incorrect major opcode!");
00965 
00966     the_server = this;
00967     if (( majorOpcode = IceRegisterForProtocolReply (const_cast<char *>("DCOP"),
00968                              const_cast<char *>(DCOPVendorString),
00969                              const_cast<char *>(DCOPReleaseString),
00970                              1, const_cast<IcePaVersionRec *>(DCOPServerVersions),
00971                              1, const_cast<char **>(DCOPAuthNames),
00972                              DCOPServerAuthProcs,
00973                              HostBasedAuthProc,
00974                              DCOPServerProtocolSetupProc,
00975                              NULL,  
00976 
00977 
00978 
00979                              NULL   
00980                              )) < 0)
00981     {
00982         qWarning("Could not register DCOP protocol with ICE");
00983     }
00984 
00985     char errormsg[256];
00986     int orig_umask = umask(0); 
00987     if (!IceListenForConnections (&numTransports, &listenObjs,
00988                   256, errormsg))
00989     {
00990         fprintf (stderr, "%s\n", errormsg);
00991         exit (1);
00992     } else {
00993         (void) umask(orig_umask);
00994         
00995         QCString fName = DCOPClient::dcopServerFile();
00996         FILE *f;
00997         if(!(f = ::fopen(fName.data(), "w+"))) {
00998             fprintf (stderr, "Can not create file %s: %s\n",
00999              fName.data(), ::strerror(errno));
01000         exit(1);
01001         }
01002         char *idlist = IceComposeNetworkIdList(numTransports, listenObjs);
01003         if (idlist != 0) {
01004             fprintf(f, "%s", idlist);
01005         free(idlist);
01006         }
01007         fprintf(f, "\n%i\n", getpid());
01008         fclose(f);
01009             
01010             QCString compatName = DCOPClient::dcopServerFileOld();
01011             ::symlink(fName,compatName);
01012     }
01013 
01014 #if 0
01015     if (!SetAuthentication_local(numTransports, listenObjs))
01016         qFatal("DCOPSERVER: authentication setup failed.");
01017 #endif
01018     if (!SetAuthentication(numTransports, listenObjs, &authDataEntries))
01019         qFatal("DCOPSERVER: authentication setup failed.");
01020 
01021     IceAddConnectionWatch (DCOPWatchProc, static_cast<IcePointer>(this));
01022     _IceWriteHandler = DCOPIceWriteChar;
01023 
01024     listener.setAutoDelete( true );
01025     DCOPListener* con;
01026     for ( int i = 0; i < numTransports; i++) {
01027     con = new DCOPListener( listenObjs[i] );
01028     listener.append( con );
01029     connect( con, SIGNAL( activated(int) ), this, SLOT( newClient(int) ) );
01030     }
01031     char c = 0;
01032     write(ready[1], &c, 1); 
01033     close(ready[1]);
01034 
01035     m_timer =  new QTimer(this);
01036     connect( m_timer, SIGNAL(timeout()), this, SLOT(slotTerminate()) );
01037     m_deadConnectionTimer = new QTimer(this);
01038     connect( m_deadConnectionTimer, SIGNAL(timeout()), this, SLOT(slotCleanDeadConnections()) );
01039 }
01040 
01041 DCOPServer::~DCOPServer()
01042 {
01043     system(findDcopserverShutdown()+" --nokill");
01044     IceFreeListenObjs(numTransports, listenObjs);
01045     FreeAuthenticationData(numTransports, authDataEntries);
01046     delete dcopSignals;
01047 }
01048 
01049 
01050 DCOPConnection* DCOPServer::findApp( const QCString& appId )
01051 {
01052     if ( appId.isNull() )
01053     return 0;
01054     DCOPConnection* conn = appIds.find( appId );
01055     return conn;
01056 }
01057 
01061 void DCOPServer::slotCleanDeadConnections()
01062 {
01063 qWarning("DCOP Cleaning up dead connections.");
01064     while(!deadConnections.isEmpty())
01065     {
01066        IceConn iceConn = deadConnections.take(0);
01067        IceSetShutdownNegotiation (iceConn, False);
01068        (void) IceCloseConnection( iceConn );
01069     }
01070 }
01071 
01075 void DCOPServer::ioError( IceConn iceConn  )
01076 {
01077     deadConnections.removeRef(iceConn);
01078     deadConnections.prepend(iceConn);
01079     m_deadConnectionTimer->start(0, true);
01080 }
01081 
01082 
01083 void DCOPServer::processData( int  )
01084 {
01085     IceConn iceConn = static_cast<const DCOPConnection*>(sender())->iceConn;
01086     IceProcessMessagesStatus status = IceProcessMessages( iceConn, 0, 0 );
01087     if ( status == IceProcessMessagesIOError ) {
01088         deadConnections.removeRef(iceConn);
01089         if (deadConnections.isEmpty())
01090            m_deadConnectionTimer->stop();
01091     IceSetShutdownNegotiation (iceConn, False);
01092     (void) IceCloseConnection( iceConn );
01093     }
01094 }
01095 
01096 void DCOPServer::newClient( int  )
01097 {
01098     IceAcceptStatus status;
01099     IceConn iceConn = IceAcceptConnection( static_cast<const  DCOPListener*>(sender())->listenObj, &status);
01100     if (!iceConn) {
01101       if (status == IceAcceptBadMalloc)
01102      qWarning("Failed to alloc connection object!\n");
01103       else 
01104          qWarning("Failed to accept ICE connection!\n");
01105       return;
01106     }
01107 
01108     IceSetShutdownNegotiation( iceConn, False );
01109 
01110     IceConnectStatus cstatus;
01111     while ((cstatus = IceConnectionStatus (iceConn))==IceConnectPending) {
01112     (void) IceProcessMessages( iceConn, 0, 0 );
01113     }
01114 
01115     if (cstatus != IceConnectAccepted) {
01116     if (cstatus == IceConnectIOError)
01117         qWarning ("IO error opening ICE Connection!\n");
01118     else
01119         qWarning ("ICE Connection rejected!\n");
01120         deadConnections.removeRef(iceConn);
01121     (void) IceCloseConnection (iceConn);
01122     }
01123 }
01124 
01125 void* DCOPServer::watchConnection( IceConn iceConn )
01126 {
01127     DCOPConnection* con = new DCOPConnection( iceConn );
01128     connect( con, SIGNAL( activated(int) ), this, SLOT( processData(int) ) );
01129 
01130     clients.insert(iceConn, con );
01131     fd_clients.insert( IceConnectionNumber(iceConn), con);
01132 
01133     return static_cast<void*>(con);
01134 }
01135 
01136 void DCOPServer::removeConnection( void* data )
01137 {
01138     DCOPConnection* conn = static_cast<DCOPConnection*>(data);
01139 
01140     dcopSignals->removeConnections(conn);
01141 
01142     clients.remove(conn->iceConn );
01143     fd_clients.remove( IceConnectionNumber(conn->iceConn) );
01144 
01145     
01146     while (!conn->waitingForReply.isEmpty()) {
01147     IceConn iceConn = conn->waitingForReply.take(0);
01148     if (iceConn) {
01149         DCOPConnection* target = clients.find( iceConn );
01150         qWarning("DCOP aborting call from '%s' to '%s'", target ? target->appId.data() : "<unknown>" , conn->appId.data() );
01151         QByteArray reply;
01152         DCOPMsg *pMsg;
01153         IceGetHeader( iceConn, majorOpcode, DCOPReplyFailed,
01154               sizeof(DCOPMsg), DCOPMsg, pMsg );
01155         pMsg->key = 1;
01156         pMsg->length += reply.size();
01157             _DCOPIceSendBegin( iceConn );
01158         DCOPIceSendData(iceConn, reply);
01159             _DCOPIceSendEnd();
01160             if (!target)
01161                qWarning("DCOP Error: unknown target in waitingForReply");
01162             else if (!target->waitingOnReply.removeRef(conn->iceConn))
01163                qWarning("DCOP Error: client in waitingForReply wasn't waiting on reply");
01164     }
01165     }
01166 
01167     
01168     while (!conn->waitingForDelayedReply.isEmpty()) {
01169     IceConn iceConn = conn->waitingForDelayedReply.take(0);
01170     if (iceConn) {
01171         DCOPConnection* target = clients.find( iceConn );
01172         qWarning("DCOP aborting (delayed) call from '%s' to '%s'", target ? target->appId.data() : "<unknown>", conn->appId.data() );
01173         QByteArray reply;
01174         DCOPMsg *pMsg;
01175         IceGetHeader( iceConn, majorOpcode, DCOPReplyFailed,
01176               sizeof(DCOPMsg), DCOPMsg, pMsg );
01177         pMsg->key = 1;
01178         pMsg->length += reply.size();
01179             _DCOPIceSendBegin( iceConn );
01180         DCOPIceSendData( iceConn, reply );
01181             _DCOPIceSendEnd();
01182             if (!target)
01183                qWarning("DCOP Error: unknown target in waitingForDelayedReply");
01184             else if (!target->waitingOnReply.removeRef(conn->iceConn))
01185                qWarning("DCOP Error: client in waitingForDelayedReply wasn't waiting on reply");
01186     }
01187     }
01188     while (!conn->waitingOnReply.isEmpty())
01189     {
01190     IceConn iceConn = conn->waitingOnReply.take(0);
01191         if (iceConn) {
01192            DCOPConnection* target = clients.find( iceConn );
01193            if (!target)
01194            {
01195                qWarning("DCOP Error: still waiting for answer from non-existing client.");
01196                continue;
01197            }
01198            qWarning("DCOP aborting while waiting for answer from '%s'", target->appId.data());
01199            if (!target->waitingForReply.removeRef(conn->iceConn) &&
01200                !target->waitingForDelayedReply.removeRef(conn->iceConn))
01201               qWarning("DCOP Error: called client has forgotten about caller");
01202         }
01203     }
01204 
01205     if ( !conn->appId.isNull() ) {
01206 #ifndef NDEBUG
01207     qDebug("DCOP: unregister '%s'", conn->appId.data() );
01208 #endif
01209         if ( !conn->daemon )
01210         {
01211             currentClientNumber--;
01212         }
01213 
01214     appIds.remove( conn->appId );
01215 
01216         broadcastApplicationRegistration( conn, "applicationRemoved(QCString)", conn->appId );
01217     }
01218 
01219     delete conn;
01220 
01221     if ( suicide && (currentClientNumber == 0) )
01222     {
01223         m_timer->start( 10000 ); 
01224     }
01225 }
01226 
01227 void DCOPServer::slotTerminate()
01228 {
01229 #ifndef NDEBUG
01230     fprintf( stderr, "DCOPServer : slotTerminate() -> sending terminateKDE signal.\n" );
01231 #endif
01232     QByteArray data;
01233     dcopSignals->emitSignal(0L , "terminateKDE()", data, false);
01234     disconnect( m_timer, SIGNAL(timeout()), this, SLOT(slotTerminate()) );
01235     connect( m_timer, SIGNAL(timeout()), this, SLOT(slotSuicide()) );
01236     system(findDcopserverShutdown()+" --nokill");
01237 }
01238 
01239 void DCOPServer::slotSuicide()
01240 {
01241 #ifndef NDEBUG
01242     fprintf( stderr, "DCOPServer : slotSuicide() -> exit.\n" );
01243 #endif
01244     exit(0);
01245 }
01246 
01247 bool DCOPServer::receive(const QCString &, const QCString &obj,
01248              const QCString &fun, const QByteArray& data,
01249              QCString& replyType, QByteArray &replyData,
01250              IceConn iceConn)
01251 {
01252     if ( obj == "emit")
01253     {
01254         DCOPConnection* conn = clients.find( iceConn );
01255         if (conn) {
01256         
01257         dcopSignals->emitSignal(conn, fun, data, false);
01258         }
01259         replyType = "void";
01260         return true;
01261     }
01262     if ( fun == "setDaemonMode(bool)" ) {
01263         QDataStream args( data, IO_ReadOnly );
01264         if ( !args.atEnd() ) {
01265             Q_INT8 iDaemon;
01266             bool daemon;
01267             args >> iDaemon;
01268 
01269             daemon = static_cast<bool>( iDaemon );
01270 
01271         DCOPConnection* conn = clients.find( iceConn );
01272             if ( conn && !conn->appId.isNull() ) {
01273                 if ( daemon ) {
01274                     if ( !conn->daemon )
01275                     {
01276                         conn->daemon = true;
01277 
01278 #ifndef NDEBUG
01279                         qDebug( "DCOP: new daemon %s", conn->appId.data() );
01280 #endif
01281 
01282                         currentClientNumber--;
01283 
01284 
01285 
01286 
01287                     }
01288                 } else
01289                 {
01290                     if ( conn->daemon ) {
01291                         conn->daemon = false;
01292 
01293                         currentClientNumber++;
01294 
01295                         m_timer->stop();
01296                     }
01297                 }
01298             }
01299 
01300             replyType = "void";
01301             return true;
01302         }
01303     }
01304     if ( fun == "registerAs(QCString)" ) {
01305     QDataStream args( data, IO_ReadOnly );
01306     if (!args.atEnd()) {
01307         QCString app2 = readQCString(args);
01308         QDataStream reply( replyData, IO_WriteOnly );
01309         DCOPConnection* conn = clients.find( iceConn );
01310         if ( conn && !app2.isEmpty() ) {
01311         if ( !conn->appId.isNull() &&
01312              appIds.find( conn->appId ) == conn ) {
01313             appIds.remove( conn->appId );
01314 
01315         }
01316 
01317                 QCString oldAppId;
01318         if ( conn->appId.isNull() )
01319                 {
01320                     currentClientNumber++;
01321                     m_timer->stop(); 
01322 #ifndef NDEBUG
01323                     qDebug("DCOP: register '%s' -> number of clients is now %d", app2.data(), currentClientNumber );
01324 #endif
01325                 }
01326 #ifndef NDEBUG
01327         else
01328                 {
01329                     oldAppId = conn->appId;
01330             qDebug("DCOP:  '%s' now known as '%s'", conn->appId.data(), app2.data() );
01331                 }
01332 #endif
01333 
01334         conn->appId = app2;
01335         if ( appIds.find( app2 ) != 0 ) {
01336             
01337             int n = 1;
01338             QCString tmp;
01339             do {
01340             n++;
01341             tmp.setNum( n );
01342             tmp.prepend("-");
01343             tmp.prepend( app2 );
01344             } while ( appIds.find( tmp ) != 0 );
01345             conn->appId = tmp;
01346         }
01347         appIds.insert( conn->appId, conn );
01348 
01349         int c = conn->appId.find( '-' );
01350         if ( c > 0 )
01351             conn->plainAppId = conn->appId.left( c );
01352         else
01353             conn->plainAppId = conn->appId;
01354 
01355                 if( !oldAppId.isEmpty())
01356                     broadcastApplicationRegistration( conn,
01357                         "applicationRemoved(QCString)", oldAppId );
01358                 broadcastApplicationRegistration( conn, "applicationRegistered(QCString)", conn->appId );
01359         }
01360         replyType = "QCString";
01361         reply << conn->appId;
01362         return true;
01363     }
01364     }
01365     else if ( fun == "registeredApplications()" ) {
01366     QDataStream reply( replyData, IO_WriteOnly );
01367     QCStringList applications;
01368     QAsciiDictIterator<DCOPConnection> it( appIds );
01369     while ( it.current() ) {
01370         applications << it.currentKey();
01371         ++it;
01372     }
01373     replyType = "QCStringList";
01374     reply << applications;
01375     return true;
01376     } else if ( fun == "isApplicationRegistered(QCString)" ) {
01377     QDataStream args( data, IO_ReadOnly );
01378     if (!args.atEnd()) {
01379         QCString s = readQCString(args);
01380         QDataStream reply( replyData, IO_WriteOnly );
01381         int b = ( findApp( s ) != 0 );
01382         replyType = "bool";
01383         reply << b;
01384         return true;
01385     }
01386     } else if ( fun == "setNotifications(bool)" ) {
01387     QDataStream args( data, IO_ReadOnly );
01388     if (!args.atEnd()) {
01389         Q_INT8 notifyActive;
01390         args >> notifyActive;
01391         DCOPConnection* conn = clients.find( iceConn );
01392         if ( conn ) {
01393         if ( notifyActive )
01394             conn->notifyRegister++;
01395         else if ( conn->notifyRegister > 0 )
01396             conn->notifyRegister--;
01397         }
01398         replyType = "void";
01399         return true;
01400     }
01401     } else if ( fun == "connectSignal(QCString,QCString,QCString,QCString,QCString,bool)") {
01402         DCOPConnection* conn = clients.find( iceConn );
01403         if (!conn) return false;
01404         QDataStream args(data, IO_ReadOnly );
01405         if (args.atEnd()) return false;
01406         QCString sender = readQCString(args);
01407         QCString senderObj = readQCString(args);
01408         QCString signal = readQCString(args);
01409         QCString receiverObj = readQCString(args);
01410         QCString slot = readQCString(args);
01411         Q_INT8 Volatile;
01412         args >> Volatile;
01413         
01414         bool b = dcopSignals->connectSignal(sender, senderObj, signal, conn, receiverObj, slot, (Volatile != 0));
01415         replyType = "bool";
01416         QDataStream reply( replyData, IO_WriteOnly );
01417         reply << (Q_INT8) (b?1:0);
01418         return true;
01419     } else if ( fun == "disconnectSignal(QCString,QCString,QCString,QCString,QCString)") {
01420         DCOPConnection* conn = clients.find( iceConn );
01421         if (!conn) return false;
01422         QDataStream args(data, IO_ReadOnly );
01423         if (args.atEnd()) return false;
01424         QCString sender = readQCString(args);
01425         QCString senderObj = readQCString(args);
01426         QCString signal = readQCString(args);
01427         QCString receiverObj = readQCString(args);
01428         QCString slot = readQCString(args);
01429         
01430         bool b = dcopSignals->disconnectSignal(sender, senderObj, signal, conn, receiverObj, slot);
01431         replyType = "bool";
01432         QDataStream reply( replyData, IO_WriteOnly );
01433         reply << (Q_INT8) (b?1:0);
01434         return true;
01435     }
01436 
01437     return false;
01438 }
01439 
01440 void DCOPServer::broadcastApplicationRegistration( DCOPConnection* conn, const QCString type,
01441     const QString&  )
01442 {
01443     QByteArray data;
01444     QDataStream datas( data, IO_WriteOnly );
01445     datas << conn->appId;
01446     QPtrDictIterator<DCOPConnection> it( clients );
01447     QByteArray ba;
01448     QDataStream ds( ba, IO_WriteOnly );
01449     ds <<QCString("DCOPServer") <<  QCString("") << QCString("")
01450        << type << data;
01451     int datalen = ba.size();
01452     DCOPMsg *pMsg = 0;
01453     while ( it.current() ) {
01454         DCOPConnection* c = it.current();
01455         ++it;
01456         if ( c->notifyRegister && (c != conn) ) {
01457             IceGetHeader( c->iceConn, majorOpcode, DCOPSend,
01458           sizeof(DCOPMsg), DCOPMsg, pMsg );
01459             pMsg->key = 1;
01460         pMsg->length += datalen;
01461             _DCOPIceSendBegin(c->iceConn);
01462         DCOPIceSendData( c->iceConn, ba );
01463             _DCOPIceSendEnd();
01464         }
01465     }
01466 }
01467 
01468 void
01469 DCOPServer::sendMessage(DCOPConnection *conn, const QCString &sApp,
01470                         const QCString &rApp, const QCString &rObj,
01471                         const QCString &rFun,  const QByteArray &data)
01472 {
01473    QByteArray ba;
01474    QDataStream ds( ba, IO_WriteOnly );
01475    ds << sApp << rApp << rObj << rFun << data;
01476    int datalen = ba.size();
01477    DCOPMsg *pMsg = 0;
01478 
01479    IceGetHeader( conn->iceConn, majorOpcode, DCOPSend,
01480                  sizeof(DCOPMsg), DCOPMsg, pMsg );
01481    pMsg->length += datalen;
01482    pMsg->key = 1; 
01483    _DCOPIceSendBegin( conn->iceConn );
01484    DCOPIceSendData(conn->iceConn, ba);
01485    _DCOPIceSendEnd();
01486 }
01487 
01488 void IoErrorHandler ( IceConn iceConn)
01489 {
01490     the_server->ioError( iceConn );
01491 }
01492 
01493 static bool isRunning(const QCString &fName, bool printNetworkId = false)
01494 {
01495     if (::access(fName.data(), R_OK) == 0) {
01496     QFile f(fName);
01497     f.open(IO_ReadOnly);
01498     int size = QMIN( 1024, f.size() ); 
01499     QCString contents( size+1 );
01500     bool ok = f.readBlock( contents.data(), size ) == size;
01501     contents[size] = '\0';
01502     int pos = contents.find('\n');
01503     ok = ok && ( pos != -1 );
01504     pid_t pid = ok ? contents.mid(pos+1).toUInt(&ok) : 0;
01505     f.close();
01506     if (ok && pid && (kill(pid, SIGHUP) == 0)) {
01507         if (printNetworkId)
01508             qWarning("%s", contents.left(pos).data());
01509         else
01510         qWarning( "---------------------------------\n"
01511               "It looks like dcopserver is already running. If you are sure\n"
01512               "that it is not already running, remove %s\n"
01513               "and start dcopserver again.\n"
01514               "---------------------------------\n",
01515               fName.data() );
01516 
01517         
01518         return true;
01519     } else {
01520         
01521         
01522         unlink(fName.data());
01523     }
01524     } else if (errno != ENOENT) {
01525         
01526         unlink(fName.data());
01527     }
01528     return false;
01529 }
01530 
01531 const char* const ABOUT =
01532 "Usage: dcopserver [--nofork] [--nosid] [--help]\n"
01533 "       dcopserver --serverid\n"
01534 "\n"
01535 "DCOP is KDE's Desktop Communications Protocol. It is a lightweight IPC/RPC\n"
01536 "mechanism built on top of the X Consortium's Inter Client Exchange protocol.\n"
01537 "It enables desktop applications to communicate reliably with low overhead.\n"
01538 "\n"
01539 "Copyright (C) 1999-2001, The KDE Developers <http://www.kde.org>\n"
01540 ;
01541 
01542 extern "C" int kdemain( int argc, char* argv[] )
01543 {
01544     bool serverid = false;
01545     bool nofork = false;
01546     bool nosid = false;
01547     bool suicide = false;
01548     for(int i = 1; i < argc; i++) {
01549     if (strcmp(argv[i], "--nofork") == 0)
01550         nofork = true;
01551     else if (strcmp(argv[i], "--nosid") == 0)
01552         nosid = true;
01553     else if (strcmp(argv[i], "--nolocal") == 0)
01554         ; 
01555     else if (strcmp(argv[i], "--suicide") == 0)
01556         suicide = true;
01557     else if (strcmp(argv[i], "--serverid") == 0)
01558         serverid = true;
01559     else {
01560         fprintf(stdout, ABOUT );
01561         return 0;
01562     }
01563     }
01564 
01565     if (serverid)
01566     {
01567        if (isRunning(DCOPClient::dcopServerFile(), true))
01568           return 0;
01569        return 1;
01570     }
01571 
01572     
01573     if (isRunning(DCOPClient::dcopServerFile()))
01574        return 0;
01575     if (isRunning(DCOPClient::dcopServerFileOld()))
01576     {
01577        
01578        QCString oldFile = DCOPClient::dcopServerFileOld();
01579        QCString newFile = DCOPClient::dcopServerFile();
01580        symlink(oldFile.data(), newFile.data());
01581        return 0;
01582     }
01583 
01584     struct rlimit limits; 
01585      
01586     int retcode = getrlimit(RLIMIT_NOFILE, &limits); 
01587     if (!retcode) { 
01588        if (limits.rlim_max > 512 && limits.rlim_cur < 512)
01589        {
01590           int cur_limit = limits.rlim_cur;
01591           limits.rlim_cur = 512; 
01592           retcode = setrlimit(RLIMIT_NOFILE, &limits); 
01593 
01594           if (retcode != 0)
01595           {
01596              qWarning("dcopserver: Could not raise limit on number of open files.");
01597              qWarning("dcopserver: Current limit = %d", cur_limit);
01598           }
01599        }
01600     }
01601 
01602     pipe(ready);
01603 
01604     if (!nofork) {
01605         pid_t pid = fork();
01606     if (pid > 0) {
01607         char c = 1;
01608         close(ready[1]);
01609         read(ready[0], &c, 1); 
01610         close(ready[0]);
01611         
01612         if (c == 0)
01613             {
01614                
01615                DCOPClient client;
01616                if (client.attach())
01617                   return 0;
01618             }
01619             qWarning("DCOPServer self-test failed.");
01620             system(findDcopserverShutdown()+" --kill");
01621             return 1;
01622     }
01623     close(ready[0]);
01624 
01625     if (!nosid)
01626         setsid();
01627 
01628     if (fork() > 0)
01629         return 0; 
01630     }
01631 
01632     signal(SIGHUP, sighandler);
01633     signal(SIGTERM, sighandler);
01634     signal(SIGPIPE, SIG_IGN);
01635 
01636     putenv(strdup("SESSION_MANAGER="));
01637 
01638     QApplication a( argc, argv, false );
01639 
01640     IceSetIOErrorHandler (IoErrorHandler );
01641     DCOPServer *server = new DCOPServer(suicide); 
01642 
01643     int ret = a.exec();
01644     delete server;
01645     return ret;
01646 }
01647 
01648 #include "dcopserver.moc"