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

KDE's Doxygen guidelines are available online.