slaveinterface.cpp
/* This file is part of the KDE libraries
Copyright (C) 2000 David Faure <faure@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
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 "kio/slaveinterface.h"
#include "kio/slavebase.h"
#include "kio/connection.h"
#include <errno.h>
#include <assert.h>
#include <kdebug.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <signal.h>
#include <kio/observer.h>
#include <kapplication.h>
#include <dcopclient.h>
#include <time.h>
#include <qtimer.h>
using namespace KIO;
QDataStream &operator <<(QDataStream &s, const KIO::UDSEntry &e )
{
// On 32-bit platforms we send UDS_SIZE with UDS_SIZE_LARGE in front
// of it to carry the 32 msb. We can't send a 64 bit UDS_SIZE because
// that would break the compatibility of the wire-protocol with KDE 2.
// We do the same on 64-bit platforms in case we run in a mixed 32/64bit
// environment.
Q_UINT32 size = 0;
KIO::UDSEntry::ConstIterator it = e.begin();
for( ; it != e.end(); ++it )
{
size++;
if ((*it).m_uds == KIO::UDS_SIZE)
size++;
}
s << size;
it = e.begin();
for( ; it != e.end(); ++it )
{
if ((*it).m_uds == KIO::UDS_SIZE)
{
KIO::UDSAtom a;
a.m_uds = KIO::UDS_SIZE_LARGE;
a.m_long = (*it).m_long >> 32;
s << a;
}
s << *it;
}
return s;
}
QDataStream &operator >>(QDataStream &s, KIO::UDSEntry &e )
{
e.clear();
Q_UINT32 size;
s >> size;
// On 32-bit platforms we send UDS_SIZE with UDS_SIZE_LARGE in front
// of it to carry the 32 msb. We can't send a 64 bit UDS_SIZE because
// that would break the compatibility of the wire-protocol with KDE 2.
// We do the same on 64-bit platforms in case we run in a mixed 32/64bit
// environment.
Q_LLONG msb = 0;
for(Q_UINT32 i = 0; i < size; i++)
{
KIO::UDSAtom a;
s >> a;
if (a.m_uds == KIO::UDS_SIZE_LARGE)
{
msb = a.m_long;
}
else
{
if (a.m_uds == KIO::UDS_SIZE)
{
if (a.m_long < 0)
a.m_long += (Q_LLONG) 1 << 32;
a.m_long += msb << 32;
}
e.append(a);
msb = 0;
}
}
return s;
}
static const unsigned int max_nums = 8;
class KIO::SlaveInterfacePrivate
{
public:
SlaveInterfacePrivate() {
slave_calcs_speed = false;
start_time.tv_sec = 0;
start_time.tv_usec = 0;
last_time = 0;
nums = 0;
filesize = 0;
offset = 0;
}
bool slave_calcs_speed;
struct timeval start_time;
uint nums;
long times[max_nums];
KIO::filesize_t sizes[max_nums];
size_t last_time;
KIO::filesize_t filesize, offset;
QTimer speed_timer;
};
SlaveInterface::SlaveInterface( Connection * connection )
{
m_pConnection = connection;
m_progressId = 0;
d = new SlaveInterfacePrivate;
connect(&d->speed_timer, SIGNAL(timeout()), SLOT(calcSpeed()));
}
SlaveInterface::~SlaveInterface()
{
// Note: no kdDebug() here (scheduler is deleted very late)
m_pConnection = 0; // a bit like the "wasDeleted" of QObject...
delete d;
}
static KIO::filesize_t readFilesize_t(QDataStream &stream)
{
KIO::filesize_t result;
unsigned long ul;
stream >> ul;
result = ul;
if (stream.atEnd())
return result;
stream >> ul;
result += ((KIO::filesize_t)ul) << 32;
return result;
}
bool SlaveInterface::dispatch()
{
assert( m_pConnection );
int cmd;
QByteArray data;
if (m_pConnection->read( &cmd, data ) == -1)
return false;
return dispatch( cmd, data );
}
void SlaveInterface::calcSpeed()
{
if (d->slave_calcs_speed) {
d->speed_timer.stop();
return;
}
struct timeval tv;
gettimeofday(&tv, 0);
long diff = ((tv.tv_sec - d->start_time.tv_sec) * 1000000 +
tv.tv_usec - d->start_time.tv_usec) / 1000;
if (diff - d->last_time >= 900) {
d->last_time = diff;
if (d->nums == max_nums) {
// let's hope gcc can optimize that well enough
// otherwise I'd try memcpy :)
for (unsigned int i = 1; i < max_nums; ++i) {
d->times[i-1] = d->times[i];
d->sizes[i-1] = d->sizes[i];
}
d->nums--;
}
d->times[d->nums] = diff;
d->sizes[d->nums++] = d->filesize - d->offset;
KIO::filesize_t lspeed = 1000 * (d->sizes[d->nums-1] - d->sizes[0]) / (d->times[d->nums-1] - d->times[0]);
// kdDebug() << "proceeed " << (long)d->filesize << " " << diff << " "
// << long(d->sizes[d->nums-1] - d->sizes[0]) << " "
// << d->times[d->nums-1] - d->times[0] << " "
// << long(lspeed) << " " << double(d->filesize) / diff
// << " " << convertSize(lspeed) << " "
// << convertSize(long(double(d->filesize) / diff) * 1000) << " "
// << endl ;
if (!lspeed) {
d->nums = 1;
d->times[0] = diff;
d->sizes[0] = d->filesize - d->offset;
}
emit speed(lspeed);
}
}
bool SlaveInterface::dispatch( int _cmd, const QByteArray &rawdata )
{
//kdDebug(7007) << "dispatch " << _cmd << endl;
QDataStream stream( rawdata, IO_ReadOnly );
QString str1;
Q_INT32 i;
Q_INT8 b;
Q_UINT32 ul;
switch( _cmd ) {
case MSG_DATA:
emit data( rawdata );
break;
case MSG_DATA_REQ:
emit dataReq();
break;
case MSG_FINISHED:
//kdDebug(7007) << "Finished [this = " << this << "]" << endl;
d->offset = 0;
d->speed_timer.stop();
emit finished();
break;
case MSG_STAT_ENTRY:
{
UDSEntry entry;
stream >> entry;
emit statEntry(entry);
}
break;
case MSG_LIST_ENTRIES:
{
Q_UINT32 count;
stream >> count;
UDSEntryList list;
UDSEntry entry;
for (uint i = 0; i < count; i++) {
stream >> entry;
list.append(entry);
}
emit listEntries(list);
}
break;
case MSG_RESUME: // From the put job
{
d->offset = readFilesize_t(stream);
emit canResume( d->offset );
}
break;
case MSG_CANRESUME: // From the get job
d->filesize = d->offset;
emit canResume(0); // the arg doesn't matter
break;
case MSG_ERROR:
stream >> i >> str1;
kdDebug(7007) << "error " << i << " " << str1 << endl;
emit error( i, str1 );
break;
case MSG_SLAVE_STATUS:
{
pid_t pid;
QCString protocol;
stream >> pid >> protocol >> str1 >> b;
emit slaveStatus(pid, protocol, str1, (b != 0));
}
break;
case MSG_CONNECTED:
emit connected();
break;
case INF_TOTAL_SIZE:
{
KIO::filesize_t size = readFilesize_t(stream);
gettimeofday(&d->start_time, 0);
d->last_time = 0;
d->filesize = d->offset;
d->sizes[0] = d->filesize - d->offset;
d->times[0] = 0;
d->nums = 1;
d->speed_timer.start(1000);
d->slave_calcs_speed = false;
emit totalSize( size );
}
break;
case INF_PROCESSED_SIZE:
{
KIO::filesize_t size = readFilesize_t(stream);
emit processedSize( size );
d->filesize = size;
}
break;
case INF_SPEED:
stream >> ul;
d->slave_calcs_speed = true;
d->speed_timer.stop();
emit speed( ul );
break;
case INF_GETTING_FILE:
break;
case INF_ERROR_PAGE:
emit errorPage();
break;
case INF_REDIRECTION:
{
KURL url;
stream >> url;
emit redirection( url );
}
break;
case INF_MIME_TYPE:
stream >> str1;
emit mimeType( str1 );
if (!m_pConnection->suspended())
m_pConnection->sendnow( CMD_NONE, QByteArray() );
break;
case INF_WARNING:
stream >> str1;
emit warning( str1 );
break;
case INF_NEED_PASSWD: {
AuthInfo info;
stream >> info;
openPassDlg( info );
break;
}
case INF_MESSAGEBOX: {
kdDebug(7007) << "needs a msg box" << endl;
QString text, caption, buttonYes, buttonNo, dontAskAgainName;
int type;
stream >> type >> text >> caption >> buttonYes >> buttonNo;
if (stream.atEnd())
messageBox(type, text, caption, buttonYes, buttonNo);
else {
stream >> dontAskAgainName;
messageBox(type, text, caption, buttonYes, buttonNo, dontAskAgainName);
}
break;
}
case INF_INFOMESSAGE: {
QString msg;
stream >> msg;
infoMessage(msg);
break;
}
case INF_META_DATA: {
MetaData meta_data;
stream >> meta_data;
metaData(meta_data);
break;
}
case MSG_NET_REQUEST: {
QString host;
QString slaveid;
stream >> host >> slaveid;
requestNetwork(host, slaveid);
break;
}
case MSG_NET_DROP: {
QString host;
QString slaveid;
stream >> host >> slaveid;
dropNetwork(host, slaveid);
break;
}
case MSG_NEED_SUBURL_DATA: {
emit needSubURLData();
break;
}
case MSG_AUTH_KEY: {
bool keep;
QCString key, group;
stream >> key >> group >> keep;
kdDebug(7007) << "Got auth-key: " << key << endl
<< " group-key: " << group << endl
<< " keep password: " << keep << endl;
emit authorizationKey( key, group, keep );
break;
}
case MSG_DEL_AUTH_KEY: {
QCString key;
stream >> key;
kdDebug(7007) << "Delete auth-key: " << key << endl;
emit delAuthorization( key );
}
default:
kdWarning(7007) << "Slave sends unknown command (" << _cmd << "), dropping slave" << endl;
return false;
}
return true;
}
void SlaveInterface::setOffset( KIO::filesize_t o)
{
d->offset = o;
}
KIO::filesize_t SlaveInterface::offset() const { return d->offset; }
void SlaveInterface::requestNetwork(const QString &host, const QString &slaveid)
{
kdDebug(7007) << "requestNetwork " << host << slaveid << endl;
QByteArray packedArgs;
QDataStream stream( packedArgs, IO_WriteOnly );
stream << true;
m_pConnection->sendnow( INF_NETWORK_STATUS, packedArgs );
}
void SlaveInterface::dropNetwork(const QString &host, const QString &slaveid)
{
kdDebug(7007) << "dropNetwork " << host << slaveid << endl;
}
void SlaveInterface::sendResumeAnswer( bool resume )
{
kdDebug(7007) << "SlaveInterface::sendResumeAnswer ok for resuming :" << resume << endl;
m_pConnection->sendnow( resume ? CMD_RESUMEANSWER : CMD_NONE, QByteArray() );
}
void SlaveInterface::openPassDlg( const QString& prompt, const QString& user, bool readOnly )
{
AuthInfo info;
info.prompt = prompt;
info.username = user;
info.readOnly = readOnly;
openPassDlg( info );
}
void SlaveInterface::openPassDlg( const QString& prompt, const QString& user,
const QString& caption, const QString& comment,
const QString& label, bool readOnly )
{
AuthInfo info;
info.prompt = prompt;
info.username = user;
info.caption = caption;
info.comment = comment;
info.commentLabel = label;
info.readOnly = readOnly;
openPassDlg( info );
}
void SlaveInterface::openPassDlg( AuthInfo& info )
{
kdDebug(7007) << "SlaveInterface::openPassDlg: "
<< "User= " << info.username
<< ", Message= " << info.prompt << endl;
bool result = Observer::self()->openPassDlg( info );
if ( m_pConnection )
{
QByteArray data;
QDataStream stream( data, IO_WriteOnly );
if ( result )
{
stream << info;
kdDebug(7007) << "SlaveInterface:::openPassDlg got: "
<< "User= " << info.username
<< ", Password= [hidden]" << endl;
m_pConnection->sendnow( CMD_USERPASS, data );
}
else
m_pConnection->sendnow( CMD_NONE, data );
}
}
void SlaveInterface::messageBox( int type, const QString &text, const QString &_caption,
const QString &buttonYes, const QString &buttonNo )
{
messageBox( type, text, _caption, buttonYes, buttonNo, QString::null );
}
void SlaveInterface::messageBox( int type, const QString &text, const QString &_caption,
const QString &buttonYes, const QString &buttonNo, const QString &dontAskAgainName )
{
kdDebug(7007) << "messageBox " << type << " " << text << " - " << _caption << " " << dontAskAgainName << endl;
QByteArray packedArgs;
QDataStream stream( packedArgs, IO_WriteOnly );
QString caption( _caption );
if ( type == KIO::SlaveBase::SSLMessageBox )
caption = QString::fromUtf8(kapp->dcopClient()->appId()); // hack, see observer.cpp
emit needProgressId();
kdDebug(7007) << "SlaveInterface::messageBox m_progressId=" << m_progressId << endl;
QGuardedPtr<SlaveInterface> me = this;
m_pConnection->suspend();
int result = Observer::/*self()->*/messageBox( m_progressId, type, text, caption, buttonYes, buttonNo, dontAskAgainName );
if ( me && m_pConnection ) // Don't do anything if deleted meanwhile
{
m_pConnection->resume();
kdDebug(7007) << this << " SlaveInterface result=" << result << endl;
stream << result;
m_pConnection->sendnow( CMD_MESSAGEBOXANSWER, packedArgs );
}
}
// No longer used.
// Remove in KDE 4.0
void SlaveInterface::sigpipe_handler(int)
{
int saved_errno = errno;
// Using kdDebug from a signal handler is not a good idea.
#ifndef NDEBUG
char msg[1000];
sprintf(msg, "*** SIGPIPE *** (ignored, pid = %ld)\n", (long) getpid());
write(2, msg, strlen(msg));
#endif
// Do nothing.
// dispatch will return false and that will trigger ERR_SLAVE_DIED in slave.cpp
errno = saved_errno;
}
void SlaveInterface::virtual_hook( int, void* )
{ /*BASE::virtual_hook( id, data );*/ }
#include "slaveinterface.moc"
KIO::Connection::sendnow
bool sendnow(int _cmd, const QByteArray &data)
Sends the given command immediately.
Definition: connection.cpp:175
KIO::AuthInfo::comment
QString comment
Additional comment to be displayed when prompting the user for authentication information.
Definition: authinfo.h:150
KIO::AuthInfo
This class is intended to make it easier to prompt for, cache and retrieve authorization information...
Definition: authinfo.h:51
KIO::UDS_SIZE
Size of the file.
Definition: global.h:316
KIO::AuthInfo::readOnly
bool readOnly
Flag which if set forces the username field to be read-only.
Definition: authinfo.h:207
KIO::MetaData
MetaData is a simple map of key/value strings.
Definition: global.h:512
KIO::Connection::suspend
void suspend()
Don't handle incoming data until resumed.
Definition: connection.cpp:65
KIO::Connection
This class provides a simple means for IPC between two applications via a pipe.
Definition: connection.h:49
KIO::SlaveInterface::sendResumeAnswer
void sendResumeAnswer(bool resume)
Send our answer to the MSG_RESUME (canResume) request (to tell the "put" job whether to resume or not...
Definition: slaveinterface.cpp:440
Observer
Observer for KIO::Job progress information.
Definition: observer.h:55
KIO::filesize_t
Q_ULLONG filesize_t
64-bit file size
Definition: global.h:39
KIO::Connection::resume
void resume()
Resume handling of incoming data.
Definition: connection.cpp:72
KIO::SlaveInterface::authorizationKey
void authorizationKey(const QCString &, const QCString &, bool)
KIO::Connection::suspended
bool suspended() const
Returns status of connection.
Definition: connection.h:135
KIO::UDSEntry
QValueList< UDSAtom > UDSEntry
An entry is the list of atoms containing all the informations for a file or URL.
Definition: global.h:504
Observer::openPassDlg
bool openPassDlg(const QString &prompt, QString &user, QString &pass, bool readOnly)
Definition: observer.cpp:221
KIO::SlaveInterface::openPassDlg
void openPassDlg(KIO::AuthInfo &info)
Prompt the user for authrization info (login & password).
Definition: slaveinterface.cpp:469
KIO::AuthInfo::username
QString username
This is required for caching.
Definition: authinfo.h:99
Observer::self
static Observer * self()
Returns the unique observer object.
Definition: observer.h:66
KIO::Connection::read
int read(int *_cmd, QByteArray &data)
Receive data.
Definition: connection.cpp:209
KIO::AuthInfo::caption
QString caption
The text to displayed in the title bar of the password prompting dialog.
Definition: authinfo.h:126
KIO::AuthInfo::commentLabel
QString commentLabel
Descriptive label to be displayed in front of the comment when prompting the user for password...
Definition: authinfo.h:159
KIO::SlaveInterface::delAuthorization
void delAuthorization(const QCString &grpkey)
KIO::AuthInfo::prompt
QString prompt
Information to be displayed when prompting the user for authentication information.
Definition: authinfo.h:115

KDE Home | KDE Accessibility Home | Description of Access Keys