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.
Definition authinfo.h:50
void setModified(bool flag)
Use this method to indicate that this object has been modified.
Definition authinfo.cpp:147
void setExtraField(const QString &fieldName, const QVariant &value)
Set Extra Field Value.
Definition authinfo.cpp:154
MetaData is a simple map of key/value strings.
Definition metadata.h:23
There are two classes that specifies the protocol between application (job) and kioslave.
Definition slavebase.h:56
void addTemporaryAuthorization(const QString &action)
Adds action to the list of PolicyKit actions which the slave is authorized to perform.
int proxyConnectTimeout()
virtual void mimetype(const QUrl &url)
Finds MIME type for one file or directory.
bool wasKilled() const
If your ioslave was killed by a signal, wasKilled() returns true.
MetaData allMetaData() const
void mimeType(const QString &_type)
Call this in mimetype() and in get(), when you know the MIME type.
virtual void dispatch(int command, const QByteArray &data)
QMap< QString, QVariant > mapConfig() const
Returns a map to query config/meta-data information from.
virtual void get(const QUrl &url)
get, aka read.
PrivilegeOperationStatus requestPrivilegeOperation(const QString &operationDetails)
Checks with job if privilege operation is allowed.
QString metaData(const QString &key) const
Queries for config/meta-data send by the application to the slave.
int openPasswordDialogV2(KIO::AuthInfo &info, const QString &errorMsg=QString())
Prompt the user for Authorization info (login & password).
void redirection(const QUrl &_url)
Call this to signal a redirection.
virtual void copy(const QUrl &src, const QUrl &dest, int permissions, JobFlags flags)
Copy src into dest.
void sendAndKeepMetaData()
Internal function to transmit meta data to the application.
void speed(unsigned long _bytes_per_second)
Call this in get and copy, to give the current transfer speed, but only if it can't be calculated out...
void infoMessage(const QString &msg)
Call to signal a message, to be displayed if the application wants to, for instance in a status bar.
void processedSize(KIO::filesize_t _bytes)
Call this during get and copy, once in a while, to give some info about the current state.
virtual void reparseConfiguration()
Called by the scheduler to tell the slave that the configuration changed (i.e. proxy settings).
void setTimeoutSpecialCommand(int timeout, const QByteArray &data=QByteArray())
This function sets a timeout of timeout seconds and calls special(data) when the timeout occurs as if...
int messageBox(MessageBoxType type, const QString &text, const QString &title=QString(), const QString &primaryActionText=QString(), const QString &secondaryActionText=QString())
Call this to show a message box from the slave.
virtual void open(const QUrl &url, QIODevice::OpenMode mode)
open.
void warning(const QString &msg)
Call to signal a warning, to be displayed in a dialog box.
virtual void seek(KIO::filesize_t offset)
seek.
void finished()
Call to signal successful completion of any command besides openConnection and closeConnection.
virtual void openConnection()
Opens the connection (forced).
void slaveStatus(const QString &host, bool connected)
Used to report the status of the slave.
bool cacheAuthentication(const AuthInfo &info)
Caches info in a persistent storage like KWallet.
void dataReq()
Asks for data from the job.
virtual void rename(const QUrl &src, const QUrl &dest, JobFlags flags)
Rename oldname into newname.
virtual void write(const QByteArray &data)
write.
void error(int _errid, const QString &_text)
Call to signal an error.
QByteArray mProtocol
Name of the protocol supported by this slave.
Definition slavebase.h: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.
Definition udsentry.h:78
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 Jun 14 2024 11:51:27 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.