00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "slaveinterface.h"
00020 #include "slaveinterface_p.h"
00021
00022 #include "slavebase.h"
00023 #include "connection.h"
00024 #include <errno.h>
00025 #include <assert.h>
00026 #include <kdebug.h>
00027 #include <stdlib.h>
00028 #include <sys/time.h>
00029 #include <unistd.h>
00030 #include <signal.h>
00031 #include <klocale.h>
00032 #include <kapplication.h>
00033 #include <ksslinfodialog.h>
00034 #include <ksslcertificate.h>
00035 #include <ksslcertchain.h>
00036 #include <kmessagebox.h>
00037 #include <time.h>
00038 #include <QtDBus/QtDBus>
00039 #include <QtCore/QPointer>
00040 #include <QtNetwork/QSslCertificate>
00041 #include <QtNetwork/QSslError>
00042
00043 using namespace KIO;
00044
00045
00046 SlaveInterface::SlaveInterface(SlaveInterfacePrivate &dd, QObject *parent)
00047 : QObject(parent), d_ptr(&dd)
00048 {
00049 connect(&d_ptr->speed_timer, SIGNAL(timeout()), SLOT(calcSpeed()));
00050 }
00051
00052 SlaveInterface::~SlaveInterface()
00053 {
00054
00055
00056 delete d_ptr;
00057 }
00058
00059 void SlaveInterface::setConnection( Connection* connection )
00060 {
00061 Q_D(SlaveInterface);
00062 d->connection = connection;
00063 }
00064
00065 Connection *SlaveInterface::connection() const
00066 {
00067 const Q_D(SlaveInterface);
00068 return d->connection;
00069 }
00070
00071 static KIO::filesize_t readFilesize_t(QDataStream &stream)
00072 {
00073 KIO::filesize_t result;
00074 stream >> result;
00075 return result;
00076 }
00077
00078 bool SlaveInterface::dispatch()
00079 {
00080 Q_D(SlaveInterface);
00081 assert( d->connection );
00082
00083 int cmd;
00084 QByteArray data;
00085
00086 int ret = d->connection->read( &cmd, data );
00087 if (ret == -1)
00088 return false;
00089
00090 return dispatch( cmd, data );
00091 }
00092
00093 void SlaveInterface::calcSpeed()
00094 {
00095 Q_D(SlaveInterface);
00096 if (d->slave_calcs_speed) {
00097 d->speed_timer.stop();
00098 return;
00099 }
00100
00101 struct timeval tv;
00102 gettimeofday(&tv, 0);
00103
00104 long diff = ((tv.tv_sec - d->start_time.tv_sec) * 1000000 +
00105 tv.tv_usec - d->start_time.tv_usec) / 1000;
00106 if (diff - d->last_time >= 900) {
00107 d->last_time = diff;
00108 if (d->nums == max_nums) {
00109
00110
00111 for (unsigned int i = 1; i < max_nums; ++i) {
00112 d->times[i-1] = d->times[i];
00113 d->sizes[i-1] = d->sizes[i];
00114 }
00115 d->nums--;
00116 }
00117 d->times[d->nums] = diff;
00118 d->sizes[d->nums++] = d->filesize - d->offset;
00119
00120 KIO::filesize_t lspeed = 1000 * (d->sizes[d->nums-1] - d->sizes[0]) / (d->times[d->nums-1] - d->times[0]);
00121
00122
00123
00124
00125
00126
00127
00128
00129 if (!lspeed) {
00130 d->nums = 1;
00131 d->times[0] = diff;
00132 d->sizes[0] = d->filesize - d->offset;
00133 }
00134 emit speed(lspeed);
00135 }
00136 }
00137
00138 #ifndef KDE_USE_FINAL // already defined in slavebase.cpp
00139
00140
00141
00142
00143 template<int T> struct PIDType { typedef pid_t PID_t; } ;
00144 template<> struct PIDType<2> { typedef qint16 PID_t; } ;
00145 template<> struct PIDType<4> { typedef qint32 PID_t; } ;
00146 #endif
00147
00148 bool SlaveInterface::dispatch( int _cmd, const QByteArray &rawdata )
00149 {
00150 Q_D(SlaveInterface);
00151
00152
00153 QDataStream stream( rawdata );
00154
00155 QString str1;
00156 qint32 i;
00157 qint8 b;
00158 quint32 ul;
00159
00160 switch( _cmd ) {
00161 case MSG_DATA:
00162 emit data( rawdata );
00163 break;
00164 case MSG_DATA_REQ:
00165 emit dataReq();
00166 break;
00167 case MSG_OPENED: {
00168 emit open();
00169 break;
00170 }
00171 case MSG_FINISHED:
00172
00173 d->offset = 0;
00174 d->speed_timer.stop();
00175 emit finished();
00176 break;
00177 case MSG_STAT_ENTRY:
00178 {
00179 UDSEntry entry;
00180 stream >> entry;
00181 emit statEntry(entry);
00182 }
00183 break;
00184 case MSG_LIST_ENTRIES:
00185 {
00186 quint32 count;
00187 stream >> count;
00188
00189 UDSEntryList list;
00190 UDSEntry entry;
00191 for (uint i = 0; i < count; i++) {
00192 stream >> entry;
00193 list.append(entry);
00194 }
00195 emit listEntries(list);
00196
00197 }
00198 break;
00199 case MSG_RESUME:
00200 {
00201 d->offset = readFilesize_t(stream);
00202 emit canResume( d->offset );
00203 }
00204 break;
00205 case MSG_CANRESUME:
00206 d->filesize = d->offset;
00207 emit canResume(0);
00208 break;
00209 case MSG_ERROR:
00210 stream >> i >> str1;
00211 kDebug(7007) << "error " << i << " " << str1;
00212 emit error( i, str1 );
00213 break;
00214 case MSG_SLAVE_STATUS:
00215 {
00216 PIDType<sizeof(pid_t)>::PID_t stream_pid;
00217 pid_t pid;
00218 QByteArray protocol;
00219 stream >> stream_pid >> protocol >> str1 >> b;
00220 pid = stream_pid;
00221 emit slaveStatus(pid, protocol, str1, (b != 0));
00222 }
00223 break;
00224 case MSG_CONNECTED:
00225 emit connected();
00226 break;
00227
00228 case MSG_WRITTEN:
00229 {
00230 KIO::filesize_t size = readFilesize_t(stream);
00231 emit written( size );
00232 }
00233 break;
00234 case INF_TOTAL_SIZE:
00235 {
00236 KIO::filesize_t size = readFilesize_t(stream);
00237 gettimeofday(&d->start_time, 0);
00238 d->last_time = 0;
00239 d->filesize = d->offset;
00240 d->sizes[0] = d->filesize - d->offset;
00241 d->times[0] = 0;
00242 d->nums = 1;
00243 d->speed_timer.start(1000);
00244 d->slave_calcs_speed = false;
00245 emit totalSize( size );
00246 }
00247 break;
00248 case INF_PROCESSED_SIZE:
00249 {
00250 KIO::filesize_t size = readFilesize_t(stream);
00251 emit processedSize( size );
00252 d->filesize = size;
00253 }
00254 break;
00255 case INF_POSITION:
00256 {
00257 KIO::filesize_t pos = readFilesize_t(stream);
00258 emit position( pos );
00259 }
00260 break;
00261 case INF_SPEED:
00262 stream >> ul;
00263 d->slave_calcs_speed = true;
00264 d->speed_timer.stop();
00265
00266 emit speed( ul );
00267 break;
00268 case INF_GETTING_FILE:
00269 break;
00270 case INF_ERROR_PAGE:
00271 emit errorPage();
00272 break;
00273 case INF_REDIRECTION:
00274 {
00275 KUrl url;
00276 stream >> url;
00277
00278 emit redirection( url );
00279 }
00280 break;
00281 case INF_MIME_TYPE:
00282 stream >> str1;
00283
00284 emit mimeType( str1 );
00285 if (!d->connection->suspended())
00286 d->connection->sendnow( CMD_NONE, QByteArray() );
00287 break;
00288 case INF_WARNING:
00289 stream >> str1;
00290
00291 emit warning( str1 );
00292 break;
00293 case INF_MESSAGEBOX: {
00294 kDebug(7007) << "needs a msg box";
00295 QString text, caption, buttonYes, buttonNo, dontAskAgainName;
00296 int type;
00297 stream >> type >> text >> caption >> buttonYes >> buttonNo;
00298 if (stream.atEnd())
00299 messageBox(type, text, caption, buttonYes, buttonNo);
00300 else {
00301 stream >> dontAskAgainName;
00302 messageBox(type, text, caption, buttonYes, buttonNo, dontAskAgainName);
00303 }
00304 break;
00305 }
00306 case INF_INFOMESSAGE: {
00307 QString msg;
00308 stream >> msg;
00309 emit infoMessage(msg);
00310 break;
00311 }
00312 case INF_META_DATA: {
00313 MetaData meta_data;
00314 stream >> meta_data;
00315 d->m_incomingMetaData += meta_data;
00316
00317
00318 emit metaData(meta_data);
00319 break;
00320 }
00321 case MSG_NET_REQUEST: {
00322 QString host;
00323 QString slaveid;
00324 stream >> host >> slaveid;
00325 requestNetwork(host, slaveid);
00326 break;
00327 }
00328 case MSG_NET_DROP: {
00329 QString host;
00330 QString slaveid;
00331 stream >> host >> slaveid;
00332 dropNetwork(host, slaveid);
00333 break;
00334 }
00335 case MSG_NEED_SUBURL_DATA: {
00336 emit needSubUrlData();
00337 break;
00338 }
00339 default:
00340 kWarning(7007) << "Slave sends unknown command (" << _cmd << "), dropping slave";
00341 return false;
00342 }
00343 return true;
00344 }
00345
00346 void SlaveInterface::setOffset( KIO::filesize_t o)
00347 {
00348 Q_D(SlaveInterface);
00349 d->offset = o;
00350 }
00351
00352 KIO::filesize_t SlaveInterface::offset() const
00353 {
00354 const Q_D(SlaveInterface);
00355 return d->offset;
00356 }
00357
00358 void SlaveInterface::requestNetwork(const QString &host, const QString &slaveid)
00359 {
00360 Q_D(SlaveInterface);
00361 kDebug(7007) << "requestNetwork " << host << slaveid;
00362 QByteArray packedArgs;
00363 QDataStream stream( &packedArgs, QIODevice::WriteOnly );
00364 stream << true;
00365 d->connection->sendnow( INF_NETWORK_STATUS, packedArgs );
00366 }
00367
00368 void SlaveInterface::dropNetwork(const QString &host, const QString &slaveid)
00369 {
00370 kDebug(7007) << "dropNetwork " << host << slaveid;
00371 }
00372
00373 void SlaveInterface::sendResumeAnswer( bool resume )
00374 {
00375 Q_D(SlaveInterface);
00376 kDebug(7007) << "ok for resuming:" << resume;
00377 d->connection->sendnow( resume ? CMD_RESUMEANSWER : CMD_NONE, QByteArray() );
00378 }
00379
00380 void SlaveInterface::messageBox( int type, const QString &text, const QString &_caption,
00381 const QString &buttonYes, const QString &buttonNo )
00382 {
00383 messageBox( type, text, _caption, buttonYes, buttonNo, QString() );
00384 }
00385
00386 void SlaveInterface::messageBox( int type, const QString &text, const QString &caption,
00387 const QString &buttonYes, const QString &buttonNo, const QString &dontAskAgainName )
00388 {
00389 Q_D(SlaveInterface);
00390 kDebug(7007) << "messageBox " << type << " " << text << " - " << caption << " " << dontAskAgainName;
00391 QByteArray packedArgs;
00392 QDataStream stream( &packedArgs, QIODevice::WriteOnly );
00393
00394 QPointer<SlaveInterface> me = this;
00395 if (d->connection) d->connection->suspend();
00396 int result = d->messageBox( type, text, caption, buttonYes, buttonNo, dontAskAgainName );
00397 if ( me && d->connection )
00398 {
00399 d->connection->resume();
00400 kDebug(7007) << this << " SlaveInterface result=" << result;
00401 stream << result;
00402 d->connection->sendnow( CMD_MESSAGEBOXANSWER, packedArgs );
00403 }
00404 }
00405
00406 int SlaveInterfacePrivate::messageBox(int type, const QString &text,
00407 const QString &caption, const QString &buttonYes,
00408 const QString &buttonNo, const QString &dontAskAgainName)
00409 {
00410 kDebug() << type << text << "caption=" << caption;
00411 int result = -1;
00412 KConfig *config = new KConfig("kioslaverc");
00413 KMessageBox::setDontShowAskAgainConfig(config);
00414
00415 switch (type) {
00416 case KIO::SlaveBase::QuestionYesNo:
00417 result = KMessageBox::questionYesNo(
00418 0, text, caption, KGuiItem(buttonYes),
00419 KGuiItem(buttonNo), dontAskAgainName);
00420 break;
00421 case KIO::SlaveBase::WarningYesNo:
00422 result = KMessageBox::warningYesNo(
00423 0, text, caption, KGuiItem(buttonYes),
00424 KGuiItem(buttonNo), dontAskAgainName);
00425 break;
00426 case KIO::SlaveBase::WarningContinueCancel:
00427 result = KMessageBox::warningContinueCancel(
00428 0, text, caption, KGuiItem(buttonYes),
00429 KStandardGuiItem::cancel(), dontAskAgainName);
00430 break;
00431 case KIO::SlaveBase::WarningYesNoCancel:
00432 result = KMessageBox::warningYesNoCancel(
00433 0, text, caption, KGuiItem(buttonYes), KGuiItem(buttonNo),
00434 KStandardGuiItem::cancel(), dontAskAgainName);
00435 break;
00436 case KIO::SlaveBase::Information:
00437 KMessageBox::information(0, text, caption, dontAskAgainName);
00438 result = 1;
00439 break;
00440 case KIO::SlaveBase::SSLMessageBox:
00441 {
00442 KIO::MetaData meta = m_incomingMetaData;
00443 KSSLInfoDialog *kid = new KSSLInfoDialog(0);
00444
00445 QStringList sl = meta["ssl_peer_chain"].split('\x01', QString::SkipEmptyParts);
00446 QList<QSslCertificate> certChain;
00447 bool decodedOk = true;
00448 foreach (const QString &s, sl) {
00449 certChain.append(QSslCertificate(s.toAscii()));
00450 if (certChain.last().isNull()) {
00451 decodedOk = false;
00452 break;
00453 }
00454 }
00455
00456 sl = meta["ssl_cert_errors"].split('\n', QString::SkipEmptyParts);
00457 QList<QSslError::SslError> errors;
00458 foreach (const QString &s, sl) {
00459 bool didConvert;
00460 QSslError::SslError error = static_cast<QSslError::SslError>(s.toInt(&didConvert));
00461 if (!didConvert) {
00462 decodedOk = false;
00463 break;
00464 }
00465 errors.append(error);
00466 }
00467
00468 if (decodedOk || true) {
00469 kid->setSslInfo(certChain,
00470 meta["ssl_peer_ip"],
00471 text,
00472 meta["ssl_protocol_version"],
00473 meta["ssl_cipher"],
00474 meta["ssl_cipher_used_bits"].toInt(),
00475 meta["ssl_cipher_bits"].toInt(),
00476 errors);
00477 kDebug(7024) << "Showing SSL Info dialog";
00478 kid->exec();
00479 kDebug(7024) << "SSL Info dialog closed";
00480 } else {
00481 KMessageBox::information(0, i18n("The peer SSL certificate chain "
00482 "appears to be corrupt."),
00483 i18n("SSL"));
00484 }
00485
00486 result = 1;
00487 break;
00488 }
00489 default:
00490 kWarning() << "unknown type" << type;
00491 result = 0;
00492 break;
00493 }
00494 KMessageBox::setDontShowAskAgainConfig(0);
00495 delete config;
00496 return result;
00497 }
00498
00499 #include "slaveinterface.moc"