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
80typedef QList<QByteArray> AuthKeysList;
81typedef QMap<QString, QByteArray> AuthKeysMap;
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 {
143 Idle,
144 InsideMethod,
145 InsideTimeoutSpecial,
146 FinishedCalled,
147 ErrorCalled
148 } m_state;
149 bool m_finalityCommand = true; // whether finished() or error() may/must be called
150 QByteArray timeoutData;
151
152#ifdef WITH_QTDBUS
153 std::unique_ptr<KPasswdServerClient> m_passwdServerClient;
154#endif
155 bool m_rootEntryListed = false;
156
157 bool m_confirmationAsked;
158 QSet<QString> m_tempAuths;
159 QString m_warningTitle;
160 QString m_warningMessage;
161 int m_privilegeOperationStatus;
162
163 void updateTempAuthStatus()
164 {
165#if defined(Q_OS_UNIX) && !defined(Q_OS_ANDROID)
166 QSet<QString>::iterator it = m_tempAuths.begin();
167 while (it != m_tempAuths.end()) {
168 KAuth::Action action(*it);
169 if (action.status() != KAuth::Action::AuthorizedStatus) {
170 it = m_tempAuths.erase(it);
171 } else {
172 ++it;
173 }
174 }
175#endif
176 }
177
178 bool hasTempAuth() const
179 {
180 return !m_tempAuths.isEmpty();
181 }
182
183 // Reconstructs configGroup from configData and mIncomingMetaData
184 void rebuildConfig()
185 {
186 mapConfig.clear();
187
188 // mIncomingMetaData cascades over config, so we write config first,
189 // to let it be overwritten
190 MetaData::ConstIterator end = configData.constEnd();
191 for (MetaData::ConstIterator it = configData.constBegin(); it != end; ++it) {
192 mapConfig.insert(it.key(), it->toUtf8());
193 }
194
195 end = q->mIncomingMetaData.constEnd();
196 for (MetaData::ConstIterator it = q->mIncomingMetaData.constBegin(); it != end; ++it) {
197 mapConfig.insert(it.key(), it->toUtf8());
198 }
199
200 delete configGroup;
201 configGroup = nullptr;
202 delete config;
203 config = nullptr;
204 }
205
206 bool finalState() const
207 {
208 return ((m_state == FinishedCalled) || (m_state == ErrorCalled));
209 }
210
211 void verifyState(const char *cmdName)
212 {
213 Q_UNUSED(cmdName)
214 KIO_STATE_ASSERT(finalState(),
215 Q_FUNC_INFO,
216 qUtf8Printable(QStringLiteral("%1 did not call finished() or error()! Please fix the %2 KIO worker.")
217 .arg(QLatin1String(cmdName))
219 // Force the command into finished state. We'll not reach this for Debug builds
220 // that fail the assertion. For Release builds we'll have made sure that the
221 // command is actually finished after the verification regardless of what
222 // the slave did.
223 if (!finalState()) {
224 q->finished();
225 }
226 }
227
228 void verifyErrorFinishedNotCalled(const char *cmdName)
229 {
230 Q_UNUSED(cmdName)
231 KIO_STATE_ASSERT(!finalState(),
232 Q_FUNC_INFO,
233 qUtf8Printable(QStringLiteral("%1 called finished() or error(), but it's not supposed to! Please fix the %2 KIO worker.")
234 .arg(QLatin1String(cmdName))
236 }
237
238#ifdef WITH_QTDBUS
239 KPasswdServerClient *passwdServerClient()
240 {
241 if (!m_passwdServerClient) {
242 m_passwdServerClient = std::make_unique<KPasswdServerClient>();
243 }
244
245 return m_passwdServerClient.get();
246 }
247#endif
248};
249
250}
251
252static volatile bool slaveWriteError = false;
253
254#ifdef Q_OS_UNIX
255static SlaveBase *globalSlave;
256
257extern "C" {
258static void genericsig_handler(int sigNumber)
259{
260 ::signal(sigNumber, SIG_IGN);
261 // WABA: Don't do anything that requires malloc, we can deadlock on it since
262 // a SIGTERM signal can come in while we are in malloc/free.
263 // qDebug()<<"kioslave : exiting due to signal "<<sigNumber;
264 // set the flag which will be checked in dispatchLoop() and which *should* be checked
265 // in lengthy operations in the various slaves
266 if (globalSlave != nullptr) {
267 globalSlave->setKillFlag();
268 }
269 ::signal(SIGALRM, SIG_DFL);
270 alarm(5); // generate an alarm signal in 5 seconds, in this time the slave has to exit
271}
272}
273#endif
274
275//////////////
276
277SlaveBase::SlaveBase(const QByteArray &protocol, const QByteArray &pool_socket, const QByteArray &app_socket)
278 : mProtocol(protocol)
279 , d(new SlaveBasePrivate(this))
280
281{
282 Q_ASSERT(!app_socket.isEmpty());
283 d->poolSocket = QFile::decodeName(pool_socket);
284
285 if (QThread::currentThread() == qApp->thread()) {
286#ifndef Q_OS_ANDROID
287 // Setup KCrash for crash reports, but not when running the worker in-app
288 if (QCoreApplication::arguments()[0].endsWith(QLatin1String("kioworker"))) {
289 KAboutData about(QStringLiteral("kioworker"), QString(), QStringLiteral(KIO_VERSION_STRING));
292 }
293#endif
294
295#ifdef Q_OS_UNIX
296 struct sigaction act;
297 act.sa_handler = sigpipe_handler;
298 sigemptyset(&act.sa_mask);
299 act.sa_flags = 0;
300 sigaction(SIGPIPE, &act, nullptr);
301
302 ::signal(SIGINT, &genericsig_handler);
303 ::signal(SIGQUIT, &genericsig_handler);
304 ::signal(SIGTERM, &genericsig_handler);
305
306 globalSlave = this;
307#endif
308 }
309
310 d->isConnectedToApp = true;
311
312 // by kahl for netmgr (need a way to identify slaves)
313 d->slaveid = QString::fromUtf8(protocol) + QString::number(getpid());
314 d->resume = false;
315 d->needSendCanResume = false;
316 d->mapConfig = QMap<QString, QVariant>();
317 d->onHold = false;
318 // d->processed_size = 0;
319 d->totalSize = 0;
320 connectSlave(QFile::decodeName(app_socket));
321
322 d->remotefile = nullptr;
323 d->inOpenLoop = false;
324}
325
326SlaveBase::~SlaveBase()
327{
328 delete d->configGroup;
329 delete d->config;
330 delete d->remotefile;
331}
332
334{
335 while (!d->exit_loop) {
336 if (d->nextTimeout.isValid() && (d->nextTimeout.hasExpired(d->nextTimeoutMsecs))) {
337 QByteArray data = d->timeoutData;
338 d->nextTimeout.invalidate();
339 d->timeoutData = QByteArray();
340 d->m_state = d->InsideTimeoutSpecial;
341 special(data);
342 d->m_state = d->Idle;
343 }
344
345 Q_ASSERT(d->appConnection.inited());
346
347 int ms = -1;
348 if (d->nextTimeout.isValid()) {
349 ms = qMax<int>(d->nextTimeoutMsecs - d->nextTimeout.elapsed(), 1);
350 }
351
352 int ret = -1;
353 if (d->appConnection.hasTaskAvailable() || d->appConnection.waitForIncomingTask(ms)) {
354 // dispatch application messages
355 int cmd;
357 ret = d->appConnection.read(&cmd, data);
358
359 if (ret != -1) {
360 if (d->inOpenLoop) {
362 } else {
363 dispatch(cmd, data);
364 }
365 }
366 } else {
367 ret = d->appConnection.isConnected() ? 0 : -1;
368 }
369
370 if (ret == -1) { // some error occurred, perhaps no more application
371 // When the app exits, should the slave be put back in the pool ?
372 if (!d->exit_loop && d->isConnectedToApp && !d->poolSocket.isEmpty()) {
373 disconnectSlave();
374 d->isConnectedToApp = false;
376 d->updateTempAuthStatus();
377 connectSlave(d->poolSocket);
378 } else {
379 break;
380 }
381 }
382
383 // I think we get here when we were killed in dispatch() and not in select()
384 if (wasKilled()) {
385 // qDebug() << "worker was killed, returning";
386 break;
387 }
388
389 // execute deferred deletes
391 }
392
393 // execute deferred deletes
395}
396
398{
399 d->appConnection.connectToRemote(QUrl(address));
400
401 if (!d->appConnection.inited()) {
402 /*qDebug() << "failed to connect to" << address << endl
403 << "Reason:" << d->appConnection.errorString();*/
404 exit();
405 }
406
407 d->inOpenLoop = false;
408}
409
410void SlaveBase::disconnectSlave()
411{
412 d->appConnection.close();
413}
414
415void SlaveBase::setMetaData(const QString &key, const QString &value)
416{
417 mOutgoingMetaData.insert(key, value); // replaces existing key if already there
418}
419
421{
422 auto it = mIncomingMetaData.find(key);
423 if (it != mIncomingMetaData.end()) {
424 return *it;
425 }
426 return d->configData.value(key);
427}
428
430{
431 return mIncomingMetaData;
432}
433
434bool SlaveBase::hasMetaData(const QString &key) const
435{
436 if (mIncomingMetaData.contains(key)) {
437 return true;
438 }
439 if (d->configData.contains(key)) {
440 return true;
441 }
442 return false;
443}
444
446{
447 return d->mapConfig;
448}
449
450bool SlaveBase::configValue(const QString &key, bool defaultValue) const
451{
452 return d->mapConfig.value(key, defaultValue).toBool();
453}
454
455int SlaveBase::configValue(const QString &key, int defaultValue) const
456{
457 return d->mapConfig.value(key, defaultValue).toInt();
458}
459
460QString SlaveBase::configValue(const QString &key, const QString &defaultValue) const
461{
462 return d->mapConfig.value(key, defaultValue).toString();
463}
464
466{
467 if (!d->config) {
468 d->config = new KConfig(QString(), KConfig::SimpleConfig);
469
470 d->configGroup = new KConfigGroup(d->config, QString());
471
472 auto end = d->mapConfig.cend();
473 for (auto it = d->mapConfig.cbegin(); it != end; ++it) {
474 d->configGroup->writeEntry(it.key(), it->toString().toUtf8(), KConfigGroup::WriteConfigFlags());
475 }
476 }
477
478 return d->configGroup;
479}
480
482{
484 mOutgoingMetaData.clear();
485}
486
488{
489 if (!mOutgoingMetaData.isEmpty()) {
490 KIO_DATA << mOutgoingMetaData;
491
492 send(INF_META_DATA, data);
493 }
494}
495
497{
498 if (d->remotefile) {
499 return d->remotefile;
500 }
501
502 const QByteArray charset(metaData(QStringLiteral("Charset")).toLatin1());
503 return (d->remotefile = new KRemoteEncoding(charset.constData()));
504}
505
507{
508 sendMetaData();
509 send(MSG_DATA, data);
510}
511
513{
514 // sendMetaData();
515 if (d->needSendCanResume) {
516 canResume(0);
517 }
518 send(MSG_DATA_REQ);
519}
520
522{
523 sendMetaData();
524 send(MSG_OPENED);
525 d->inOpenLoop = true;
526}
527
528void SlaveBase::error(int _errid, const QString &_text)
529{
530 if (d->m_state == d->InsideTimeoutSpecial) {
531 qWarning(KIO_CORE) << "TimeoutSpecialCommand failed with" << _errid << _text;
532 return;
533 }
534
535 KIO_STATE_ASSERT(
536 d->m_finalityCommand,
537 Q_FUNC_INFO,
538 qUtf8Printable(QStringLiteral("error() was called, but it's not supposed to! Please fix the %1 KIO worker.").arg(QCoreApplication::applicationName())));
539
540 if (d->m_state == d->ErrorCalled) {
541 KIO_STATE_ASSERT(false,
542 Q_FUNC_INFO,
543 qUtf8Printable(QStringLiteral("error() called twice! Please fix the %1 KIO worker.").arg(QCoreApplication::applicationName())));
544 return;
545 } else if (d->m_state == d->FinishedCalled) {
546 KIO_STATE_ASSERT(
547 false,
548 Q_FUNC_INFO,
549 qUtf8Printable(QStringLiteral("error() called after finished()! Please fix the %1 KIO worker.").arg(QCoreApplication::applicationName())));
550 return;
551 }
552
553 d->m_state = d->ErrorCalled;
554 mIncomingMetaData.clear(); // Clear meta data
555 d->rebuildConfig();
556 mOutgoingMetaData.clear();
557 KIO_DATA << static_cast<qint32>(_errid) << _text;
558
559 send(MSG_ERROR, data);
560 // reset
561 d->totalSize = 0;
562 d->inOpenLoop = false;
563 d->m_confirmationAsked = false;
564 d->m_privilegeOperationStatus = OperationNotAllowed;
565}
566
568{
569 send(MSG_CONNECTED);
570}
571
573{
574 if (d->m_state == d->InsideTimeoutSpecial) {
575 return;
576 }
577
578 if (!d->pendingListEntries.isEmpty()) {
579 if (!d->m_rootEntryListed) {
580 qCWarning(KIO_CORE) << "UDSEntry for '.' not found, creating a default one. Please fix the" << QCoreApplication::applicationName() << "KIO worker.";
581 KIO::UDSEntry entry;
582 entry.reserve(4);
583 entry.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral("."));
586 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH);
587 d->pendingListEntries.append(entry);
588 }
589
590 listEntries(d->pendingListEntries);
591 d->pendingListEntries.clear();
592 }
593
594 KIO_STATE_ASSERT(
595 d->m_finalityCommand,
596 Q_FUNC_INFO,
597 qUtf8Printable(
598 QStringLiteral("finished() was called, but it's not supposed to! Please fix the %2 KIO worker.").arg(QCoreApplication::applicationName())));
599
600 if (d->m_state == d->FinishedCalled) {
601 KIO_STATE_ASSERT(false,
602 Q_FUNC_INFO,
603 qUtf8Printable(QStringLiteral("finished() called twice! Please fix the %1 KIO worker.").arg(QCoreApplication::applicationName())));
604 return;
605 } else if (d->m_state == d->ErrorCalled) {
606 KIO_STATE_ASSERT(
607 false,
608 Q_FUNC_INFO,
609 qUtf8Printable(QStringLiteral("finished() called after error()! Please fix the %1 KIO worker.").arg(QCoreApplication::applicationName())));
610 return;
611 }
612
613 d->m_state = d->FinishedCalled;
614 mIncomingMetaData.clear(); // Clear meta data
615 d->rebuildConfig();
616 sendMetaData();
617 send(MSG_FINISHED);
618
619 // reset
620 d->totalSize = 0;
621 d->inOpenLoop = false;
622 d->m_rootEntryListed = false;
623 d->m_confirmationAsked = false;
624 d->m_privilegeOperationStatus = OperationNotAllowed;
625}
626
628{
629 qint64 pid = getpid();
630 qint8 b = connected ? 1 : 0;
631 KIO_DATA << pid << mProtocol << host << b << d->onHold << d->onHoldUrl << d->hasTempAuth();
632 send(MSG_WORKER_STATUS, data);
633}
634
636{
637 send(MSG_CANRESUME);
638}
639
641{
642 KIO_DATA << static_cast<quint64>(_bytes);
643 send(INF_TOTAL_SIZE, data);
644
645 // this one is usually called before the first item is listed in listDir()
646 d->totalSize = _bytes;
647}
648
650{
651 bool emitSignal = false;
652
653 if (_bytes == d->totalSize) {
654 emitSignal = true;
655 } else {
656 if (d->lastTimeout.isValid()) {
657 emitSignal = d->lastTimeout.hasExpired(100); // emit size 10 times a second
658 } else {
659 emitSignal = true;
660 }
661 }
662
663 if (emitSignal) {
664 KIO_DATA << static_cast<quint64>(_bytes);
665 send(INF_PROCESSED_SIZE, data);
666 d->lastTimeout.start();
667 }
668
669 // d->processed_size = _bytes;
670}
671
672void SlaveBase::written(KIO::filesize_t _bytes)
673{
674 KIO_DATA << static_cast<quint64>(_bytes);
675 send(MSG_WRITTEN, data);
676}
677
678void SlaveBase::position(KIO::filesize_t _pos)
679{
680 KIO_DATA << static_cast<quint64>(_pos);
681 send(INF_POSITION, data);
682}
683
685{
686 KIO_DATA << static_cast<quint64>(_length);
687 send(INF_TRUNCATED, data);
688}
689
690void SlaveBase::processedPercent(float /* percent */)
691{
692 // qDebug() << "STUB";
693}
694
695void SlaveBase::speed(unsigned long _bytes_per_second)
696{
697 KIO_DATA << static_cast<quint32>(_bytes_per_second);
698 send(INF_SPEED, data);
699}
700
702{
703 KIO_DATA << _url;
704 send(INF_REDIRECTION, data);
705}
706
707static bool isSubCommand(int cmd)
708{
709 /* clang-format off */
710 return cmd == CMD_REPARSECONFIGURATION
711 || cmd == CMD_META_DATA
712 || cmd == CMD_CONFIG
713 || cmd == CMD_WORKER_STATUS;
714 /* clang-format on */
715}
716
717void SlaveBase::mimeType(const QString &_type)
718{
719 qCDebug(KIO_CORE) << "detected mimetype" << _type;
720 int cmd = CMD_NONE;
721 do {
722 if (wasKilled()) {
723 break;
724 }
725
726 // Send the meta-data each time we send the MIME type.
727 if (!mOutgoingMetaData.isEmpty()) {
728 qCDebug(KIO_CORE) << "sending mimetype meta data";
729 KIO_DATA << mOutgoingMetaData;
730 send(INF_META_DATA, data);
731 }
732 KIO_DATA << _type;
733 send(INF_MIME_TYPE, data);
734 while (true) {
735 cmd = 0;
736 int ret = -1;
737 if (d->appConnection.hasTaskAvailable() || d->appConnection.waitForIncomingTask(-1)) {
738 ret = d->appConnection.read(&cmd, data);
739 }
740 if (ret == -1) {
741 qCDebug(KIO_CORE) << "read error on app connection while sending mimetype";
742 exit();
743 break;
744 }
745 qCDebug(KIO_CORE) << "got reply after sending mimetype" << cmd;
746 if (cmd == CMD_HOST) { // Ignore.
747 continue;
748 }
749 if (!isSubCommand(cmd)) {
750 break;
751 }
752
753 dispatch(cmd, data);
754 }
755 } while (cmd != CMD_NONE);
756 mOutgoingMetaData.clear();
757}
758
759void SlaveBase::exit() // possibly called from another thread, only use atomics in here
760{
761 d->exit_loop = true;
762 if (d->runInThread) {
763 d->wasKilled = true;
764 } else {
765 // Using ::exit() here is too much (crashes in qdbus's qglobalstatic object),
766 // so let's cleanly exit dispatchLoop() instead.
767 // Update: we do need to call exit(), otherwise a long download (get()) would
768 // keep going until it ends, even though the application exited.
769 ::exit(255);
770 }
771}
772
774{
775 KIO_DATA << _msg;
776 send(INF_WARNING, data);
777}
778
780{
781 KIO_DATA << _msg;
782 send(INF_INFOMESSAGE, data);
783}
784
786{
787 KIO_DATA << entry;
788 send(MSG_STAT_ENTRY, data);
789}
790
792{
793 // #366795: many slaves don't create an entry for ".", so we keep track if they do
794 // and we provide a fallback in finished() otherwise.
796 d->m_rootEntryListed = true;
797 }
798
799 // We start measuring the time from the point we start filling the list
800 if (d->pendingListEntries.isEmpty()) {
801 d->m_timeSinceLastBatch.restart();
802 }
803
804 d->pendingListEntries.append(entry);
805
806 // If more then KIO_MAX_SEND_BATCH_TIME time is passed, emit the current batch
807 // Also emit if we have piled up a large number of entries already, to save memory (and time)
808 if (d->m_timeSinceLastBatch.elapsed() > KIO_MAX_SEND_BATCH_TIME || d->pendingListEntries.size() > KIO_MAX_ENTRIES_PER_BATCH) {
809 listEntries(d->pendingListEntries);
810 d->pendingListEntries.clear();
811
812 // Restart time
813 d->m_timeSinceLastBatch.restart();
814 }
815}
816
818{
821
822 for (const UDSEntry &entry : list) {
823 stream << entry;
824 }
825
826 send(MSG_LIST_ENTRIES, data);
827}
828
829static void sigpipe_handler(int)
830{
831 // We ignore a SIGPIPE in slaves.
832 // A SIGPIPE can happen in two cases:
833 // 1) Communication error with application.
834 // 2) Communication error with network.
835 slaveWriteError = true;
836
837 // Don't add anything else here, especially no debug output
838}
839
840void SlaveBase::setHost(QString const &, quint16, QString const &, QString const &)
841{
842}
843
844// TODO: move unsupportedActionErrorString() to workerbase.cpp
845// once SlaveBase is dissolved and folded into WorkerBase
846// forward declaration is already in workerbase.h
847namespace KIO
848{
849KIOCORE_EXPORT QString unsupportedActionErrorString(const QString &protocol, int cmd)
850{
851 switch (cmd) {
852 case CMD_CONNECT:
853 return i18n("Opening connections is not supported with the protocol %1.", protocol);
854 case CMD_DISCONNECT:
855 return i18n("Closing connections is not supported with the protocol %1.", protocol);
856 case CMD_STAT:
857 return i18n("Accessing files is not supported with the protocol %1.", protocol);
858 case CMD_PUT:
859 return i18n("Writing to %1 is not supported.", protocol);
860 case CMD_SPECIAL:
861 return i18n("There are no special actions available for protocol %1.", protocol);
862 case CMD_LISTDIR:
863 return i18n("Listing folders is not supported for protocol %1.", protocol);
864 case CMD_GET:
865 return i18n("Retrieving data from %1 is not supported.", protocol);
866 case CMD_MIMETYPE:
867 return i18n("Retrieving mime type information from %1 is not supported.", protocol);
868 case CMD_RENAME:
869 return i18n("Renaming or moving files within %1 is not supported.", protocol);
870 case CMD_SYMLINK:
871 return i18n("Creating symlinks is not supported with protocol %1.", protocol);
872 case CMD_COPY:
873 return i18n("Copying files within %1 is not supported.", protocol);
874 case CMD_DEL:
875 return i18n("Deleting files from %1 is not supported.", protocol);
876 case CMD_MKDIR:
877 return i18n("Creating folders is not supported with protocol %1.", protocol);
878 case CMD_CHMOD:
879 return i18n("Changing the attributes of files is not supported with protocol %1.", protocol);
880 case CMD_CHOWN:
881 return i18n("Changing the ownership of files is not supported with protocol %1.", protocol);
882 case CMD_OPEN:
883 return i18n("Opening files is not supported with protocol %1.", protocol);
884 default:
885 return i18n("Protocol %1 does not support action %2.", protocol, cmd);
886 } /*end switch*/
887}
888}
889
891{
892 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_CONNECT));
893}
895{
896} // No response!
898{
899 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_STAT));
900}
901void SlaveBase::put(QUrl const &, int, JobFlags)
902{
903 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_PUT));
904}
906{
907 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_SPECIAL));
908}
910{
911 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_LISTDIR));
912}
913void SlaveBase::get(QUrl const &)
914{
915 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_GET));
916}
918{
919 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_OPEN));
920}
922{
923 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_READ));
924}
926{
927 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_WRITE));
928}
930{
931 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_SEEK));
932}
934{
935 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_CLOSE));
936}
937void SlaveBase::mimetype(QUrl const &url)
938{
939 get(url);
940}
941void SlaveBase::rename(QUrl const &, QUrl const &, JobFlags)
942{
943 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_RENAME));
944}
946{
947 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_SYMLINK));
948}
949void SlaveBase::copy(QUrl const &, QUrl const &, int, JobFlags)
950{
951 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_COPY));
952}
953void SlaveBase::del(QUrl const &, bool)
954{
955 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_DEL));
956}
957void SlaveBase::setLinkDest(const QUrl &, const QString &)
958{
959 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_SETLINKDEST));
960}
961void SlaveBase::mkdir(QUrl const &, int)
962{
963 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_MKDIR));
964}
965void SlaveBase::chmod(QUrl const &, int)
966{
967 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_CHMOD));
968}
970{
971 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_SETMODIFICATIONTIME));
972}
973void SlaveBase::chown(QUrl const &, const QString &, const QString &)
974{
975 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_CHOWN));
976}
977
979{
980 slaveStatus(QString(), false);
981}
982
984{
985 delete d->remotefile;
986 d->remotefile = nullptr;
987}
988
990{
991 const long windowId = metaData(QStringLiteral("window-id")).toLong();
992 const unsigned long userTimestamp = metaData(QStringLiteral("user-timestamp")).toULong();
993 QString errorMessage;
994 if (metaData(QStringLiteral("no-auth-prompt")).compare(QLatin1String("true"), Qt::CaseInsensitive) == 0) {
995 errorMessage = QStringLiteral("<NoAuthPrompt>");
996 } else {
997 errorMessage = errorMsg;
998 }
999
1000 AuthInfo dlgInfo(info);
1001 // Make sure the modified flag is not set.
1002 dlgInfo.setModified(false);
1003 // Prevent queryAuthInfo from caching the user supplied password since
1004 // we need the ioslaves to first authenticate against the server with
1005 // it to ensure it is valid.
1006 dlgInfo.setExtraField(QStringLiteral("skip-caching-on-query"), true);
1007
1008#ifdef WITH_QTDBUS
1009 KPasswdServerClient *passwdServerClient = d->passwdServerClient();
1010 const int errCode = passwdServerClient->queryAuthInfo(&dlgInfo, errorMessage, windowId, userTimestamp);
1011 if (errCode == KJob::NoError) {
1012 info = dlgInfo;
1013 }
1014 return errCode;
1015#else
1016 return KJob::NoError;
1017#endif
1018}
1019
1020int SlaveBase::messageBox(MessageBoxType type, const QString &text, const QString &title, const QString &primaryActionText, const QString &secondaryActionText)
1021{
1022 return messageBox(text, type, title, primaryActionText, secondaryActionText, QString());
1023}
1024
1026 MessageBoxType type,
1027 const QString &title,
1028 const QString &primaryActionText,
1029 const QString &secondaryActionText,
1030 const QString &dontAskAgainName)
1031{
1032 KIO_DATA << static_cast<qint32>(type) << text << title << primaryActionText << secondaryActionText << dontAskAgainName;
1033 send(INF_MESSAGEBOX, data);
1034 if (waitForAnswer(CMD_MESSAGEBOXANSWER, 0, data) != -1) {
1035 QDataStream stream(data);
1036 int answer;
1037 stream >> answer;
1038 return answer;
1039 } else {
1040 return 0; // communication failure
1041 }
1042}
1043
1044int SlaveBase::sslError(const QVariantMap &sslData)
1045{
1046 KIO_DATA << sslData;
1047 send(INF_SSLERROR, data);
1048 if (waitForAnswer(CMD_SSLERRORANSWER, 0, data) != -1) {
1049 QDataStream stream(data);
1050 int answer;
1051 stream >> answer;
1052 return answer;
1053 } else {
1054 return 0; // communication failure
1055 }
1056}
1057
1059{
1060 // qDebug() << "offset=" << KIO::number(offset);
1061 d->needSendCanResume = false;
1062 KIO_DATA << static_cast<quint64>(offset);
1063 send(MSG_RESUME, data);
1064 if (offset) {
1065 int cmd;
1066 if (waitForAnswer(CMD_RESUMEANSWER, CMD_NONE, data, &cmd) != -1) {
1067 // qDebug() << "returning" << (cmd == CMD_RESUMEANSWER);
1068 return cmd == CMD_RESUMEANSWER;
1069 } else {
1070 return false;
1071 }
1072 } else { // No resuming possible -> no answer to wait for
1073 return true;
1074 }
1075}
1076
1077int SlaveBase::waitForAnswer(int expected1, int expected2, QByteArray &data, int *pCmd)
1078{
1079 int cmd = 0;
1080 int result = -1;
1081 for (;;) {
1082 if (d->appConnection.hasTaskAvailable() || d->appConnection.waitForIncomingTask(-1)) {
1083 result = d->appConnection.read(&cmd, data);
1084 }
1085 if (result == -1) {
1086 // qDebug() << "read error.";
1087 return -1;
1088 }
1089
1090 if (cmd == expected1 || cmd == expected2) {
1091 if (pCmd) {
1092 *pCmd = cmd;
1093 }
1094 return result;
1095 }
1096 if (isSubCommand(cmd)) {
1097 dispatch(cmd, data);
1098 } else {
1099 qFatal("Fatal Error: Got cmd %d, while waiting for an answer!", cmd);
1100 }
1101 }
1102}
1103
1105{
1106 int result = waitForAnswer(MSG_DATA, 0, buffer);
1107 // qDebug() << "readData: length = " << result << " ";
1108 return result;
1109}
1110
1112{
1113 if (timeout > 0) {
1114 d->nextTimeoutMsecs = timeout * 1000; // from seconds to milliseconds
1115 d->nextTimeout.start();
1116 } else if (timeout == 0) {
1117 d->nextTimeoutMsecs = 1000; // Immediate timeout
1118 d->nextTimeout.start();
1119 } else {
1120 d->nextTimeout.invalidate(); // Canceled
1121 }
1122
1123 d->timeoutData = data;
1124}
1125
1126void SlaveBase::dispatch(int command, const QByteArray &data)
1127{
1128 QDataStream stream(data);
1129
1130 QUrl url;
1131 int i;
1132
1133 d->m_finalityCommand = true; // default
1134
1135 switch (command) {
1136 case CMD_HOST: {
1137 QString passwd;
1138 QString host;
1139 QString user;
1140 quint16 port;
1141 stream >> host >> port >> user >> passwd;
1142 d->m_state = d->InsideMethod;
1143 d->m_finalityCommand = false;
1144 setHost(host, port, user, passwd);
1145 d->m_state = d->Idle;
1146 break;
1147 }
1148 case CMD_CONNECT: {
1150 break;
1151 }
1152 case CMD_DISCONNECT: {
1154 break;
1155 }
1156 case CMD_WORKER_STATUS: {
1157 d->m_state = d->InsideMethod;
1158 d->m_finalityCommand = false;
1159 slave_status();
1160 // TODO verify that the slave has called slaveStatus()?
1161 d->m_state = d->Idle;
1162 break;
1163 }
1164 case CMD_REPARSECONFIGURATION: {
1165 d->m_state = d->InsideMethod;
1166 d->m_finalityCommand = false;
1168 d->m_state = d->Idle;
1169 break;
1170 }
1171 case CMD_CONFIG: {
1172 stream >> d->configData;
1173 d->rebuildConfig();
1174 delete d->remotefile;
1175 d->remotefile = nullptr;
1176 break;
1177 }
1178 case CMD_GET: {
1179 stream >> url;
1180 d->m_state = d->InsideMethod;
1181 get(url);
1182 d->verifyState("get()");
1183 d->m_state = d->Idle;
1184 break;
1185 }
1186 case CMD_OPEN: {
1187 stream >> url >> i;
1188 QIODevice::OpenMode mode = QFlag(i);
1189 d->m_state = d->InsideMethod;
1190 open(url, mode); // krazy:exclude=syscalls
1191 d->m_state = d->Idle;
1192 break;
1193 }
1194 case CMD_PUT: {
1195 int permissions;
1196 qint8 iOverwrite;
1197 qint8 iResume;
1198 stream >> url >> iOverwrite >> iResume >> permissions;
1199 JobFlags flags;
1200 if (iOverwrite != 0) {
1201 flags |= Overwrite;
1202 }
1203 if (iResume != 0) {
1204 flags |= Resume;
1205 }
1206
1207 // Remember that we need to send canResume(), TransferJob is expecting
1208 // it. Well, in theory this shouldn't be done if resume is true.
1209 // (the resume bool is currently unused)
1210 d->needSendCanResume = true /* !resume */;
1211
1212 d->m_state = d->InsideMethod;
1213 put(url, permissions, flags);
1214 d->verifyState("put()");
1215 d->m_state = d->Idle;
1216 break;
1217 }
1218 case CMD_STAT: {
1219 stream >> url;
1220 d->m_state = d->InsideMethod;
1221 stat(url); // krazy:exclude=syscalls
1222 d->verifyState("stat()");
1223 d->m_state = d->Idle;
1224 break;
1225 }
1226 case CMD_MIMETYPE: {
1227 stream >> url;
1228 d->m_state = d->InsideMethod;
1229 mimetype(url);
1230 d->verifyState("mimetype()");
1231 d->m_state = d->Idle;
1232 break;
1233 }
1234 case CMD_LISTDIR: {
1235 stream >> url;
1236 d->m_state = d->InsideMethod;
1237 listDir(url);
1238 d->verifyState("listDir()");
1239 d->m_state = d->Idle;
1240 break;
1241 }
1242 case CMD_MKDIR: {
1243 stream >> url >> i;
1244 d->m_state = d->InsideMethod;
1245 mkdir(url, i); // krazy:exclude=syscalls
1246 d->verifyState("mkdir()");
1247 d->m_state = d->Idle;
1248 break;
1249 }
1250 case CMD_RENAME: {
1251 qint8 iOverwrite;
1252 QUrl url2;
1253 stream >> url >> url2 >> iOverwrite;
1254 JobFlags flags;
1255 if (iOverwrite != 0) {
1256 flags |= Overwrite;
1257 }
1258 d->m_state = d->InsideMethod;
1259 rename(url, url2, flags); // krazy:exclude=syscalls
1260 d->verifyState("rename()");
1261 d->m_state = d->Idle;
1262 break;
1263 }
1264 case CMD_SYMLINK: {
1265 qint8 iOverwrite;
1266 QString target;
1267 stream >> target >> url >> iOverwrite;
1268 JobFlags flags;
1269 if (iOverwrite != 0) {
1270 flags |= Overwrite;
1271 }
1272 d->m_state = d->InsideMethod;
1273 symlink(target, url, flags);
1274 d->verifyState("symlink()");
1275 d->m_state = d->Idle;
1276 break;
1277 }
1278 case CMD_COPY: {
1279 int permissions;
1280 qint8 iOverwrite;
1281 QUrl url2;
1282 stream >> url >> url2 >> permissions >> iOverwrite;
1283 JobFlags flags;
1284 if (iOverwrite != 0) {
1285 flags |= Overwrite;
1286 }
1287 d->m_state = d->InsideMethod;
1288 copy(url, url2, permissions, flags);
1289 d->verifyState("copy()");
1290 d->m_state = d->Idle;
1291 break;
1292 }
1293 case CMD_DEL: {
1294 qint8 isFile;
1295 stream >> url >> isFile;
1296 d->m_state = d->InsideMethod;
1297 del(url, isFile != 0);
1298 d->verifyState("del()");
1299 d->m_state = d->Idle;
1300 break;
1301 }
1302 case CMD_CHMOD: {
1303 stream >> url >> i;
1304 d->m_state = d->InsideMethod;
1305 chmod(url, i);
1306 d->verifyState("chmod()");
1307 d->m_state = d->Idle;
1308 break;
1309 }
1310 case CMD_CHOWN: {
1311 QString owner;
1312 QString group;
1313 stream >> url >> owner >> group;
1314 d->m_state = d->InsideMethod;
1315 chown(url, owner, group);
1316 d->verifyState("chown()");
1317 d->m_state = d->Idle;
1318 break;
1319 }
1320 case CMD_SETMODIFICATIONTIME: {
1321 QDateTime dt;
1322 stream >> url >> dt;
1323 d->m_state = d->InsideMethod;
1324 setModificationTime(url, dt);
1325 d->verifyState("setModificationTime()");
1326 d->m_state = d->Idle;
1327 break;
1328 }
1329 case CMD_SPECIAL: {
1330 d->m_state = d->InsideMethod;
1331 special(data);
1332 d->verifyState("special()");
1333 d->m_state = d->Idle;
1334 break;
1335 }
1336 case CMD_META_DATA: {
1337 // qDebug() << "(" << getpid() << ") Incoming meta-data...";
1338 stream >> mIncomingMetaData;
1339 d->rebuildConfig();
1340 break;
1341 }
1342 case CMD_NONE: {
1343 qCWarning(KIO_CORE) << "Got unexpected CMD_NONE!";
1344 break;
1345 }
1346 case CMD_FILESYSTEMFREESPACE: {
1347 stream >> url;
1348
1349 void *data = static_cast<void *>(&url);
1350
1351 d->m_state = d->InsideMethod;
1352 virtual_hook(GetFileSystemFreeSpace, data);
1353 d->verifyState("fileSystemFreeSpace()");
1354 d->m_state = d->Idle;
1355 break;
1356 }
1357 default: {
1358 // Some command we don't understand.
1359 // Just ignore it, it may come from some future version of KIO.
1360 break;
1361 }
1362 }
1363}
1364
1366{
1367#ifdef WITH_QTDBUS
1368 KPasswdServerClient *passwdServerClient = d->passwdServerClient();
1369 return (passwdServerClient->checkAuthInfo(&info, metaData(QStringLiteral("window-id")).toLong(), metaData(QStringLiteral("user-timestamp")).toULong()));
1370#else
1371 return false;
1372#endif
1373}
1374
1376{
1377 QDataStream stream(data);
1378
1379 switch (command) {
1380 case CMD_READ: {
1381 KIO::filesize_t bytes;
1382 stream >> bytes;
1383 read(bytes);
1384 break;
1385 }
1386 case CMD_WRITE: {
1387 write(data);
1388 break;
1389 }
1390 case CMD_SEEK: {
1391 KIO::filesize_t offset;
1392 stream >> offset;
1393 seek(offset);
1394 break;
1395 }
1396 case CMD_TRUNCATE: {
1397 KIO::filesize_t length;
1398 stream >> length;
1399 void *data = static_cast<void *>(&length);
1400 virtual_hook(Truncate, data);
1401 break;
1402 }
1403 case CMD_NONE:
1404 break;
1405 case CMD_CLOSE:
1406 close(); // must call finish(), which will set d->inOpenLoop=false
1407 break;
1408 default:
1409 // Some command we don't understand.
1410 // Just ignore it, it may come from some future version of KIO.
1411 break;
1412 }
1413}
1414
1416{
1417#ifdef WITH_QTDBUS
1418 KPasswdServerClient *passwdServerClient = d->passwdServerClient();
1419 passwdServerClient->addAuthInfo(info, metaData(QStringLiteral("window-id")).toLongLong());
1420#endif
1421 return true;
1422}
1423
1424#if KIOCORE_BUILD_DEPRECATED_SINCE(6, 11)
1426{
1427 bool ok;
1428 QString tmp = metaData(QStringLiteral("ConnectTimeout"));
1429 int result = tmp.toInt(&ok);
1430 if (ok) {
1431 return result;
1432 }
1433 return DEFAULT_CONNECT_TIMEOUT;
1434}
1435#endif
1436
1437#if KIOCORE_BUILD_DEPRECATED_SINCE(6, 11)
1439{
1440 bool ok;
1441 QString tmp = metaData(QStringLiteral("ProxyConnectTimeout"));
1442 int result = tmp.toInt(&ok);
1443 if (ok) {
1444 return result;
1445 }
1446 return DEFAULT_PROXY_CONNECT_TIMEOUT;
1447}
1448#endif
1449
1450#if KIOCORE_BUILD_DEPRECATED_SINCE(6, 11)
1452{
1453 bool ok;
1454 QString tmp = metaData(QStringLiteral("ResponseTimeout"));
1455 int result = tmp.toInt(&ok);
1456 if (ok) {
1457 return result;
1458 }
1459 return DEFAULT_RESPONSE_TIMEOUT;
1460}
1461#endif
1462
1463#if KIOCORE_BUILD_DEPRECATED_SINCE(6, 11)
1465{
1466 bool ok;
1467 QString tmp = metaData(QStringLiteral("ReadTimeout"));
1468 int result = tmp.toInt(&ok);
1469 if (ok) {
1470 return result;
1471 }
1472 return DEFAULT_READ_TIMEOUT;
1473}
1474#endif
1475
1477{
1478 return d->wasKilled;
1479}
1480
1482{
1483 d->wasKilled = true;
1484}
1485
1486void SlaveBase::send(int cmd, const QByteArray &arr)
1487{
1488 if (d->runInThread) {
1489 if (!d->appConnection.send(cmd, arr)) {
1490 exit();
1491 }
1492 } else {
1493 slaveWriteError = false;
1494 if (!d->appConnection.send(cmd, arr))
1495 // Note that slaveWriteError can also be set by sigpipe_handler
1496 {
1497 slaveWriteError = true;
1498 }
1499 if (slaveWriteError) {
1500 qCWarning(KIO_CORE) << "An error occurred during write. The worker terminates now.";
1501 exit();
1502 }
1503 }
1504}
1505
1506void SlaveBase::virtual_hook(int id, void *data)
1507{
1508 Q_UNUSED(data);
1509
1510 switch (id) {
1511 case GetFileSystemFreeSpace: {
1512 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_FILESYSTEMFREESPACE));
1513 break;
1514 }
1515 case Truncate: {
1516 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_TRUNCATE));
1517 break;
1518 }
1519 }
1520}
1521
1522void SlaveBase::setRunInThread(bool b)
1523{
1524 d->runInThread = b;
1525}
1526
1528{
1529 KIO_DATA << host;
1530 send(MSG_HOST_INFO_REQ, data);
1531}
1532
1534{
1536 int result = waitForAnswer(CMD_HOST_INFO, 0, data);
1537
1538 if (result == -1) {
1540 info.setErrorString(i18n("Unknown Error"));
1541 return result;
1542 }
1543
1544 QDataStream stream(data);
1545 QString hostName;
1546 QList<QHostAddress> addresses;
1547 int error;
1548 QString errorString;
1549
1550 stream >> hostName >> addresses >> error >> errorString;
1551
1552 info.setHostName(hostName);
1553 info.setAddresses(addresses);
1555 info.setErrorString(errorString);
1556
1557 return result;
1558}
1559
1561{
1562 if (d->m_privilegeOperationStatus == OperationNotAllowed) {
1563 QByteArray buffer;
1564 send(MSG_PRIVILEGE_EXEC);
1565 waitForAnswer(MSG_PRIVILEGE_EXEC, 0, buffer);
1566 QDataStream ds(buffer);
1567 ds >> d->m_privilegeOperationStatus >> d->m_warningTitle >> d->m_warningMessage;
1568 }
1569
1570 if (metaData(QStringLiteral("UnitTesting")) != QLatin1String("true") && d->m_privilegeOperationStatus == OperationAllowed && !d->m_confirmationAsked) {
1571 // WORKER_MESSAGEBOX_DETAILS_HACK
1572 // SlaveBase::messageBox() overloads miss a parameter to pass an details argument.
1573 // As workaround details are passed instead via metadata before and then cached by the WorkerInterface,
1574 // to be used in the upcoming messageBox call (needs WarningContinueCancelDetailed type)
1575 // TODO: add a messageBox() overload taking details and use here,
1576 // then remove or adapt all code marked with WORKER_MESSAGEBOX_DETAILS
1577 setMetaData(QStringLiteral("privilege_conf_details"), operationDetails);
1578 sendMetaData();
1579
1580 int result = messageBox(d->m_warningMessage, WarningContinueCancelDetailed, d->m_warningTitle, QString(), QString(), QString());
1581 d->m_privilegeOperationStatus = result == Continue ? OperationAllowed : OperationCanceled;
1582 d->m_confirmationAsked = true;
1583 }
1584
1585 return KIO::PrivilegeOperationStatus(d->m_privilegeOperationStatus);
1586}
1587
1589{
1590 d->m_tempAuths.insert(action);
1591}
static void setApplicationData(const KAboutData &aboutData)
QFlags< WriteConfigFlag > WriteConfigFlags
This class is intended to make it easier to prompt for, cache and retrieve authorization information.
Definition authinfo.h:50
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.
Definition metadata.h:23
There are two classes that specifies the protocol between application (job) and kioslave.
Definition slavebase.h:56
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:938
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.
Definition udsentry.h:79
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
QList< UDSEntry > UDSEntryList
A directory listing is a list of UDSEntry instances.
Definition udsentry.h:379
QFlags< JobFlag > JobFlags
Stores a combination of JobFlag values.
Definition job_base.h:281
@ 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 setTestModeEnabled(bool testMode)
void clear()
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-2025 The KDE developers.
Generated on Fri Jan 24 2025 11:49:37 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.