File indexing completed on 2024-04-28 03:55:19
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2000 David Faure <faure@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only 0006 */ 0007 0008 #include "workerinterface_p.h" 0009 0010 #include "commands_p.h" 0011 #include "connection_p.h" 0012 #include "hostinfo.h" 0013 #include "kiocoredebug.h" 0014 #include "usernotificationhandler_p.h" 0015 #include "workerbase.h" 0016 0017 #include <KLocalizedString> 0018 #include <signal.h> 0019 #include <time.h> 0020 0021 #include <QDataStream> 0022 #include <QDateTime> 0023 0024 using namespace KIO; 0025 0026 Q_GLOBAL_STATIC(UserNotificationHandler, globalUserNotificationHandler) 0027 0028 WorkerInterface::WorkerInterface(QObject *parent) 0029 : QObject(parent) 0030 { 0031 connect(&m_speed_timer, &QTimer::timeout, this, &WorkerInterface::calcSpeed); 0032 } 0033 0034 WorkerInterface::~WorkerInterface() 0035 { 0036 // Note: no Debug() here (scheduler is deleted very late) 0037 0038 delete m_connection; 0039 } 0040 0041 static KIO::filesize_t readFilesize_t(QDataStream &stream) 0042 { 0043 KIO::filesize_t result; 0044 stream >> result; 0045 return result; 0046 } 0047 0048 bool WorkerInterface::dispatch() 0049 { 0050 Q_ASSERT(m_connection); 0051 0052 int cmd; 0053 QByteArray data; 0054 0055 int ret = m_connection->read(&cmd, data); 0056 if (ret == -1) { 0057 return false; 0058 } 0059 0060 return dispatch(cmd, data); 0061 } 0062 0063 void WorkerInterface::calcSpeed() 0064 { 0065 if (m_worker_calcs_speed || !m_connection->isConnected()) { // killing a job results in disconnection but the timer never stops 0066 m_speed_timer.stop(); 0067 return; 0068 } 0069 0070 const qint64 currentTime = QDateTime::currentMSecsSinceEpoch(); 0071 const qint64 diff = currentTime - m_start_time; 0072 if (diff - m_last_time >= 900) { 0073 m_last_time = diff; 0074 if (m_nums == max_nums) { 0075 // let's hope gcc can optimize that well enough 0076 // otherwise I'd try memcpy :) 0077 for (unsigned int i = 1; i < max_nums; ++i) { 0078 m_times[i - 1] = m_times[i]; 0079 m_sizes[i - 1] = m_sizes[i]; 0080 } 0081 m_nums--; 0082 } 0083 m_times[m_nums] = diff; 0084 m_sizes[m_nums++] = m_filesize - m_offset; 0085 0086 KIO::filesize_t lspeed = 1000 * (m_sizes[m_nums - 1] - m_sizes[0]) / (m_times[m_nums - 1] - m_times[0]); 0087 0088 // qDebug() << (long)m_filesize << diff 0089 // << long(m_sizes[m_nums-1] - m_sizes[0]) 0090 // << m_times[m_nums-1] - m_times[0] 0091 // << long(lspeed) << double(m_filesize) / diff 0092 // << convertSize(lspeed) 0093 // << convertSize(long(double(m_filesize) / diff) * 1000); 0094 0095 if (!lspeed) { 0096 m_nums = 1; 0097 m_times[0] = diff; 0098 m_sizes[0] = m_filesize - m_offset; 0099 } 0100 Q_EMIT speed(lspeed); 0101 } 0102 } 0103 0104 bool WorkerInterface::dispatch(int _cmd, const QByteArray &rawdata) 0105 { 0106 // qDebug() << "dispatch " << _cmd; 0107 0108 QDataStream stream(rawdata); 0109 0110 QString str1; 0111 qint32 i; 0112 qint8 b; 0113 quint32 ul; 0114 0115 switch (_cmd) { 0116 case MSG_DATA: 0117 Q_EMIT data(rawdata); 0118 break; 0119 case MSG_DATA_REQ: 0120 Q_EMIT dataReq(); 0121 break; 0122 case MSG_OPENED: 0123 Q_EMIT open(); 0124 break; 0125 case MSG_FINISHED: 0126 // qDebug() << "Finished [this = " << this << "]"; 0127 m_offset = 0; 0128 m_speed_timer.stop(); 0129 Q_EMIT finished(); 0130 break; 0131 case MSG_STAT_ENTRY: { 0132 UDSEntry entry; 0133 stream >> entry; 0134 Q_EMIT statEntry(entry); 0135 break; 0136 } 0137 case MSG_LIST_ENTRIES: { 0138 UDSEntryList list; 0139 UDSEntry entry; 0140 0141 while (!stream.atEnd()) { 0142 stream >> entry; 0143 list.append(entry); 0144 } 0145 0146 Q_EMIT listEntries(list); 0147 break; 0148 } 0149 case MSG_RESUME: { // From the put job 0150 m_offset = readFilesize_t(stream); 0151 Q_EMIT canResume(m_offset); 0152 break; 0153 } 0154 case MSG_CANRESUME: // From the get job 0155 m_filesize = m_offset; 0156 Q_EMIT canResume(0); // the arg doesn't matter 0157 break; 0158 case MSG_ERROR: 0159 stream >> i >> str1; 0160 // qDebug() << "error " << i << " " << str1; 0161 Q_EMIT error(i, str1); 0162 break; 0163 case MSG_WORKER_STATUS: { 0164 qint64 pid; 0165 QByteArray protocol; 0166 stream >> pid >> protocol >> str1 >> b; 0167 Q_EMIT workerStatus(pid, protocol, str1, (b != 0)); 0168 break; 0169 } 0170 case MSG_CONNECTED: 0171 Q_EMIT connected(); 0172 break; 0173 case MSG_WRITTEN: { 0174 KIO::filesize_t size = readFilesize_t(stream); 0175 Q_EMIT written(size); 0176 break; 0177 } 0178 case INF_TOTAL_SIZE: { 0179 KIO::filesize_t size = readFilesize_t(stream); 0180 m_start_time = QDateTime::currentMSecsSinceEpoch(); 0181 m_last_time = 0; 0182 m_filesize = m_offset; 0183 m_sizes[0] = m_filesize - m_offset; 0184 m_times[0] = 0; 0185 m_nums = 1; 0186 m_speed_timer.start(1000); 0187 m_worker_calcs_speed = false; 0188 Q_EMIT totalSize(size); 0189 break; 0190 } 0191 case INF_PROCESSED_SIZE: { 0192 KIO::filesize_t size = readFilesize_t(stream); 0193 Q_EMIT processedSize(size); 0194 m_filesize = size; 0195 break; 0196 } 0197 case INF_POSITION: { 0198 KIO::filesize_t pos = readFilesize_t(stream); 0199 Q_EMIT position(pos); 0200 break; 0201 } 0202 case INF_TRUNCATED: { 0203 KIO::filesize_t length = readFilesize_t(stream); 0204 Q_EMIT truncated(length); 0205 break; 0206 } 0207 case INF_SPEED: 0208 stream >> ul; 0209 m_worker_calcs_speed = true; 0210 m_speed_timer.stop(); 0211 Q_EMIT speed(ul); 0212 break; 0213 case INF_ERROR_PAGE: 0214 Q_EMIT errorPage(); 0215 break; 0216 case INF_REDIRECTION: { 0217 QUrl url; 0218 stream >> url; 0219 Q_EMIT redirection(url); 0220 break; 0221 } 0222 case INF_MIME_TYPE: 0223 stream >> str1; 0224 Q_EMIT mimeType(str1); 0225 if (!m_connection->suspended()) { 0226 m_connection->sendnow(CMD_NONE, QByteArray()); 0227 } 0228 break; 0229 case INF_WARNING: 0230 stream >> str1; 0231 Q_EMIT warning(str1); 0232 break; 0233 case INF_MESSAGEBOX: { 0234 // qDebug() << "needs a msg box"; 0235 QString text; 0236 QString title; 0237 QString primaryActionText; 0238 QString secondaryActionText; 0239 QString dontAskAgainName; 0240 int type; 0241 stream >> type >> text >> title >> primaryActionText >> secondaryActionText; 0242 if (stream.atEnd()) { 0243 messageBox(type, text, title, primaryActionText, secondaryActionText); 0244 } else { 0245 stream >> dontAskAgainName; 0246 messageBox(type, text, title, primaryActionText, secondaryActionText, dontAskAgainName); 0247 } 0248 break; 0249 } 0250 case INF_INFOMESSAGE: { 0251 QString msg; 0252 stream >> msg; 0253 Q_EMIT infoMessage(msg); 0254 break; 0255 } 0256 case INF_SSLERROR: { 0257 QVariantMap sslErrorData; 0258 stream >> sslErrorData; 0259 globalUserNotificationHandler->sslError(this, sslErrorData); 0260 break; 0261 } 0262 case INF_META_DATA: { 0263 MetaData m; 0264 stream >> m; 0265 if (auto it = m.constFind(QStringLiteral("privilege_conf_details")); it != m.cend()) { 0266 // see WORKER_MESSAGEBOX_DETAILS_HACK 0267 m_messageBoxDetails = it.value(); 0268 } 0269 Q_EMIT metaData(m); 0270 break; 0271 } 0272 case MSG_HOST_INFO_REQ: { 0273 QString hostName; 0274 stream >> hostName; 0275 HostInfo::lookupHost(hostName, this, SLOT(slotHostInfo(QHostInfo))); 0276 break; 0277 } 0278 case MSG_PRIVILEGE_EXEC: 0279 Q_EMIT privilegeOperationRequested(); 0280 break; 0281 default: 0282 qCWarning(KIO_CORE) << "Worker sends unknown command (" << _cmd << "), dropping worker."; 0283 return false; 0284 } 0285 return true; 0286 } 0287 0288 void WorkerInterface::setOffset(KIO::filesize_t o) 0289 { 0290 m_offset = o; 0291 } 0292 0293 KIO::filesize_t WorkerInterface::offset() const 0294 { 0295 return m_offset; 0296 } 0297 0298 void WorkerInterface::sendResumeAnswer(bool resume) 0299 { 0300 // qDebug() << "ok for resuming:" << resume; 0301 m_connection->sendnow(resume ? CMD_RESUMEANSWER : CMD_NONE, QByteArray()); 0302 } 0303 0304 void WorkerInterface::sendMessageBoxAnswer(int result) 0305 { 0306 if (!m_connection) { 0307 return; 0308 } 0309 0310 if (m_connection->suspended()) { 0311 m_connection->resume(); 0312 } 0313 QByteArray packedArgs; 0314 QDataStream stream(&packedArgs, QIODevice::WriteOnly); 0315 stream << result; 0316 m_connection->sendnow(CMD_MESSAGEBOXANSWER, packedArgs); 0317 // qDebug() << "message box answer" << result; 0318 } 0319 0320 void WorkerInterface::sendSslErrorAnswer(int result) 0321 { 0322 if (!m_connection) { 0323 return; 0324 } 0325 0326 if (m_connection->suspended()) { 0327 m_connection->resume(); 0328 } 0329 QByteArray packedArgs; 0330 QDataStream stream(&packedArgs, QIODevice::WriteOnly); 0331 stream << result; 0332 m_connection->sendnow(CMD_SSLERRORANSWER, packedArgs); 0333 // qDebug() << "message box answer" << result; 0334 } 0335 0336 void WorkerInterface::messageBox(int type, const QString &text, const QString &title, const QString &primaryActionText, const QString &secondaryActionText) 0337 { 0338 messageBox(type, text, title, primaryActionText, secondaryActionText, QString()); 0339 } 0340 0341 void WorkerInterface::messageBox(int type, 0342 const QString &text, 0343 const QString &title, 0344 const QString &primaryActionText, 0345 const QString &secondaryActionText, 0346 const QString &dontAskAgainName) 0347 { 0348 if (m_connection) { 0349 m_connection->suspend(); 0350 } 0351 0352 QHash<UserNotificationHandler::MessageBoxDataType, QVariant> data; 0353 data.insert(UserNotificationHandler::MSG_TEXT, text); 0354 data.insert(UserNotificationHandler::MSG_TITLE, title); 0355 data.insert(UserNotificationHandler::MSG_PRIMARYACTION_TEXT, primaryActionText); 0356 data.insert(UserNotificationHandler::MSG_SECONDARYACTION_TEXT, secondaryActionText); 0357 data.insert(UserNotificationHandler::MSG_DONT_ASK_AGAIN, dontAskAgainName); 0358 0359 // SMELL: the braindead way to support button icons 0360 // TODO: Fix this in KIO::WorkerBase. 0361 if (primaryActionText == i18n("&Details")) { 0362 data.insert(UserNotificationHandler::MSG_PRIMARYACTION_ICON, QLatin1String("help-about")); 0363 } else if (primaryActionText == i18n("&Forever")) { 0364 data.insert(UserNotificationHandler::MSG_PRIMARYACTION_ICON, QLatin1String("flag-green")); 0365 } 0366 0367 if (secondaryActionText == i18n("Co&ntinue")) { 0368 data.insert(UserNotificationHandler::MSG_SECONDARYACTION_ICON, QLatin1String("arrow-right")); 0369 } else if (secondaryActionText == i18n("&Current Session only")) { 0370 data.insert(UserNotificationHandler::MSG_SECONDARYACTION_ICON, QLatin1String("chronometer")); 0371 } 0372 0373 if (type == KIO::WorkerBase::WarningContinueCancelDetailed) { // see WORKER_MESSAGEBOX_DETAILS_HACK 0374 data.insert(UserNotificationHandler::MSG_DETAILS, m_messageBoxDetails); 0375 } 0376 0377 globalUserNotificationHandler()->requestMessageBox(this, type, data); 0378 } 0379 0380 void WorkerInterface::slotHostInfo(const QHostInfo &info) 0381 { 0382 QByteArray data; 0383 QDataStream stream(&data, QIODevice::WriteOnly); 0384 stream << info.hostName() << info.addresses() << info.error() << info.errorString(); 0385 m_connection->send(CMD_HOST_INFO, data); 0386 } 0387 0388 #include "moc_workerinterface_p.cpp"