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 {
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
627void SlaveBase::slaveStatus(const QString &host, bool connected)
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
1375void SlaveBase::dispatchOpenCommand(int command, const QByteArray &data)
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
1425{
1426 bool ok;
1427 QString tmp = metaData(QStringLiteral("ConnectTimeout"));
1428 int result = tmp.toInt(&ok);
1429 if (ok) {
1430 return result;
1431 }
1432 return DEFAULT_CONNECT_TIMEOUT;
1433}
1434
1436{
1437 bool ok;
1438 QString tmp = metaData(QStringLiteral("ProxyConnectTimeout"));
1439 int result = tmp.toInt(&ok);
1440 if (ok) {
1441 return result;
1442 }
1443 return DEFAULT_PROXY_CONNECT_TIMEOUT;
1444}
1445
1447{
1448 bool ok;
1449 QString tmp = metaData(QStringLiteral("ResponseTimeout"));
1450 int result = tmp.toInt(&ok);
1451 if (ok) {
1452 return result;
1453 }
1454 return DEFAULT_RESPONSE_TIMEOUT;
1455}
1456
1458{
1459 bool ok;
1460 QString tmp = metaData(QStringLiteral("ReadTimeout"));
1461 int result = tmp.toInt(&ok);
1462 if (ok) {
1463 return result;
1464 }
1465 return DEFAULT_READ_TIMEOUT;
1466}
1467
1469{
1470 return d->wasKilled;
1471}
1472
1474{
1475 d->wasKilled = true;
1476}
1477
1478void SlaveBase::send(int cmd, const QByteArray &arr)
1479{
1480 if (d->runInThread) {
1481 if (!d->appConnection.send(cmd, arr)) {
1482 exit();
1483 }
1484 } else {
1485 slaveWriteError = false;
1486 if (!d->appConnection.send(cmd, arr))
1487 // Note that slaveWriteError can also be set by sigpipe_handler
1488 {
1489 slaveWriteError = true;
1490 }
1491 if (slaveWriteError) {
1492 qCWarning(KIO_CORE) << "An error occurred during write. The worker terminates now.";
1493 exit();
1494 }
1495 }
1496}
1497
1498void SlaveBase::virtual_hook(int id, void *data)
1499{
1500 Q_UNUSED(data);
1501
1502 switch (id) {
1503 case GetFileSystemFreeSpace: {
1504 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_FILESYSTEMFREESPACE));
1505 break;
1506 }
1507 case Truncate: {
1508 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_TRUNCATE));
1509 break;
1510 }
1511 }
1512}
1513
1514void SlaveBase::setRunInThread(bool b)
1515{
1516 d->runInThread = b;
1517}
1518
1520{
1521 KIO_DATA << host;
1522 send(MSG_HOST_INFO_REQ, data);
1523}
1524
1526{
1528 int result = waitForAnswer(CMD_HOST_INFO, 0, data);
1529
1530 if (result == -1) {
1532 info.setErrorString(i18n("Unknown Error"));
1533 return result;
1534 }
1535
1536 QDataStream stream(data);
1537 QString hostName;
1538 QList<QHostAddress> addresses;
1539 int error;
1540 QString errorString;
1541
1542 stream >> hostName >> addresses >> error >> errorString;
1543
1544 info.setHostName(hostName);
1545 info.setAddresses(addresses);
1547 info.setErrorString(errorString);
1548
1549 return result;
1550}
1551
1553{
1554 if (d->m_privilegeOperationStatus == OperationNotAllowed) {
1555 QByteArray buffer;
1556 send(MSG_PRIVILEGE_EXEC);
1557 waitForAnswer(MSG_PRIVILEGE_EXEC, 0, buffer);
1558 QDataStream ds(buffer);
1559 ds >> d->m_privilegeOperationStatus >> d->m_warningTitle >> d->m_warningMessage;
1560 }
1561
1562 if (metaData(QStringLiteral("UnitTesting")) != QLatin1String("true") && d->m_privilegeOperationStatus == OperationAllowed && !d->m_confirmationAsked) {
1563 // WORKER_MESSAGEBOX_DETAILS_HACK
1564 // SlaveBase::messageBox() overloads miss a parameter to pass an details argument.
1565 // As workaround details are passed instead via metadata before and then cached by the WorkerInterface,
1566 // to be used in the upcoming messageBox call (needs WarningContinueCancelDetailed type)
1567 // TODO: add a messageBox() overload taking details and use here,
1568 // then remove or adapt all code marked with WORKER_MESSAGEBOX_DETAILS
1569 setMetaData(QStringLiteral("privilege_conf_details"), operationDetails);
1570 sendMetaData();
1571
1572 int result = messageBox(d->m_warningMessage, WarningContinueCancelDetailed, d->m_warningTitle, QString(), QString(), QString());
1573 d->m_privilegeOperationStatus = result == Continue ? OperationAllowed : OperationCanceled;
1574 d->m_confirmationAsked = true;
1575 }
1576
1577 return KIO::PrivilegeOperationStatus(d->m_privilegeOperationStatus);
1578}
1579
1581{
1582 d->m_tempAuths.insert(action);
1583}
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 Sat Dec 21 2024 16:58:45 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.