kio Library API Documentation

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: slavebase.cpp,v 1.138 2002/11/05 11:15:35 faure Exp $
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., 59 Temple Place - Suite 330,
00022  *  Boston, MA 02111-1307, USA.
00023  *
00024  **/
00025 
00026 #include <config.h>
00027 
00028 #include <sys/time.h>
00029 #ifdef HAVE_SYS_SELECT_H
00030 #include <sys/select.h>     // Needed on some systems.
00031 #endif
00032 
00033 #include <assert.h>
00034 #include <kdebug.h>
00035 #include <stdlib.h>
00036 #include <errno.h>
00037 #include <unistd.h>
00038 #include <signal.h>
00039 #include <time.h>
00040 
00041 #include <qfile.h>
00042 
00043 #include <dcopclient.h>
00044 
00045 #include <kapplication.h>
00046 #include <ksock.h>
00047 #include <kcrash.h>
00048 #include <kdesu/client.h>
00049 #include <klocale.h>
00050 
00051 #include <ksocks.h>
00052 
00053 #include "slavebase.h"
00054 
00055 #include "kio/slavebase.h"
00056 #include "kio/connection.h"
00057 #include "kio/ioslave_defaults.h"
00058 #include "kio/slaveinterface.h"
00059 
00060 using namespace KIO;
00061 
00062 template class QPtrList<QValueList<UDSAtom> >;
00063 typedef QValueList<QCString> AuthKeysList;
00064 typedef QMap<QString,QCString> AuthKeysMap;
00065 #define KIO_DATA QByteArray data; QDataStream stream( data, IO_WriteOnly ); stream
00066 #define KIO_FILESIZE_T(x) (unsigned long)(x & 0xffffffff) << (unsigned long)(x >> 32)
00067 
00068 namespace KIO {
00069 
00070 class SlaveBaseConfig : public KConfigBase
00071 {
00072 public:
00073    SlaveBaseConfig(SlaveBase *_slave)
00074     : slave(_slave) { }
00075 
00076    bool internalHasGroup(const QCString &) const { qWarning("hasGroup(const QCString &)");
00077 return false; }
00078 
00079    QStringList groupList() const { return QStringList(); }
00080 
00081    QMap<QString,QString> entryMap(const QString &) const
00082       { return QMap<QString,QString>(); }
00083 
00084    void reparseConfiguration() { }
00085 
00086    KEntryMap internalEntryMap( const QString &) const { return KEntryMap(); }
00087 
00088    KEntryMap internalEntryMap() const { return KEntryMap(); }
00089 
00090    void putData(const KEntryKey &, const KEntry&, bool) { }
00091 
00092    KEntry lookupData(const KEntryKey &key) const
00093    {
00094      KEntry entry;
00095      QString value = slave->metaData(key.c_key);
00096      if (!value.isNull())
00097         entry.mValue = value.utf8();
00098      return entry;
00099    }
00100 protected:
00101    SlaveBase *slave;
00102 };
00103 
00104 
00105 class SlaveBasePrivate {
00106 public:
00107     QString slaveid;
00108     bool resume:1;
00109     bool needSendCanResume:1;
00110     bool multipleAuthCaching:1;
00111     bool onHold:1;
00112     bool wasKilled:1;
00113     MetaData configData;
00114     SlaveBaseConfig *config;
00115     KURL onHoldUrl;
00116 
00117     struct timeval last_tv;
00118     KIO::filesize_t totalSize;
00119     KIO::filesize_t sentListEntries;
00120     DCOPClient *dcopClient;
00121     time_t timeout;
00122     QByteArray timeoutData;
00123 };
00124 
00125 };
00126 
00127 SlaveBase *globalSlave=0;
00128 long SlaveBase::s_seqNr = 0;
00129 
00130 static volatile bool slaveWriteError = false;
00131 
00132 void sigalarm_handler(int sigNumber)
00133 {
00134    signal(sigNumber,SIG_IGN);
00135    //I don't think we can have the same problem here as in the sigsegv handler
00136    kdDebug()<<"kioslave : exiting due to alarm signal "<<endl;
00137    exit(2);
00138 };
00139 
00140 void genericsig_handler(int sigNumber)
00141 {
00142    signal(sigNumber,SIG_IGN);
00143    //I don't think we can have the same problem here as in the sigsegv handler
00144    kdDebug()<<"kioslave : 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,&sigalarm_handler);
00150    alarm(5);  //generate an alarm signal in 5 seconds, in this time the slave has to exit
00151 };
00152 
00154 
00155 SlaveBase::SlaveBase( const QCString &protocol,
00156                       const QCString &pool_socket,
00157                       const QCString &app_socket )
00158     : mProtocol(protocol), m_pConnection(0),
00159       mPoolSocket( QFile::decodeName(pool_socket)),
00160       mAppSocket( QFile::decodeName(app_socket))
00161 {
00162     if (!getenv("KDE_DEBUG"))
00163         KCrash::setCrashHandler( sigsegv_handler );
00164     signal( SIGPIPE, sigpipe_handler );
00165 
00166    signal(SIGINT,&genericsig_handler);
00167     signal(SIGQUIT,&genericsig_handler);
00168     signal(SIGILL,&genericsig_handler);
00169     signal(SIGTRAP,&genericsig_handler);
00170     signal(SIGABRT,&genericsig_handler);
00171     signal(SIGBUS,&genericsig_handler);
00172     signal(SIGALRM,&genericsig_handler);
00173     signal(SIGTERM,&genericsig_handler);
00174     signal(SIGFPE,&genericsig_handler);
00175 #ifdef SIGPOLL
00176    signal(SIGPOLL, &genericsig_handler);
00177 #endif
00178 #ifdef SIGSYS
00179    signal(SIGSYS, &genericsig_handler);
00180 #endif
00181 #ifdef SIGVTALRM
00182    signal(SIGVTALRM, &genericsig_handler);
00183 #endif
00184 #ifdef SIGXCPU
00185    signal(SIGXCPU, &genericsig_handler);
00186 #endif
00187 #ifdef SIGXFSZ
00188    signal(SIGXFSZ, &genericsig_handler);
00189 #endif
00190    globalSlave=this;
00191 
00192     appconn = new Connection();
00193     listEntryCurrentSize = 100;
00194     struct timeval tp;
00195     gettimeofday(&tp, 0);
00196     listEntry_sec = tp.tv_sec;
00197     listEntry_usec = tp.tv_usec;
00198     mConnectedToApp = true;
00199 
00200     d = new SlaveBasePrivate;
00201     // by kahl for netmgr (need a way to identify slaves)
00202     d->slaveid = protocol;
00203     d->slaveid += QString::number(getpid());
00204     d->resume = false;
00205     d->needSendCanResume = false;
00206     d->multipleAuthCaching = false;
00207     d->config = new SlaveBaseConfig(this);
00208     d->onHold = false;
00209     d->wasKilled=false;
00210     d->last_tv.tv_sec = 0;
00211     d->last_tv.tv_usec = 0;
00212 //    d->processed_size = 0;
00213     d->totalSize=0;
00214     d->sentListEntries=0;
00215     d->timeout = 0;
00216     connectSlave(mAppSocket);
00217     
00218     d->dcopClient = 0;
00219 }
00220 
00221 SlaveBase::~SlaveBase()
00222 {
00223     delete d;
00224 }
00225 
00226 DCOPClient *SlaveBase::dcopClient()
00227 {
00228     if (!d->dcopClient)
00229     {
00230        d->dcopClient = new DCOPClient();
00231        d->dcopClient->attach();
00232     }
00233     return d->dcopClient;
00234 }
00235 
00236 void SlaveBase::dispatchLoop()
00237 {
00238     fd_set rfds;
00239     int retval;
00240 
00241     while (true) {
00242     if (d->timeout && (d->timeout < time(0)))
00243     {
00244        QByteArray data = d->timeoutData;
00245        d->timeout = 0;
00246        d->timeoutData = QByteArray();
00247        special(data);
00248     }
00249     FD_ZERO(&rfds);
00250 
00251     assert(appconn->inited());
00252     FD_SET(appconn->fd_from(), &rfds);
00253 
00254     struct timeval tv;
00255     tv.tv_sec = 1;
00256     tv.tv_usec = 0; // 1 second timeout
00257     retval = select(appconn->fd_from()+ 1, &rfds, NULL, NULL, &tv);
00258     if ((retval>0) && FD_ISSET(appconn->fd_from(), &rfds))
00259     { // dispatch application messages
00260         int cmd;
00261         QByteArray data;
00262         if ( appconn->read(&cmd, data) != -1 )
00263         {
00264           dispatch(cmd, data);
00265         }
00266         else // some error occured, perhaps no more application
00267         {
00268           // When the app exits, should the slave be put back in the pool ?
00269           if (mConnectedToApp && !mPoolSocket.isEmpty())
00270           {
00271             disconnectSlave();
00272             mConnectedToApp = false;
00273             closeConnection();
00274             connectSlave(mPoolSocket);
00275           }
00276           else
00277           {
00278             return;
00279           }
00280         }
00281     }
00282     else if (retval<0)
00283     {
00284        kdDebug(7019) << "dispatchLoop(): select returned " << retval << " "
00285           << (errno==EBADF?"EBADF":errno==EINTR?"EINTR":errno==EINVAL?"EINVAL":errno==ENOMEM?"ENOMEM":"unknown")
00286           << " (" << errno << ")" << endl;
00287        return;
00288     };
00289     //I think we get here when we were killed in dispatch() and not in select()
00290     if (wasKilled())
00291     {
00292        kdDebug(7019)<<" dispatchLoop() slave was killed, returning"<<endl;
00293        return;
00294     }
00295   }
00296 }
00297 
00298 void SlaveBase::connectSlave(const QString& path)
00299 {
00300     appconn->init(new KSocket(QFile::encodeName(path)));
00301     if (!appconn->inited())
00302     {
00303         kdDebug(7019) << "SlaveBase: failed to connect to " << path << endl;
00304         exit();
00305     }
00306 
00307     setConnection(appconn);
00308 }
00309 
00310 void SlaveBase::disconnectSlave()
00311 {
00312     appconn->close();
00313 }
00314 
00315 void SlaveBase::setMetaData(const QString &key, const QString &value)
00316 {
00317    mOutgoingMetaData.replace(key, value);
00318 }
00319 
00320 QString SlaveBase::metaData(const QString &key)
00321 {
00322    if (mIncomingMetaData.contains(key))
00323       return mIncomingMetaData[key];
00324    if (d->configData.contains(key))
00325       return d->configData[key];
00326    return QString::null;
00327 }
00328 
00329 bool SlaveBase::hasMetaData(const QString &key)
00330 {
00331    if (mIncomingMetaData.contains(key))
00332       return true;
00333    if (d->configData.contains(key))
00334       return true;
00335    return false;
00336 }
00337 
00338 KConfigBase *SlaveBase::config()
00339 {
00340    return d->config;
00341 }
00342 
00343 void SlaveBase::sendMetaData()
00344 {
00345    KIO_DATA << mOutgoingMetaData;
00346 
00347    slaveWriteError = false;
00348    m_pConnection->send( INF_META_DATA, data );
00349    if (slaveWriteError) exit();
00350    mOutgoingMetaData.clear(); // Clear
00351 }
00352 
00353 
00354 void SlaveBase::data( const QByteArray &data )
00355 {
00356    if (!mOutgoingMetaData.isEmpty())
00357       sendMetaData();
00358    slaveWriteError = false;
00359    m_pConnection->send( MSG_DATA, data );
00360    if (slaveWriteError) exit();
00361 }
00362 
00363 void SlaveBase::dataReq( )
00364 {
00365 /*
00366    if (!mOutgoingMetaData.isEmpty())
00367       sendMetaData();
00368 */
00369    if (d->needSendCanResume)
00370       canResume(0);
00371    m_pConnection->send( MSG_DATA_REQ );
00372 }
00373 
00374 void SlaveBase::error( int _errid, const QString &_text )
00375 {
00376     mIncomingMetaData.clear(); // Clear meta data
00377     mOutgoingMetaData.clear();
00378     KIO_DATA << _errid << _text;
00379 
00380     m_pConnection->send( MSG_ERROR, data );
00381     //reset
00382     listEntryCurrentSize = 100;
00383     d->sentListEntries=0;
00384     d->totalSize=0;
00385 }
00386 
00387 void SlaveBase::connected()
00388 {
00389     slaveWriteError = false;
00390     m_pConnection->send( MSG_CONNECTED );
00391     if (slaveWriteError) exit();
00392 }
00393 
00394 void SlaveBase::finished()
00395 {
00396     mIncomingMetaData.clear(); // Clear meta data
00397     if (!mOutgoingMetaData.isEmpty())
00398        sendMetaData();
00399     m_pConnection->send( MSG_FINISHED );
00400 
00401     // reset
00402     listEntryCurrentSize = 100;
00403     d->sentListEntries=0;
00404     d->totalSize=0;
00405 }
00406 
00407 void SlaveBase::needSubURLData()
00408 {
00409     m_pConnection->send( MSG_NEED_SUBURL_DATA );
00410 }
00411 
00412 void SlaveBase::slaveStatus( const QString &host, bool connected )
00413 {
00414     pid_t pid = getpid();
00415     Q_INT8 b = connected ? 1 : 0;
00416     KIO_DATA << pid << mProtocol << host << b;
00417     if (d->onHold)
00418        stream << d->onHoldUrl;
00419     m_pConnection->send( MSG_SLAVE_STATUS, data );
00420 }
00421 
00422 void SlaveBase::canResume()
00423 {
00424     m_pConnection->send( MSG_CANRESUME );
00425 }
00426 
00427 void SlaveBase::totalSize( KIO::filesize_t _bytes )
00428 {
00429     KIO_DATA << KIO_FILESIZE_T(_bytes);
00430     slaveWriteError = false;
00431     m_pConnection->send( INF_TOTAL_SIZE, data );
00432     if (slaveWriteError) exit();
00433 
00434     //this one is usually called before the first item is listed in listDir()
00435     struct timeval tp;
00436     gettimeofday(&tp, 0);
00437     listEntry_sec = tp.tv_sec;
00438     listEntry_usec = tp.tv_usec;
00439     d->totalSize=_bytes;
00440     d->sentListEntries=0;
00441 }
00442 
00443 void SlaveBase::processedSize( KIO::filesize_t _bytes )
00444 {
00445     struct timeval tv;
00446     if ( gettimeofday( &tv, 0L ) == 0 ) {
00447     time_t msecdiff = 2000;
00448     if (d->last_tv.tv_sec) {
00449         // Compute difference, in ms
00450         msecdiff = 1000 * ( tv.tv_sec - d->last_tv.tv_sec );
00451         time_t usecdiff = tv.tv_usec - d->last_tv.tv_usec;
00452         if ( usecdiff < 0 ) {
00453         msecdiff--;
00454         msecdiff += 1000;
00455         }
00456         msecdiff += usecdiff / 1000;
00457     }
00458     if ( msecdiff >= 100 ) { // emit size 10 times a second
00459         KIO_DATA << KIO_FILESIZE_T(_bytes);
00460         slaveWriteError = false;
00461         m_pConnection->send( INF_PROCESSED_SIZE, data );
00462             if (slaveWriteError) exit();
00463         d->last_tv.tv_sec = tv.tv_sec;
00464         d->last_tv.tv_usec = tv.tv_usec;
00465     }
00466     }
00467 //    d->processed_size = _bytes;
00468 }
00469 
00470 void SlaveBase::processedPercent( float /* percent */ )
00471 {
00472   kdDebug(7019) << "SlaveBase::processedPercent: STUB" << endl;
00473 }
00474 
00475 
00476 void SlaveBase::speed( unsigned long _bytes_per_second )
00477 {
00478     KIO_DATA << _bytes_per_second;
00479     slaveWriteError = false;
00480     m_pConnection->send( INF_SPEED, data );
00481     if (slaveWriteError) exit();
00482 }
00483 
00484 void SlaveBase::redirection( const KURL& _url )
00485 {
00486     KIO_DATA << _url;
00487     m_pConnection->send( INF_REDIRECTION, data );
00488 }
00489 
00490 void SlaveBase::errorPage()
00491 {
00492     m_pConnection->send( INF_ERROR_PAGE );
00493 }
00494 
00495 static bool isSubCommand(int cmd)
00496 {
00497    return ( (cmd == CMD_REPARSECONFIGURATION) ||
00498             (cmd == CMD_META_DATA) ||
00499             (cmd == CMD_CONFIG) ||
00500             (cmd == CMD_SUBURL) ||
00501             (cmd == CMD_SLAVE_STATUS) ||
00502             (cmd == CMD_SLAVE_CONNECT) ||
00503             (cmd == CMD_SLAVE_HOLD) ||
00504             (cmd == CMD_MULTI_GET));
00505 }
00506 
00507 void SlaveBase::mimeType( const QString &_type)
00508 {
00509   // kdDebug(7019) << "(" << getpid() << ") SlaveBase::mimeType '" << _type << "'" << endl;
00510   int cmd;
00511   do
00512   {
00513     // Send the meta-data each time we send the mime-type.
00514     if (!mOutgoingMetaData.isEmpty())
00515     {
00516       // kdDebug(7019) << "(" << getpid() << ") mimeType: emitting meta data" << endl;
00517       KIO_DATA << mOutgoingMetaData;
00518       m_pConnection->send( INF_META_DATA, data );
00519     }
00520     KIO_DATA << _type;
00521     m_pConnection->send( INF_MIME_TYPE, data );
00522     while(true)
00523     {
00524        cmd = 0;
00525        if ( m_pConnection->read( &cmd, data ) == -1 ) {
00526            kdDebug(7019) << "SlaveBase: mimetype: read error" << endl;
00527            exit();
00528        }
00529        // kdDebug(7019) << "(" << getpid() << ") Slavebase: mimetype got " << cmd << endl;
00530        if ( cmd == CMD_HOST) // Ignore.
00531           continue;
00532        if ( isSubCommand(cmd) )
00533        {
00534           dispatch( cmd, data );
00535           continue; // Disguised goto
00536        };
00537        break;
00538     }
00539   }
00540   while (cmd != CMD_NONE);
00541   mOutgoingMetaData.clear();
00542 }
00543 
00544 void SlaveBase::exit()
00545 {
00546     this->~SlaveBase();
00547     ::exit(255);
00548 }
00549 
00550 void SlaveBase::warning( const QString &_msg)
00551 {
00552     KIO_DATA << _msg;
00553     m_pConnection->send( INF_WARNING, data );
00554 }
00555 
00556 void SlaveBase::infoMessage( const QString &_msg)
00557 {
00558     KIO_DATA << _msg;
00559     m_pConnection->send( INF_INFOMESSAGE, data );
00560 }
00561 
00562 bool SlaveBase::requestNetwork(const QString& host)
00563 {
00564     KIO_DATA << host << d->slaveid;
00565     m_pConnection->send( MSG_NET_REQUEST, data );
00566 
00567     if ( waitForAnswer( INF_NETWORK_STATUS, 0, data ) != -1 )
00568     {
00569         bool status;
00570         QDataStream stream( data, IO_ReadOnly );
00571         stream >> status;
00572         return status;
00573     } else
00574         return false;
00575 }
00576 
00577 void SlaveBase::dropNetwork(const QString& host)
00578 {
00579     KIO_DATA << host << d->slaveid;
00580     m_pConnection->send( MSG_NET_DROP, data );
00581 }
00582 
00583 void SlaveBase::statEntry( const UDSEntry& entry )
00584 {
00585     KIO_DATA << entry;
00586     slaveWriteError = false;
00587     m_pConnection->send( MSG_STAT_ENTRY, data );
00588     if (slaveWriteError) exit();
00589 }
00590 
00591 void SlaveBase::listEntry( const UDSEntry& entry, bool _ready )
00592 {
00593    static struct timeval tp;
00594    static const int maximum_updatetime = 300;
00595    static const int minimum_updatetime = 100;
00596 
00597    if (!_ready) {
00598       pendingListEntries.append(entry);
00599 
00600       if (pendingListEntries.count() > listEntryCurrentSize) {
00601          gettimeofday(&tp, 0);
00602 
00603          long diff = ((tp.tv_sec - listEntry_sec) * 1000000 +
00604                       tp.tv_usec - listEntry_usec) / 1000;
00605          if (diff==0) diff=1;
00606 
00607          if (diff > maximum_updatetime) {
00608             listEntryCurrentSize = listEntryCurrentSize * 3 / 4;
00609             _ready = true;
00610          }
00611 //if we can send all list entries of this dir which have not yet been sent
00612 //within maximum_updatetime, then make listEntryCurrentSize big enough for all of them
00613          else if (((pendingListEntries.count()*maximum_updatetime)/diff) > (d->totalSize-d->sentListEntries))
00614             listEntryCurrentSize=d->totalSize-d->sentListEntries+1;
00615 //if we are below minimum_updatetime, estimate how much we will get within
00616 //maximum_updatetime
00617          else if (diff < minimum_updatetime)
00618             listEntryCurrentSize = (pendingListEntries.count() * maximum_updatetime) / diff;
00619          else
00620             _ready=true;
00621       }
00622    }
00623    if (_ready) { // may happen when we started with !ready
00624       listEntries( pendingListEntries );
00625       pendingListEntries.clear();
00626 
00627       gettimeofday(&tp, 0);
00628       listEntry_sec = tp.tv_sec;
00629       listEntry_usec = tp.tv_usec;
00630    }
00631 }
00632 
00633 void SlaveBase::listEntries( const UDSEntryList& list )
00634 {
00635     KIO_DATA << (uint)list.count();
00636     UDSEntryListConstIterator it = list.begin();
00637     UDSEntryListConstIterator end = list.end();
00638     for (; it != end; ++it)
00639       stream << *it;
00640     slaveWriteError = false;
00641     m_pConnection->send( MSG_LIST_ENTRIES, data);
00642     if (slaveWriteError) exit();
00643     d->sentListEntries+=(uint)list.count();
00644 }
00645 
00646 void SlaveBase::sendAuthenticationKey( const QCString& key,
00647                                        const QCString& group,
00648                                        bool keepPass )
00649 {
00650     KIO_DATA << key << group << keepPass;
00651     m_pConnection->send( MSG_AUTH_KEY, data );
00652 }
00653 
00654 void SlaveBase::delCachedAuthentication( const QString& key )
00655 {
00656     KIO_DATA << key.utf8() ;
00657     m_pConnection->send( MSG_DEL_AUTH_KEY, data );
00658 }
00659 
00660 void SlaveBase::sigsegv_handler (int)
00661 {
00662     signal(SIGSEGV,SIG_IGN);
00663     // Debug and printf should be avoided because they might
00664     // call malloc.. and get in a nice recursive malloc loop
00665     write(2, "kioslave : ###############SEG FAULT#############\n", 49);
00666     ::exit(1);
00667 }
00668 
00669 void SlaveBase::sigpipe_handler (int)
00670 {
00671     signal(SIGPIPE,SIG_IGN);
00672     // We ignore a SIGPIPE in slaves.
00673     // A SIGPIPE can happen in two cases:
00674     // 1) Communication error with application.
00675     // 2) Communication error with network.
00676     kdDebug(7019) << "SIGPIPE" << endl;
00677     signal(SIGPIPE,&sigpipe_handler);
00678     slaveWriteError = true;
00679 }
00680 
00681 void SlaveBase::setHost(QString const &, int, QString const &, QString const &)
00682 {
00683 }
00684 
00685 void SlaveBase::openConnection(void)
00686 { error(  ERR_UNSUPPORTED_ACTION, i18n("Opening connections is not supported with the protocol %1" ).arg(mProtocol)); }
00687 void SlaveBase::closeConnection(void)
00688 { } // No response!
00689 void SlaveBase::stat(KURL const &)
00690 { error(  ERR_UNSUPPORTED_ACTION, i18n("Accessing files is not supported with the protocol %1").arg(mProtocol) ); }
00691 void SlaveBase::put(KURL const &, int, bool, bool)
00692 { error(  ERR_UNSUPPORTED_ACTION, i18n("Writing to %1 is not supported").arg(mProtocol) ); }
00693 void SlaveBase::special(const QByteArray &)
00694 { error(  ERR_UNSUPPORTED_ACTION, i18n("There are no special actions available for protocol %1").arg(mProtocol) ); }
00695 void SlaveBase::listDir(KURL const &)
00696 { error(  ERR_UNSUPPORTED_ACTION, i18n("Listing directories is not supported for protocol %1").arg(mProtocol) ); }
00697 void SlaveBase::get(KURL const & )
00698 { error(  ERR_UNSUPPORTED_ACTION, i18n("Retrieving data from %1 is not supported").arg(mProtocol) ); }
00699 void SlaveBase::mimetype(KURL const &url)
00700 { get(url); }
00701 void SlaveBase::rename(KURL const &, KURL const &, bool)
00702 { error(  ERR_UNSUPPORTED_ACTION, i18n("Renaming or moving files within %1 is not supported").arg(mProtocol) ); }
00703 void SlaveBase::symlink(QString const &, KURL const &, bool)
00704 { error(  ERR_UNSUPPORTED_ACTION, i18n("Creating symlinks is not supported with protocol %1").arg(mProtocol) ); }
00705 void SlaveBase::copy(KURL const &, KURL const &, int, bool)
00706 { error(  ERR_UNSUPPORTED_ACTION, i18n("Copying files within %1 is not supported").arg(mProtocol) ); }
00707 void SlaveBase::del(KURL const &, bool)
00708 { error(  ERR_UNSUPPORTED_ACTION, i18n("Deleting files from %1 is not supported").arg(mProtocol) ); }
00709 void SlaveBase::mkdir(KURL const &, int)
00710 { error(  ERR_UNSUPPORTED_ACTION, i18n("Creating directories is not supported with protocol %1").arg(mProtocol) ); }
00711 void SlaveBase::chmod(KURL const &, int)
00712 { error(  ERR_UNSUPPORTED_ACTION, i18n("Changing the attributes of files is not supported with protocol %1").arg(mProtocol) ); }
00713 void SlaveBase::setSubURL(KURL const &)
00714 { error(  ERR_UNSUPPORTED_ACTION, i18n("Using sub-URLs with %1 is not supported").arg(mProtocol) ); }
00715 void SlaveBase::multiGet(const QByteArray &)
00716 { error(  ERR_UNSUPPORTED_ACTION, i18n("Multiple get is not supported with protocol %1").arg(mProtocol) ); }
00717 
00718 
00719 void SlaveBase::slave_status()
00720 { slaveStatus( QString::null, false ); }
00721 
00722 void SlaveBase::reparseConfiguration()
00723 {
00724 }
00725 
00726 bool SlaveBase::dispatch()
00727 {
00728     assert( m_pConnection );
00729 
00730     int cmd;
00731     QByteArray data;
00732     if ( m_pConnection->read( &cmd, data ) == -1 )
00733     {
00734         kdDebug(7019) << "SlaveBase::dispatch() has read error." << endl;
00735         return false;
00736     }
00737 
00738     dispatch( cmd, data );
00739     return true;
00740 }
00741 
00742 bool SlaveBase::openPassDlg( AuthInfo& info )
00743 {
00744     return openPassDlg(info, QString::null);
00745 }
00746 
00747 bool SlaveBase::openPassDlg( AuthInfo& info, const QString &errorMsg )
00748 {
00749     kdDebug(7019) << "SlaveBase::OpenPassDlg User= " << info.username << endl;
00750 
00751     QCString replyType;
00752     QByteArray params;
00753     QByteArray reply;
00754     AuthInfo authResult;
00755     long windowId = metaData("window-id").toLong();
00756 
00757     (void) dcopClient(); // Make sure to have a dcop client.
00758             
00759     QDataStream stream(params, IO_WriteOnly);
00760     stream << info << errorMsg << windowId << s_seqNr;
00761             
00762     if (!d->dcopClient->call( "kded", "kpasswdserver", "queryAuthInfo(KIO::AuthInfo, QString, long int, long int)",
00763                                params, replyType, reply ) )
00764     {
00765        kdWarning(7019) << "Can't communicate with kded!" << endl;
00766        return false;
00767     }
00768     
00769     if ( replyType == "KIO::AuthInfo" )
00770     {
00771        QDataStream stream2( reply, IO_ReadOnly );
00772        stream2 >> authResult >> s_seqNr;
00773     }
00774     else
00775     {
00776        kdError(7019) << "DCOP function queryAuthInfo(...) returns "
00777                      << replyType << ", expected KIO::AuthInfo" << endl;
00778        return false;
00779     }
00780 
00781     if (!authResult.isModified())
00782        return false;
00783 
00784     info = authResult;
00785     return true;
00786 }
00787 
00788 int SlaveBase::messageBox( MessageBoxType type, const QString &text, const QString &caption,
00789                            const QString &buttonYes, const QString &buttonNo )
00790 {
00791     kdDebug(7019) << "messageBox " << type << " " << text << " - " << caption << buttonYes << buttonNo << endl;
00792     KIO_DATA << (int)type << text << caption << buttonYes << buttonNo;
00793     m_pConnection->send( INF_MESSAGEBOX, data );
00794     if ( waitForAnswer( CMD_MESSAGEBOXANSWER, 0, data ) != -1 )
00795     {
00796         QDataStream stream( data, IO_ReadOnly );
00797         int answer;
00798         stream >> answer;
00799         kdDebug(7019) << "got messagebox answer" << answer << endl;
00800         return answer;
00801     } else
00802         return 0; // communication failure
00803 }
00804 
00805 bool SlaveBase::canResume( KIO::filesize_t offset )
00806 {
00807     kdDebug(7019) << "SlaveBase::canResume offset=" << KIO::number(offset) << endl;
00808     d->needSendCanResume = false;
00809     KIO_DATA << KIO_FILESIZE_T(offset);
00810     m_pConnection->send( MSG_RESUME, data );
00811     if ( offset )
00812     {
00813         int cmd;
00814         if ( waitForAnswer( CMD_RESUMEANSWER, CMD_NONE, data, &cmd ) != -1 )
00815         {
00816             kdDebug(7019) << "SlaveBase::canResume returning " << (cmd == CMD_RESUMEANSWER) << endl;
00817             return cmd == CMD_RESUMEANSWER;
00818         } else
00819             return false;
00820     }
00821     else // No resuming possible -> no answer to wait for
00822         return true;
00823 }
00824 
00825 
00826 
00827 int SlaveBase::waitForAnswer( int expected1, int expected2, QByteArray & data, int *pCmd )
00828 {
00829     int cmd, result;
00830     for (;;)
00831     {
00832         result = m_pConnection->read( &cmd, data );
00833         if ( result == -1 )
00834         {
00835             kdDebug(7019) << "SlaveBase::waitForAnswer has read error." << endl;
00836             return -1;
00837         }
00838         if ( cmd == expected1 || cmd == expected2 )
00839         {
00840             if ( pCmd ) *pCmd = cmd;
00841             return result;
00842         }
00843         if ( isSubCommand(cmd) )
00844         {
00845             dispatch( cmd, data );
00846         }
00847         else
00848         {
00849             kdWarning() << "Got cmd " << cmd << " while waiting for an answer!" << endl;
00850         }
00851     }
00852 }
00853 
00854 
00855 int SlaveBase::readData( QByteArray &buffer)
00856 {
00857    int result = waitForAnswer( MSG_DATA, 0, buffer );
00858    //kdDebug(7019) << "readData: length = " << result << " " << endl;
00859    return result;
00860 }
00861 
00862 void SlaveBase::setTimeoutSpecialCommand(int timeout, const QByteArray &data)
00863 {
00864    if (timeout > 0)
00865       d->timeout = time(0)+(time_t)timeout;
00866    else if (timeout == 0)
00867       d->timeout = 1; // Immediate timeout
00868    else
00869       d->timeout = 0; // Canceled
00870       
00871    d->timeoutData = data;
00872 }
00873 
00874 void SlaveBase::dispatch( int command, const QByteArray &data )
00875 {
00876     QDataStream stream( data, IO_ReadOnly );
00877 
00878     KURL url;
00879     int i;
00880 
00881     switch( command ) {
00882     case CMD_HOST: {
00883         // Reset s_seqNr, see kpasswdserver/DESIGN
00884         s_seqNr = 0;
00885         QString passwd;
00886         QString host, user;
00887         stream >> host >> i >> user >> passwd;
00888         setHost( host, i, user, passwd );
00889     }
00890     break;
00891     case CMD_CONNECT:
00892         openConnection( );
00893         break;
00894     case CMD_DISCONNECT:
00895         closeConnection( );
00896         break;
00897     case CMD_SLAVE_STATUS:
00898         slave_status();
00899         break;
00900     case CMD_SLAVE_CONNECT:
00901     {
00902         d->onHold = false;
00903         QString app_socket;
00904         QDataStream stream( data, IO_ReadOnly);
00905         stream >> app_socket;
00906         appconn->send( MSG_SLAVE_ACK );
00907         disconnectSlave();
00908         mConnectedToApp = true;
00909         connectSlave(app_socket);
00910     } break;
00911     case CMD_SLAVE_HOLD:
00912     {
00913         KURL url;
00914         QDataStream stream( data, IO_ReadOnly);
00915         stream >> url;
00916         d->onHoldUrl = url;
00917         d->onHold = true;
00918         disconnectSlave();
00919         mConnectedToApp = false;
00920         // Do not close connection!
00921         connectSlave(mPoolSocket);
00922     } break;
00923     case CMD_REPARSECONFIGURATION:
00924         reparseConfiguration();
00925         break;
00926     case CMD_CONFIG:
00927         stream >> d->configData;
00928         KSocks::setConfig(d->config);
00929         break;
00930     case CMD_GET:
00931     {
00932         stream >> url;
00933         get( url );
00934     } break;
00935     case CMD_PUT:
00936     {
00937         int permissions;
00938         Q_INT8 iOverwrite, iResume;
00939         stream >> url >> iOverwrite >> iResume >> permissions;
00940         bool overwrite = ( iOverwrite != 0 );
00941         bool resume = ( iResume != 0 );
00942 
00943         // Remember that we need to send canResume(), TransferJob is expecting
00944         // it. Well, in theory this shouldn't be done if resume is true.
00945         //   (the resume bool is currently unused)
00946         d->needSendCanResume = true   /* !resume */;
00947 
00948         put( url, permissions, overwrite, resume);
00949     } break;
00950     case CMD_STAT:
00951         stream >> url;
00952         stat( url );
00953         break;
00954     case CMD_MIMETYPE:
00955         stream >> url;
00956         mimetype( url );
00957         break;
00958     case CMD_LISTDIR:
00959         stream >> url;
00960         listDir( url );
00961         break;
00962     case CMD_MKDIR:
00963         stream >> url >> i;
00964         mkdir( url, i );
00965         break;
00966     case CMD_RENAME:
00967     {
00968         Q_INT8 iOverwrite;
00969         KURL url2;
00970         stream >> url >> url2 >> iOverwrite;
00971         bool overwrite = (iOverwrite != 0);
00972         rename( url, url2, overwrite );
00973     } break;
00974     case CMD_SYMLINK:
00975     {
00976         Q_INT8 iOverwrite;
00977         QString target;
00978         stream >> target >> url >> iOverwrite;
00979         bool overwrite = (iOverwrite != 0);
00980         symlink( target, url, overwrite );
00981     } break;
00982     case CMD_COPY:
00983     {
00984         int permissions;
00985         Q_INT8 iOverwrite;
00986         KURL url2;
00987         stream >> url >> url2 >> permissions >> iOverwrite;
00988         bool overwrite = (iOverwrite != 0);
00989         copy( url, url2, permissions, overwrite );
00990     } break;
00991     case CMD_DEL:
00992     {
00993         Q_INT8 isFile;
00994         stream >> url >> isFile;
00995         del( url, isFile != 0);
00996     } break;
00997     case CMD_CHMOD:
00998         stream >> url >> i;
00999         chmod( url, i);
01000         break;
01001     case CMD_SPECIAL:
01002         special( data );
01003         break;
01004     case CMD_META_DATA:
01005         //kdDebug(7019) << "(" << getpid() << ") Incoming meta-data..." << endl;
01006         stream >> mIncomingMetaData;
01007         break;
01008     case CMD_SUBURL:
01009         stream >> url;
01010         setSubURL(url);
01011         break;
01012     case CMD_NONE:
01013         fprintf(stderr, "Got unexpected CMD_NONE!\n");
01014         break;
01015     case CMD_MULTI_GET:
01016         multiGet( data );
01017         break;
01018     default:
01019         // Some command we don't understand.
01020         // Just ignore it, it may come from some future version of KDE.
01021         break;
01022     }
01023 }
01024 
01025 QString SlaveBase::createAuthCacheKey( const KURL& url )
01026 {
01027     if( url.isMalformed() )
01028         return QString::null;
01029 
01030     // Generate the basic key sequence.
01031     QString key = url.protocol();
01032     key += '-';
01033     key += url.host();
01034     int port = url.port();
01035     if( port )
01036     {
01037       key += ':';
01038       key += QString::number(port);
01039     }
01040 
01041     return key;
01042 }
01043 
01044 bool SlaveBase::pingCacheDaemon() const
01045 {
01046     // TODO: Ping kded / kpasswdserver
01047     KDEsuClient client;
01048     int sucess = client.ping();
01049     if( sucess == -1 )
01050     {
01051         sucess = client.startServer();
01052         if( sucess == -1 )
01053         {
01054             kdDebug(7019) << "Cannot start a new deamon!!" << endl;
01055             return false;
01056         }
01057         kdDebug(7019) << "Sucessfully started new cache deamon!!" << endl;
01058     }
01059     return true;
01060 }
01061 
01062 bool SlaveBase::checkCachedAuthentication( AuthInfo& info )
01063 {
01064     QCString replyType;
01065     QByteArray params;
01066     QByteArray reply;
01067     AuthInfo authResult;
01068     long windowId = metaData("window-id").toLong();
01069 
01070     kdDebug(7019) << "SlaveBase::checkCachedAuthInfo window = " << windowId << " url = " << info.url.url() << endl; 
01071 
01072     (void) dcopClient(); // Make sure to have a dcop client.
01073 
01074     QDataStream stream(params, IO_WriteOnly);
01075     stream << info << windowId;
01076 
01077     if ( !d->dcopClient->call( "kded", "kpasswdserver", "checkAuthInfo(KIO::AuthInfo, long int)",
01078                                params, replyType, reply ) )
01079     {
01080        kdWarning(7019) << "Can't communicate with kded!" << endl;
01081        return false;
01082     }
01083 
01084     if ( replyType == "KIO::AuthInfo" )
01085     {
01086        QDataStream stream2( reply, IO_ReadOnly );
01087        stream2 >> authResult;
01088     }
01089     else
01090     {
01091        kdError(7019) << "DCOP function checkAuthInfo(...) returns "
01092                      << replyType << ", expected KIO::AuthInfo" << endl;
01093        return false;
01094     }
01095     if (!authResult.isModified())
01096     {
01097        return false;
01098     }
01099 
01100     info = authResult;
01101     return true;
01102 }
01103 
01104 bool SlaveBase::storeAuthInfo( const QCString&, const QCString&,
01105                                const AuthInfo& )
01106 {
01107     // Obsolete
01108     return false;
01109 }
01110 
01111 bool SlaveBase::cacheAuthentication( const AuthInfo& info )
01112 {
01113     QByteArray params;
01114     long windowId = metaData("window-id").toLong();
01115 
01116     (void) dcopClient(); // Make sure to have a dcop client.
01117 
01118     QDataStream stream(params, IO_WriteOnly);
01119     stream << info << windowId;
01120 
01121     d->dcopClient->send( "kded", "kpasswdserver", "addAuthInfo(KIO::AuthInfo, long int)", params );
01122 
01123     return true;
01124 }
01125 
01126 void SlaveBase::setMultipleAuthCaching( bool enable )
01127 {
01128     d->multipleAuthCaching = enable;
01129 }
01130 
01131 bool SlaveBase::multipleAuthCaching() const
01132 {
01133     return d->multipleAuthCaching;
01134 }
01135 
01136 int SlaveBase::connectTimeout()
01137 {
01138     bool ok;
01139     QString tmp = metaData("ConnectTimeout");
01140     int result = tmp.toInt(&ok);
01141     if (ok)
01142        return result;
01143     return DEFAULT_CONNECT_TIMEOUT;
01144 }
01145 
01146 int SlaveBase::proxyConnectTimeout()
01147 {
01148     bool ok;
01149     QString tmp = metaData("ProxyConnectTimeout");
01150     int result = tmp.toInt(&ok);
01151     if (ok)
01152        return result;
01153     return DEFAULT_PROXY_CONNECT_TIMEOUT;
01154 }
01155 
01156 
01157 int SlaveBase::responseTimeout()
01158 {
01159     bool ok;
01160     QString tmp = metaData("ResponseTimeout");
01161     int result = tmp.toInt(&ok);
01162     if (ok)
01163        return result;
01164     return DEFAULT_RESPONSE_TIMEOUT;
01165 }
01166 
01167 
01168 int SlaveBase::readTimeout()
01169 {
01170     bool ok;
01171     QString tmp = metaData("ReadTimeout");
01172     int result = tmp.toInt(&ok);
01173     if (ok)
01174        return result;
01175     return DEFAULT_READ_TIMEOUT;
01176 }
01177 
01178 bool SlaveBase::wasKilled() const
01179 {
01180    return d->wasKilled;
01181 };
01182 
01183 void SlaveBase::setKillFlag()
01184 {
01185    d->wasKilled=true;
01186 };
01187 
01188 void SlaveBase::virtual_hook( int, void* )
01189 { /*BASE::virtual_hook( id, data );*/ }
01190 
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:21:33 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001