• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdeio/tdeio
 

tdeio/tdeio

slavebase.cpp
00001 /*
00002  *
00003  *  This file is part of the KDE libraries
00004  *  Copyright (c) 2000 Waldo Bastian <bastian@kde.org>
00005  *  Copyright (c) 2000 David Faure <faure@kde.org>
00006  *  Copyright (c) 2000 Stephan Kulow <coolo@kde.org>
00007  *
00008  *  $Id$
00009  *
00010  *  This library is free software; you can redistribute it and/or
00011  *  modify it under the terms of the GNU Library General Public
00012  *  License version 2 as published by the Free Software Foundation.
00013  *
00014  *  This library is distributed in the hope that it will be useful,
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  *  Library General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU Library General Public License
00020  *  along with this library; see the file COPYING.LIB.  If not, write to
00021  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00022  *  Boston, MA 02110-1301, USA.
00023  *
00024  **/
00025 
00026 #include "slavebase.h"
00027 
00028 #include <config.h>
00029 
00030 #include <sys/time.h>
00031 #ifdef HAVE_SYS_SELECT_H
00032 #include <sys/select.h>     // Needed on some systems.
00033 #endif
00034 
00035 #include <assert.h>
00036 #include <kdebug.h>
00037 #include <stdlib.h>
00038 #include <errno.h>
00039 #include <unistd.h>
00040 #include <signal.h>
00041 #include <time.h>
00042 
00043 #include <tqfile.h>
00044 
00045 #include <dcopclient.h>
00046 
00047 #include <tdeapplication.h>
00048 #include <ksock.h>
00049 #include <kcrash.h>
00050 #include <tdesu/client.h>
00051 #include <tdelocale.h>
00052 #include <ksocks.h>
00053 
00054 #include "kremoteencoding.h"
00055 
00056 #include "tdeio/slavebase.h"
00057 #include "tdeio/connection.h"
00058 #include "tdeio/ioslave_defaults.h"
00059 #include "tdeio/slaveinterface.h"
00060 
00061 #include "uiserver_stub.h"
00062 
00063 using namespace TDEIO;
00064 
00065 template class TQPtrList<TQValueList<UDSAtom> >;
00066 typedef TQValueList<TQCString> AuthKeysList;
00067 typedef TQMap<TQString,TQCString> AuthKeysMap;
00068 #define TDEIO_DATA TQByteArray data; TQDataStream stream( data, IO_WriteOnly ); stream
00069 #define TDEIO_FILESIZE_T(x) (unsigned long)(x & 0xffffffff) << (unsigned long)(x >> 32)
00070 
00071 namespace TDEIO {
00072 
00073 class SlaveBaseConfig : public TDEConfigBase
00074 {
00075 public:
00076    SlaveBaseConfig(SlaveBase *_slave)
00077     : slave(_slave) { }
00078 
00079    bool internalHasGroup(const TQCString &) const { tqWarning("hasGroup(const TQCString &)");
00080 return false; }
00081 
00082    TQStringList groupList() const { return TQStringList(); }
00083 
00084    TQMap<TQString,TQString> entryMap(const TQString &group) const
00085       { Q_UNUSED(group); return TQMap<TQString,TQString>(); }
00086 
00087    void reparseConfiguration() { }
00088 
00089    KEntryMap internalEntryMap( const TQString &pGroup) const { Q_UNUSED(pGroup); return KEntryMap(); }
00090 
00091    KEntryMap internalEntryMap() const { return KEntryMap(); }
00092 
00093    void putData(const KEntryKey &_key, const KEntry&_data, bool _checkGroup) 
00094    { Q_UNUSED(_key); Q_UNUSED(_data); Q_UNUSED(_checkGroup); }
00095 
00096    KEntry lookupData(const KEntryKey &_key) const
00097    {
00098      KEntry entry;
00099      TQString value = slave->metaData(_key.c_key);
00100      if (!value.isNull())
00101         entry.mValue = value.utf8();
00102      return entry;
00103    }
00104 protected:
00105    SlaveBase *slave;
00106 };
00107 
00108 
00109 class SlaveBasePrivate {
00110 public:
00111     TQString slaveid;
00112     bool resume:1;
00113     bool needSendCanResume:1;
00114     bool onHold:1;
00115     bool wasKilled:1;
00116     MetaData configData;
00117     SlaveBaseConfig *config;
00118     KURL onHoldUrl;
00119 
00120     struct timeval last_tv;
00121     TDEIO::filesize_t totalSize;
00122     TDEIO::filesize_t sentListEntries;
00123     DCOPClient *dcopClient;
00124     KRemoteEncoding *remotefile;
00125     time_t timeout;
00126     TQByteArray timeoutData;
00127 };
00128 
00129 }
00130 
00131 static SlaveBase *globalSlave;
00132 long SlaveBase::s_seqNr;
00133 
00134 static volatile bool slaveWriteError = false;
00135 
00136 static const char *s_protocol;
00137 
00138 #ifdef Q_OS_UNIX
00139 static void genericsig_handler(int sigNumber)
00140 {
00141    signal(sigNumber,SIG_IGN);
00142    //WABA: Don't do anything that requires malloc, we can deadlock on it since
00143    //a SIGTERM signal can come in while we are in malloc/free.
00144    //kdDebug()<<"tdeioslave : exiting due to signal "<<sigNumber<<endl;
00145    //set the flag which will be checked in dispatchLoop() and which *should* be checked
00146    //in lengthy operations in the various slaves
00147    if (globalSlave!=0)
00148       globalSlave->setKillFlag();
00149    signal(SIGALRM,SIG_DFL);
00150    alarm(5);  //generate an alarm signal in 5 seconds, in this time the slave has to exit
00151 }
00152 #endif
00153 
00155 
00156 SlaveBase::SlaveBase( const TQCString &protocol,
00157                       const TQCString &pool_socket,
00158                       const TQCString &app_socket )
00159     : mProtocol(protocol), m_pConnection(0),
00160       mPoolSocket( TQFile::decodeName(pool_socket)),
00161       mAppSocket( TQFile::decodeName(app_socket))
00162 {
00163     s_protocol = protocol.data();
00164 #ifdef Q_OS_UNIX
00165     if (!getenv("TDE_DEBUG"))
00166     {
00167         TDECrash::setCrashHandler( sigsegv_handler );
00168         signal(SIGILL,&sigsegv_handler);
00169         signal(SIGTRAP,&sigsegv_handler);
00170         signal(SIGABRT,&sigsegv_handler);
00171         signal(SIGBUS,&sigsegv_handler);
00172         signal(SIGALRM,&sigsegv_handler);
00173         signal(SIGFPE,&sigsegv_handler);
00174 #ifdef SIGPOLL
00175         signal(SIGPOLL, &sigsegv_handler);
00176 #endif
00177 #ifdef SIGSYS
00178         signal(SIGSYS, &sigsegv_handler);
00179 #endif
00180 #ifdef SIGVTALRM
00181         signal(SIGVTALRM, &sigsegv_handler);
00182 #endif
00183 #ifdef SIGXCPU
00184         signal(SIGXCPU, &sigsegv_handler);
00185 #endif
00186 #ifdef SIGXFSZ
00187         signal(SIGXFSZ, &sigsegv_handler);
00188 #endif
00189     }
00190 
00191     struct sigaction act;
00192     act.sa_handler = sigpipe_handler;
00193     sigemptyset( &act.sa_mask );
00194     act.sa_flags = 0;
00195     sigaction( SIGPIPE, &act, 0 );
00196 
00197     signal(SIGINT,&genericsig_handler);
00198     signal(SIGQUIT,&genericsig_handler);
00199     signal(SIGTERM,&genericsig_handler);
00200 #endif
00201 
00202     globalSlave=this;
00203 
00204     appconn = new Connection();
00205     listEntryCurrentSize = 100;
00206     struct timeval tp;
00207     gettimeofday(&tp, 0);
00208     listEntry_sec = tp.tv_sec;
00209     listEntry_usec = tp.tv_usec;
00210     mConnectedToApp = true;
00211 
00212     d = new SlaveBasePrivate;
00213     // by kahl for netmgr (need a way to identify slaves)
00214     d->slaveid = protocol;
00215     d->slaveid += TQString::number(getpid());
00216     d->resume = false;
00217     d->needSendCanResume = false;
00218     d->config = new SlaveBaseConfig(this);
00219     d->onHold = false;
00220     d->wasKilled=false;
00221     d->last_tv.tv_sec = 0;
00222     d->last_tv.tv_usec = 0;
00223 //    d->processed_size = 0;
00224     d->totalSize=0;
00225     d->sentListEntries=0;
00226     d->timeout = 0;
00227     connectSlave(mAppSocket);
00228 
00229     d->dcopClient = 0;
00230     d->remotefile = 0;
00231 }
00232 
00233 SlaveBase::~SlaveBase()
00234 {
00235     delete d;
00236     s_protocol = "";
00237 }
00238 
00239 DCOPClient *SlaveBase::dcopClient()
00240 {
00241     if (!d->dcopClient)
00242     {
00243        d->dcopClient = TDEApplication::dcopClient();
00244        if (!d->dcopClient->isAttached())
00245           d->dcopClient->attach();
00246        d->dcopClient->setDaemonMode( true );
00247     }
00248     return d->dcopClient;
00249 }
00250 
00251 void SlaveBase::dispatchLoop()
00252 {
00253 #ifdef Q_OS_UNIX //TODO: WIN32
00254     fd_set rfds;
00255     int retval;
00256 
00257     while (true)
00258     {
00259        if (d->timeout && (d->timeout < time(0)))
00260        {
00261           TQByteArray data = d->timeoutData;
00262           d->timeout = 0;
00263           d->timeoutData = TQByteArray();
00264           special(data);
00265        }
00266        FD_ZERO(&rfds);
00267 
00268        assert(appconn->inited());
00269        int maxfd = appconn->fd_from();
00270        FD_SET(appconn->fd_from(), &rfds);
00271        if( d->dcopClient )
00272        {
00273            FD_SET( d->dcopClient->socket(), &rfds );
00274            if( d->dcopClient->socket() > maxfd )
00275                maxfd = d->dcopClient->socket();
00276        }
00277 
00278        if (!d->timeout) // we can wait forever
00279        {
00280           retval = select( maxfd + 1, &rfds, NULL, NULL, NULL);
00281        }
00282        else
00283        {
00284           struct timeval tv;
00285           tv.tv_sec = kMax(d->timeout-time(0),(time_t) 1);
00286           tv.tv_usec = 0;
00287           retval = select( maxfd + 1, &rfds, NULL, NULL, &tv);
00288        }
00289        if ((retval>0) && FD_ISSET(appconn->fd_from(), &rfds))
00290        { // dispatch application messages
00291           int cmd;
00292           TQByteArray data;
00293           if ( appconn->read(&cmd, data) != -1 )
00294           {
00295              dispatch(cmd, data);
00296           }
00297           else // some error occurred, perhaps no more application
00298           {
00299              // When the app exits, should the slave be put back in the pool ?
00300              if (mConnectedToApp && !mPoolSocket.isEmpty())
00301              {
00302                 disconnectSlave();
00303                 mConnectedToApp = false;
00304                 closeConnection();
00305                 connectSlave(mPoolSocket);
00306              }
00307              else
00308              {
00309                 return;
00310              }
00311           }
00312        }
00313        if( retval > 0 && d->dcopClient && FD_ISSET( d->dcopClient->socket(), &rfds ))
00314        {
00315            d->dcopClient->processSocketData( d->dcopClient->socket());
00316        }
00317        if ((retval<0) && (errno != EINTR))
00318        {
00319           kdDebug(7019) << "dispatchLoop(): select returned " << retval << " "
00320             << (errno==EBADF?"EBADF":errno==EINTR?"EINTR":errno==EINVAL?"EINVAL":errno==ENOMEM?"ENOMEM":"unknown")
00321             << " (" << errno << ")" << endl;
00322           return;
00323        }
00324        //I think we get here when we were killed in dispatch() and not in select()
00325        if (wasKilled())
00326        {
00327           kdDebug(7019)<<" dispatchLoop() slave was killed, returning"<<endl;
00328           return;
00329        }
00330     }
00331 #else
00332 #error The TDEIO slave system only works under UNIX
00333 #endif
00334 }
00335 
00336 void SlaveBase::connectSlave(const TQString& path)
00337 {
00338 #ifdef Q_OS_UNIX //TODO: TDESocket not yet available on WIN32
00339     appconn->init(new TDESocket(TQFile::encodeName(path).data()));
00340     if (!appconn->inited())
00341     {
00342         kdDebug(7019) << "SlaveBase: failed to connect to " << path << endl;
00343         exit();
00344     }
00345 
00346     setConnection(appconn);
00347 #endif
00348 }
00349 
00350 void SlaveBase::disconnectSlave()
00351 {
00352     appconn->close();
00353 }
00354 
00355 void SlaveBase::setMetaData(const TQString &key, const TQString &value)
00356 {
00357    mOutgoingMetaData.replace(key, value);
00358 }
00359 
00360 TQString SlaveBase::metaData(const TQString &key) const
00361 {
00362    if (mIncomingMetaData.contains(key))
00363       return mIncomingMetaData[key];
00364    if (d->configData.contains(key))
00365       return d->configData[key];
00366    return TQString::null;
00367 }
00368 
00369 bool SlaveBase::hasMetaData(const TQString &key) const
00370 {
00371    if (mIncomingMetaData.contains(key))
00372       return true;
00373    if (d->configData.contains(key))
00374       return true;
00375    return false;
00376 }
00377 
00378 // ### remove the next two methods for KDE4 (they miss the const)
00379 TQString SlaveBase::metaData(const TQString &key) {
00380    return const_cast<const SlaveBase*>(this)->metaData( key );
00381 }
00382 bool SlaveBase::hasMetaData(const TQString &key) {
00383    return const_cast<const SlaveBase*>(this)->hasMetaData( key );
00384 }
00385 
00386 TDEConfigBase *SlaveBase::config()
00387 {
00388    return d->config;
00389 }
00390 
00391 void SlaveBase::sendMetaData()
00392 {
00393    TDEIO_DATA << mOutgoingMetaData;
00394 
00395    slaveWriteError = false;
00396    m_pConnection->send( INF_META_DATA, data );
00397    if (slaveWriteError) exit();
00398    mOutgoingMetaData.clear(); // Clear
00399 }
00400 
00401 KRemoteEncoding *SlaveBase::remoteEncoding()
00402 {
00403    if (d->remotefile != 0)
00404       return d->remotefile;
00405 
00406    return d->remotefile = new KRemoteEncoding(metaData("Charset").latin1());
00407 }
00408 
00409 void SlaveBase::data( const TQByteArray &data )
00410 {
00411    if (!mOutgoingMetaData.isEmpty())
00412       sendMetaData();
00413    slaveWriteError = false;
00414    m_pConnection->send( MSG_DATA, data );
00415    if (slaveWriteError) exit();
00416 }
00417 
00418 void SlaveBase::dataReq( )
00419 {
00420 /*
00421    if (!mOutgoingMetaData.isEmpty())
00422       sendMetaData();
00423 */
00424    if (d->needSendCanResume)
00425       canResume(0);
00426    m_pConnection->send( MSG_DATA_REQ );
00427 }
00428 
00429 void SlaveBase::error( int _errid, const TQString &_text )
00430 {
00431     mIncomingMetaData.clear(); // Clear meta data
00432     mOutgoingMetaData.clear();
00433     TDEIO_DATA << (TQ_INT32) _errid << _text;
00434 
00435     m_pConnection->send( MSG_ERROR, data );
00436     //reset
00437     listEntryCurrentSize = 100;
00438     d->sentListEntries=0;
00439     d->totalSize=0;
00440 }
00441 
00442 void SlaveBase::connected()
00443 {
00444     slaveWriteError = false;
00445     m_pConnection->send( MSG_CONNECTED );
00446     if (slaveWriteError) exit();
00447 }
00448 
00449 void SlaveBase::finished()
00450 {
00451     mIncomingMetaData.clear(); // Clear meta data
00452     if (!mOutgoingMetaData.isEmpty())
00453        sendMetaData();
00454     m_pConnection->send( MSG_FINISHED );
00455 
00456     // reset
00457     listEntryCurrentSize = 100;
00458     d->sentListEntries=0;
00459     d->totalSize=0;
00460 }
00461 
00462 void SlaveBase::needSubURLData()
00463 {
00464     m_pConnection->send( MSG_NEED_SUBURL_DATA );
00465 }
00466 
00467 void SlaveBase::slaveStatus( const TQString &host, bool connected )
00468 {
00469     pid_t pid = getpid();
00470     TQ_INT8 b = connected ? 1 : 0;
00471     TDEIO_DATA << pid << mProtocol << host << b;
00472     if (d->onHold)
00473        stream << d->onHoldUrl;
00474     m_pConnection->send( MSG_SLAVE_STATUS, data );
00475 }
00476 
00477 void SlaveBase::canResume()
00478 {
00479     m_pConnection->send( MSG_CANRESUME );
00480 }
00481 
00482 void SlaveBase::totalSize( TDEIO::filesize_t _bytes )
00483 {
00484     TDEIO_DATA << TDEIO_FILESIZE_T(_bytes);
00485     slaveWriteError = false;
00486     m_pConnection->send( INF_TOTAL_SIZE, data );
00487     if (slaveWriteError) exit();
00488 
00489     //this one is usually called before the first item is listed in listDir()
00490     struct timeval tp;
00491     gettimeofday(&tp, 0);
00492     listEntry_sec = tp.tv_sec;
00493     listEntry_usec = tp.tv_usec;
00494     d->totalSize=_bytes;
00495     d->sentListEntries=0;
00496 }
00497 
00498 void SlaveBase::processedSize( TDEIO::filesize_t _bytes )
00499 {
00500     bool           emitSignal=false;
00501     struct timeval tv;
00502     int            gettimeofday_res=gettimeofday( &tv, 0L );
00503 
00504     if( _bytes == d->totalSize )
00505         emitSignal=true;
00506     else if ( gettimeofday_res == 0 ) {
00507         time_t msecdiff = 2000;
00508         if (d->last_tv.tv_sec) {
00509             // Compute difference, in ms
00510             msecdiff = 1000 * ( tv.tv_sec - d->last_tv.tv_sec );
00511             time_t usecdiff = tv.tv_usec - d->last_tv.tv_usec;
00512             if ( usecdiff < 0 ) {
00513                 msecdiff--;
00514                 msecdiff += 1000;
00515             }
00516             msecdiff += usecdiff / 1000;
00517         }
00518         emitSignal=msecdiff >= 100; // emit size 10 times a second
00519     }
00520 
00521     if( emitSignal ) {
00522         TDEIO_DATA << TDEIO_FILESIZE_T(_bytes);
00523         slaveWriteError = false;
00524         m_pConnection->send( INF_PROCESSED_SIZE, data );
00525             if (slaveWriteError) exit();
00526         if ( gettimeofday_res == 0 ) {
00527             d->last_tv.tv_sec = tv.tv_sec;
00528             d->last_tv.tv_usec = tv.tv_usec;
00529         }
00530     }
00531 //    d->processed_size = _bytes;
00532 }
00533 
00534 void SlaveBase::processedPercent( float /* percent */ )
00535 {
00536   kdDebug(7019) << "SlaveBase::processedPercent: STUB" << endl;
00537 }
00538 
00539 
00540 void SlaveBase::speed( unsigned long _bytes_per_second )
00541 {
00542     TDEIO_DATA << (TQ_UINT32) _bytes_per_second;
00543     slaveWriteError = false;
00544     m_pConnection->send( INF_SPEED, data );
00545     if (slaveWriteError) exit();
00546 }
00547 
00548 void SlaveBase::redirection( const KURL& _url )
00549 {
00550     TDEIO_DATA << _url;
00551     m_pConnection->send( INF_REDIRECTION, data );
00552 }
00553 
00554 void SlaveBase::errorPage()
00555 {
00556     m_pConnection->send( INF_ERROR_PAGE );
00557 }
00558 
00559 static bool isSubCommand(int cmd)
00560 {
00561    return ( (cmd == CMD_REPARSECONFIGURATION) ||
00562             (cmd == CMD_META_DATA) ||
00563             (cmd == CMD_CONFIG) ||
00564             (cmd == CMD_SUBURL) ||
00565             (cmd == CMD_SLAVE_STATUS) ||
00566             (cmd == CMD_SLAVE_CONNECT) ||
00567             (cmd == CMD_SLAVE_HOLD) ||
00568             (cmd == CMD_MULTI_GET));
00569 }
00570 
00571 void SlaveBase::mimeType( const TQString &_type)
00572 {
00573   // kdDebug(7019) << "(" << getpid() << ") SlaveBase::mimeType '" << _type << "'" << endl;
00574   int cmd;
00575   do
00576   {
00577     // Send the meta-data each time we send the mime-type.
00578     if (!mOutgoingMetaData.isEmpty())
00579     {
00580       // kdDebug(7019) << "(" << getpid() << ") mimeType: emitting meta data" << endl;
00581       TDEIO_DATA << mOutgoingMetaData;
00582       m_pConnection->send( INF_META_DATA, data );
00583     }
00584     TDEIO_DATA << _type;
00585     m_pConnection->send( INF_MIME_TYPE, data );
00586     while(true)
00587     {
00588        cmd = 0;
00589        if ( m_pConnection->read( &cmd, data ) == -1 ) {
00590            kdDebug(7019) << "SlaveBase: mimetype: read error" << endl;
00591            exit();
00592        }
00593        // kdDebug(7019) << "(" << getpid() << ") Slavebase: mimetype got " << cmd << endl;
00594        if ( cmd == CMD_HOST) // Ignore.
00595           continue;
00596        if ( isSubCommand(cmd) )
00597        {
00598           dispatch( cmd, data );
00599           continue; // Disguised goto
00600        }
00601        break;
00602     }
00603   }
00604   while (cmd != CMD_NONE);
00605   mOutgoingMetaData.clear();
00606 }
00607 
00608 void SlaveBase::exit()
00609 {
00610     this->~SlaveBase();
00611     ::exit(255);
00612 }
00613 
00614 void SlaveBase::warning( const TQString &_msg)
00615 {
00616     TDEIO_DATA << _msg;
00617     m_pConnection->send( INF_WARNING, data );
00618 }
00619 
00620 void SlaveBase::infoMessage( const TQString &_msg)
00621 {
00622     TDEIO_DATA << _msg;
00623     m_pConnection->send( INF_INFOMESSAGE, data );
00624 }
00625 
00626 bool SlaveBase::requestNetwork(const TQString& host)
00627 {
00628     TDEIO_DATA << host << d->slaveid;
00629     m_pConnection->send( MSG_NET_REQUEST, data );
00630 
00631     if ( waitForAnswer( INF_NETWORK_STATUS, 0, data ) != -1 )
00632     {
00633         bool status;
00634         TQDataStream stream( data, IO_ReadOnly );
00635         stream >> status;
00636         return status;
00637     } else
00638         return false;
00639 }
00640 
00641 void SlaveBase::dropNetwork(const TQString& host)
00642 {
00643     TDEIO_DATA << host << d->slaveid;
00644     m_pConnection->send( MSG_NET_DROP, data );
00645 }
00646 
00647 void SlaveBase::statEntry( const UDSEntry& entry )
00648 {
00649     TDEIO_DATA << entry;
00650     slaveWriteError = false;
00651     m_pConnection->send( MSG_STAT_ENTRY, data );
00652     if (slaveWriteError) exit();
00653 }
00654 
00655 void SlaveBase::listEntry( const UDSEntry& entry, bool _ready )
00656 {
00657    static struct timeval tp;
00658    static const int maximum_updatetime = 300;
00659    static const int minimum_updatetime = 100;
00660 
00661    if (!_ready) {
00662       pendingListEntries.append(entry);
00663 
00664       if (pendingListEntries.count() > listEntryCurrentSize) {
00665          gettimeofday(&tp, 0);
00666 
00667          long diff = ((tp.tv_sec - listEntry_sec) * 1000000 +
00668                       tp.tv_usec - listEntry_usec) / 1000;
00669          if (diff==0) diff=1;
00670 
00671          if (diff > maximum_updatetime) {
00672             listEntryCurrentSize = listEntryCurrentSize * 3 / 4;
00673             _ready = true;
00674          }
00675 //if we can send all list entries of this dir which have not yet been sent
00676 //within maximum_updatetime, then make listEntryCurrentSize big enough for all of them
00677          else if (((pendingListEntries.count()*maximum_updatetime)/diff) > (d->totalSize-d->sentListEntries))
00678             listEntryCurrentSize=d->totalSize-d->sentListEntries+1;
00679 //if we are below minimum_updatetime, estimate how much we will get within
00680 //maximum_updatetime
00681          else if (diff < minimum_updatetime)
00682             listEntryCurrentSize = (pendingListEntries.count() * maximum_updatetime) / diff;
00683          else
00684             _ready=true;
00685       }
00686    }
00687    if (_ready) { // may happen when we started with !ready
00688       listEntries( pendingListEntries );
00689       pendingListEntries.clear();
00690 
00691       gettimeofday(&tp, 0);
00692       listEntry_sec = tp.tv_sec;
00693       listEntry_usec = tp.tv_usec;
00694    }
00695 }
00696 
00697 void SlaveBase::listEntries( const UDSEntryList& list )
00698 {
00699     TDEIO_DATA << (TQ_UINT32)list.count();
00700     UDSEntryListConstIterator it = list.begin();
00701     UDSEntryListConstIterator end = list.end();
00702     for (; it != end; ++it)
00703       stream << *it;
00704     slaveWriteError = false;
00705     m_pConnection->send( MSG_LIST_ENTRIES, data);
00706     if (slaveWriteError) exit();
00707     d->sentListEntries+=(uint)list.count();
00708 }
00709 
00710 void SlaveBase::sendAuthenticationKey( const TQCString& key,
00711                                        const TQCString& group,
00712                                        bool keepPass )
00713 {
00714     TDEIO_DATA << key << group << keepPass;
00715     m_pConnection->send( MSG_AUTH_KEY, data );
00716 }
00717 
00718 void SlaveBase::delCachedAuthentication( const TQString& key )
00719 {
00720     TDEIO_DATA << key.utf8() ;
00721     m_pConnection->send( MSG_DEL_AUTH_KEY, data );
00722 }
00723 
00724 void SlaveBase::sigsegv_handler(int sig)
00725 {
00726 #ifdef Q_OS_UNIX
00727     signal(sig,SIG_DFL); // Next one kills
00728 
00729     //Kill us if we deadlock
00730     signal(SIGALRM,SIG_DFL);
00731     alarm(5);  //generate an alarm signal in 5 seconds, in this time the slave has to exit
00732 
00733     // Debug and printf should be avoided because they might
00734     // call malloc.. and get in a nice recursive malloc loop
00735     char buffer[120];
00736     snprintf(buffer, sizeof(buffer), "tdeioslave: ####### CRASH ###### protocol = %s pid = %d signal = %d\n", s_protocol, getpid(), sig);
00737     if (write(2, buffer, strlen(buffer)) >= 0) {
00738 #ifdef SECURE_DEBUG
00739     kdBacktraceFD();
00740 #else // SECURE_DEBUG
00741     // Screw the malloc issue! We want nice demangled backtraces!
00742     // Anyway we are not supposed to go into infinite loop because next signal
00743     // will kill us. If you are unlucky and  there is a second crash during
00744     // backtrase in your system, you can define SECURE_DEBUG to avoid it
00745 
00746     // Extra sync here so we are sure even if the backtrace will fail
00747     // we will pass at least some crash message.
00748     fsync(2);
00749     TQString backtrace = kdBacktrace();
00750     if (write(2, backtrace.ascii(), backtrace.length()) < 0) {
00751         // FIXME
00752         // Could not write crash information
00753     }
00754 #endif // SECURE_DEBUG
00755     }
00756     ::exit(1);
00757 #endif
00758 }
00759 
00760 void SlaveBase::sigpipe_handler (int)
00761 {
00762     // We ignore a SIGPIPE in slaves.
00763     // A SIGPIPE can happen in two cases:
00764     // 1) Communication error with application.
00765     // 2) Communication error with network.
00766     slaveWriteError = true;
00767 
00768     // Don't add anything else here, especially no debug output
00769 }
00770 
00771 void SlaveBase::setHost(TQString const &, int, TQString const &, TQString const &)
00772 {
00773 }
00774 
00775 void SlaveBase::openConnection(void)
00776 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CONNECT)); }
00777 void SlaveBase::closeConnection(void)
00778 { } // No response!
00779 void SlaveBase::stat(KURL const &)
00780 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_STAT)); }
00781 void SlaveBase::put(KURL const &, int, bool, bool)
00782 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_PUT)); }
00783 void SlaveBase::special(const TQByteArray &)
00784 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SPECIAL)); }
00785 void SlaveBase::listDir(KURL const &)
00786 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_LISTDIR)); }
00787 void SlaveBase::get(KURL const & )
00788 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_GET)); }
00789 void SlaveBase::mimetype(KURL const &url)
00790 { get(url); }
00791 void SlaveBase::rename(KURL const &, KURL const &, bool)
00792 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_RENAME)); }
00793 void SlaveBase::symlink(TQString const &, KURL const &, bool)
00794 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SYMLINK)); }
00795 void SlaveBase::copy(KURL const &, KURL const &, int, bool)
00796 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_COPY)); }
00797 void SlaveBase::del(KURL const &, bool)
00798 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_DEL)); }
00799 void SlaveBase::mkdir(KURL const &, int)
00800 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_MKDIR)); }
00801 void SlaveBase::chmod(KURL const &, int)
00802 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CHMOD)); }
00803 void SlaveBase::setSubURL(KURL const &)
00804 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SUBURL)); }
00805 void SlaveBase::multiGet(const TQByteArray &)
00806 { error(  ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_MULTI_GET)); }
00807 
00808 
00809 void SlaveBase::slave_status()
00810 { slaveStatus( TQString::null, false ); }
00811 
00812 void SlaveBase::reparseConfiguration()
00813 {
00814 }
00815 
00816 void SlaveBase::localURL(const KURL& remoteURL)
00817 {
00818     bool local = remoteURL.isLocalFile();
00819     TQ_INT8 islocal;
00820     KURL retURL;
00821     if (local) {
00822         islocal = true;
00823         retURL = remoteURL;
00824     }
00825     else {
00826         islocal = false;
00827         retURL = remoteURL;
00828     }
00829     TDEIO_DATA << islocal << retURL;
00830     m_pConnection->send( INF_LOCALURL, data );
00831 }
00832 
00833 bool SlaveBase::dispatch()
00834 {
00835     assert( m_pConnection );
00836 
00837     int cmd;
00838     TQByteArray data;
00839     if ( m_pConnection->read( &cmd, data ) == -1 )
00840     {
00841         kdDebug(7019) << "SlaveBase::dispatch() has read error." << endl;
00842         return false;
00843     }
00844 
00845     dispatch( cmd, data );
00846     return true;
00847 }
00848 
00849 bool SlaveBase::openPassDlg( AuthInfo& info )
00850 {
00851     return openPassDlg(info, TQString::null);
00852 }
00853 
00854 bool SlaveBase::openPassDlg( AuthInfo& info, const TQString &errorMsg )
00855 {
00856     TQCString replyType;
00857     TQByteArray params;
00858     TQByteArray reply;
00859     AuthInfo authResult;
00860     long windowId = metaData("window-id").toLong();
00861     long progressId = metaData("progress-id").toLong();
00862     unsigned long userTimestamp = metaData("user-timestamp").toULong();
00863 
00864     kdDebug(7019) << "SlaveBase::openPassDlg window-id=" << windowId << " progress-id=" << progressId << endl;
00865 
00866     (void) dcopClient(); // Make sure to have a dcop client.
00867 
00868     UIServer_stub uiserver( "tdeio_uiserver", "UIServer" );
00869     if (progressId)
00870       uiserver.setJobVisible( progressId, false );
00871 
00872     TQDataStream stream(params, IO_WriteOnly);
00873 
00874     if (metaData("no-auth-prompt").lower() == "true")
00875        stream << info << TQString("<NoAuthPrompt>") << windowId << s_seqNr << userTimestamp;
00876     else
00877        stream << info << errorMsg << windowId << s_seqNr << userTimestamp;
00878 
00879     bool callOK = d->dcopClient->call( "kded", "kpasswdserver", "queryAuthInfo(TDEIO::AuthInfo, TQString, long int, long int, unsigned long int)",
00880                                         params, replyType, reply );
00881 
00882     if (progressId)
00883       uiserver.setJobVisible( progressId, true );
00884 
00885     if (!callOK)
00886     {
00887        kdWarning(7019) << "Can't communicate with kded_kpasswdserver (openPassDlg)!" << endl;
00888        return false;
00889     }
00890 
00891     if ( replyType == "TDEIO::AuthInfo" )
00892     {
00893        TQDataStream stream2( reply, IO_ReadOnly );
00894        stream2 >> authResult >> s_seqNr;
00895     }
00896     else
00897     {
00898        kdError(7019) << "DCOP function queryAuthInfo(...) returns "
00899                      << replyType << ", expected TDEIO::AuthInfo" << endl;
00900        return false;
00901     }
00902 
00903     if (!authResult.isModified())
00904        return false;
00905 
00906     info = authResult;
00907 
00908     kdDebug(7019) << "SlaveBase::openPassDlg: username=" << info.username << endl;
00909     kdDebug(7019) << "SlaveBase::openPassDlg: password=[hidden]" << endl;
00910 
00911     return true;
00912 }
00913 
00914 int SlaveBase::messageBox( MessageBoxType type, const TQString &text, const TQString &caption,
00915                            const TQString &buttonYes, const TQString &buttonNo )
00916 {
00917     return messageBox( text, type, caption, buttonYes, buttonNo, TQString::null );
00918 }
00919 
00920 int SlaveBase::messageBox( const TQString &text, MessageBoxType type, const TQString &caption,
00921                            const TQString &buttonYes, const TQString &buttonNo, const TQString &dontAskAgainName )
00922 {
00923     kdDebug(7019) << "messageBox " << type << " " << text << " - " << caption << buttonYes << buttonNo << endl;
00924     TDEIO_DATA << (TQ_INT32)type << text << caption << buttonYes << buttonNo << dontAskAgainName;
00925     m_pConnection->send( INF_MESSAGEBOX, data );
00926     if ( waitForAnswer( CMD_MESSAGEBOXANSWER, 0, data ) != -1 )
00927     {
00928         TQDataStream stream( data, IO_ReadOnly );
00929         int answer;
00930         stream >> answer;
00931         kdDebug(7019) << "got messagebox answer" << answer << endl;
00932         return answer;
00933     } else
00934         return 0; // communication failure
00935 }
00936 
00937 bool SlaveBase::canResume( TDEIO::filesize_t offset )
00938 {
00939     kdDebug(7019) << "SlaveBase::canResume offset=" << TDEIO::number(offset) << endl;
00940     d->needSendCanResume = false;
00941     TDEIO_DATA << TDEIO_FILESIZE_T(offset);
00942     m_pConnection->send( MSG_RESUME, data );
00943     if ( offset )
00944     {
00945         int cmd;
00946         if ( waitForAnswer( CMD_RESUMEANSWER, CMD_NONE, data, &cmd ) != -1 )
00947         {
00948             kdDebug(7019) << "SlaveBase::canResume returning " << (cmd == CMD_RESUMEANSWER) << endl;
00949             return cmd == CMD_RESUMEANSWER;
00950         } else
00951             return false;
00952     }
00953     else // No resuming possible -> no answer to wait for
00954         return true;
00955 }
00956 
00957 
00958 
00959 int SlaveBase::waitForAnswer( int expected1, int expected2, TQByteArray & data, int *pCmd )
00960 {
00961     int cmd, result;
00962     for (;;)
00963     {
00964         result = m_pConnection->read( &cmd, data );
00965         if ( result == -1 )
00966         {
00967             kdDebug(7019) << "SlaveBase::waitForAnswer has read error." << endl;
00968             return -1;
00969         }
00970         if ( cmd == expected1 || cmd == expected2 )
00971         {
00972             if ( pCmd ) *pCmd = cmd;
00973             return result;
00974         }
00975         if ( isSubCommand(cmd) )
00976         {
00977             dispatch( cmd, data );
00978         }
00979         else
00980         {
00981             kdWarning() << "Got cmd " << cmd << " while waiting for an answer!" << endl;
00982         }
00983     }
00984 }
00985 
00986 
00987 int SlaveBase::readData( TQByteArray &buffer)
00988 {
00989    int result = waitForAnswer( MSG_DATA, 0, buffer );
00990    //kdDebug(7019) << "readData: length = " << result << " " << endl;
00991    return result;
00992 }
00993 
00994 void SlaveBase::setTimeoutSpecialCommand(int timeout, const TQByteArray &data)
00995 {
00996    if (timeout > 0)
00997       d->timeout = time(0)+(time_t)timeout;
00998    else if (timeout == 0)
00999       d->timeout = 1; // Immediate timeout
01000    else
01001       d->timeout = 0; // Canceled
01002 
01003    d->timeoutData = data;
01004 }
01005 
01006 void SlaveBase::dispatch( int command, const TQByteArray &data )
01007 {
01008     TQDataStream stream( data, IO_ReadOnly );
01009 
01010     KURL url;
01011     int i;
01012 
01013     switch( command ) {
01014     case CMD_HOST: {
01015         // Reset s_seqNr, see kpasswdserver/DESIGN
01016         s_seqNr = 0;
01017         TQString passwd;
01018         TQString host, user;
01019         stream >> host >> i >> user >> passwd;
01020         setHost( host, i, user, passwd );
01021     }
01022     break;
01023     case CMD_CONNECT:
01024         openConnection( );
01025         break;
01026     case CMD_DISCONNECT:
01027         closeConnection( );
01028         break;
01029     case CMD_SLAVE_STATUS:
01030         slave_status();
01031         break;
01032     case CMD_SLAVE_CONNECT:
01033     {
01034         d->onHold = false;
01035         TQString app_socket;
01036         TQDataStream stream( data, IO_ReadOnly);
01037         stream >> app_socket;
01038         appconn->send( MSG_SLAVE_ACK );
01039         disconnectSlave();
01040         mConnectedToApp = true;
01041         connectSlave(app_socket);
01042     } break;
01043     case CMD_SLAVE_HOLD:
01044     {
01045         KURL url;
01046         TQDataStream stream( data, IO_ReadOnly);
01047         stream >> url;
01048         d->onHoldUrl = url;
01049         d->onHold = true;
01050         disconnectSlave();
01051         mConnectedToApp = false;
01052         // Do not close connection!
01053         connectSlave(mPoolSocket);
01054     } break;
01055     case CMD_REPARSECONFIGURATION:
01056         reparseConfiguration();
01057         break;
01058     case CMD_CONFIG:
01059         stream >> d->configData;
01060 #ifdef Q_OS_UNIX //TODO: not yet available on WIN32
01061         KSocks::setConfig(d->config);
01062 #endif
01063     delete d->remotefile;
01064     d->remotefile = 0;
01065         break;
01066     case CMD_GET:
01067     {
01068         stream >> url;
01069         get( url );
01070     } break;
01071     case CMD_PUT:
01072     {
01073         int permissions;
01074         TQ_INT8 iOverwrite, iResume;
01075         stream >> url >> iOverwrite >> iResume >> permissions;
01076         bool overwrite = ( iOverwrite != 0 );
01077         bool resume = ( iResume != 0 );
01078 
01079         // Remember that we need to send canResume(), TransferJob is expecting
01080         // it. Well, in theory this shouldn't be done if resume is true.
01081         //   (the resume bool is currently unused)
01082         d->needSendCanResume = true   /* !resume */;
01083 
01084         put( url, permissions, overwrite, resume);
01085     } break;
01086     case CMD_STAT:
01087         stream >> url;
01088         stat( url );
01089         break;
01090     case CMD_MIMETYPE:
01091         stream >> url;
01092         mimetype( url );
01093         break;
01094     case CMD_LISTDIR:
01095         stream >> url;
01096         listDir( url );
01097         break;
01098     case CMD_MKDIR:
01099         stream >> url >> i;
01100         mkdir( url, i );
01101         break;
01102     case CMD_RENAME:
01103     {
01104         TQ_INT8 iOverwrite;
01105         KURL url2;
01106         stream >> url >> url2 >> iOverwrite;
01107         bool overwrite = (iOverwrite != 0);
01108         rename( url, url2, overwrite );
01109     } break;
01110     case CMD_SYMLINK:
01111     {
01112         TQ_INT8 iOverwrite;
01113         TQString target;
01114         stream >> target >> url >> iOverwrite;
01115         bool overwrite = (iOverwrite != 0);
01116         symlink( target, url, overwrite );
01117     } break;
01118     case CMD_COPY:
01119     {
01120         int permissions;
01121         TQ_INT8 iOverwrite;
01122         KURL url2;
01123         stream >> url >> url2 >> permissions >> iOverwrite;
01124         bool overwrite = (iOverwrite != 0);
01125         copy( url, url2, permissions, overwrite );
01126     } break;
01127     case CMD_DEL:
01128     {
01129         TQ_INT8 isFile;
01130         stream >> url >> isFile;
01131         del( url, isFile != 0);
01132     } break;
01133     case CMD_CHMOD:
01134         stream >> url >> i;
01135         chmod( url, i);
01136         break;
01137     case CMD_SPECIAL:
01138         special( data );
01139         break;
01140     case CMD_META_DATA:
01141         //kdDebug(7019) << "(" << getpid() << ") Incoming meta-data..." << endl;
01142         stream >> mIncomingMetaData;
01143         break;
01144     case CMD_SUBURL:
01145         stream >> url;
01146         setSubURL(url);
01147         break;
01148     case CMD_NONE:
01149         fprintf(stderr, "Got unexpected CMD_NONE!\n");
01150         break;
01151     case CMD_MULTI_GET:
01152         multiGet( data );
01153         break;
01154     case CMD_LOCALURL:
01155     {
01156         stream >> url;
01157         localURL( url );
01158     } break;
01159     default:
01160         // Some command we don't understand.
01161         // Just ignore it, it may come from some future version of KDE.
01162         break;
01163     }
01164 }
01165 
01166 TQString SlaveBase::createAuthCacheKey( const KURL& url )
01167 {
01168     if( !url.isValid() )
01169         return TQString::null;
01170 
01171     // Generate the basic key sequence.
01172     TQString key = url.protocol();
01173     key += '-';
01174     key += url.host();
01175     int port = url.port();
01176     if( port )
01177     {
01178       key += ':';
01179       key += TQString::number(port);
01180     }
01181 
01182     return key;
01183 }
01184 
01185 bool SlaveBase::pingCacheDaemon() const
01186 {
01187 #ifdef Q_OS_UNIX
01188     // TODO: Ping kded / kpasswdserver
01189     TDEsuClient client;
01190     int success = client.ping();
01191     if( success == -1 )
01192     {
01193         success = client.startServer();
01194         if( success == -1 )
01195         {
01196             kdDebug(7019) << "Cannot start a new deamon!!" << endl;
01197             return false;
01198         }
01199         kdDebug(7019) << "Sucessfully started new cache deamon!!" << endl;
01200     }
01201     return true;
01202 #else
01203     return false;
01204 #endif
01205 }
01206 
01207 bool SlaveBase::checkCachedAuthentication( AuthInfo& info )
01208 {
01209     TQCString replyType;
01210     TQByteArray params;
01211     TQByteArray reply;
01212     AuthInfo authResult;
01213     long windowId = metaData("window-id").toLong();
01214     unsigned long userTimestamp = metaData("user-timestamp").toULong();
01215 
01216     kdDebug(7019) << "SlaveBase::checkCachedAuthInfo window = " << windowId << " url = " << info.url.url() << endl;
01217 
01218     (void) dcopClient(); // Make sure to have a dcop client.
01219 
01220     TQDataStream stream(params, IO_WriteOnly);
01221     stream << info << windowId << userTimestamp;
01222 
01223     if ( !d->dcopClient->call( "kded", "kpasswdserver", "checkAuthInfo(TDEIO::AuthInfo, long int, unsigned long int)",
01224                                params, replyType, reply ) )
01225     {
01226        kdWarning(7019) << "Can't communicate with kded_kpasswdserver (checkCachedAuthentication)!" << endl;
01227        return false;
01228     }
01229 
01230     if ( replyType == "TDEIO::AuthInfo" )
01231     {
01232        TQDataStream stream2( reply, IO_ReadOnly );
01233        stream2 >> authResult;
01234     }
01235     else
01236     {
01237        kdError(7019) << "DCOP function checkAuthInfo(...) returns "
01238                      << replyType << ", expected TDEIO::AuthInfo" << endl;
01239        return false;
01240     }
01241     if (!authResult.isModified())
01242     {
01243        return false;
01244     }
01245 
01246     info = authResult;
01247     return true;
01248 }
01249 
01250 bool SlaveBase::cacheAuthentication( const AuthInfo& info )
01251 {
01252     TQByteArray params;
01253     long windowId = metaData("window-id").toLong();
01254 
01255     (void) dcopClient(); // Make sure to have a dcop client.
01256 
01257     TQDataStream stream(params, IO_WriteOnly);
01258     stream << info << windowId;
01259 
01260     d->dcopClient->send( "kded", "kpasswdserver", "addAuthInfo(TDEIO::AuthInfo, long int)", params );
01261 
01262     return true;
01263 }
01264 
01265 int SlaveBase::connectTimeout()
01266 {
01267     bool ok;
01268     TQString tmp = metaData("ConnectTimeout");
01269     int result = tmp.toInt(&ok);
01270     if (ok)
01271        return result;
01272     return DEFAULT_CONNECT_TIMEOUT;
01273 }
01274 
01275 int SlaveBase::proxyConnectTimeout()
01276 {
01277     bool ok;
01278     TQString tmp = metaData("ProxyConnectTimeout");
01279     int result = tmp.toInt(&ok);
01280     if (ok)
01281        return result;
01282     return DEFAULT_PROXY_CONNECT_TIMEOUT;
01283 }
01284 
01285 
01286 int SlaveBase::responseTimeout()
01287 {
01288     bool ok;
01289     TQString tmp = metaData("ResponseTimeout");
01290     int result = tmp.toInt(&ok);
01291     if (ok)
01292        return result;
01293     return DEFAULT_RESPONSE_TIMEOUT;
01294 }
01295 
01296 
01297 int SlaveBase::readTimeout()
01298 {
01299     bool ok;
01300     TQString tmp = metaData("ReadTimeout");
01301     int result = tmp.toInt(&ok);
01302     if (ok)
01303        return result;
01304     return DEFAULT_READ_TIMEOUT;
01305 }
01306 
01307 bool SlaveBase::wasKilled() const
01308 {
01309    return d->wasKilled;
01310 }
01311 
01312 void SlaveBase::setKillFlag()
01313 {
01314    d->wasKilled=true;
01315 }
01316 
01317 void SlaveBase::virtual_hook( int, void* )
01318 { /*BASE::virtual_hook( id, data );*/ }
01319 

tdeio/tdeio

Skip menu "tdeio/tdeio"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdeio/tdeio

Skip menu "tdeio/tdeio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeio/tdeio by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.