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.2.5 2003/06/11 13:04:15 waba 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 genericsig_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 signal "<<sigNumber<<endl;
00137    //set the flag which will be checked in dispatchLoop() and which *should* be checked
00138    //in lengthy operations in the various slaves
00139    if (globalSlave!=0)
00140       globalSlave->setKillFlag();
00141    signal(SIGALRM,SIG_DFL);
00142    alarm(5);  //generate an alarm signal in 5 seconds, in this time the slave has to exit
00143 }
00144 
00146 
00147 SlaveBase::SlaveBase( const QCString &protocol,
00148                       const QCString &pool_socket,
00149                       const QCString &app_socket )
00150     : mProtocol(protocol), m_pConnection(0),
00151       mPoolSocket( QFile::decodeName(pool_socket)),
00152       mAppSocket( QFile::decodeName(app_socket))
00153 {
00154     if (!getenv("KDE_DEBUG"))
00155     {
00156         KCrash::setCrashHandler( sigsegv_handler );
00157         signal(SIGILL,&sigsegv_handler);
00158         signal(SIGTRAP,&sigsegv_handler);
00159         signal(SIGABRT,&sigsegv_handler);
00160         signal(SIGBUS,&sigsegv_handler);
00161         signal(SIGALRM,&sigsegv_handler);
00162         signal(SIGFPE,&sigsegv_handler);
00163 #ifdef SIGPOLL
00164         signal(SIGPOLL, &sigsegv_handler);
00165 #endif
00166 #ifdef SIGSYS
00167         signal(SIGSYS, &sigsegv_handler);
00168 #endif
00169 #ifdef SIGVTALRM
00170         signal(SIGVTALRM, &sigsegv_handler);
00171 #endif
00172 #ifdef SIGXCPU
00173         signal(SIGXCPU, &sigsegv_handler);
00174 #endif
00175 #ifdef SIGXFSZ
00176         signal(SIGXFSZ, &sigsegv_handler);
00177 #endif
00178     }
00179         
00180     struct sigaction act;
00181     act.sa_handler = sigpipe_handler;
00182     sigemptyset( &act.sa_mask );
00183     act.sa_flags = 0;
00184     sigaction( SIGPIPE, &act, 0 );
00185 
00186     signal(SIGINT,&genericsig_handler);
00187     signal(SIGQUIT,&genericsig_handler);
00188     signal(SIGTERM,&genericsig_handler);
00189 
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) && (errno != EINTR))
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 sig)
00661 {
00662     signal(sig,SIG_DFL); // Next one kills
00663 
00664     //Kill us if we deadlock
00665     signal(SIGALRM,SIG_DFL);
00666     alarm(5);  //generate an alarm signal in 5 seconds, in this time the slave has to exit
00667 
00668     // Debug and printf should be avoided because they might
00669     // call malloc.. and get in a nice recursive malloc loop
00670     char buffer[80];
00671     snprintf(buffer, sizeof(buffer), "kioslave: ####### CRASH ###### pid = %d signal = %d\n", getpid(), sig);
00672     write(2, buffer, strlen(buffer));
00673     ::exit(1);
00674 }
00675 
00676 void SlaveBase::sigpipe_handler (int)
00677 {
00678     // We ignore a SIGPIPE in slaves.
00679     // A SIGPIPE can happen in two cases:
00680     // 1) Communication error with application.
00681     // 2) Communication error with network.
00682     slaveWriteError = true;
00683     
00684     // Don't add anything else here, especially no debug output
00685 }
00686 
00687 void SlaveBase::setHost(QString const &, int, QString const &, QString const &)
00688 {
00689 }
00690 
00691 void SlaveBase::openConnection(void)
00692 { error(  ERR_UNSUPPORTED_ACTION, i18n("Opening connections is not supported with the protocol %1" ).arg(mProtocol)); }
00693 void SlaveBase::closeConnection(void)
00694 { } // No response!
00695 void SlaveBase::stat(KURL const &)
00696 { error(  ERR_UNSUPPORTED_ACTION, i18n("Accessing files is not supported with the protocol %1").arg(mProtocol) ); }
00697 void SlaveBase::put(KURL const &, int, bool, bool)
00698 { error(  ERR_UNSUPPORTED_ACTION, i18n("Writing to %1 is not supported").arg(mProtocol) ); }
00699 void SlaveBase::special(const QByteArray &)
00700 { error(  ERR_UNSUPPORTED_ACTION, i18n("There are no special actions available for protocol %1").arg(mProtocol) ); }
00701 void SlaveBase::listDir(KURL const &)
00702 { error(  ERR_UNSUPPORTED_ACTION, i18n("Listing directories is not supported for protocol %1").arg(mProtocol) ); }
00703 void SlaveBase::get(KURL const & )
00704 { error(  ERR_UNSUPPORTED_ACTION, i18n("Retrieving data from %1 is not supported").arg(mProtocol) ); }
00705 void SlaveBase::mimetype(KURL const &url)
00706 { get(url); }
00707 void SlaveBase::rename(KURL const &, KURL const &, bool)
00708 { error(  ERR_UNSUPPORTED_ACTION, i18n("Renaming or moving files within %1 is not supported").arg(mProtocol) ); }
00709 void SlaveBase::symlink(QString const &, KURL const &, bool)
00710 { error(  ERR_UNSUPPORTED_ACTION, i18n("Creating symlinks is not supported with protocol %1").arg(mProtocol) ); }
00711 void SlaveBase::copy(KURL const &, KURL const &, int, bool)
00712 { error(  ERR_UNSUPPORTED_ACTION, i18n("Copying files within %1 is not supported").arg(mProtocol) ); }
00713 void SlaveBase::del(KURL const &, bool)
00714 { error(  ERR_UNSUPPORTED_ACTION, i18n("Deleting files from %1 is not supported").arg(mProtocol) ); }
00715 void SlaveBase::mkdir(KURL const &, int)
00716 { error(  ERR_UNSUPPORTED_ACTION, i18n("Creating directories is not supported with protocol %1").arg(mProtocol) ); }
00717 void SlaveBase::chmod(KURL const &, int)
00718 { error(  ERR_UNSUPPORTED_ACTION, i18n("Changing the attributes of files is not supported with protocol %1").arg(mProtocol) ); }
00719 void SlaveBase::setSubURL(KURL const &)
00720 { error(  ERR_UNSUPPORTED_ACTION, i18n("Using sub-URLs with %1 is not supported").arg(mProtocol) ); }
00721 void SlaveBase::multiGet(const QByteArray &)
00722 { error(  ERR_UNSUPPORTED_ACTION, i18n("Multiple get is not supported with protocol %1").arg(mProtocol) ); }
00723 
00724 
00725 void SlaveBase::slave_status()
00726 { slaveStatus( QString::null, false ); }
00727 
00728 void SlaveBase::reparseConfiguration()
00729 {
00730 }
00731 
00732 bool SlaveBase::dispatch()
00733 {
00734     assert( m_pConnection );
00735 
00736     int cmd;
00737     QByteArray data;
00738     if ( m_pConnection->read( &cmd, data ) == -1 )
00739     {
00740         kdDebug(7019) << "SlaveBase::dispatch() has read error." << endl;
00741         return false;
00742     }
00743 
00744     dispatch( cmd, data );
00745     return true;
00746 }
00747 
00748 bool SlaveBase::openPassDlg( AuthInfo& info )
00749 {
00750     return openPassDlg(info, QString::null);
00751 }
00752 
00753 bool SlaveBase::openPassDlg( AuthInfo& info, const QString &errorMsg )
00754 {
00755     kdDebug(7019) << "SlaveBase::OpenPassDlg User= " << info.username << endl;
00756 
00757     QCString replyType;
00758     QByteArray params;
00759     QByteArray reply;
00760     AuthInfo authResult;
00761     long windowId = metaData("window-id").toLong();
00762 
00763     (void) dcopClient(); // Make sure to have a dcop client.
00764             
00765     QDataStream stream(params, IO_WriteOnly);
00766     
00767     if (metaData("no-auth-prompt").lower() == "true")
00768        stream << info << QString("<NoAuthPrompt>") << windowId << s_seqNr;
00769     else
00770        stream << info << errorMsg << windowId << s_seqNr;
00771             
00772     if (!d->dcopClient->call( "kded", "kpasswdserver", "queryAuthInfo(KIO::AuthInfo, QString, long int, long int)",
00773                                params, replyType, reply ) )
00774     {
00775        kdWarning(7019) << "Can't communicate with kded!" << endl;
00776        return false;
00777     }
00778     
00779     if ( replyType == "KIO::AuthInfo" )
00780     {
00781        QDataStream stream2( reply, IO_ReadOnly );
00782        stream2 >> authResult >> s_seqNr;
00783     }
00784     else
00785     {
00786        kdError(7019) << "DCOP function queryAuthInfo(...) returns "
00787                      << replyType << ", expected KIO::AuthInfo" << endl;
00788        return false;
00789     }
00790 
00791     if (!authResult.isModified())
00792        return false;
00793 
00794     info = authResult;
00795     return true;
00796 }
00797 
00798 int SlaveBase::messageBox( MessageBoxType type, const QString &text, const QString &caption,
00799                            const QString &buttonYes, const QString &buttonNo )
00800 {
00801     kdDebug(7019) << "messageBox " << type << " " << text << " - " << caption << buttonYes << buttonNo << endl;
00802     KIO_DATA << (int)type << text << caption << buttonYes << buttonNo;
00803     m_pConnection->send( INF_MESSAGEBOX, data );
00804     if ( waitForAnswer( CMD_MESSAGEBOXANSWER, 0, data ) != -1 )
00805     {
00806         QDataStream stream( data, IO_ReadOnly );
00807         int answer;
00808         stream >> answer;
00809         kdDebug(7019) << "got messagebox answer" << answer << endl;
00810         return answer;
00811     } else
00812         return 0; // communication failure
00813 }
00814 
00815 bool SlaveBase::canResume( KIO::filesize_t offset )
00816 {
00817     kdDebug(7019) << "SlaveBase::canResume offset=" << KIO::number(offset) << endl;
00818     d->needSendCanResume = false;
00819     KIO_DATA << KIO_FILESIZE_T(offset);
00820     m_pConnection->send( MSG_RESUME, data );
00821     if ( offset )
00822     {
00823         int cmd;
00824         if ( waitForAnswer( CMD_RESUMEANSWER, CMD_NONE, data, &cmd ) != -1 )
00825         {
00826             kdDebug(7019) << "SlaveBase::canResume returning " << (cmd == CMD_RESUMEANSWER) << endl;
00827             return cmd == CMD_RESUMEANSWER;
00828         } else
00829             return false;
00830     }
00831     else // No resuming possible -> no answer to wait for
00832         return true;
00833 }
00834 
00835 
00836 
00837 int SlaveBase::waitForAnswer( int expected1, int expected2, QByteArray & data, int *pCmd )
00838 {
00839     int cmd, result;
00840     for (;;)
00841     {
00842         result = m_pConnection->read( &cmd, data );
00843         if ( result == -1 )
00844         {
00845             kdDebug(7019) << "SlaveBase::waitForAnswer has read error." << endl;
00846             return -1;
00847         }
00848         if ( cmd == expected1 || cmd == expected2 )
00849         {
00850             if ( pCmd ) *pCmd = cmd;
00851             return result;
00852         }
00853         if ( isSubCommand(cmd) )
00854         {
00855             dispatch( cmd, data );
00856         }
00857         else
00858         {
00859             kdWarning() << "Got cmd " << cmd << " while waiting for an answer!" << endl;
00860         }
00861     }
00862 }
00863 
00864 
00865 int SlaveBase::readData( QByteArray &buffer)
00866 {
00867    int result = waitForAnswer( MSG_DATA, 0, buffer );
00868    //kdDebug(7019) << "readData: length = " << result << " " << endl;
00869    return result;
00870 }
00871 
00872 void SlaveBase::setTimeoutSpecialCommand(int timeout, const QByteArray &data)
00873 {
00874    if (timeout > 0)
00875       d->timeout = time(0)+(time_t)timeout;
00876    else if (timeout == 0)
00877       d->timeout = 1; // Immediate timeout
00878    else
00879       d->timeout = 0; // Canceled
00880       
00881    d->timeoutData = data;
00882 }
00883 
00884 void SlaveBase::dispatch( int command, const QByteArray &data )
00885 {
00886     QDataStream stream( data, IO_ReadOnly );
00887 
00888     KURL url;
00889     int i;
00890 
00891     switch( command ) {
00892     case CMD_HOST: {
00893         // Reset s_seqNr, see kpasswdserver/DESIGN
00894         s_seqNr = 0;
00895         QString passwd;
00896         QString host, user;
00897         stream >> host >> i >> user >> passwd;
00898         setHost( host, i, user, passwd );
00899     }
00900     break;
00901     case CMD_CONNECT:
00902         openConnection( );
00903         break;
00904     case CMD_DISCONNECT:
00905         closeConnection( );
00906         break;
00907     case CMD_SLAVE_STATUS:
00908         slave_status();
00909         break;
00910     case CMD_SLAVE_CONNECT:
00911     {
00912         d->onHold = false;
00913         QString app_socket;
00914         QDataStream stream( data, IO_ReadOnly);
00915         stream >> app_socket;
00916         appconn->send( MSG_SLAVE_ACK );
00917         disconnectSlave();
00918         mConnectedToApp = true;
00919         connectSlave(app_socket);
00920     } break;
00921     case CMD_SLAVE_HOLD:
00922     {
00923         KURL url;
00924         QDataStream stream( data, IO_ReadOnly);
00925         stream >> url;
00926         d->onHoldUrl = url;
00927         d->onHold = true;
00928         disconnectSlave();
00929         mConnectedToApp = false;
00930         // Do not close connection!
00931         connectSlave(mPoolSocket);
00932     } break;
00933     case CMD_REPARSECONFIGURATION:
00934         reparseConfiguration();
00935         break;
00936     case CMD_CONFIG:
00937         stream >> d->configData;
00938         KSocks::setConfig(d->config);
00939         break;
00940     case CMD_GET:
00941     {
00942         stream >> url;
00943         get( url );
00944     } break;
00945     case CMD_PUT:
00946     {
00947         int permissions;
00948         Q_INT8 iOverwrite, iResume;
00949         stream >> url >> iOverwrite >> iResume >> permissions;
00950         bool overwrite = ( iOverwrite != 0 );
00951         bool resume = ( iResume != 0 );
00952 
00953         // Remember that we need to send canResume(), TransferJob is expecting
00954         // it. Well, in theory this shouldn't be done if resume is true.
00955         //   (the resume bool is currently unused)
00956         d->needSendCanResume = true   /* !resume */;
00957 
00958         put( url, permissions, overwrite, resume);
00959     } break;
00960     case CMD_STAT:
00961         stream >> url;
00962         stat( url );
00963         break;
00964     case CMD_MIMETYPE:
00965         stream >> url;
00966         mimetype( url );
00967         break;
00968     case CMD_LISTDIR:
00969         stream >> url;
00970         listDir( url );
00971         break;
00972     case CMD_MKDIR:
00973         stream >> url >> i;
00974         mkdir( url, i );
00975         break;
00976     case CMD_RENAME:
00977     {
00978         Q_INT8 iOverwrite;
00979         KURL url2;
00980         stream >> url >> url2 >> iOverwrite;
00981         bool overwrite = (iOverwrite != 0);
00982         rename( url, url2, overwrite );
00983     } break;
00984     case CMD_SYMLINK:
00985     {
00986         Q_INT8 iOverwrite;
00987         QString target;
00988         stream >> target >> url >> iOverwrite;
00989         bool overwrite = (iOverwrite != 0);
00990         symlink( target, url, overwrite );
00991     } break;
00992     case CMD_COPY:
00993     {
00994         int permissions;
00995         Q_INT8 iOverwrite;
00996         KURL url2;
00997         stream >> url >> url2 >> permissions >> iOverwrite;
00998         bool overwrite = (iOverwrite != 0);
00999         copy( url, url2, permissions, overwrite );
01000     } break;
01001     case CMD_DEL:
01002     {
01003         Q_INT8 isFile;
01004         stream >> url >> isFile;
01005         del( url, isFile != 0);
01006     } break;
01007     case CMD_CHMOD:
01008         stream >> url >> i;
01009         chmod( url, i);
01010         break;
01011     case CMD_SPECIAL:
01012         special( data );
01013         break;
01014     case CMD_META_DATA:
01015         //kdDebug(7019) << "(" << getpid() << ") Incoming meta-data..." << endl;
01016         stream >> mIncomingMetaData;
01017         break;
01018     case CMD_SUBURL:
01019         stream >> url;
01020         setSubURL(url);
01021         break;
01022     case CMD_NONE:
01023         fprintf(stderr, "Got unexpected CMD_NONE!\n");
01024         break;
01025     case CMD_MULTI_GET:
01026         multiGet( data );
01027         break;
01028     default:
01029         // Some command we don't understand.
01030         // Just ignore it, it may come from some future version of KDE.
01031         break;
01032     }
01033 }
01034 
01035 QString SlaveBase::createAuthCacheKey( const KURL& url )
01036 {
01037     if( url.isMalformed() )
01038         return QString::null;
01039 
01040     // Generate the basic key sequence.
01041     QString key = url.protocol();
01042     key += '-';
01043     key += url.host();
01044     int port = url.port();
01045     if( port )
01046     {
01047       key += ':';
01048       key += QString::number(port);
01049     }
01050 
01051     return key;
01052 }
01053 
01054 bool SlaveBase::pingCacheDaemon() const
01055 {
01056     // TODO: Ping kded / kpasswdserver
01057     KDEsuClient client;
01058     int sucess = client.ping();
01059     if( sucess == -1 )
01060     {
01061         sucess = client.startServer();
01062         if( sucess == -1 )
01063         {
01064             kdDebug(7019) << "Cannot start a new deamon!!" << endl;
01065             return false;
01066         }
01067         kdDebug(7019) << "Sucessfully started new cache deamon!!" << endl;
01068     }
01069     return true;
01070 }
01071 
01072 bool SlaveBase::checkCachedAuthentication( AuthInfo& info )
01073 {
01074     QCString replyType;
01075     QByteArray params;
01076     QByteArray reply;
01077     AuthInfo authResult;
01078     long windowId = metaData("window-id").toLong();
01079 
01080     kdDebug(7019) << "SlaveBase::checkCachedAuthInfo window = " << windowId << " url = " << info.url.url() << endl; 
01081 
01082     (void) dcopClient(); // Make sure to have a dcop client.
01083 
01084     QDataStream stream(params, IO_WriteOnly);
01085     stream << info << windowId;
01086 
01087     if ( !d->dcopClient->call( "kded", "kpasswdserver", "checkAuthInfo(KIO::AuthInfo, long int)",
01088                                params, replyType, reply ) )
01089     {
01090        kdWarning(7019) << "Can't communicate with kded!" << endl;
01091        return false;
01092     }
01093 
01094     if ( replyType == "KIO::AuthInfo" )
01095     {
01096        QDataStream stream2( reply, IO_ReadOnly );
01097        stream2 >> authResult;
01098     }
01099     else
01100     {
01101        kdError(7019) << "DCOP function checkAuthInfo(...) returns "
01102                      << replyType << ", expected KIO::AuthInfo" << endl;
01103        return false;
01104     }
01105     if (!authResult.isModified())
01106     {
01107        return false;
01108     }
01109 
01110     info = authResult;
01111     return true;
01112 }
01113 
01114 bool SlaveBase::storeAuthInfo( const QCString&, const QCString&,
01115                                const AuthInfo& )
01116 {
01117     // Obsolete
01118     return false;
01119 }
01120 
01121 bool SlaveBase::cacheAuthentication( const AuthInfo& info )
01122 {
01123     QByteArray params;
01124     long windowId = metaData("window-id").toLong();
01125 
01126     (void) dcopClient(); // Make sure to have a dcop client.
01127 
01128     QDataStream stream(params, IO_WriteOnly);
01129     stream << info << windowId;
01130 
01131     d->dcopClient->send( "kded", "kpasswdserver", "addAuthInfo(KIO::AuthInfo, long int)", params );
01132 
01133     return true;
01134 }
01135 
01136 void SlaveBase::setMultipleAuthCaching( bool enable )
01137 {
01138     d->multipleAuthCaching = enable;
01139 }
01140 
01141 bool SlaveBase::multipleAuthCaching() const
01142 {
01143     return d->multipleAuthCaching;
01144 }
01145 
01146 int SlaveBase::connectTimeout()
01147 {
01148     bool ok;
01149     QString tmp = metaData("ConnectTimeout");
01150     int result = tmp.toInt(&ok);
01151     if (ok)
01152        return result;
01153     return DEFAULT_CONNECT_TIMEOUT;
01154 }
01155 
01156 int SlaveBase::proxyConnectTimeout()
01157 {
01158     bool ok;
01159     QString tmp = metaData("ProxyConnectTimeout");
01160     int result = tmp.toInt(&ok);
01161     if (ok)
01162        return result;
01163     return DEFAULT_PROXY_CONNECT_TIMEOUT;
01164 }
01165 
01166 
01167 int SlaveBase::responseTimeout()
01168 {
01169     bool ok;
01170     QString tmp = metaData("ResponseTimeout");
01171     int result = tmp.toInt(&ok);
01172     if (ok)
01173        return result;
01174     return DEFAULT_RESPONSE_TIMEOUT;
01175 }
01176 
01177 
01178 int SlaveBase::readTimeout()
01179 {
01180     bool ok;
01181     QString tmp = metaData("ReadTimeout");
01182     int result = tmp.toInt(&ok);
01183     if (ok)
01184        return result;
01185     return DEFAULT_READ_TIMEOUT;
01186 }
01187 
01188 bool SlaveBase::wasKilled() const
01189 {
01190    return d->wasKilled;
01191 }
01192 
01193 void SlaveBase::setKillFlag()
01194 {
01195    d->wasKilled=true;
01196 }
01197 
01198 void SlaveBase::virtual_hook( int, void* )
01199 { /*BASE::virtual_hook( id, data );*/ }
01200 
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:15:33 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001