KIO

workerinterface.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2000 David Faure <faure@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-only
6*/
7
8#include "workerinterface_p.h"
9
10#include "commands_p.h"
11#include "connection_p.h"
12#include "hostinfo.h"
13#include "kiocoredebug.h"
14#include "usernotificationhandler_p.h"
15#include "workerbase.h"
16
17#include <KLocalizedString>
18
19#include <QDataStream>
20#include <QDateTime>
21
22using namespace KIO;
23
24Q_GLOBAL_STATIC(UserNotificationHandler, globalUserNotificationHandler)
25
26WorkerInterface::WorkerInterface(QObject *parent)
27 : QObject(parent)
28{
29 connect(&m_speed_timer, &QTimer::timeout, this, &WorkerInterface::calcSpeed);
30}
31
32WorkerInterface::~WorkerInterface()
33{
34 // Note: no Debug() here (scheduler is deleted very late)
35
36 delete m_connection;
37}
38
39static KIO::filesize_t readFilesize_t(QDataStream &stream)
40{
41 KIO::filesize_t result;
42 stream >> result;
43 return result;
44}
45
46bool WorkerInterface::dispatch()
47{
48 Q_ASSERT(m_connection);
49
50 int cmd;
51 QByteArray data;
52
53 int ret = m_connection->read(&cmd, data);
54 if (ret == -1) {
55 return false;
56 }
57
58 return dispatch(cmd, data);
59}
60
61void WorkerInterface::calcSpeed()
62{
63 if (m_worker_calcs_speed || !m_connection->isConnected()) { // killing a job results in disconnection but the timer never stops
64 m_speed_timer.stop();
65 return;
66 }
67
68 const qint64 currentTime = QDateTime::currentMSecsSinceEpoch();
69 const qint64 diff = currentTime - m_start_time;
70 if (diff - m_last_time >= 900) {
71 m_last_time = diff;
72 if (m_nums == max_nums) {
73 // let's hope gcc can optimize that well enough
74 // otherwise I'd try memcpy :)
75 for (unsigned int i = 1; i < max_nums; ++i) {
76 m_times[i - 1] = m_times[i];
77 m_sizes[i - 1] = m_sizes[i];
78 }
79 m_nums--;
80 }
81 m_times[m_nums] = diff;
82 m_sizes[m_nums++] = m_filesize - m_offset;
83
84 KIO::filesize_t lspeed = 1000 * (m_sizes[m_nums - 1] - m_sizes[0]) / (m_times[m_nums - 1] - m_times[0]);
85
86 // qDebug() << (long)m_filesize << diff
87 // << long(m_sizes[m_nums-1] - m_sizes[0])
88 // << m_times[m_nums-1] - m_times[0]
89 // << long(lspeed) << double(m_filesize) / diff
90 // << convertSize(lspeed)
91 // << convertSize(long(double(m_filesize) / diff) * 1000);
92
93 if (!lspeed) {
94 m_nums = 1;
95 m_times[0] = diff;
96 m_sizes[0] = m_filesize - m_offset;
97 }
98 Q_EMIT speed(lspeed);
99 }
100}
101
102bool WorkerInterface::dispatch(int _cmd, const QByteArray &rawdata)
103{
104 // qDebug() << "dispatch " << _cmd;
105
106 QDataStream stream(rawdata);
107
108 QString str1;
109 qint32 i;
110 qint8 b;
111 quint32 ul;
112
113 switch (_cmd) {
114 case MSG_DATA:
115 Q_EMIT data(rawdata);
116 break;
117 case MSG_DATA_REQ:
118 Q_EMIT dataReq();
119 break;
120 case MSG_OPENED:
121 Q_EMIT open();
122 break;
123 case MSG_FINISHED:
124 // qDebug() << "Finished [this = " << this << "]";
125 m_offset = 0;
126 m_speed_timer.stop();
127 Q_EMIT finished();
128 break;
129 case MSG_STAT_ENTRY: {
130 UDSEntry entry;
131 stream >> entry;
132 Q_EMIT statEntry(entry);
133 break;
134 }
135 case MSG_LIST_ENTRIES: {
137 UDSEntry entry;
138
139 while (!stream.atEnd()) {
140 stream >> entry;
141 list.append(entry);
142 }
143
144 Q_EMIT listEntries(list);
145 break;
146 }
147 case MSG_RESUME: { // From the put job
148 m_offset = readFilesize_t(stream);
149 Q_EMIT canResume(m_offset);
150 break;
151 }
152 case MSG_CANRESUME: // From the get job
153 m_filesize = m_offset;
154 Q_EMIT canResume(0); // the arg doesn't matter
155 break;
156 case MSG_ERROR:
157 stream >> i >> str1;
158 // qDebug() << "error " << i << " " << str1;
159 Q_EMIT error(i, str1);
160 break;
161 case MSG_WORKER_STATUS: {
162 qint64 pid;
163 QByteArray protocol;
164 stream >> pid >> protocol >> str1 >> b;
165 Q_EMIT workerStatus(pid, protocol, str1, (b != 0));
166 break;
167 }
168 case MSG_CONNECTED:
169 Q_EMIT connected();
170 break;
171 case MSG_WRITTEN: {
172 KIO::filesize_t size = readFilesize_t(stream);
173 Q_EMIT written(size);
174 break;
175 }
176 case INF_TOTAL_SIZE: {
177 KIO::filesize_t size = readFilesize_t(stream);
178 m_start_time = QDateTime::currentMSecsSinceEpoch();
179 m_last_time = 0;
180 m_filesize = m_offset;
181 m_sizes[0] = m_filesize - m_offset;
182 m_times[0] = 0;
183 m_nums = 1;
184 m_speed_timer.start(1000);
185 m_worker_calcs_speed = false;
186 Q_EMIT totalSize(size);
187 break;
188 }
189 case INF_PROCESSED_SIZE: {
190 KIO::filesize_t size = readFilesize_t(stream);
191 Q_EMIT processedSize(size);
192 m_filesize = size;
193 break;
194 }
195 case INF_POSITION: {
196 KIO::filesize_t pos = readFilesize_t(stream);
197 Q_EMIT position(pos);
198 break;
199 }
200 case INF_TRUNCATED: {
201 KIO::filesize_t length = readFilesize_t(stream);
202 Q_EMIT truncated(length);
203 break;
204 }
205 case INF_SPEED:
206 stream >> ul;
207 m_worker_calcs_speed = true;
208 m_speed_timer.stop();
209 Q_EMIT speed(ul);
210 break;
211 case INF_ERROR_PAGE:
212 break;
213 case INF_REDIRECTION: {
214 QUrl url;
215 stream >> url;
216 Q_EMIT redirection(url);
217 break;
218 }
219 case INF_MIME_TYPE:
220 stream >> str1;
221 Q_EMIT mimeType(str1);
222 if (!m_connection->suspended()) {
223 m_connection->sendnow(CMD_NONE, QByteArray());
224 }
225 break;
226 case INF_WARNING:
227 stream >> str1;
228 Q_EMIT warning(str1);
229 break;
230 case INF_MESSAGEBOX: {
231 // qDebug() << "needs a msg box";
232 QString text;
233 QString title;
234 QString primaryActionText;
235 QString secondaryActionText;
236 QString dontAskAgainName;
237 int type;
238 stream >> type >> text >> title >> primaryActionText >> secondaryActionText;
239 if (stream.atEnd()) {
240 messageBox(type, text, title, primaryActionText, secondaryActionText);
241 } else {
242 stream >> dontAskAgainName;
243 messageBox(type, text, title, primaryActionText, secondaryActionText, dontAskAgainName);
244 }
245 break;
246 }
247 case INF_INFOMESSAGE: {
248 QString msg;
249 stream >> msg;
250 Q_EMIT infoMessage(msg);
251 break;
252 }
253 case INF_SSLERROR: {
254 QVariantMap sslErrorData;
255 stream >> sslErrorData;
256 globalUserNotificationHandler->sslError(this, sslErrorData);
257 break;
258 }
259 case INF_META_DATA: {
260 MetaData m;
261 stream >> m;
262 if (auto it = m.constFind(QStringLiteral("privilege_conf_details")); it != m.cend()) {
263 // see WORKER_MESSAGEBOX_DETAILS_HACK
264 m_messageBoxDetails = it.value();
265 }
266 Q_EMIT metaData(m);
267 break;
268 }
269 case MSG_HOST_INFO_REQ: {
270 QString hostName;
271 stream >> hostName;
272 HostInfo::lookupHost(hostName, this, SLOT(slotHostInfo(QHostInfo)));
273 break;
274 }
275 case MSG_PRIVILEGE_EXEC:
276 Q_EMIT privilegeOperationRequested();
277 break;
278 default:
279 qCWarning(KIO_CORE) << "Worker sends unknown command (" << _cmd << "), dropping worker.";
280 return false;
281 }
282 return true;
283}
284
285void WorkerInterface::setOffset(KIO::filesize_t o)
286{
287 m_offset = o;
288}
289
290KIO::filesize_t WorkerInterface::offset() const
291{
292 return m_offset;
293}
294
295void WorkerInterface::sendResumeAnswer(bool resume)
296{
297 // qDebug() << "ok for resuming:" << resume;
298 m_connection->sendnow(resume ? CMD_RESUMEANSWER : CMD_NONE, QByteArray());
299}
300
301void WorkerInterface::sendMessageBoxAnswer(int result)
302{
303 if (!m_connection) {
304 return;
305 }
306
307 if (m_connection->suspended()) {
308 m_connection->resume();
309 }
310 QByteArray packedArgs;
311 QDataStream stream(&packedArgs, QIODevice::WriteOnly);
312 stream << result;
313 m_connection->sendnow(CMD_MESSAGEBOXANSWER, packedArgs);
314 // qDebug() << "message box answer" << result;
315}
316
317void WorkerInterface::sendSslErrorAnswer(int result)
318{
319 if (!m_connection) {
320 return;
321 }
322
323 if (m_connection->suspended()) {
324 m_connection->resume();
325 }
326 QByteArray packedArgs;
327 QDataStream stream(&packedArgs, QIODevice::WriteOnly);
328 stream << result;
329 m_connection->sendnow(CMD_SSLERRORANSWER, packedArgs);
330 // qDebug() << "message box answer" << result;
331}
332
333void WorkerInterface::messageBox(int type, const QString &text, const QString &title, const QString &primaryActionText, const QString &secondaryActionText)
334{
335 messageBox(type, text, title, primaryActionText, secondaryActionText, QString());
336}
337
338void WorkerInterface::messageBox(int type,
339 const QString &text,
340 const QString &title,
341 const QString &primaryActionText,
342 const QString &secondaryActionText,
343 const QString &dontAskAgainName)
344{
345 if (m_connection) {
346 m_connection->suspend();
347 }
348
350 data.insert(UserNotificationHandler::MSG_TEXT, text);
351 data.insert(UserNotificationHandler::MSG_TITLE, title);
352 data.insert(UserNotificationHandler::MSG_PRIMARYACTION_TEXT, primaryActionText);
353 data.insert(UserNotificationHandler::MSG_SECONDARYACTION_TEXT, secondaryActionText);
354 data.insert(UserNotificationHandler::MSG_DONT_ASK_AGAIN, dontAskAgainName);
355
356 // SMELL: the braindead way to support button icons
357 // TODO: Fix this in KIO::WorkerBase.
358 if (primaryActionText == i18n("&Details")) {
359 data.insert(UserNotificationHandler::MSG_PRIMARYACTION_ICON, QLatin1String("help-about"));
360 } else if (primaryActionText == i18n("&Forever")) {
361 data.insert(UserNotificationHandler::MSG_PRIMARYACTION_ICON, QLatin1String("flag-green"));
362 }
363
364 if (secondaryActionText == i18n("Co&ntinue")) {
365 data.insert(UserNotificationHandler::MSG_SECONDARYACTION_ICON, QLatin1String("arrow-right"));
366 } else if (secondaryActionText == i18n("&Current Session only")) {
367 data.insert(UserNotificationHandler::MSG_SECONDARYACTION_ICON, QLatin1String("chronometer"));
368 }
369
370 if (type == KIO::WorkerBase::WarningContinueCancelDetailed) { // see WORKER_MESSAGEBOX_DETAILS_HACK
371 data.insert(UserNotificationHandler::MSG_DETAILS, m_messageBoxDetails);
372 }
373
374 globalUserNotificationHandler()->requestMessageBox(this, type, data);
375}
376
377void WorkerInterface::slotHostInfo(const QHostInfo &info)
378{
379 QByteArray data;
380 QDataStream stream(&data, QIODevice::WriteOnly);
381 stream << info.hostName() << info.addresses() << info.error() << info.errorString();
382 m_connection->send(CMD_HOST_INFO, data);
383}
384
385#include "moc_workerinterface_p.cpp"
MetaData is a simple map of key/value strings.
Universal Directory Service.
QString i18n(const char *text, const TYPE &arg...)
Type type(const QSqlDatabase &db)
KCALUTILS_EXPORT QString mimeType()
void lookupHost(const QString &hostName, QObject *receiver, const char *member)
Definition hostinfo.cpp:237
A namespace for KIO globals.
KIOCORE_EXPORT FileJob * open(const QUrl &url, QIODevice::OpenMode mode)
Open ( random access I/O )
Definition filejob.cpp:239
qulonglong filesize_t
64-bit file size
Definition global.h:35
ButtonCode messageBox(QWidget *parent, DialogType type, const QString &text, const QString &title, const KGuiItem &primaryAction, const KGuiItem &secondaryAction, const KGuiItem &cancelAction=KStandardGuiItem::cancel(), const QString &dontShowAskAgainName=QString(), Options options=Notify)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
Returns a list of directories associated with this file-class.
qint64 currentMSecsSinceEpoch()
iterator insert(const Key &key, const T &value)
QList< QHostAddress > addresses() const const
HostInfoError error() const const
QString errorString() const const
QString hostName() const const
void append(QList< T > &&value)
const_iterator cend() const const
const_iterator constFind(const Key &key) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void timeout()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 16:58:45 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.