📄 slavebase.cpp
字号:
/* This file is part of the KDE project Copyright (C) 2000-2001 Simon Hausmann <hausmann@kde.org> Copyright (C) 2001 Dirk Mueller <mueller@kde.org> Copyright (C) 2002 Marc Espie <espie@nerim.net> Copyright (C) 2002 Paul Chitescu <paulc-devel@null.ro> Copyright (C) 2003 Luciano Montanaro <mikelima@cirulla.net> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.*/#include <config.h>#include "slavebase.h"#include "job.h"// for DAV in kio_http#include <qdom.h>#include "http.h"#include "kio_file.h"#if defined(ENABLE_FTP)#include "kio_ftp.h"#endif#include "slaveinterface.h"#include "connection.h"#include <qdatastream.h>#include <qcstring.h>#include <kconfig.h>#include <kdebug.h>#include <kremoteencoding.h>#include <assert.h>#include <sys/time.h>#include <sys/types.h>#include <sys/socket.h>#include <unistd.h>#include <stdlib.h>#include <errno.h>using namespace KIO;#define KIO_FILESIZE_T(x) (unsigned long)(x & 0xffffffff) << (unsigned long)(x >> 32)class SlaveConfig : public KConfigBackend{public: SlaveConfig( SlaveBase *slave ) : m_slave( slave ) {} virtual void load(); virtual void save(); virtual QString group(); virtual void setGroup( const QString &group ); virtual QStringList groupList() const; virtual bool hasGroup( const QString &group ) const; virtual bool hasKey( const QString &key ); virtual QMap<QString, QString> entryMap( const QString &group ); virtual bool lookup( const QString &key, QString &value ); virtual void put( const QString &key, const QString &value ); virtual bool deleteGroup( const QString &group ); virtual void deleteEntry( const QString& key );private: SlaveBase *m_slave;};void SlaveConfig::load(){}void SlaveConfig::save(){}QString SlaveConfig::group(){ return QString::null;}void SlaveConfig::setGroup( const QString & ){ assert( false );}QStringList SlaveConfig::groupList() const{ assert( false ); return QStringList();}bool SlaveConfig::hasGroup( const QString & ) const{ assert( false ); return false;}bool SlaveConfig::hasKey( const QString &key ){ return m_slave->hasMetaData( key );}QMap<QString, QString> SlaveConfig::entryMap( const QString & ){ assert( false ); return QMap<QString, QString>();}bool SlaveConfig::lookup( const QString &key, QString &value ){ bool hasMetaData = m_slave->hasMetaData( key ); if ( !hasMetaData ) return false; value = m_slave->metaData( key ); return true;}void SlaveConfig::put( const QString &, const QString & ){ assert( false );}bool SlaveConfig::deleteGroup( const QString & ){ assert( false ); return false;}void SlaveConfig::deleteEntry( const QString & ){ assert( false );}SlaveBase *SlaveBase::createSlave( const QString &prot ){ SlaveBase * res = 0; if ( false ) {} // Test first for externally defined protocols // so we can override the standard ones else if ( File::implementsProto( prot ) ) res = new File( prot ); else if ( prot == "http" ) res = new HTTPProtocol( prot.ascii(), "", "" );#if !defined(Q_WS_WIN) else if ( prot == "https" ) res = new HTTPProtocol( prot.ascii(), "", "" );#endif#if defined(ENABLE_FTP) else if ( prot == "ftp" ) res = new FtpSlave;#endif return res;}bool SlaveBase::knownProtocol( const QString &protocol ){ return ( protocol == "http" || protocol == "https" ||#if defined(ENABLE_FTP) protocol == "ftp" ||#endif File::implementsProto( protocol ) );}SlaveBase::SlaveBase( const QCString &protocol, const QCString &, const QCString & ) : mProtocol( protocol ), m_dcc( new DCOPClient ), m_remotefile(0), m_connection( 0 ), m_kconfig( new KConfig( new SlaveConfig( this ), true ) ), m_multipleAuthCaching( false ), m_timeout( 0 ){}SlaveBase::~SlaveBase(){ delete m_connection; delete m_dcc; delete m_kconfig; delete m_remotefile;}KRemoteEncoding *SlaveBase::remoteEncoding(){ if (m_remotefile != 0) return m_remotefile; return m_remotefile = new KRemoteEncoding(metaData("Charset").latin1());}void SlaveBase::dispatchLoop(){ assert( m_connection );#if defined(Q_WS_WIN) while ( 42 ) { QByteArray data; int cmd; m_connection->read( &cmd, data ); if ( cmd == CMD_DISCONNECT ) return; dispatch( cmd, data ); }#else fd_set fds; struct timeval tv; int retval; while ( 42 ) { if (m_timeout && (m_timeout < time(0))) { QByteArray data = m_timeoutData; m_timeout = 0; m_timeoutData = QByteArray(); special(data); } FD_ZERO( &fds ); FD_SET( m_connection->fd_from(), &fds ); tv.tv_sec = 30; tv.tv_usec = 0; retval = select( m_connection->fd_from() + 1, &fds, NULL, NULL, &tv ); if ( retval > 0 ) { if ( FD_ISSET( m_connection->fd_from(), &fds ) ) { int cmd; QByteArray data; if ( m_connection->read( &cmd, data ) != -1 ) dispatch( cmd, data ); else { kdDebug() << "SlaveBase: read() error " << errno << ", " << QString(strerror(errno)) << "! exiting!" << endl; ::exit( 0 ); } } } else if ( retval == -1 ) { kdDebug() << "SlaveBase: select() error " << errno << ", " << QString(strerror(errno)) << "! exiting!" << endl; ::exit( 0 ); } }#endif}void SlaveBase::data( const QByteArray &data ){ sendMetaData(); m_connection->send( MSG_DATA, data );}void SlaveBase::dataReq(){ sendMetaData(); m_connection->send( MSG_DATA_REQ );}void SlaveBase::error( int _errid, const QString &_text ){ m_incomingMetaData.clear(); mOutgoingMetaData.clear(); KIO_ARGS << _errid << _text; m_connection->send( MSG_ERROR, packedArgs );}void SlaveBase::connected(){}void SlaveBase::finished(){ sendMetaData(); m_connection->send( MSG_FINISHED );}void SlaveBase::slaveStatus( const QString &, bool ){}void SlaveBase::statEntry( const UDSEntry & ){}void SlaveBase::totalSize( KIO::filesize_t s ){ KIO_ARGS << KIO_FILESIZE_T(s); m_connection->send( INF_TOTAL_SIZE, packedArgs );}void SlaveBase::processedSize( KIO::filesize_t s ){ KIO_ARGS << KIO_FILESIZE_T(s); m_connection->send( INF_PROCESSED_SIZE, packedArgs );}void SlaveBase::speed( unsigned long ){}void SlaveBase::redirection( const KURL &url ){ KIO_ARGS << url; m_connection->send( INF_REDIRECTION, packedArgs );}void SlaveBase::errorPage(){ m_connection->send( INF_ERROR_PAGE );}void SlaveBase::mimeType( const QString &_type ){ kdDebug(7019) << "(" << getpid() << ") SlaveBase::mimeType '" << _type << "'" << endl; if ( !mOutgoingMetaData.isEmpty() ) { KIO_ARGS << mOutgoingMetaData; m_connection->send( INF_META_DATA, packedArgs ); } KIO_ARGS << _type; m_connection->send( INF_MIME_TYPE, packedArgs );}void SlaveBase::listEntry( const UDSEntry &, bool ){}void SlaveBase::infoMessage( const QString &msg ){ KIO_ARGS << msg; m_connection->send( INF_INFOMESSAGE, packedArgs );}bool SlaveBase::openPassDlg( AuthInfo &info, const QString& /*errorMsg*/ ){ KIO_ARGS << info; int cmd; m_connection->send( INF_NEED_PASSWD, packedArgs ); QByteArray replyData; if ( waitForAnswer( CMD_USERPASS, CMD_NONE, replyData, &cmd ) != -1 && cmd == CMD_USERPASS ) { AuthInfo res; QDataStream replyStream( replyData, IO_ReadOnly ); replyStream >> res; info.username = res.username; info.password = res.password; info.keepPassword = res.keepPassword; return true; } return false;}// This seems to have appeared in 3.3.something// I see no real difference with the one above except the arguments// are shuffled around?int SlaveBase::messageBox( const QString &text, MessageBoxType type, const QString &caption, const QString &buttonYes, const QString &buttonNo, const QString &){ // FIXME really look at this once it builds return messageBox((int)type,text,caption,buttonYes,buttonNo);}int SlaveBase::messageBox( int type, const QString &text, const QString &caption, const QString &buttonYes, const QString &buttonNo ){ KIO_ARGS << type << text << caption << buttonYes << buttonNo; m_connection->send( INF_MESSAGEBOX, packedArgs ); QByteArray replyData; if ( waitForAnswer( CMD_MESSAGEBOXANSWER, 0, replyData, 0 ) != -1 ) { QDataStream replyStream( replyData, IO_ReadOnly ); int answer; replyStream >> answer; return answer; } else { assert( false ); return 0; }}void SlaveBase::setMetaData( const QString &key, const QString &value ){ mOutgoingMetaData.insert( key, value );}bool SlaveBase::hasMetaData( const QString &key ) const{ if ( m_incomingMetaData.find( key ) != m_incomingMetaData.end() ) return true; if ( m_config.find( key ) != m_config.end() ) return true; return false;}QString SlaveBase::metaData( const QString &key ) const{ MetaData::ConstIterator it = m_incomingMetaData.find( key ); if ( it == m_incomingMetaData.end() ) { it = m_config.find( key ); if ( it == m_config.end() ) return QString::null; } return it.data();}void SlaveBase::setHost( const QString &, int , const QString &, const QString & ){}void SlaveBase::get( const KURL & ){}void SlaveBase::put( const KURL &, int , bool , bool ){}void SlaveBase::stat( const KURL & ){}void SlaveBase::mimetype( const KURL & ){}void SlaveBase::special( const QByteArray & ){}void SlaveBase::slave_status(){}void SlaveBase::reparseConfiguration(){}int SlaveBase::readData( QByteArray &buffer ){ return waitForAnswer( MSG_DATA, 0, buffer, 0 );}void SlaveBase::setTimeoutSpecialCommand(int timeout, const QByteArray &data){ if (timeout > 0) m_timeout = time(0) + (time_t)timeout; else if (timeout == 0) m_timeout = 1; // Immediate timeout else m_timeout = 0; // Canceled m_timeoutData = data;}bool SlaveBase::checkCachedAuthentication( AuthInfo &info ){ QCString replyType; QByteArray params, reply; QDataStream stream(params, IO_WriteOnly); QStringList result; stream << info.url.host() << info.realmValue; if (!m_dcc->call("authcache", "authcache", "searchAuthCache(QString,QString)", params, replyType, reply)) { kdWarning(7103) << "Can't communicate with authcache!" << endl; return false; } QDataStream stream2(reply, IO_ReadOnly); if(replyType != "QStringList") { kdError(7103) << "DCOP function searchAuthCache(...) returns " << replyType << ", expected QStringList" << endl; return false; } stream2 >> result; if(result.isEmpty()) return false; info.username = result[0]; info.password = result[1]; info.digestInfo = result[2]; return true;}void SlaveBase::cacheAuthentication( const AuthInfo &info ){ QByteArray params; QDataStream stream(params, IO_WriteOnly); stream << info.url.host() << info.realmValue << info.username << info.password << info.digestInfo; if (!m_dcc->send("authcache", "authcache", "storeAuthCache(QString,QString,QString,QString,QString)", params)) { kdWarning(7103) << "Can't communicate with authcache!" << endl; }}void SlaveBase::sendMetaData(){ if ( mOutgoingMetaData.isEmpty() ) return; KIO_ARGS << mOutgoingMetaData; m_connection->send( INF_META_DATA, packedArgs ); mOutgoingMetaData.clear();}void SlaveBase::dispatch( int command, const QByteArray &packedArgs ){ QDataStream stream( packedArgs, IO_ReadOnly ); KURL url; switch ( command ) { case CMD_GET: stream >> url; get( url ); break; case CMD_MIMETYPE: stream >> url; mimetype( url ); break; case CMD_META_DATA: stream >> m_incomingMetaData; break; case CMD_SPECIAL: special( packedArgs ); break; case CMD_HOST: { QString host, user, pass; Q_INT32 port; stream >> host >> port >> user >> pass; setHost( host, port, user, pass ); } break; case CMD_CONFIG: { stream >> m_config; } break; case CMD_NONE: break; default: assert( 0 ); }}// Needed by kdelibs 3.2bool SlaveBase::canResume( KIO::filesize_t offset ){ kdDebug(7019) << "SlaveBase::canResume offset=" << KIO::number(offset) << endl; KIO_ARGS << KIO_FILESIZE_T(offset); m_connection->send( MSG_RESUME, packedArgs ); if ( offset ) { int cmd; if ( waitForAnswer( CMD_RESUMEANSWER, CMD_NONE, packedArgs, &cmd ) != -1 ) { kdDebug(7019) << "SlaveBase::canResume returning " << (cmd == CMD_RESUMEANSWER) << endl; return cmd == CMD_RESUMEANSWER; } else return false; } else // No resuming possible -> no answer to wait for return true;}int SlaveBase::waitForAnswer( int expected1, int expected2, QByteArray &data, int *_cmd ){ int res; int cmd; while ( 42 ) { res = m_connection->read( &cmd, data ); if ( res == -1 ) return res; if ( cmd == expected1 || cmd == expected2 ) { if ( _cmd ) *_cmd = cmd; return res; } // ### if ( cmd == CMD_META_DATA ) dispatch( cmd, data ); else kdDebug() << "received unexpected command " << cmd << " while actually waiting for " << expected1 << endl; }}void SlaveBase::virtual_hook( int, void* ){ /*BASE::virtual_hook( id, data );*/ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -