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