KIO

slavebase.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2000 Waldo Bastian <bastian@kde.org>
4 SPDX-FileCopyrightText: 2000 David Faure <faure@kde.org>
5 SPDX-FileCopyrightText: 2000 Stephan Kulow <coolo@kde.org>
6 SPDX-FileCopyrightText: 2007 Thiago Macieira <thiago@kde.org>
7
8 SPDX-License-Identifier: LGPL-2.0-only
9*/
10
11#include "slavebase.h"
12
13#include <config-kiocore.h>
14
15#include <qplatformdefs.h>
16#include <signal.h>
17#include <stdlib.h>
18#ifdef Q_OS_WIN
19#include <process.h>
20#endif
21
22#include <QCoreApplication>
23#include <QDataStream>
24#include <QDateTime>
25#include <QElapsedTimer>
26#include <QFile>
27#include <QList>
28#include <QMap>
29#include <QSsl>
30#include <QtGlobal>
31
32#include <KAboutData>
33#include <KConfig>
34#include <KConfigGroup>
35#include <KLocalizedString>
36#include <QThread>
37
38#ifndef Q_OS_ANDROID
39#include <KCrash>
40#endif
41
42#include "authinfo.h"
43#include "kremoteencoding.h"
44
45#include "commands_p.h"
46#include "connection_p.h"
47#include "ioworker_defaults.h"
48#include "kio_version.h"
49#include "kiocoredebug.h"
50#include "kioglobal_p.h"
51#include "kpasswdserverclient.h"
52#include "workerinterface_p.h"
53
54#if defined(Q_OS_UNIX) && !defined(Q_OS_ANDROID)
55#include <KAuth/Action>
56#endif
57
58// TODO: Enable once file KIO worker is ported away and add endif, similar in the header file
59// #if KIOCORE_BUILD_DEPRECATED_SINCE(version where file:/ KIO worker was ported)
60
61#if KIO_ASSERT_WORKER_STATES
62#define KIO_STATE_ASSERT(cond, where, what) Q_ASSERT_X(cond, where, what)
63#else
64/* clang-format off */
65#define KIO_STATE_ASSERT(cond, where, what) \
66 do { \
67 if (!(cond)) { \
68 qCWarning(KIO_CORE) << what; \
69 } \
70 } while (false)
71#endif
72/* clang-format on */
73
74extern "C" {
75static void sigpipe_handler(int sig);
76}
77
78using namespace KIO;
79
82
83/* clang-format off */
84#define KIO_DATA \
85 QByteArray data; \
86 QDataStream stream(&data, QIODevice::WriteOnly); \
87 stream
88/* clang-format on */
89
90static constexpr int KIO_MAX_ENTRIES_PER_BATCH = 200;
91static constexpr int KIO_MAX_SEND_BATCH_TIME = 300;
92
93namespace KIO
94{
95class SlaveBasePrivate
96{
97public:
98 SlaveBase *const q;
99 explicit SlaveBasePrivate(SlaveBase *owner)
100 : q(owner)
101 , nextTimeoutMsecs(0)
102 , m_confirmationAsked(false)
103 , m_privilegeOperationStatus(OperationNotAllowed)
104 {
105 if (!qEnvironmentVariableIsEmpty("KIOWORKER_ENABLE_TESTMODE")) {
107 } else if (!qEnvironmentVariableIsEmpty("KIOSLAVE_ENABLE_TESTMODE")) {
109 qCWarning(KIO_CORE)
110 << "KIOSLAVE_ENABLE_TESTMODE is deprecated for KF6, and will be unsupported soon. Please use KIOWORKER_ENABLE_TESTMODE with KF6.";
111 }
112 pendingListEntries.reserve(KIO_MAX_ENTRIES_PER_BATCH);
113 appConnection.setReadMode(Connection::ReadMode::Polled);
114 }
115 ~SlaveBasePrivate() = default;
116
117 UDSEntryList pendingListEntries;
118 QElapsedTimer m_timeSinceLastBatch;
119 Connection appConnection{Connection::Type::Worker};
120 QString poolSocket;
121 bool isConnectedToApp;
122
123 QString slaveid;
124 bool resume : 1;
125 bool needSendCanResume : 1;
126 bool onHold : 1;
127 bool inOpenLoop : 1;
128 std::atomic<bool> wasKilled = false;
129 std::atomic<bool> exit_loop = false;
130 std::atomic<bool> runInThread = false;
131 MetaData configData;
132 KConfig *config = nullptr;
133 KConfigGroup *configGroup = nullptr;
134 QMap<QString, QVariant> mapConfig;
135 QUrl onHoldUrl;
136
137 QElapsedTimer lastTimeout;
138 QElapsedTimer nextTimeout;
139 qint64 nextTimeoutMsecs;
140 KIO::filesize_t totalSize;
141 KRemoteEncoding *remotefile = nullptr;
142 enum { Idle, InsideMethod, InsideTimeoutSpecial, FinishedCalled, ErrorCalled } m_state;
143 bool m_finalityCommand = true; // whether finished() or error() may/must be called
144 QByteArray timeoutData;
145
146#ifdef WITH_QTDBUS
147 std::unique_ptr<KPasswdServerClient> m_passwdServerClient;
148#endif
149 bool m_rootEntryListed = false;
150
151 bool m_confirmationAsked;
152 QSet<QString> m_tempAuths;
153 QString m_warningTitle;
154 QString m_warningMessage;
155 int m_privilegeOperationStatus;
156
157 void updateTempAuthStatus()
158 {
159#if defined(Q_OS_UNIX) && !defined(Q_OS_ANDROID)
160 QSet<QString>::iterator it = m_tempAuths.begin();
161 while (it != m_tempAuths.end()) {
162 KAuth::Action action(*it);
163 if (action.status() != KAuth::Action::AuthorizedStatus) {
164 it = m_tempAuths.erase(it);
165 } else {
166 ++it;
167 }
168 }
169#endif
170 }
171
172 bool hasTempAuth() const
173 {
174 return !m_tempAuths.isEmpty();
175 }
176
177 // Reconstructs configGroup from configData and mIncomingMetaData
178 void rebuildConfig()
179 {
180 mapConfig.clear();
181
182 // mIncomingMetaData cascades over config, so we write config first,
183 // to let it be overwritten
184 MetaData::ConstIterator end = configData.constEnd();
185 for (MetaData::ConstIterator it = configData.constBegin(); it != end; ++it) {
186 mapConfig.insert(it.key(), it->toUtf8());
187 }
188
189 end = q->mIncomingMetaData.constEnd();
190 for (MetaData::ConstIterator it = q->mIncomingMetaData.constBegin(); it != end; ++it) {
191 mapConfig.insert(it.key(), it->toUtf8());
192 }
193
194 delete configGroup;
195 configGroup = nullptr;
196 delete config;
197 config = nullptr;
198 }
199
200 bool finalState() const
201 {
202 return ((m_state == FinishedCalled) || (m_state == ErrorCalled));
203 }
204
205 void verifyState(const char *cmdName)
206 {
207 Q_UNUSED(cmdName)
208 KIO_STATE_ASSERT(finalState(),
209 Q_FUNC_INFO,
210 qUtf8Printable(QStringLiteral("%1 did not call finished() or error()! Please fix the %2 KIO worker.")
211 .arg(QLatin1String(cmdName))
213 // Force the command into finished state. We'll not reach this for Debug builds
214 // that fail the assertion. For Release builds we'll have made sure that the
215 // command is actually finished after the verification regardless of what
216 // the slave did.
217 if (!finalState()) {
218 q->finished();
219 }
220 }
221
222 void verifyErrorFinishedNotCalled(const char *cmdName)
223 {
224 Q_UNUSED(cmdName)
225 KIO_STATE_ASSERT(!finalState(),
226 Q_FUNC_INFO,
227 qUtf8Printable(QStringLiteral("%1 called finished() or error(), but it's not supposed to! Please fix the %2 KIO worker.")
228 .arg(QLatin1String(cmdName))
230 }
231
232#ifdef WITH_QTDBUS
233 KPasswdServerClient *passwdServerClient()
234 {
235 if (!m_passwdServerClient) {
236 m_passwdServerClient = std::make_unique<KPasswdServerClient>();
237 }
238
239 return m_passwdServerClient.get();
240 }
241#endif
242};
243
244}
245
246static volatile bool slaveWriteError = false;
247
248#ifdef Q_OS_UNIX
249static SlaveBase *globalSlave;
250
251extern "C" {
252static void genericsig_handler(int sigNumber)
253{
254 ::signal(sigNumber, SIG_IGN);
255 // WABA: Don't do anything that requires malloc, we can deadlock on it since
256 // a SIGTERM signal can come in while we are in malloc/free.
257 // qDebug()<<"kioslave : exiting due to signal "<<sigNumber;
258 // set the flag which will be checked in dispatchLoop() and which *should* be checked
259 // in lengthy operations in the various slaves
260 if (globalSlave != nullptr) {
261 globalSlave->setKillFlag();
262 }
263 ::signal(SIGALRM, SIG_DFL);
264 alarm(5); // generate an alarm signal in 5 seconds, in this time the slave has to exit
265}
266}
267#endif
268
269//////////////
270
271SlaveBase::SlaveBase(const QByteArray &protocol, const QByteArray &pool_socket, const QByteArray &app_socket)
272 : mProtocol(protocol)
273 , d(new SlaveBasePrivate(this))
274
275{
276 Q_ASSERT(!app_socket.isEmpty());
277 d->poolSocket = QFile::decodeName(pool_socket);
278
279 if (QThread::currentThread() == qApp->thread()) {
280#ifndef Q_OS_ANDROID
281 // Setup KCrash for crash reports, but not when running the worker in-app
282 if (QCoreApplication::arguments()[0].endsWith(QLatin1String("kioworker"))) {
283 KAboutData about(QStringLiteral("kioworker"), QString(), QStringLiteral(KIO_VERSION_STRING));
286 }
287#endif
288
289#ifdef Q_OS_UNIX
290 struct sigaction act;
291 act.sa_handler = sigpipe_handler;
292 sigemptyset(&act.sa_mask);
293 act.sa_flags = 0;
294 sigaction(SIGPIPE, &act, nullptr);
295
296 ::signal(SIGINT, &genericsig_handler);
297 ::signal(SIGQUIT, &genericsig_handler);
298 ::signal(SIGTERM, &genericsig_handler);
299
300 globalSlave = this;
301#endif
302 }
303
304 d->isConnectedToApp = true;
305
306 // by kahl for netmgr (need a way to identify slaves)
307 d->slaveid = QString::fromUtf8(protocol) + QString::number(getpid());
308 d->resume = false;
309 d->needSendCanResume = false;
310 d->mapConfig = QMap<QString, QVariant>();
311 d->onHold = false;
312 // d->processed_size = 0;
313 d->totalSize = 0;
314 connectSlave(QFile::decodeName(app_socket));
315
316 d->remotefile = nullptr;
317 d->inOpenLoop = false;
318}
319
320SlaveBase::~SlaveBase()
321{
322 delete d->configGroup;
323 delete d->config;
324 delete d->remotefile;
325}
326
328{
329 while (!d->exit_loop) {
330 if (d->nextTimeout.isValid() && (d->nextTimeout.hasExpired(d->nextTimeoutMsecs))) {
331 QByteArray data = d->timeoutData;
332 d->nextTimeout.invalidate();
333 d->timeoutData = QByteArray();
334 d->m_state = d->InsideTimeoutSpecial;
335 special(data);
336 d->m_state = d->Idle;
337 }
338
339 Q_ASSERT(d->appConnection.inited());
340
341 int ms = -1;
342 if (d->nextTimeout.isValid()) {
343 ms = qMax<int>(d->nextTimeoutMsecs - d->nextTimeout.elapsed(), 1);
344 }
345
346 int ret = -1;
347 if (d->appConnection.hasTaskAvailable() || d->appConnection.waitForIncomingTask(ms)) {
348 // dispatch application messages
349 int cmd;
351 ret = d->appConnection.read(&cmd, data);
352
353 if (ret != -1) {
354 if (d->inOpenLoop) {
356 } else {
357 dispatch(cmd, data);
358 }
359 }
360 } else {
361 ret = d->appConnection.isConnected() ? 0 : -1;
362 }
363
364 if (ret == -1) { // some error occurred, perhaps no more application
365 // When the app exits, should the slave be put back in the pool ?
366 if (!d->exit_loop && d->isConnectedToApp && !d->poolSocket.isEmpty()) {
367 disconnectSlave();
368 d->isConnectedToApp = false;
370 d->updateTempAuthStatus();
371 connectSlave(d->poolSocket);
372 } else {
373 break;
374 }
375 }
376
377 // I think we get here when we were killed in dispatch() and not in select()
378 if (wasKilled()) {
379 // qDebug() << "worker was killed, returning";
380 break;
381 }
382
383 // execute deferred deletes
385 }
386
387 // execute deferred deletes
389}
390
392{
393 d->appConnection.connectToRemote(QUrl(address));
394
395 if (!d->appConnection.inited()) {
396 /*qDebug() << "failed to connect to" << address << endl
397 << "Reason:" << d->appConnection.errorString();*/
398 exit();
399 }
400
401 d->inOpenLoop = false;
402}
403
404void SlaveBase::disconnectSlave()
405{
406 d->appConnection.close();
407}
408
409void SlaveBase::setMetaData(const QString &key, const QString &value)
410{
411 mOutgoingMetaData.insert(key, value); // replaces existing key if already there
412}
413
415{
416 auto it = mIncomingMetaData.find(key);
417 if (it != mIncomingMetaData.end()) {
418 return *it;
419 }
420 return d->configData.value(key);
421}
422
424{
425 return mIncomingMetaData;
426}
427
428bool SlaveBase::hasMetaData(const QString &key) const
429{
430 if (mIncomingMetaData.contains(key)) {
431 return true;
432 }
433 if (d->configData.contains(key)) {
434 return true;
435 }
436 return false;
437}
438
440{
441 return d->mapConfig;
442}
443
444bool SlaveBase::configValue(const QString &key, bool defaultValue) const
445{
446 return d->mapConfig.value(key, defaultValue).toBool();
447}
448
449int SlaveBase::configValue(const QString &key, int defaultValue) const
450{
451 return d->mapConfig.value(key, defaultValue).toInt();
452}
453
454QString SlaveBase::configValue(const QString &key, const QString &defaultValue) const
455{
456 return d->mapConfig.value(key, defaultValue).toString();
457}
458
460{
461 if (!d->config) {
462 d->config = new KConfig(QString(), KConfig::SimpleConfig);
463
464 d->configGroup = new KConfigGroup(d->config, QString());
465
466 auto end = d->mapConfig.cend();
467 for (auto it = d->mapConfig.cbegin(); it != end; ++it) {
468 d->configGroup->writeEntry(it.key(), it->toString().toUtf8(), KConfigGroup::WriteConfigFlags());
469 }
470 }
471
472 return d->configGroup;
473}
474
476{
478 mOutgoingMetaData.clear();
479}
480
482{
483 if (!mOutgoingMetaData.isEmpty()) {
484 KIO_DATA << mOutgoingMetaData;
485
486 send(INF_META_DATA, data);
487 }
488}
489
491{
492 if (d->remotefile) {
493 return d->remotefile;
494 }
495
496 const QByteArray charset(metaData(QStringLiteral("Charset")).toLatin1());
497 return (d->remotefile = new KRemoteEncoding(charset.constData()));
498}
499
501{
502 sendMetaData();
503 send(MSG_DATA, data);
504}
505
507{
508 // sendMetaData();
509 if (d->needSendCanResume) {
510 canResume(0);
511 }
512 send(MSG_DATA_REQ);
513}
514
516{
517 sendMetaData();
518 send(MSG_OPENED);
519 d->inOpenLoop = true;
520}
521
522void SlaveBase::error(int _errid, const QString &_text)
523{
524 if (d->m_state == d->InsideTimeoutSpecial) {
525 qWarning(KIO_CORE) << "TimeoutSpecialCommand failed with" << _errid << _text;
526 return;
527 }
528
529 KIO_STATE_ASSERT(
530 d->m_finalityCommand,
531 Q_FUNC_INFO,
532 qUtf8Printable(QStringLiteral("error() was called, but it's not supposed to! Please fix the %1 KIO worker.").arg(QCoreApplication::applicationName())));
533
534 if (d->m_state == d->ErrorCalled) {
535 KIO_STATE_ASSERT(false,
536 Q_FUNC_INFO,
537 qUtf8Printable(QStringLiteral("error() called twice! Please fix the %1 KIO worker.").arg(QCoreApplication::applicationName())));
538 return;
539 } else if (d->m_state == d->FinishedCalled) {
540 KIO_STATE_ASSERT(
541 false,
542 Q_FUNC_INFO,
543 qUtf8Printable(QStringLiteral("error() called after finished()! Please fix the %1 KIO worker.").arg(QCoreApplication::applicationName())));
544 return;
545 }
546
547 d->m_state = d->ErrorCalled;
548 mIncomingMetaData.clear(); // Clear meta data
549 d->rebuildConfig();
550 mOutgoingMetaData.clear();
551 KIO_DATA << static_cast<qint32>(_errid) << _text;
552
553 send(MSG_ERROR, data);
554 // reset
555 d->totalSize = 0;
556 d->inOpenLoop = false;
557 d->m_confirmationAsked = false;
558 d->m_privilegeOperationStatus = OperationNotAllowed;
559}
560
562{
563 send(MSG_CONNECTED);
564}
565
567{
568 if (d->m_state == d->InsideTimeoutSpecial) {
569 return;
570 }
571
572 if (!d->pendingListEntries.isEmpty()) {
573 if (!d->m_rootEntryListed) {
574 qCWarning(KIO_CORE) << "UDSEntry for '.' not found, creating a default one. Please fix the" << QCoreApplication::applicationName() << "KIO worker.";
575 KIO::UDSEntry entry;
576 entry.reserve(4);
577 entry.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral("."));
580 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH);
581 d->pendingListEntries.append(entry);
582 }
583
584 listEntries(d->pendingListEntries);
585 d->pendingListEntries.clear();
586 }
587
588 KIO_STATE_ASSERT(
589 d->m_finalityCommand,
590 Q_FUNC_INFO,
591 qUtf8Printable(
592 QStringLiteral("finished() was called, but it's not supposed to! Please fix the %2 KIO worker.").arg(QCoreApplication::applicationName())));
593
594 if (d->m_state == d->FinishedCalled) {
595 KIO_STATE_ASSERT(false,
596 Q_FUNC_INFO,
597 qUtf8Printable(QStringLiteral("finished() called twice! Please fix the %1 KIO worker.").arg(QCoreApplication::applicationName())));
598 return;
599 } else if (d->m_state == d->ErrorCalled) {
600 KIO_STATE_ASSERT(
601 false,
602 Q_FUNC_INFO,
603 qUtf8Printable(QStringLiteral("finished() called after error()! Please fix the %1 KIO worker.").arg(QCoreApplication::applicationName())));
604 return;
605 }
606
607 d->m_state = d->FinishedCalled;
608 mIncomingMetaData.clear(); // Clear meta data
609 d->rebuildConfig();
610 sendMetaData();
611 send(MSG_FINISHED);
612
613 // reset
614 d->totalSize = 0;
615 d->inOpenLoop = false;
616 d->m_rootEntryListed = false;
617 d->m_confirmationAsked = false;
618 d->m_privilegeOperationStatus = OperationNotAllowed;
619}
620
621void SlaveBase::slaveStatus(const QString &host, bool connected)
622{
623 qint64 pid = getpid();
624 qint8 b = connected ? 1 : 0;
625 KIO_DATA << pid << mProtocol << host << b << d->onHold << d->onHoldUrl << d->hasTempAuth();
626 send(MSG_WORKER_STATUS, data);
627}
628
630{
631 send(MSG_CANRESUME);
632}
633
635{
636 KIO_DATA << static_cast<quint64>(_bytes);
637 send(INF_TOTAL_SIZE, data);
638
639 // this one is usually called before the first item is listed in listDir()
640 d->totalSize = _bytes;
641}
642
644{
645 bool emitSignal = false;
646
647 if (_bytes == d->totalSize) {
648 emitSignal = true;
649 } else {
650 if (d->lastTimeout.isValid()) {
651 emitSignal = d->lastTimeout.hasExpired(100); // emit size 10 times a second
652 } else {
653 emitSignal = true;
654 }
655 }
656
657 if (emitSignal) {
658 KIO_DATA << static_cast<quint64>(_bytes);
659 send(INF_PROCESSED_SIZE, data);
660 d->lastTimeout.start();
661 }
662
663 // d->processed_size = _bytes;
664}
665
666void SlaveBase::written(KIO::filesize_t _bytes)
667{
668 KIO_DATA << static_cast<quint64>(_bytes);
669 send(MSG_WRITTEN, data);
670}
671
672void SlaveBase::position(KIO::filesize_t _pos)
673{
674 KIO_DATA << static_cast<quint64>(_pos);
675 send(INF_POSITION, data);
676}
677
679{
680 KIO_DATA << static_cast<quint64>(_length);
681 send(INF_TRUNCATED, data);
682}
683
684void SlaveBase::processedPercent(float /* percent */)
685{
686 // qDebug() << "STUB";
687}
688
689void SlaveBase::speed(unsigned long _bytes_per_second)
690{
691 KIO_DATA << static_cast<quint32>(_bytes_per_second);
692 send(INF_SPEED, data);
693}
694
696{
697 KIO_DATA << _url;
698 send(INF_REDIRECTION, data);
699}
700
701static bool isSubCommand(int cmd)
702{
703 /* clang-format off */
704 return cmd == CMD_REPARSECONFIGURATION
705 || cmd == CMD_META_DATA
706 || cmd == CMD_CONFIG
707 || cmd == CMD_WORKER_STATUS;
708 /* clang-format on */
709}
710
711void SlaveBase::mimeType(const QString &_type)
712{
713 qCDebug(KIO_CORE) << "detected mimetype" << _type;
714 int cmd = CMD_NONE;
715 do {
716 if (wasKilled()) {
717 break;
718 }
719
720 // Send the meta-data each time we send the MIME type.
721 if (!mOutgoingMetaData.isEmpty()) {
722 qCDebug(KIO_CORE) << "sending mimetype meta data";
723 KIO_DATA << mOutgoingMetaData;
724 send(INF_META_DATA, data);
725 }
726 KIO_DATA << _type;
727 send(INF_MIME_TYPE, data);
728 while (true) {
729 cmd = 0;
730 int ret = -1;
731 if (d->appConnection.hasTaskAvailable() || d->appConnection.waitForIncomingTask(-1)) {
732 ret = d->appConnection.read(&cmd, data);
733 }
734 if (ret == -1) {
735 qCDebug(KIO_CORE) << "read error on app connection while sending mimetype";
736 exit();
737 break;
738 }
739 qCDebug(KIO_CORE) << "got reply after sending mimetype" << cmd;
740 if (cmd == CMD_HOST) { // Ignore.
741 continue;
742 }
743 if (!isSubCommand(cmd)) {
744 break;
745 }
746
747 dispatch(cmd, data);
748 }
749 } while (cmd != CMD_NONE);
750 mOutgoingMetaData.clear();
751}
752
753void SlaveBase::exit() // possibly called from another thread, only use atomics in here
754{
755 d->exit_loop = true;
756 if (d->runInThread) {
757 d->wasKilled = true;
758 } else {
759 // Using ::exit() here is too much (crashes in qdbus's qglobalstatic object),
760 // so let's cleanly exit dispatchLoop() instead.
761 // Update: we do need to call exit(), otherwise a long download (get()) would
762 // keep going until it ends, even though the application exited.
763 ::exit(255);
764 }
765}
766
768{
769 KIO_DATA << _msg;
770 send(INF_WARNING, data);
771}
772
774{
775 KIO_DATA << _msg;
776 send(INF_INFOMESSAGE, data);
777}
778
780{
781 KIO_DATA << entry;
782 send(MSG_STAT_ENTRY, data);
783}
784
786{
787 // #366795: many slaves don't create an entry for ".", so we keep track if they do
788 // and we provide a fallback in finished() otherwise.
790 d->m_rootEntryListed = true;
791 }
792
793 // We start measuring the time from the point we start filling the list
794 if (d->pendingListEntries.isEmpty()) {
795 d->m_timeSinceLastBatch.restart();
796 }
797
798 d->pendingListEntries.append(entry);
799
800 // If more then KIO_MAX_SEND_BATCH_TIME time is passed, emit the current batch
801 // Also emit if we have piled up a large number of entries already, to save memory (and time)
802 if (d->m_timeSinceLastBatch.elapsed() > KIO_MAX_SEND_BATCH_TIME || d->pendingListEntries.size() > KIO_MAX_ENTRIES_PER_BATCH) {
803 listEntries(d->pendingListEntries);
804 d->pendingListEntries.clear();
805
806 // Restart time
807 d->m_timeSinceLastBatch.restart();
808 }
809}
810
812{
815
816 for (const UDSEntry &entry : list) {
817 stream << entry;
818 }
819
820 send(MSG_LIST_ENTRIES, data);
821}
822
823static void sigpipe_handler(int)
824{
825 // We ignore a SIGPIPE in slaves.
826 // A SIGPIPE can happen in two cases:
827 // 1) Communication error with application.
828 // 2) Communication error with network.
829 slaveWriteError = true;
830
831 // Don't add anything else here, especially no debug output
832}
833
834void SlaveBase::setHost(QString const &, quint16, QString const &, QString const &)
835{
836}
837
838// TODO: move unsupportedActionErrorString() to workerbase.cpp
839// once SlaveBase is dissolved and folded into WorkerBase
840// forward declaration is already in workerbase.h
841namespace KIO
842{
843KIOCORE_EXPORT QString unsupportedActionErrorString(const QString &protocol, int cmd)
844{
845 switch (cmd) {
846 case CMD_CONNECT:
847 return i18n("Opening connections is not supported with the protocol %1.", protocol);
848 case CMD_DISCONNECT:
849 return i18n("Closing connections is not supported with the protocol %1.", protocol);
850 case CMD_STAT:
851 return i18n("Accessing files is not supported with the protocol %1.", protocol);
852 case CMD_PUT:
853 return i18n("Writing to %1 is not supported.", protocol);
854 case CMD_SPECIAL:
855 return i18n("There are no special actions available for protocol %1.", protocol);
856 case CMD_LISTDIR:
857 return i18n("Listing folders is not supported for protocol %1.", protocol);
858 case CMD_GET:
859 return i18n("Retrieving data from %1 is not supported.", protocol);
860 case CMD_MIMETYPE:
861 return i18n("Retrieving mime type information from %1 is not supported.", protocol);
862 case CMD_RENAME:
863 return i18n("Renaming or moving files within %1 is not supported.", protocol);
864 case CMD_SYMLINK:
865 return i18n("Creating symlinks is not supported with protocol %1.", protocol);
866 case CMD_COPY:
867 return i18n("Copying files within %1 is not supported.", protocol);
868 case CMD_DEL:
869 return i18n("Deleting files from %1 is not supported.", protocol);
870 case CMD_MKDIR:
871 return i18n("Creating folders is not supported with protocol %1.", protocol);
872 case CMD_CHMOD:
873 return i18n("Changing the attributes of files is not supported with protocol %1.", protocol);
874 case CMD_CHOWN:
875 return i18n("Changing the ownership of files is not supported with protocol %1.", protocol);
876 case CMD_OPEN:
877 return i18n("Opening files is not supported with protocol %1.", protocol);
878 default:
879 return i18n("Protocol %1 does not support action %2.", protocol, cmd);
880 } /*end switch*/
881}
882}
883
885{
886 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_CONNECT));
887}
889{
890} // No response!
892{
893 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_STAT));
894}
895void SlaveBase::put(QUrl const &, int, JobFlags)
896{
897 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_PUT));
898}
900{
901 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_SPECIAL));
902}
904{
905 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_LISTDIR));
906}
907void SlaveBase::get(QUrl const &)
908{
909 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_GET));
910}
912{
913 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_OPEN));
914}
916{
917 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_READ));
918}
920{
921 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_WRITE));
922}
924{
925 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_SEEK));
926}
928{
929 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_CLOSE));
930}
931void SlaveBase::mimetype(QUrl const &url)
932{
933 get(url);
934}
935void SlaveBase::rename(QUrl const &, QUrl const &, JobFlags)
936{
937 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_RENAME));
938}
940{
941 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_SYMLINK));
942}
943void SlaveBase::copy(QUrl const &, QUrl const &, int, JobFlags)
944{
945 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_COPY));
946}
947void SlaveBase::del(QUrl const &, bool)
948{
949 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_DEL));
950}
951void SlaveBase::setLinkDest(const QUrl &, const QString &)
952{
953 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_SETLINKDEST));
954}
955void SlaveBase::mkdir(QUrl const &, int)
956{
957 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_MKDIR));
958}
959void SlaveBase::chmod(QUrl const &, int)
960{
961 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_CHMOD));
962}
964{
965 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_SETMODIFICATIONTIME));
966}
967void SlaveBase::chown(QUrl const &, const QString &, const QString &)
968{
969 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_CHOWN));
970}
971
973{
974 slaveStatus(QString(), false);
975}
976
978{
979 delete d->remotefile;
980 d->remotefile = nullptr;
981}
982
984{
985 const long windowId = metaData(QStringLiteral("window-id")).toLong();
986 const unsigned long userTimestamp = metaData(QStringLiteral("user-timestamp")).toULong();
987 QString errorMessage;
988 if (metaData(QStringLiteral("no-auth-prompt")).compare(QLatin1String("true"), Qt::CaseInsensitive) == 0) {
989 errorMessage = QStringLiteral("<NoAuthPrompt>");
990 } else {
991 errorMessage = errorMsg;
992 }
993
994 AuthInfo dlgInfo(info);
995 // Make sure the modified flag is not set.
996 dlgInfo.setModified(false);
997 // Prevent queryAuthInfo from caching the user supplied password since
998 // we need the ioslaves to first authenticate against the server with
999 // it to ensure it is valid.
1000 dlgInfo.setExtraField(QStringLiteral("skip-caching-on-query"), true);
1001
1002#ifdef WITH_QTDBUS
1003 KPasswdServerClient *passwdServerClient = d->passwdServerClient();
1004 const int errCode = passwdServerClient->queryAuthInfo(&dlgInfo, errorMessage, windowId, userTimestamp);
1005 if (errCode == KJob::NoError) {
1006 info = dlgInfo;
1007 }
1008 return errCode;
1009#else
1010 return KJob::NoError;
1011#endif
1012}
1013
1014int SlaveBase::messageBox(MessageBoxType type, const QString &text, const QString &title, const QString &primaryActionText, const QString &secondaryActionText)
1015{
1016 return messageBox(text, type, title, primaryActionText, secondaryActionText, QString());
1017}
1018
1020 MessageBoxType type,
1021 const QString &title,
1022 const QString &primaryActionText,
1023 const QString &secondaryActionText,
1024 const QString &dontAskAgainName)
1025{
1026 KIO_DATA << static_cast<qint32>(type) << text << title << primaryActionText << secondaryActionText << dontAskAgainName;
1027 send(INF_MESSAGEBOX, data);
1028 if (waitForAnswer(CMD_MESSAGEBOXANSWER, 0, data) != -1) {
1029 QDataStream stream(data);
1030 int answer;
1031 stream >> answer;
1032 return answer;
1033 } else {
1034 return 0; // communication failure
1035 }
1036}
1037
1038int SlaveBase::sslError(const QVariantMap &sslData)
1039{
1040 KIO_DATA << sslData;
1041 send(INF_SSLERROR, data);
1042 if (waitForAnswer(CMD_SSLERRORANSWER, 0, data) != -1) {
1043 QDataStream stream(data);
1044 int answer;
1045 stream >> answer;
1046 return answer;
1047 } else {
1048 return 0; // communication failure
1049 }
1050}
1051
1053{
1054 // qDebug() << "offset=" << KIO::number(offset);
1055 d->needSendCanResume = false;
1056 KIO_DATA << static_cast<quint64>(offset);
1057 send(MSG_RESUME, data);
1058 if (offset) {
1059 int cmd;
1060 if (waitForAnswer(CMD_RESUMEANSWER, CMD_NONE, data, &cmd) != -1) {
1061 // qDebug() << "returning" << (cmd == CMD_RESUMEANSWER);
1062 return cmd == CMD_RESUMEANSWER;
1063 } else {
1064 return false;
1065 }
1066 } else { // No resuming possible -> no answer to wait for
1067 return true;
1068 }
1069}
1070
1071int SlaveBase::waitForAnswer(int expected1, int expected2, QByteArray &data, int *pCmd)
1072{
1073 int cmd = 0;
1074 int result = -1;
1075 for (;;) {
1076 if (d->appConnection.hasTaskAvailable() || d->appConnection.waitForIncomingTask(-1)) {
1077 result = d->appConnection.read(&cmd, data);
1078 }
1079 if (result == -1) {
1080 // qDebug() << "read error.";
1081 return -1;
1082 }
1083
1084 if (cmd == expected1 || cmd == expected2) {
1085 if (pCmd) {
1086 *pCmd = cmd;
1087 }
1088 return result;
1089 }
1090 if (isSubCommand(cmd)) {
1091 dispatch(cmd, data);
1092 } else {
1093 qFatal("Fatal Error: Got cmd %d, while waiting for an answer!", cmd);
1094 }
1095 }
1096}
1097
1099{
1100 int result = waitForAnswer(MSG_DATA, 0, buffer);
1101 // qDebug() << "readData: length = " << result << " ";
1102 return result;
1103}
1104
1106{
1107 if (timeout > 0) {
1108 d->nextTimeoutMsecs = timeout * 1000; // from seconds to milliseconds
1109 d->nextTimeout.start();
1110 } else if (timeout == 0) {
1111 d->nextTimeoutMsecs = 1000; // Immediate timeout
1112 d->nextTimeout.start();
1113 } else {
1114 d->nextTimeout.invalidate(); // Canceled
1115 }
1116
1117 d->timeoutData = data;
1118}
1119
1120void SlaveBase::dispatch(int command, const QByteArray &data)
1121{
1122 QDataStream stream(data);
1123
1124 QUrl url;
1125 int i;
1126
1127 d->m_finalityCommand = true; // default
1128
1129 switch (command) {
1130 case CMD_HOST: {
1131 QString passwd;
1132 QString host;
1133 QString user;
1134 quint16 port;
1135 stream >> host >> port >> user >> passwd;
1136 d->m_state = d->InsideMethod;
1137 d->m_finalityCommand = false;
1138 setHost(host, port, user, passwd);
1139 d->m_state = d->Idle;
1140 break;
1141 }
1142 case CMD_CONNECT: {
1144 break;
1145 }
1146 case CMD_DISCONNECT: {
1148 break;
1149 }
1150 case CMD_WORKER_STATUS: {
1151 d->m_state = d->InsideMethod;
1152 d->m_finalityCommand = false;
1153 slave_status();
1154 // TODO verify that the slave has called slaveStatus()?
1155 d->m_state = d->Idle;
1156 break;
1157 }
1158 case CMD_REPARSECONFIGURATION: {
1159 d->m_state = d->InsideMethod;
1160 d->m_finalityCommand = false;
1162 d->m_state = d->Idle;
1163 break;
1164 }
1165 case CMD_CONFIG: {
1166 stream >> d->configData;
1167 d->rebuildConfig();
1168 delete d->remotefile;
1169 d->remotefile = nullptr;
1170 break;
1171 }
1172 case CMD_GET: {
1173 stream >> url;
1174 d->m_state = d->InsideMethod;
1175 get(url);
1176 d->verifyState("get()");
1177 d->m_state = d->Idle;
1178 break;
1179 }
1180 case CMD_OPEN: {
1181 stream >> url >> i;
1182 QIODevice::OpenMode mode = QFlag(i);
1183 d->m_state = d->InsideMethod;
1184 open(url, mode); // krazy:exclude=syscalls
1185 d->m_state = d->Idle;
1186 break;
1187 }
1188 case CMD_PUT: {
1189 int permissions;
1190 qint8 iOverwrite;
1191 qint8 iResume;
1192 stream >> url >> iOverwrite >> iResume >> permissions;
1193 JobFlags flags;
1194 if (iOverwrite != 0) {
1195 flags |= Overwrite;
1196 }
1197 if (iResume != 0) {
1198 flags |= Resume;
1199 }
1200
1201 // Remember that we need to send canResume(), TransferJob is expecting
1202 // it. Well, in theory this shouldn't be done if resume is true.
1203 // (the resume bool is currently unused)
1204 d->needSendCanResume = true /* !resume */;
1205
1206 d->m_state = d->InsideMethod;
1207 put(url, permissions, flags);
1208 d->verifyState("put()");
1209 d->m_state = d->Idle;
1210 break;
1211 }
1212 case CMD_STAT: {
1213 stream >> url;
1214 d->m_state = d->InsideMethod;
1215 stat(url); // krazy:exclude=syscalls
1216 d->verifyState("stat()");
1217 d->m_state = d->Idle;
1218 break;
1219 }
1220 case CMD_MIMETYPE: {
1221 stream >> url;
1222 d->m_state = d->InsideMethod;
1223 mimetype(url);
1224 d->verifyState("mimetype()");
1225 d->m_state = d->Idle;
1226 break;
1227 }
1228 case CMD_LISTDIR: {
1229 stream >> url;
1230 d->m_state = d->InsideMethod;
1231 listDir(url);
1232 d->verifyState("listDir()");
1233 d->m_state = d->Idle;
1234 break;
1235 }
1236 case CMD_MKDIR: {
1237 stream >> url >> i;
1238 d->m_state = d->InsideMethod;
1239 mkdir(url, i); // krazy:exclude=syscalls
1240 d->verifyState("mkdir()");
1241 d->m_state = d->Idle;
1242 break;
1243 }
1244 case CMD_RENAME: {
1245 qint8 iOverwrite;
1246 QUrl url2;
1247 stream >> url >> url2 >> iOverwrite;
1248 JobFlags flags;
1249 if (iOverwrite != 0) {
1250 flags |= Overwrite;
1251 }
1252 d->m_state = d->InsideMethod;
1253 rename(url, url2, flags); // krazy:exclude=syscalls
1254 d->verifyState("rename()");
1255 d->m_state = d->Idle;
1256 break;
1257 }
1258 case CMD_SYMLINK: {
1259 qint8 iOverwrite;
1260 QString target;
1261 stream >> target >> url >> iOverwrite;
1262 JobFlags flags;
1263 if (iOverwrite != 0) {
1264 flags |= Overwrite;
1265 }
1266 d->m_state = d->InsideMethod;
1267 symlink(target, url, flags);
1268 d->verifyState("symlink()");
1269 d->m_state = d->Idle;
1270 break;
1271 }
1272 case CMD_COPY: {
1273 int permissions;
1274 qint8 iOverwrite;
1275 QUrl url2;
1276 stream >> url >> url2 >> permissions >> iOverwrite;
1277 JobFlags flags;
1278 if (iOverwrite != 0) {
1279 flags |= Overwrite;
1280 }
1281 d->m_state = d->InsideMethod;
1282 copy(url, url2, permissions, flags);
1283 d->verifyState("copy()");
1284 d->m_state = d->Idle;
1285 break;
1286 }
1287 case CMD_DEL: {
1288 qint8 isFile;
1289 stream >> url >> isFile;
1290 d->m_state = d->InsideMethod;
1291 del(url, isFile != 0);
1292 d->verifyState("del()");
1293 d->m_state = d->Idle;
1294 break;
1295 }
1296 case CMD_CHMOD: {
1297 stream >> url >> i;
1298 d->m_state = d->InsideMethod;
1299 chmod(url, i);
1300 d->verifyState("chmod()");
1301 d->m_state = d->Idle;
1302 break;
1303 }
1304 case CMD_CHOWN: {
1305 QString owner;
1306 QString group;
1307 stream >> url >> owner >> group;
1308 d->m_state = d->InsideMethod;
1309 chown(url, owner, group);
1310 d->verifyState("chown()");
1311 d->m_state = d->Idle;
1312 break;
1313 }
1314 case CMD_SETMODIFICATIONTIME: {
1315 QDateTime dt;
1316 stream >> url >> dt;
1317 d->m_state = d->InsideMethod;
1318 setModificationTime(url, dt);
1319 d->verifyState("setModificationTime()");
1320 d->m_state = d->Idle;
1321 break;
1322 }
1323 case CMD_SPECIAL: {
1324 d->m_state = d->InsideMethod;
1325 special(data);
1326 d->verifyState("special()");
1327 d->m_state = d->Idle;
1328 break;
1329 }
1330 case CMD_META_DATA: {
1331 // qDebug() << "(" << getpid() << ") Incoming meta-data...";
1332 stream >> mIncomingMetaData;
1333 d->rebuildConfig();
1334 break;
1335 }
1336 case CMD_NONE: {
1337 qCWarning(KIO_CORE) << "Got unexpected CMD_NONE!";
1338 break;
1339 }
1340 case CMD_FILESYSTEMFREESPACE: {
1341 stream >> url;
1342
1343 void *data = static_cast<void *>(&url);
1344
1345 d->m_state = d->InsideMethod;
1346 virtual_hook(GetFileSystemFreeSpace, data);
1347 d->verifyState("fileSystemFreeSpace()");
1348 d->m_state = d->Idle;
1349 break;
1350 }
1351 default: {
1352 // Some command we don't understand.
1353 // Just ignore it, it may come from some future version of KIO.
1354 break;
1355 }
1356 }
1357}
1358
1360{
1361#ifdef WITH_QTDBUS
1362 KPasswdServerClient *passwdServerClient = d->passwdServerClient();
1363 return (passwdServerClient->checkAuthInfo(&info, metaData(QStringLiteral("window-id")).toLong(), metaData(QStringLiteral("user-timestamp")).toULong()));
1364#else
1365 return false;
1366#endif
1367}
1368
1369void SlaveBase::dispatchOpenCommand(int command, const QByteArray &data)
1370{
1371 QDataStream stream(data);
1372
1373 switch (command) {
1374 case CMD_READ: {
1375 KIO::filesize_t bytes;
1376 stream >> bytes;
1377 read(bytes);
1378 break;
1379 }
1380 case CMD_WRITE: {
1381 write(data);
1382 break;
1383 }
1384 case CMD_SEEK: {
1385 KIO::filesize_t offset;
1386 stream >> offset;
1387 seek(offset);
1388 break;
1389 }
1390 case CMD_TRUNCATE: {
1391 KIO::filesize_t length;
1392 stream >> length;
1393 void *data = static_cast<void *>(&length);
1394 virtual_hook(Truncate, data);
1395 break;
1396 }
1397 case CMD_NONE:
1398 break;
1399 case CMD_CLOSE:
1400 close(); // must call finish(), which will set d->inOpenLoop=false
1401 break;
1402 default:
1403 // Some command we don't understand.
1404 // Just ignore it, it may come from some future version of KIO.
1405 break;
1406 }
1407}
1408
1410{
1411#ifdef WITH_QTDBUS
1412 KPasswdServerClient *passwdServerClient = d->passwdServerClient();
1413 passwdServerClient->addAuthInfo(info, metaData(QStringLiteral("window-id")).toLongLong());
1414#endif
1415 return true;
1416}
1417
1419{
1420 bool ok;
1421 QString tmp = metaData(QStringLiteral("ConnectTimeout"));
1422 int result = tmp.toInt(&ok);
1423 if (ok) {
1424 return result;
1425 }
1426 return DEFAULT_CONNECT_TIMEOUT;
1427}
1428
1430{
1431 bool ok;
1432 QString tmp = metaData(QStringLiteral("ProxyConnectTimeout"));
1433 int result = tmp.toInt(&ok);
1434 if (ok) {
1435 return result;
1436 }
1437 return DEFAULT_PROXY_CONNECT_TIMEOUT;
1438}
1439
1441{
1442 bool ok;
1443 QString tmp = metaData(QStringLiteral("ResponseTimeout"));
1444 int result = tmp.toInt(&ok);
1445 if (ok) {
1446 return result;
1447 }
1448 return DEFAULT_RESPONSE_TIMEOUT;
1449}
1450
1452{
1453 bool ok;
1454 QString tmp = metaData(QStringLiteral("ReadTimeout"));
1455 int result = tmp.toInt(&ok);
1456 if (ok) {
1457 return result;
1458 }
1459 return DEFAULT_READ_TIMEOUT;
1460}
1461
1463{
1464 return d->wasKilled;
1465}
1466
1468{
1469 d->wasKilled = true;
1470}
1471
1472void SlaveBase::send(int cmd, const QByteArray &arr)
1473{
1474 if (d->runInThread) {
1475 if (!d->appConnection.send(cmd, arr)) {
1476 exit();
1477 }
1478 } else {
1479 slaveWriteError = false;
1480 if (!d->appConnection.send(cmd, arr))
1481 // Note that slaveWriteError can also be set by sigpipe_handler
1482 {
1483 slaveWriteError = true;
1484 }
1485 if (slaveWriteError) {
1486 qCWarning(KIO_CORE) << "An error occurred during write. The worker terminates now.";
1487 exit();
1488 }
1489 }
1490}
1491
1492void SlaveBase::virtual_hook(int id, void *data)
1493{
1494 Q_UNUSED(data);
1495
1496 switch (id) {
1497 case GetFileSystemFreeSpace: {
1498 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_FILESYSTEMFREESPACE));
1499 break;
1500 }
1501 case Truncate: {
1502 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_TRUNCATE));
1503 break;
1504 }
1505 }
1506}
1507
1508void SlaveBase::setRunInThread(bool b)
1509{
1510 d->runInThread = b;
1511}
1512
1514{
1515 KIO_DATA << host;
1516 send(MSG_HOST_INFO_REQ, data);
1517}
1518
1520{
1522 int result = waitForAnswer(CMD_HOST_INFO, 0, data);
1523
1524 if (result == -1) {
1526 info.setErrorString(i18n("Unknown Error"));
1527 return result;
1528 }
1529
1530 QDataStream stream(data);
1531 QString hostName;
1532 QList<QHostAddress> addresses;
1533 int error;
1534 QString errorString;
1535
1536 stream >> hostName >> addresses >> error >> errorString;
1537
1538 info.setHostName(hostName);
1539 info.setAddresses(addresses);
1541 info.setErrorString(errorString);
1542
1543 return result;
1544}
1545
1547{
1548 if (d->m_privilegeOperationStatus == OperationNotAllowed) {
1549 QByteArray buffer;
1550 send(MSG_PRIVILEGE_EXEC);
1551 waitForAnswer(MSG_PRIVILEGE_EXEC, 0, buffer);
1552 QDataStream ds(buffer);
1553 ds >> d->m_privilegeOperationStatus >> d->m_warningTitle >> d->m_warningMessage;
1554 }
1555
1556 if (metaData(QStringLiteral("UnitTesting")) != QLatin1String("true") && d->m_privilegeOperationStatus == OperationAllowed && !d->m_confirmationAsked) {
1557 // WORKER_MESSAGEBOX_DETAILS_HACK
1558 // SlaveBase::messageBox() overloads miss a parameter to pass an details argument.
1559 // As workaround details are passed instead via metadata before and then cached by the WorkerInterface,
1560 // to be used in the upcoming messageBox call (needs WarningContinueCancelDetailed type)
1561 // TODO: add a messageBox() overload taking details and use here,
1562 // then remove or adapt all code marked with WORKER_MESSAGEBOX_DETAILS
1563 setMetaData(QStringLiteral("privilege_conf_details"), operationDetails);
1564 sendMetaData();
1565
1566 int result = messageBox(d->m_warningMessage, WarningContinueCancelDetailed, d->m_warningTitle, QString(), QString(), QString());
1567 d->m_privilegeOperationStatus = result == Continue ? OperationAllowed : OperationCanceled;
1568 d->m_confirmationAsked = true;
1569 }
1570
1571 return KIO::PrivilegeOperationStatus(d->m_privilegeOperationStatus);
1572}
1573
1575{
1576 d->m_tempAuths.insert(action);
1577}
static void setApplicationData(const KAboutData &aboutData)
This class is intended to make it easier to prompt for, cache and retrieve authorization information.
void setModified(bool flag)
Use this method to indicate that this object has been modified.
Definition authinfo.cpp:147
void setExtraField(const QString &fieldName, const QVariant &value)
Set Extra Field Value.
Definition authinfo.cpp:154
MetaData is a simple map of key/value strings.
There are two classes that specifies the protocol between application (job) and kioslave.
void addTemporaryAuthorization(const QString &action)
Adds action to the list of PolicyKit actions which the slave is authorized to perform.
int proxyConnectTimeout()
virtual void mimetype(const QUrl &url)
Finds MIME type for one file or directory.
bool wasKilled() const
If your ioslave was killed by a signal, wasKilled() returns true.
MetaData allMetaData() const
void mimeType(const QString &_type)
Call this in mimetype() and in get(), when you know the MIME type.
virtual void dispatch(int command, const QByteArray &data)
QMap< QString, QVariant > mapConfig() const
Returns a map to query config/meta-data information from.
virtual void get(const QUrl &url)
get, aka read.
PrivilegeOperationStatus requestPrivilegeOperation(const QString &operationDetails)
Checks with job if privilege operation is allowed.
QString metaData(const QString &key) const
Queries for config/meta-data send by the application to the slave.
int openPasswordDialogV2(KIO::AuthInfo &info, const QString &errorMsg=QString())
Prompt the user for Authorization info (login & password).
void redirection(const QUrl &_url)
Call this to signal a redirection.
virtual void copy(const QUrl &src, const QUrl &dest, int permissions, JobFlags flags)
Copy src into dest.
void sendAndKeepMetaData()
Internal function to transmit meta data to the application.
void speed(unsigned long _bytes_per_second)
Call this in get and copy, to give the current transfer speed, but only if it can't be calculated out...
void infoMessage(const QString &msg)
Call to signal a message, to be displayed if the application wants to, for instance in a status bar.
void processedSize(KIO::filesize_t _bytes)
Call this during get and copy, once in a while, to give some info about the current state.
virtual void reparseConfiguration()
Called by the scheduler to tell the slave that the configuration changed (i.e. proxy settings).
void setTimeoutSpecialCommand(int timeout, const QByteArray &data=QByteArray())
This function sets a timeout of timeout seconds and calls special(data) when the timeout occurs as if...
int messageBox(MessageBoxType type, const QString &text, const QString &title=QString(), const QString &primaryActionText=QString(), const QString &secondaryActionText=QString())
Call this to show a message box from the slave.
virtual void open(const QUrl &url, QIODevice::OpenMode mode)
open.
void warning(const QString &msg)
Call to signal a warning, to be displayed in a dialog box.
virtual void seek(KIO::filesize_t offset)
seek.
void finished()
Call to signal successful completion of any command besides openConnection and closeConnection.
virtual void openConnection()
Opens the connection (forced).
void slaveStatus(const QString &host, bool connected)
Used to report the status of the slave.
bool cacheAuthentication(const AuthInfo &info)
Caches info in a persistent storage like KWallet.
void dataReq()
Asks for data from the job.
virtual void rename(const QUrl &src, const QUrl &dest, JobFlags flags)
Rename oldname into newname.
virtual void write(const QByteArray &data)
write.
void error(int _errid, const QString &_text)
Call to signal an error.
QByteArray mProtocol
Name of the protocol supported by this slave.
Definition slavebase.h:930
virtual void setLinkDest(const QUrl &url, const QString &target)
Change the destination of a symlink.
void truncated(KIO::filesize_t _length)
virtual void listDir(const QUrl &url)
Lists the contents of url.
void sendMetaData()
Internal function to transmit meta data to the application.
void listEntry(const UDSEntry &entry)
It collects entries and emits them via listEntries when enough of them are there or a certain time fr...
bool hasMetaData(const QString &key) const
Queries for the existence of a certain config/meta-data entry send by the application to the slave.
void statEntry(const UDSEntry &_entry)
Call this from stat() to express details about an object, the UDSEntry customarily contains the atoms...
virtual void setHost(const QString &host, quint16 port, const QString &user, const QString &pass)
Set the host.
virtual void chown(const QUrl &url, const QString &owner, const QString &group)
Change ownership of url.
void connected()
Call in openConnection, if you reimplement it, when you're done.
KRemoteEncoding * remoteEncoding()
Returns an object that can translate remote filenames into proper Unicode forms.
void dispatchLoop()
virtual void dispatchOpenCommand(int command, const QByteArray &data)
virtual void symlink(const QString &target, const QUrl &dest, JobFlags flags)
Creates a symbolic link named dest, pointing to target, which may be a relative or an absolute path.
int readData(QByteArray &buffer)
Read data sent by the job, after a dataReq.
MessageBoxType
Type of message box.
Definition slavebase.h:250
void connectSlave(const QString &path)
internal function to connect a slave to/ disconnect from either the slave pool or the application
virtual void put(const QUrl &url, int permissions, JobFlags flags)
put, i.e. write data into a file.
int waitForHostInfo(QHostInfo &info)
Internally used.
void processedPercent(float percent)
Only use this if you can't know in advance the size of the copied data.
virtual void special(const QByteArray &data)
Used for any command that is specific to this slave (protocol).
virtual void del(const QUrl &url, bool isfile)
Delete a file or directory.
void data(const QByteArray &data)
Sends data in the slave to the job (i.e. in get).
virtual void chmod(const QUrl &url, int permissions)
Change permissions on url.
void listEntries(const UDSEntryList &_entry)
Call this in listDir, each time you have a bunch of entries to report.
virtual void setModificationTime(const QUrl &url, const QDateTime &mtime)
Sets the modification time for url.
virtual void slave_status()
Called to get the status of the slave.
void totalSize(KIO::filesize_t _bytes)
Call this in get and copy, to give the total size of the file.
virtual void closeConnection()
Closes the connection (forced).
virtual void read(KIO::filesize_t size)
read.
void setKillFlag()
Internally used.
virtual void stat(const QUrl &url)
Finds all details for one file or directory.
virtual void mkdir(const QUrl &url, int permissions)
Create a directory.
int waitForAnswer(int expected1, int expected2, QByteArray &data, int *pCmd=nullptr)
Wait for an answer to our request, until we get expected1 or expected2.
void canResume()
Call this at the beginning of get(), if the "range-start" metadata was set and returning byte ranges ...
bool checkCachedAuthentication(AuthInfo &info)
Checks for cached authentication based on parameters given by info.
void setMetaData(const QString &key, const QString &value)
Sets meta-data to be send to the application before the first data() or finished() signal.
KConfigGroup * config()
Returns a configuration object to query config/meta-data information from.
virtual void close()
close.
void lookupHost(const QString &host)
Internally used.
void opened()
open succeeds
bool configValue(const QString &key, bool defaultValue) const
Returns a bool from the config/meta-data information.
Universal Directory Service.
void reserve(int size)
Calling this function before inserting items into an empty UDSEntry may save time and memory.
Definition udsentry.cpp:385
void fastInsert(uint field, const QString &value)
insert field with string value, it will assert if the field is already inserted.
Definition udsentry.cpp:390
QString stringValue(uint field) const
Definition udsentry.cpp:365
@ UDS_FILE_TYPE
File type, part of the mode returned by stat (for a link, this returns the file type of the pointed i...
Definition udsentry.h:242
@ UDS_SIZE
Size of the file.
Definition udsentry.h:203
@ UDS_NAME
Filename - as displayed in directory listings etc.
Definition udsentry.h:224
@ UDS_ACCESS
Access permissions (part of the mode returned by stat)
Definition udsentry.h:232
Interface class for kpasswdserver.
void addAuthInfo(const KIO::AuthInfo &info, qlonglong windowId)
Manually add authentication information to kpasswdserver's cache.
bool checkAuthInfo(KIO::AuthInfo *info, qlonglong windowId, qlonglong usertime)
Check if kpasswdserver has cached authentication information regarding an AuthInfo object.
int queryAuthInfo(KIO::AuthInfo *info, const QString &errorMsg, qlonglong windowId, qlonglong usertime)
Let kpasswdserver ask the user for authentication information.
Allows encoding and decoding properly remote filenames into Unicode.
QString i18n(const char *text, const TYPE &arg...)
KCRASH_EXPORT void initialize()
A namespace for KIO globals.
KIOCORE_EXPORT QString unsupportedActionErrorString(const QString &protocol, int cmd)
Returns an appropriate error message if the given command cmd is an unsupported action (ERR_UNSUPPORT...
PrivilegeOperationStatus
Specifies privilege file operation status.
Definition global.h:239
@ Resume
When set, automatically append to the destination file if it exists already.
Definition job_base.h:260
@ Overwrite
When set, automatically overwrite the destination if it exists already.
Definition job_base.h:267
qulonglong filesize_t
64-bit file size
Definition global.h:35
const QList< QKeySequence > & end()
const char * constData() const const
bool isEmpty() const const
QStringList arguments()
void sendPostedEvents(QObject *receiver, int event_type)
QString decodeName(const QByteArray &localFileName)
void setAddresses(const QList< QHostAddress > &addresses)
void setError(HostInfoError error)
void setErrorString(const QString &str)
void setHostName(const QString &hostName)
void reserve(qsizetype size)
void clear()
const_iterator constBegin() const const
const_iterator constEnd() const const
bool contains(const Key &key) const const
iterator end()
iterator find(const Key &key)
iterator insert(const Key &key, const T &value)
bool isEmpty() const const
QThread * thread() const const
iterator begin()
iterator end()
iterator erase(const_iterator pos)
bool isEmpty() const const
void setTestModeEnabled(bool testMode)
QString fromUtf8(QByteArrayView str)
QString number(double n, char format, int precision)
int toInt(bool *ok, int base) const const
long toLong(bool *ok, int base) const const
ulong toULong(bool *ok, int base) const const
CaseInsensitive
QThread * currentThread()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:11:14 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.