KIO
slaveinterface.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2000 David Faure <faure@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License version 2 as published by the Free Software Foundation. 00007 00008 This library is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 Library General Public License for more details. 00012 00013 You should have received a copy of the GNU Library General Public License 00014 along with this library; see the file COPYING.LIB. If not, write to 00015 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00016 Boston, MA 02110-1301, USA. 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 <kmessagebox.h> 00036 #include <time.h> 00037 #include <QtDBus/QtDBus> 00038 #include <QtCore/QPointer> 00039 #include <QtNetwork/QSslCertificate> 00040 #include <QtNetwork/QSslError> 00041 00042 using namespace KIO; 00043 00044 00045 SlaveInterface::SlaveInterface(SlaveInterfacePrivate &dd, QObject *parent) 00046 : QObject(parent), d_ptr(&dd) 00047 { 00048 connect(&d_ptr->speed_timer, SIGNAL(timeout()), SLOT(calcSpeed())); 00049 } 00050 00051 SlaveInterface::~SlaveInterface() 00052 { 00053 // Note: no kDebug() here (scheduler is deleted very late) 00054 00055 delete d_ptr; 00056 } 00057 00058 void SlaveInterface::setConnection( Connection* connection ) 00059 { 00060 Q_D(SlaveInterface); 00061 d->connection = connection; 00062 } 00063 00064 Connection *SlaveInterface::connection() const 00065 { 00066 const Q_D(SlaveInterface); 00067 return d->connection; 00068 } 00069 00070 static KIO::filesize_t readFilesize_t(QDataStream &stream) 00071 { 00072 KIO::filesize_t result; 00073 stream >> result; 00074 return result; 00075 } 00076 00077 bool SlaveInterface::dispatch() 00078 { 00079 Q_D(SlaveInterface); 00080 assert( d->connection ); 00081 00082 int cmd; 00083 QByteArray data; 00084 00085 int ret = d->connection->read( &cmd, data ); 00086 if (ret == -1) 00087 return false; 00088 00089 return dispatch( cmd, data ); 00090 } 00091 00092 void SlaveInterface::calcSpeed() 00093 { 00094 Q_D(SlaveInterface); 00095 if (d->slave_calcs_speed) { 00096 d->speed_timer.stop(); 00097 return; 00098 } 00099 00100 struct timeval tv; 00101 gettimeofday(&tv, 0); 00102 00103 long diff = ((tv.tv_sec - d->start_time.tv_sec) * 1000000 + 00104 tv.tv_usec - d->start_time.tv_usec) / 1000; 00105 if (diff - d->last_time >= 900) { 00106 d->last_time = diff; 00107 if (d->nums == max_nums) { 00108 // let's hope gcc can optimize that well enough 00109 // otherwise I'd try memcpy :) 00110 for (unsigned int i = 1; i < max_nums; ++i) { 00111 d->times[i-1] = d->times[i]; 00112 d->sizes[i-1] = d->sizes[i]; 00113 } 00114 d->nums--; 00115 } 00116 d->times[d->nums] = diff; 00117 d->sizes[d->nums++] = d->filesize - d->offset; 00118 00119 KIO::filesize_t lspeed = 1000 * (d->sizes[d->nums-1] - d->sizes[0]) / (d->times[d->nums-1] - d->times[0]); 00120 00121 // kDebug() << (long)d->filesize << diff 00122 // << long(d->sizes[d->nums-1] - d->sizes[0]) 00123 // << d->times[d->nums-1] - d->times[0] 00124 // << long(lspeed) << double(d->filesize) / diff 00125 // << convertSize(lspeed) 00126 // << convertSize(long(double(d->filesize) / diff) * 1000); 00127 00128 if (!lspeed) { 00129 d->nums = 1; 00130 d->times[0] = diff; 00131 d->sizes[0] = d->filesize - d->offset; 00132 } 00133 emit speed(lspeed); 00134 } 00135 } 00136 00137 #ifndef KDE_USE_FINAL // already defined in slavebase.cpp 00138 /* 00139 * Map pid_t to a signed integer type that makes sense for QByteArray; 00140 * only the most common sizes 16 bit and 32 bit are special-cased. 00141 */ 00142 template<int T> struct PIDType { typedef pid_t PID_t; } ; 00143 template<> struct PIDType<2> { typedef qint16 PID_t; } ; 00144 template<> struct PIDType<4> { typedef qint32 PID_t; } ; 00145 #endif 00146 00147 bool SlaveInterface::dispatch(int _cmd, const QByteArray &rawdata) 00148 { 00149 Q_D(SlaveInterface); 00150 //kDebug(7007) << "dispatch " << _cmd; 00151 00152 QDataStream stream(rawdata); 00153 00154 QString str1; 00155 qint32 i; 00156 qint8 b; 00157 quint32 ul; 00158 00159 switch(_cmd) { 00160 case MSG_DATA: 00161 emit data(rawdata); 00162 break; 00163 case MSG_DATA_REQ: 00164 emit dataReq(); 00165 break; 00166 case MSG_OPENED: 00167 emit open(); 00168 break; 00169 case MSG_FINISHED: 00170 //kDebug(7007) << "Finished [this = " << this << "]"; 00171 d->offset = 0; 00172 d->speed_timer.stop(); 00173 emit finished(); 00174 break; 00175 case MSG_STAT_ENTRY: { 00176 UDSEntry entry; 00177 stream >> entry; 00178 emit statEntry(entry); 00179 break; 00180 } 00181 case MSG_LIST_ENTRIES: { 00182 quint32 count; 00183 stream >> count; 00184 00185 UDSEntryList list; 00186 UDSEntry entry; 00187 for (uint i = 0; i < count; i++) { 00188 stream >> entry; 00189 list.append(entry); 00190 } 00191 emit listEntries(list); 00192 break; 00193 } 00194 case MSG_RESUME: { // From the put job 00195 d->offset = readFilesize_t(stream); 00196 emit canResume(d->offset); 00197 break; 00198 } 00199 case MSG_CANRESUME: // From the get job 00200 d->filesize = d->offset; 00201 emit canResume(0); // the arg doesn't matter 00202 break; 00203 case MSG_ERROR: 00204 stream >> i >> str1; 00205 kDebug(7007) << "error " << i << " " << str1; 00206 emit error(i, str1); 00207 break; 00208 case MSG_SLAVE_STATUS: { 00209 PIDType<sizeof(pid_t)>::PID_t stream_pid; 00210 pid_t pid; 00211 QByteArray protocol; 00212 stream >> stream_pid >> protocol >> str1 >> b; 00213 pid = stream_pid; 00214 emit slaveStatus(pid, protocol, str1, (b != 0)); 00215 break; 00216 } 00217 case MSG_CONNECTED: 00218 emit connected(); 00219 break; 00220 case MSG_WRITTEN: { 00221 KIO::filesize_t size = readFilesize_t(stream); 00222 emit written(size); 00223 break; 00224 } 00225 case INF_TOTAL_SIZE: { 00226 KIO::filesize_t size = readFilesize_t(stream); 00227 gettimeofday(&d->start_time, 0); 00228 d->last_time = 0; 00229 d->filesize = d->offset; 00230 d->sizes[0] = d->filesize - d->offset; 00231 d->times[0] = 0; 00232 d->nums = 1; 00233 d->speed_timer.start(1000); 00234 d->slave_calcs_speed = false; 00235 emit totalSize(size); 00236 break; 00237 } 00238 case INF_PROCESSED_SIZE: { 00239 KIO::filesize_t size = readFilesize_t(stream); 00240 emit processedSize( size ); 00241 d->filesize = size; 00242 break; 00243 } 00244 case INF_POSITION: { 00245 KIO::filesize_t pos = readFilesize_t(stream); 00246 emit position(pos); 00247 break; 00248 } 00249 case INF_SPEED: 00250 stream >> ul; 00251 d->slave_calcs_speed = true; 00252 d->speed_timer.stop(); 00253 emit speed( ul ); 00254 break; 00255 case INF_GETTING_FILE: 00256 break; 00257 case INF_ERROR_PAGE: 00258 emit errorPage(); 00259 break; 00260 case INF_REDIRECTION: { 00261 KUrl url; 00262 stream >> url; 00263 emit redirection( url ); 00264 break; 00265 } 00266 case INF_MIME_TYPE: 00267 stream >> str1; 00268 emit mimeType(str1); 00269 if (!d->connection->suspended()) 00270 d->connection->sendnow(CMD_NONE, QByteArray()); 00271 break; 00272 case INF_WARNING: 00273 stream >> str1; 00274 emit warning(str1); 00275 break; 00276 case INF_MESSAGEBOX: { 00277 kDebug(7007) << "needs a msg box"; 00278 QString text, caption, buttonYes, buttonNo, dontAskAgainName; 00279 int type; 00280 stream >> type >> text >> caption >> buttonYes >> buttonNo; 00281 if (stream.atEnd()) { 00282 messageBox(type, text, caption, buttonYes, buttonNo); 00283 } else { 00284 stream >> dontAskAgainName; 00285 messageBox(type, text, caption, buttonYes, buttonNo, dontAskAgainName); 00286 } 00287 break; 00288 } 00289 case INF_INFOMESSAGE: { 00290 QString msg; 00291 stream >> msg; 00292 emit infoMessage(msg); 00293 break; 00294 } 00295 case INF_META_DATA: { 00296 MetaData m; 00297 stream >> m; 00298 if (m.contains(QLatin1String("ssl_in_use"))) { 00299 const QLatin1String ssl_("ssl_"); 00300 const MetaData constM = m; 00301 for (MetaData::ConstIterator it = constM.lowerBound(ssl_); it != constM.constEnd(); ++it) { 00302 if (it.key().startsWith(ssl_)) { 00303 d->sslMetaData.insert(it.key(), it.value()); 00304 } else { 00305 // we're past the ssl_* entries; remember that QMap is ordered. 00306 break; 00307 } 00308 } 00309 } 00310 emit metaData(m); 00311 break; 00312 } 00313 case MSG_NET_REQUEST: { 00314 QString host; 00315 QString slaveid; 00316 stream >> host >> slaveid; 00317 requestNetwork(host, slaveid); 00318 break; 00319 } 00320 case MSG_NET_DROP: { 00321 QString host; 00322 QString slaveid; 00323 stream >> host >> slaveid; 00324 dropNetwork(host, slaveid); 00325 break; 00326 } 00327 case MSG_NEED_SUBURL_DATA: { 00328 emit needSubUrlData(); 00329 break; 00330 } 00331 case MSG_HOST_INFO_REQ: { 00332 QString hostName; 00333 stream >> hostName; 00334 HostInfo::lookupHost(hostName, this, SLOT(slotHostInfo(QHostInfo))); 00335 break; 00336 } 00337 default: 00338 kWarning(7007) << "Slave sends unknown command (" << _cmd << "), dropping slave"; 00339 return false; 00340 } 00341 return true; 00342 } 00343 00344 void SlaveInterface::setOffset( KIO::filesize_t o) 00345 { 00346 Q_D(SlaveInterface); 00347 d->offset = o; 00348 } 00349 00350 KIO::filesize_t SlaveInterface::offset() const 00351 { 00352 const Q_D(SlaveInterface); 00353 return d->offset; 00354 } 00355 00356 void SlaveInterface::requestNetwork(const QString &host, const QString &slaveid) 00357 { 00358 Q_D(SlaveInterface); 00359 kDebug(7007) << "requestNetwork " << host << slaveid; 00360 QByteArray packedArgs; 00361 QDataStream stream( &packedArgs, QIODevice::WriteOnly ); 00362 stream << true; 00363 d->connection->sendnow( INF_NETWORK_STATUS, packedArgs ); 00364 } 00365 00366 void SlaveInterface::dropNetwork(const QString &host, const QString &slaveid) 00367 { 00368 kDebug(7007) << "dropNetwork " << host << slaveid; 00369 } 00370 00371 void SlaveInterface::sendResumeAnswer( bool resume ) 00372 { 00373 Q_D(SlaveInterface); 00374 kDebug(7007) << "ok for resuming:" << resume; 00375 d->connection->sendnow( resume ? CMD_RESUMEANSWER : CMD_NONE, QByteArray() ); 00376 } 00377 00378 void SlaveInterface::messageBox( int type, const QString &text, const QString &_caption, 00379 const QString &buttonYes, const QString &buttonNo ) 00380 { 00381 messageBox( type, text, _caption, buttonYes, buttonNo, QString() ); 00382 } 00383 00384 void SlaveInterface::messageBox( int type, const QString &text, const QString &caption, 00385 const QString &buttonYes, const QString &buttonNo, const QString &dontAskAgainName ) 00386 { 00387 Q_D(SlaveInterface); 00388 kDebug(7007) << "messageBox " << type << " " << text << " - " << caption << " " << dontAskAgainName; 00389 QByteArray packedArgs; 00390 QDataStream stream( &packedArgs, QIODevice::WriteOnly ); 00391 00392 QPointer<SlaveInterface> me = this; 00393 if (d->connection) d->connection->suspend(); 00394 int result = d->messageBox( type, text, caption, buttonYes, buttonNo, dontAskAgainName ); 00395 if ( me && d->connection ) // Don't do anything if deleted meanwhile 00396 { 00397 d->connection->resume(); 00398 kDebug(7007) << this << " SlaveInterface result=" << result; 00399 stream << result; 00400 d->connection->sendnow( CMD_MESSAGEBOXANSWER, packedArgs ); 00401 } 00402 } 00403 00404 int SlaveInterfacePrivate::messageBox(int type, const QString &text, 00405 const QString &caption, const QString &buttonYes, 00406 const QString &buttonNo, const QString &dontAskAgainName) 00407 { 00408 kDebug() << type << text << "caption=" << caption; 00409 int result = -1; 00410 KConfig *config = new KConfig("kioslaverc"); 00411 KMessageBox::setDontShowAskAgainConfig(config); 00412 00413 // SMELL: the braindead way to support button icons 00414 KGuiItem buttonYesGui, buttonNoGui; 00415 00416 if (buttonYes == i18n("&Details")) 00417 buttonYesGui = KGuiItem(buttonYes, "help-about"); 00418 else if (buttonYes == i18n("&Forever")) 00419 buttonYesGui = KGuiItem(buttonYes, "flag-green"); 00420 else 00421 buttonYesGui = KGuiItem(buttonYes); 00422 00423 if (buttonNo == i18n("Co&ntinue")) 00424 buttonNoGui = KGuiItem(buttonNo, "arrow-right"); 00425 else if (buttonNo == i18n("&Current Session only")) 00426 buttonNoGui = KGuiItem(buttonNo, "chronometer"); 00427 else 00428 buttonNoGui = KGuiItem(buttonNo); 00429 00430 switch (type) { 00431 case KIO::SlaveBase::QuestionYesNo: 00432 result = KMessageBox::questionYesNo( 00433 0, text, caption, buttonYesGui, 00434 buttonNoGui, dontAskAgainName); 00435 break; 00436 case KIO::SlaveBase::WarningYesNo: 00437 result = KMessageBox::warningYesNo( 00438 0, text, caption, buttonYesGui, 00439 buttonNoGui, dontAskAgainName); 00440 break; 00441 case KIO::SlaveBase::WarningContinueCancel: 00442 result = KMessageBox::warningContinueCancel( 00443 0, text, caption, buttonYesGui, 00444 KStandardGuiItem::cancel(), dontAskAgainName); 00445 break; 00446 case KIO::SlaveBase::WarningYesNoCancel: 00447 result = KMessageBox::warningYesNoCancel( 00448 0, text, caption, buttonYesGui, buttonNoGui, 00449 KStandardGuiItem::cancel(), dontAskAgainName); 00450 break; 00451 case KIO::SlaveBase::Information: 00452 KMessageBox::information(0, text, caption, dontAskAgainName); 00453 result = 1; // whatever 00454 break; 00455 case KIO::SlaveBase::SSLMessageBox: 00456 { 00457 KIO::MetaData meta = sslMetaData; 00458 KSslInfoDialog *kid = new KSslInfoDialog(0); 00459 //### this is boilerplate code and appears in khtml_part.cpp almost unchanged! 00460 QStringList sl = meta["ssl_peer_chain"].split('\x01', QString::SkipEmptyParts); 00461 QList<QSslCertificate> certChain; 00462 bool decodedOk = true; 00463 foreach (const QString &s, sl) { 00464 certChain.append(QSslCertificate(s.toAscii())); //or is it toLocal8Bit or whatever? 00465 if (certChain.last().isNull()) { 00466 decodedOk = false; 00467 break; 00468 } 00469 } 00470 00471 if (decodedOk || true/*H4X*/) { 00472 kid->setSslInfo(certChain, 00473 meta["ssl_peer_ip"], 00474 text, // the URL 00475 meta["ssl_protocol_version"], 00476 meta["ssl_cipher"], 00477 meta["ssl_cipher_used_bits"].toInt(), 00478 meta["ssl_cipher_bits"].toInt(), 00479 KSslInfoDialog::errorsFromString(meta["ssl_cert_errors"])); 00480 kDebug(7024) << "Showing SSL Info dialog"; 00481 kid->exec(); 00482 kDebug(7024) << "SSL Info dialog closed"; 00483 } else { 00484 KMessageBox::information(0, i18n("The peer SSL certificate chain " 00485 "appears to be corrupt."), 00486 i18n("SSL")); 00487 } 00488 // KSslInfoDialog deletes itself (Qt::WA_DeleteOnClose). 00489 result = 1; // whatever 00490 break; 00491 } 00492 default: 00493 kWarning() << "unknown type" << type; 00494 result = 0; 00495 break; 00496 } 00497 KMessageBox::setDontShowAskAgainConfig(0); 00498 delete config; 00499 return result; 00500 } 00501 00502 void SlaveInterfacePrivate::slotHostInfo(const QHostInfo& info) 00503 { 00504 QByteArray data; 00505 QDataStream stream(&data, QIODevice::WriteOnly); 00506 stream << info.hostName() << info.addresses() << info.error() << info.errorString(); 00507 connection->send(CMD_HOST_INFO, data); 00508 } 00509 00510 #include "slaveinterface.moc"
KDE 4.6 API Reference