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