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 
72 extern "C" {
73 static void sigpipe_handler(int sig);
74 }
75 
76 using 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 
88 static constexpr int KIO_MAX_ENTRIES_PER_BATCH = 200;
89 static constexpr int KIO_MAX_SEND_BATCH_TIME = 300;
90 
91 namespace KIO
92 {
93 class SlaveBasePrivate
94 {
95 public:
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;
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 #ifndef KIO_ANDROID_STUB
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 #ifndef KIO_ANDROID_STUB
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 
244 static volatile bool slaveWriteError = false;
245 
246 #ifdef Q_OS_UNIX
247 static SlaveBase *globalSlave;
248 
249 extern "C" {
250 static 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 
269 SlaveBase::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 
313 SlaveBase::~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;
362  closeConnection();
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 
384 void SlaveBase::connectSlave(const QString &address)
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 
397 void SlaveBase::disconnectSlave()
398 {
399  d->appConnection.close();
400 }
401 
402 void 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 
421 bool 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 
437 bool SlaveBase::configValue(const QString &key, bool defaultValue) const
438 {
439  return d->mapConfig.value(key, defaultValue).toBool();
440 }
441 
442 int SlaveBase::configValue(const QString &key, int defaultValue) const
443 {
444  return d->mapConfig.value(key, defaultValue).toInt();
445 }
446 
447 QString 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 
493 void SlaveBase::data(const QByteArray &data)
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 
515 void 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 
614 void 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 
659 void SlaveBase::written(KIO::filesize_t _bytes)
660 {
661  KIO_DATA << static_cast<quint64>(_bytes);
662  send(MSG_WRITTEN, data);
663 }
664 
665 void 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 
677 void SlaveBase::processedPercent(float /* percent */)
678 {
679  // qDebug() << "STUB";
680 }
681 
682 void SlaveBase::speed(unsigned long _bytes_per_second)
683 {
684  KIO_DATA << static_cast<quint32>(_bytes_per_second);
685  send(INF_SPEED, data);
686 }
687 
688 void SlaveBase::redirection(const QUrl &_url)
689 {
690  KIO_DATA << _url;
691  send(INF_REDIRECTION, data);
692 }
693 
695 {
696  send(INF_ERROR_PAGE);
697 }
698 
699 static bool isSubCommand(int cmd)
700 {
701  /* clang-format off */
702  return cmd == CMD_REPARSECONFIGURATION
703  || cmd == CMD_META_DATA
704  || cmd == CMD_CONFIG
705  || cmd == CMD_WORKER_STATUS;
706  /* clang-format on */
707 }
708 
709 void SlaveBase::mimeType(const QString &_type)
710 {
711  qCDebug(KIO_CORE) << "detected mimetype" << _type;
712  int cmd = CMD_NONE;
713  do {
714  if (wasKilled()) {
715  break;
716  }
717 
718  // Send the meta-data each time we send the MIME type.
719  if (!mOutgoingMetaData.isEmpty()) {
720  qCDebug(KIO_CORE) << "sending mimetype meta data";
721  KIO_DATA << mOutgoingMetaData;
722  send(INF_META_DATA, data);
723  }
724  KIO_DATA << _type;
725  send(INF_MIME_TYPE, data);
726  while (true) {
727  cmd = 0;
728  int ret = -1;
729  if (d->appConnection.hasTaskAvailable() || d->appConnection.waitForIncomingTask(-1)) {
730  ret = d->appConnection.read(&cmd, data);
731  }
732  if (ret == -1) {
733  qCDebug(KIO_CORE) << "read error on app connection while sending mimetype";
734  exit();
735  break;
736  }
737  qCDebug(KIO_CORE) << "got reply after sending mimetype" << cmd;
738  if (cmd == CMD_HOST) { // Ignore.
739  continue;
740  }
741  if (!isSubCommand(cmd)) {
742  break;
743  }
744 
745  dispatch(cmd, data);
746  }
747  } while (cmd != CMD_NONE);
748  mOutgoingMetaData.clear();
749 }
750 
751 void SlaveBase::exit() // possibly called from another thread, only use atomics in here
752 {
753  d->exit_loop = true;
754  if (d->runInThread) {
755  d->wasKilled = true;
756  } else {
757  // Using ::exit() here is too much (crashes in qdbus's qglobalstatic object),
758  // so let's cleanly exit dispatchLoop() instead.
759  // Update: we do need to call exit(), otherwise a long download (get()) would
760  // keep going until it ends, even though the application exited.
761  ::exit(255);
762  }
763 }
764 
765 void SlaveBase::warning(const QString &_msg)
766 {
767  KIO_DATA << _msg;
768  send(INF_WARNING, data);
769 }
770 
772 {
773  KIO_DATA << _msg;
774  send(INF_INFOMESSAGE, data);
775 }
776 
777 void SlaveBase::statEntry(const UDSEntry &entry)
778 {
779  KIO_DATA << entry;
780  send(MSG_STAT_ENTRY, data);
781 }
782 
783 void SlaveBase::listEntry(const UDSEntry &entry)
784 {
785  // #366795: many slaves don't create an entry for ".", so we keep track if they do
786  // and we provide a fallback in finished() otherwise.
787  if (entry.stringValue(KIO::UDSEntry::UDS_NAME) == QLatin1Char('.')) {
788  d->m_rootEntryListed = true;
789  }
790 
791  // We start measuring the time from the point we start filling the list
792  if (d->pendingListEntries.isEmpty()) {
793  d->m_timeSinceLastBatch.restart();
794  }
795 
796  d->pendingListEntries.append(entry);
797 
798  // If more then KIO_MAX_SEND_BATCH_TIME time is passed, emit the current batch
799  // Also emit if we have piled up a large number of entries already, to save memory (and time)
800  if (d->m_timeSinceLastBatch.elapsed() > KIO_MAX_SEND_BATCH_TIME || d->pendingListEntries.size() > KIO_MAX_ENTRIES_PER_BATCH) {
801  listEntries(d->pendingListEntries);
802  d->pendingListEntries.clear();
803 
804  // Restart time
805  d->m_timeSinceLastBatch.restart();
806  }
807 }
808 
810 {
813 
814  for (const UDSEntry &entry : list) {
815  stream << entry;
816  }
817 
818  send(MSG_LIST_ENTRIES, data);
819 }
820 
821 static void sigpipe_handler(int)
822 {
823  // We ignore a SIGPIPE in slaves.
824  // A SIGPIPE can happen in two cases:
825  // 1) Communication error with application.
826  // 2) Communication error with network.
827  slaveWriteError = true;
828 
829  // Don't add anything else here, especially no debug output
830 }
831 
832 void SlaveBase::setHost(QString const &, quint16, QString const &, QString const &)
833 {
834 }
835 
836 // TODO: move unsupportedActionErrorString() to workerbase.cpp
837 // once SlaveBase is dissolved and folded into WorkerBase
838 // forward declaration is already in workerbase.h
839 namespace KIO
840 {
841 KIOCORE_EXPORT QString unsupportedActionErrorString(const QString &protocol, int cmd)
842 {
843  switch (cmd) {
844  case CMD_CONNECT:
845  return i18n("Opening connections is not supported with the protocol %1.", protocol);
846  case CMD_DISCONNECT:
847  return i18n("Closing connections is not supported with the protocol %1.", protocol);
848  case CMD_STAT:
849  return i18n("Accessing files is not supported with the protocol %1.", protocol);
850  case CMD_PUT:
851  return i18n("Writing to %1 is not supported.", protocol);
852  case CMD_SPECIAL:
853  return i18n("There are no special actions available for protocol %1.", protocol);
854  case CMD_LISTDIR:
855  return i18n("Listing folders is not supported for protocol %1.", protocol);
856  case CMD_GET:
857  return i18n("Retrieving data from %1 is not supported.", protocol);
858  case CMD_MIMETYPE:
859  return i18n("Retrieving mime type information from %1 is not supported.", protocol);
860  case CMD_RENAME:
861  return i18n("Renaming or moving files within %1 is not supported.", protocol);
862  case CMD_SYMLINK:
863  return i18n("Creating symlinks is not supported with protocol %1.", protocol);
864  case CMD_COPY:
865  return i18n("Copying files within %1 is not supported.", protocol);
866  case CMD_DEL:
867  return i18n("Deleting files from %1 is not supported.", protocol);
868  case CMD_MKDIR:
869  return i18n("Creating folders is not supported with protocol %1.", protocol);
870  case CMD_CHMOD:
871  return i18n("Changing the attributes of files is not supported with protocol %1.", protocol);
872  case CMD_CHOWN:
873  return i18n("Changing the ownership of files is not supported with protocol %1.", protocol);
874  case CMD_OPEN:
875  return i18n("Opening files is not supported with protocol %1.", protocol);
876  default:
877  return i18n("Protocol %1 does not support action %2.", protocol, cmd);
878  } /*end switch*/
879 }
880 }
881 
883 {
884  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_CONNECT));
885 }
887 {
888 } // No response!
889 void SlaveBase::stat(QUrl const &)
890 {
891  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_STAT));
892 }
893 void SlaveBase::put(QUrl const &, int, JobFlags)
894 {
895  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_PUT));
896 }
898 {
899  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_SPECIAL));
900 }
902 {
903  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_LISTDIR));
904 }
905 void SlaveBase::get(QUrl const &)
906 {
907  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_GET));
908 }
910 {
911  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_OPEN));
912 }
914 {
915  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_READ));
916 }
918 {
919  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_WRITE));
920 }
922 {
923  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_SEEK));
924 }
926 {
927  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_CLOSE));
928 }
929 void SlaveBase::mimetype(QUrl const &url)
930 {
931  get(url);
932 }
933 void SlaveBase::rename(QUrl const &, QUrl const &, JobFlags)
934 {
935  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_RENAME));
936 }
937 void SlaveBase::symlink(QString const &, QUrl const &, JobFlags)
938 {
939  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_SYMLINK));
940 }
941 void SlaveBase::copy(QUrl const &, QUrl const &, int, JobFlags)
942 {
943  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_COPY));
944 }
945 void SlaveBase::del(QUrl const &, bool)
946 {
947  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_DEL));
948 }
949 void SlaveBase::setLinkDest(const QUrl &, const QString &)
950 {
951  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_SETLINKDEST));
952 }
953 void SlaveBase::mkdir(QUrl const &, int)
954 {
955  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_MKDIR));
956 }
957 void SlaveBase::chmod(QUrl const &, int)
958 {
959  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_CHMOD));
960 }
962 {
963  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_SETMODIFICATIONTIME));
964 }
965 void SlaveBase::chown(QUrl const &, const QString &, const QString &)
966 {
967  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_CHOWN));
968 }
969 
971 {
972  slaveStatus(QString(), false);
973 }
974 
976 {
977  delete d->remotefile;
978  d->remotefile = nullptr;
979 }
980 
982 {
983  const long windowId = metaData(QStringLiteral("window-id")).toLong();
984  const unsigned long userTimestamp = metaData(QStringLiteral("user-timestamp")).toULong();
986  if (metaData(QStringLiteral("no-auth-prompt")).compare(QLatin1String("true"), Qt::CaseInsensitive) == 0) {
987  errorMessage = QStringLiteral("<NoAuthPrompt>");
988  } else {
989  errorMessage = errorMsg;
990  }
991 
992  AuthInfo dlgInfo(info);
993  // Make sure the modified flag is not set.
994  dlgInfo.setModified(false);
995  // Prevent queryAuthInfo from caching the user supplied password since
996  // we need the ioslaves to first authenticate against the server with
997  // it to ensure it is valid.
998  dlgInfo.setExtraField(QStringLiteral("skip-caching-on-query"), true);
999 
1000 #ifndef KIO_ANDROID_STUB
1001  KPasswdServerClient *passwdServerClient = d->passwdServerClient();
1002  const int errCode = passwdServerClient->queryAuthInfo(&dlgInfo, errorMessage, windowId, userTimestamp);
1003  if (errCode == KJob::NoError) {
1004  info = dlgInfo;
1005  }
1006  return errCode;
1007 #else
1008  return KJob::NoError;
1009 #endif
1010 }
1011 
1012 int SlaveBase::messageBox(MessageBoxType type, const QString &text, const QString &title, const QString &primaryActionText, const QString &secondaryActionText)
1013 {
1014  return messageBox(text, type, title, primaryActionText, secondaryActionText, QString());
1015 }
1016 
1018  MessageBoxType type,
1019  const QString &title,
1020  const QString &primaryActionText,
1021  const QString &secondaryActionText,
1022  const QString &dontAskAgainName)
1023 {
1024  KIO_DATA << static_cast<qint32>(type) << text << title << primaryActionText << secondaryActionText << dontAskAgainName;
1025  send(INF_MESSAGEBOX, data);
1026  if (waitForAnswer(CMD_MESSAGEBOXANSWER, 0, data) != -1) {
1027  QDataStream stream(data);
1028  int answer;
1029  stream >> answer;
1030  return answer;
1031  } else {
1032  return 0; // communication failure
1033  }
1034 }
1035 
1036 int SlaveBase::sslError(const QVariantMap &sslData)
1037 {
1038  KIO_DATA << sslData;
1039  send(INF_SSLERROR, data);
1040  if (waitForAnswer(CMD_SSLERRORANSWER, 0, data) != -1) {
1041  QDataStream stream(data);
1042  int answer;
1043  stream >> answer;
1044  return answer;
1045  } else {
1046  return 0; // communication failure
1047  }
1048 }
1049 
1051 {
1052  // qDebug() << "offset=" << KIO::number(offset);
1053  d->needSendCanResume = false;
1054  KIO_DATA << static_cast<quint64>(offset);
1055  send(MSG_RESUME, data);
1056  if (offset) {
1057  int cmd;
1058  if (waitForAnswer(CMD_RESUMEANSWER, CMD_NONE, data, &cmd) != -1) {
1059  // qDebug() << "returning" << (cmd == CMD_RESUMEANSWER);
1060  return cmd == CMD_RESUMEANSWER;
1061  } else {
1062  return false;
1063  }
1064  } else { // No resuming possible -> no answer to wait for
1065  return true;
1066  }
1067 }
1068 
1069 int SlaveBase::waitForAnswer(int expected1, int expected2, QByteArray &data, int *pCmd)
1070 {
1071  int cmd = 0;
1072  int result = -1;
1073  for (;;) {
1074  if (d->appConnection.hasTaskAvailable() || d->appConnection.waitForIncomingTask(-1)) {
1075  result = d->appConnection.read(&cmd, data);
1076  }
1077  if (result == -1) {
1078  // qDebug() << "read error.";
1079  return -1;
1080  }
1081 
1082  if (cmd == expected1 || cmd == expected2) {
1083  if (pCmd) {
1084  *pCmd = cmd;
1085  }
1086  return result;
1087  }
1088  if (isSubCommand(cmd)) {
1089  dispatch(cmd, data);
1090  } else {
1091  qFatal("Fatal Error: Got cmd %d, while waiting for an answer!", cmd);
1092  }
1093  }
1094 }
1095 
1097 {
1098  int result = waitForAnswer(MSG_DATA, 0, buffer);
1099  // qDebug() << "readData: length = " << result << " ";
1100  return result;
1101 }
1102 
1103 void SlaveBase::setTimeoutSpecialCommand(int timeout, const QByteArray &data)
1104 {
1105  if (timeout > 0) {
1106  d->nextTimeoutMsecs = timeout * 1000; // from seconds to milliseconds
1107  d->nextTimeout.start();
1108  } else if (timeout == 0) {
1109  d->nextTimeoutMsecs = 1000; // Immediate timeout
1110  d->nextTimeout.start();
1111  } else {
1112  d->nextTimeout.invalidate(); // Canceled
1113  }
1114 
1115  d->timeoutData = data;
1116 }
1117 
1118 void SlaveBase::dispatch(int command, const QByteArray &data)
1119 {
1120  QDataStream stream(data);
1121 
1122  QUrl url;
1123  int i;
1124 
1125  d->m_finalityCommand = true; // default
1126 
1127  switch (command) {
1128  case CMD_HOST: {
1129  QString passwd;
1130  QString host;
1131  QString user;
1132  quint16 port;
1133  stream >> host >> port >> user >> passwd;
1134  d->m_state = d->InsideMethod;
1135  d->m_finalityCommand = false;
1136  setHost(host, port, user, passwd);
1137  d->m_state = d->Idle;
1138  break;
1139  }
1140  case CMD_CONNECT: {
1141  openConnection();
1142  break;
1143  }
1144  case CMD_DISCONNECT: {
1145  closeConnection();
1146  break;
1147  }
1148  case CMD_WORKER_STATUS: {
1149  d->m_state = d->InsideMethod;
1150  d->m_finalityCommand = false;
1151  slave_status();
1152  // TODO verify that the slave has called slaveStatus()?
1153  d->m_state = d->Idle;
1154  break;
1155  }
1156  case CMD_REPARSECONFIGURATION: {
1157  d->m_state = d->InsideMethod;
1158  d->m_finalityCommand = false;
1160  d->m_state = d->Idle;
1161  break;
1162  }
1163  case CMD_CONFIG: {
1164  stream >> d->configData;
1165  d->rebuildConfig();
1166  delete d->remotefile;
1167  d->remotefile = nullptr;
1168  break;
1169  }
1170  case CMD_GET: {
1171  stream >> url;
1172  d->m_state = d->InsideMethod;
1173  get(url);
1174  d->verifyState("get()");
1175  d->m_state = d->Idle;
1176  break;
1177  }
1178  case CMD_OPEN: {
1179  stream >> url >> i;
1180  QIODevice::OpenMode mode = QFlag(i);
1181  d->m_state = d->InsideMethod;
1182  open(url, mode); // krazy:exclude=syscalls
1183  d->m_state = d->Idle;
1184  break;
1185  }
1186  case CMD_PUT: {
1187  int permissions;
1188  qint8 iOverwrite;
1189  qint8 iResume;
1190  stream >> url >> iOverwrite >> iResume >> permissions;
1191  JobFlags flags;
1192  if (iOverwrite != 0) {
1193  flags |= Overwrite;
1194  }
1195  if (iResume != 0) {
1196  flags |= Resume;
1197  }
1198 
1199  // Remember that we need to send canResume(), TransferJob is expecting
1200  // it. Well, in theory this shouldn't be done if resume is true.
1201  // (the resume bool is currently unused)
1202  d->needSendCanResume = true /* !resume */;
1203 
1204  d->m_state = d->InsideMethod;
1205  put(url, permissions, flags);
1206  d->verifyState("put()");
1207  d->m_state = d->Idle;
1208  break;
1209  }
1210  case CMD_STAT: {
1211  stream >> url;
1212  d->m_state = d->InsideMethod;
1213  stat(url); // krazy:exclude=syscalls
1214  d->verifyState("stat()");
1215  d->m_state = d->Idle;
1216  break;
1217  }
1218  case CMD_MIMETYPE: {
1219  stream >> url;
1220  d->m_state = d->InsideMethod;
1221  mimetype(url);
1222  d->verifyState("mimetype()");
1223  d->m_state = d->Idle;
1224  break;
1225  }
1226  case CMD_LISTDIR: {
1227  stream >> url;
1228  d->m_state = d->InsideMethod;
1229  listDir(url);
1230  d->verifyState("listDir()");
1231  d->m_state = d->Idle;
1232  break;
1233  }
1234  case CMD_MKDIR: {
1235  stream >> url >> i;
1236  d->m_state = d->InsideMethod;
1237  mkdir(url, i); // krazy:exclude=syscalls
1238  d->verifyState("mkdir()");
1239  d->m_state = d->Idle;
1240  break;
1241  }
1242  case CMD_RENAME: {
1243  qint8 iOverwrite;
1244  QUrl url2;
1245  stream >> url >> url2 >> iOverwrite;
1246  JobFlags flags;
1247  if (iOverwrite != 0) {
1248  flags |= Overwrite;
1249  }
1250  d->m_state = d->InsideMethod;
1251  rename(url, url2, flags); // krazy:exclude=syscalls
1252  d->verifyState("rename()");
1253  d->m_state = d->Idle;
1254  break;
1255  }
1256  case CMD_SYMLINK: {
1257  qint8 iOverwrite;
1258  QString target;
1259  stream >> target >> url >> iOverwrite;
1260  JobFlags flags;
1261  if (iOverwrite != 0) {
1262  flags |= Overwrite;
1263  }
1264  d->m_state = d->InsideMethod;
1265  symlink(target, url, flags);
1266  d->verifyState("symlink()");
1267  d->m_state = d->Idle;
1268  break;
1269  }
1270  case CMD_COPY: {
1271  int permissions;
1272  qint8 iOverwrite;
1273  QUrl url2;
1274  stream >> url >> url2 >> permissions >> iOverwrite;
1275  JobFlags flags;
1276  if (iOverwrite != 0) {
1277  flags |= Overwrite;
1278  }
1279  d->m_state = d->InsideMethod;
1280  copy(url, url2, permissions, flags);
1281  d->verifyState("copy()");
1282  d->m_state = d->Idle;
1283  break;
1284  }
1285  case CMD_DEL: {
1286  qint8 isFile;
1287  stream >> url >> isFile;
1288  d->m_state = d->InsideMethod;
1289  del(url, isFile != 0);
1290  d->verifyState("del()");
1291  d->m_state = d->Idle;
1292  break;
1293  }
1294  case CMD_CHMOD: {
1295  stream >> url >> i;
1296  d->m_state = d->InsideMethod;
1297  chmod(url, i);
1298  d->verifyState("chmod()");
1299  d->m_state = d->Idle;
1300  break;
1301  }
1302  case CMD_CHOWN: {
1303  QString owner;
1304  QString group;
1305  stream >> url >> owner >> group;
1306  d->m_state = d->InsideMethod;
1307  chown(url, owner, group);
1308  d->verifyState("chown()");
1309  d->m_state = d->Idle;
1310  break;
1311  }
1312  case CMD_SETMODIFICATIONTIME: {
1313  QDateTime dt;
1314  stream >> url >> dt;
1315  d->m_state = d->InsideMethod;
1316  setModificationTime(url, dt);
1317  d->verifyState("setModificationTime()");
1318  d->m_state = d->Idle;
1319  break;
1320  }
1321  case CMD_SPECIAL: {
1322  d->m_state = d->InsideMethod;
1323  special(data);
1324  d->verifyState("special()");
1325  d->m_state = d->Idle;
1326  break;
1327  }
1328  case CMD_META_DATA: {
1329  // qDebug() << "(" << getpid() << ") Incoming meta-data...";
1330  stream >> mIncomingMetaData;
1331  d->rebuildConfig();
1332  break;
1333  }
1334  case CMD_NONE: {
1335  qCWarning(KIO_CORE) << "Got unexpected CMD_NONE!";
1336  break;
1337  }
1338  case CMD_FILESYSTEMFREESPACE: {
1339  stream >> url;
1340 
1341  void *data = static_cast<void *>(&url);
1342 
1343  d->m_state = d->InsideMethod;
1344  virtual_hook(GetFileSystemFreeSpace, data);
1345  d->verifyState("fileSystemFreeSpace()");
1346  d->m_state = d->Idle;
1347  break;
1348  }
1349  default: {
1350  // Some command we don't understand.
1351  // Just ignore it, it may come from some future version of KIO.
1352  break;
1353  }
1354  }
1355 }
1356 
1358 {
1359 #ifndef KIO_ANDROID_STUB
1360  KPasswdServerClient *passwdServerClient = d->passwdServerClient();
1361  return (passwdServerClient->checkAuthInfo(&info, metaData(QStringLiteral("window-id")).toLong(), metaData(QStringLiteral("user-timestamp")).toULong()));
1362 #else
1363  return false;
1364 #endif
1365 }
1366 
1367 void SlaveBase::dispatchOpenCommand(int command, const QByteArray &data)
1368 {
1369  QDataStream stream(data);
1370 
1371  switch (command) {
1372  case CMD_READ: {
1373  KIO::filesize_t bytes;
1374  stream >> bytes;
1375  read(bytes);
1376  break;
1377  }
1378  case CMD_WRITE: {
1379  write(data);
1380  break;
1381  }
1382  case CMD_SEEK: {
1383  KIO::filesize_t offset;
1384  stream >> offset;
1385  seek(offset);
1386  break;
1387  }
1388  case CMD_TRUNCATE: {
1389  KIO::filesize_t length;
1390  stream >> length;
1391  void *data = static_cast<void *>(&length);
1392  virtual_hook(Truncate, data);
1393  break;
1394  }
1395  case CMD_NONE:
1396  break;
1397  case CMD_CLOSE:
1398  close(); // must call finish(), which will set d->inOpenLoop=false
1399  break;
1400  default:
1401  // Some command we don't understand.
1402  // Just ignore it, it may come from some future version of KIO.
1403  break;
1404  }
1405 }
1406 
1408 {
1409 #ifndef KIO_ANDROID_STUB
1410  KPasswdServerClient *passwdServerClient = d->passwdServerClient();
1411  passwdServerClient->addAuthInfo(info, metaData(QStringLiteral("window-id")).toLongLong());
1412 #endif
1413  return true;
1414 }
1415 
1417 {
1418  bool ok;
1419  QString tmp = metaData(QStringLiteral("ConnectTimeout"));
1420  int result = tmp.toInt(&ok);
1421  if (ok) {
1422  return result;
1423  }
1424  return DEFAULT_CONNECT_TIMEOUT;
1425 }
1426 
1428 {
1429  bool ok;
1430  QString tmp = metaData(QStringLiteral("ProxyConnectTimeout"));
1431  int result = tmp.toInt(&ok);
1432  if (ok) {
1433  return result;
1434  }
1435  return DEFAULT_PROXY_CONNECT_TIMEOUT;
1436 }
1437 
1439 {
1440  bool ok;
1441  QString tmp = metaData(QStringLiteral("ResponseTimeout"));
1442  int result = tmp.toInt(&ok);
1443  if (ok) {
1444  return result;
1445  }
1446  return DEFAULT_RESPONSE_TIMEOUT;
1447 }
1448 
1450 {
1451  bool ok;
1452  QString tmp = metaData(QStringLiteral("ReadTimeout"));
1453  int result = tmp.toInt(&ok);
1454  if (ok) {
1455  return result;
1456  }
1457  return DEFAULT_READ_TIMEOUT;
1458 }
1459 
1461 {
1462  return d->wasKilled;
1463 }
1464 
1466 {
1467  d->wasKilled = true;
1468 }
1469 
1470 void SlaveBase::send(int cmd, const QByteArray &arr)
1471 {
1472  if (d->runInThread) {
1473  if (!d->appConnection.send(cmd, arr)) {
1474  exit();
1475  }
1476  } else {
1477  slaveWriteError = false;
1478  if (!d->appConnection.send(cmd, arr))
1479  // Note that slaveWriteError can also be set by sigpipe_handler
1480  {
1481  slaveWriteError = true;
1482  }
1483  if (slaveWriteError) {
1484  qCWarning(KIO_CORE) << "An error occurred during write. The worker terminates now.";
1485  exit();
1486  }
1487  }
1488 }
1489 
1490 void SlaveBase::virtual_hook(int id, void *data)
1491 {
1492  Q_UNUSED(data);
1493 
1494  switch (id) {
1495  case GetFileSystemFreeSpace: {
1496  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_FILESYSTEMFREESPACE));
1497  break;
1498  }
1499  case Truncate: {
1500  error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(protocolName(), CMD_TRUNCATE));
1501  break;
1502  }
1503  }
1504 }
1505 
1506 void SlaveBase::setRunInThread(bool b)
1507 {
1508  d->runInThread = b;
1509 }
1510 
1512 {
1513  KIO_DATA << host;
1514  send(MSG_HOST_INFO_REQ, data);
1515 }
1516 
1518 {
1519  QByteArray data;
1520  int result = waitForAnswer(CMD_HOST_INFO, 0, data);
1521 
1522  if (result == -1) {
1524  info.setErrorString(i18n("Unknown Error"));
1525  return result;
1526  }
1527 
1528  QDataStream stream(data);
1529  QString hostName;
1530  QList<QHostAddress> addresses;
1531  int error;
1532  QString errorString;
1533 
1534  stream >> hostName >> addresses >> error >> errorString;
1535 
1536  info.setHostName(hostName);
1537  info.setAddresses(addresses);
1539  info.setErrorString(errorString);
1540 
1541  return result;
1542 }
1543 
1545 {
1546  if (d->m_privilegeOperationStatus == OperationNotAllowed) {
1547  QByteArray buffer;
1548  send(MSG_PRIVILEGE_EXEC);
1549  waitForAnswer(MSG_PRIVILEGE_EXEC, 0, buffer);
1550  QDataStream ds(buffer);
1551  ds >> d->m_privilegeOperationStatus >> d->m_warningTitle >> d->m_warningMessage;
1552  }
1553 
1554  if (metaData(QStringLiteral("UnitTesting")) != QLatin1String("true") && d->m_privilegeOperationStatus == OperationAllowed && !d->m_confirmationAsked) {
1555  // WORKER_MESSAGEBOX_DETAILS_HACK
1556  // SlaveBase::messageBox() overloads miss a parameter to pass an details argument.
1557  // As workaround details are passed instead via metadata before and then cached by the WorkerInterface,
1558  // to be used in the upcoming messageBox call (needs WarningContinueCancelDetailed type)
1559  // TODO: add a messageBox() overload taking details and use here,
1560  // then remove or adapt all code marked with WORKER_MESSAGEBOX_DETAILS
1561  setMetaData(QStringLiteral("privilege_conf_details"), operationDetails);
1562  sendMetaData();
1563 
1564  int result = messageBox(d->m_warningMessage, WarningContinueCancelDetailed, d->m_warningTitle, QString(), QString(), QString());
1565  d->m_privilegeOperationStatus = result == Continue ? OperationAllowed : OperationCanceled;
1566  d->m_confirmationAsked = true;
1567  }
1568 
1569  return KIO::PrivilegeOperationStatus(d->m_privilegeOperationStatus);
1570 }
1571 
1573 {
1574  d->m_tempAuths.insert(action);
1575 }
@ Overwrite
When set, automatically overwrite the destination if it exists already.
Definition: job_base.h:267
QMap::const_iterator constBegin() const const
void lookupHost(const QString &host)
Internally used.
Definition: slavebase.cpp:1511
void data(const QByteArray &data)
Sends data in the slave to the job (i.e. in get).
Definition: slavebase.cpp:493
virtual void stat(const QUrl &url)
Finds all details for one file or directory.
Definition: slavebase.cpp:889
void connected()
Call in openConnection, if you reimplement it, when you're done.
Definition: slavebase.cpp:554
MetaData allMetaData() const
Definition: slavebase.cpp:416
void sendAndKeepMetaData()
Internal function to transmit meta data to the application.
Definition: slavebase.cpp:474
int waitForAnswer(int expected1, int expected2, QByteArray &data, int *pCmd=nullptr)
Wait for an answer to our request, until we get expected1 or expected2.
Definition: slavebase.cpp:1069
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.
Definition: slavebase.cpp:1012
bool contains(const Key &key) const const
int connectTimeout()
Definition: slavebase.cpp:1416
virtual void chmod(const QUrl &url, int permissions)
Change permissions on url.
Definition: slavebase.cpp:957
virtual void slave_status()
Called to get the status of the slave.
Definition: slavebase.cpp:970
QString number(int n, int base)
void setAddresses(const QList< QHostAddress > &addresses)
QString fromUtf8(const char *str, int size)
CaseInsensitive
virtual void read(KIO::filesize_t size)
read.
Definition: slavebase.cpp:913
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.
Definition: slavebase.cpp:937
bool wasKilled() const
If your ioslave was killed by a signal, wasKilled() returns true.
Definition: slavebase.cpp:1460
QSet::iterator erase(QSet::iterator pos)
void truncated(KIO::filesize_t _length)
Definition: slavebase.cpp:671
void clear()
qulonglong filesize_t
64-bit file size
Definition: global.h:35
KCRASH_EXPORT void initialize()
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...
Definition: slavebase.cpp:682
int queryAuthInfo(KIO::AuthInfo *info, const QString &errorMsg, qlonglong windowId, qlonglong usertime)
Let kpasswdserver ask the user for authentication information.
void slaveStatus(const QString &host, bool connected)
Used to report the status of the slave.
Definition: slavebase.cpp:614
@ 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
int readData(QByteArray &buffer)
Read data sent by the job, after a dataReq.
Definition: slavebase.cpp:1096
QThread * thread() const const
@ UDS_NAME
Filename - as displayed in directory listings etc.
Definition: udsentry.h:224
int proxyConnectTimeout()
Definition: slavebase.cpp:1427
ulong toULong(bool *ok, int base) const const
void sendMetaData()
Internal function to transmit meta data to the application.
Definition: slavebase.cpp:468
void listEntry(const UDSEntry &entry)
It collects entries and emits them via listEntries when enough of them are there or a certain time fr...
Definition: slavebase.cpp:783
QString stringValue(uint field) const
Definition: udsentry.cpp:365
KCALUTILS_EXPORT QString errorMessage(const KCalendarCore::Exception &exception)
A class for handling remote filenames.
void listEntries(const UDSEntryList &_entry)
Call this in listDir, each time you have a bunch of entries to report.
Definition: slavebase.cpp:809
QMap::iterator insert(const Key &key, const T &value)
A two way messaging class for passing authentication information.
Definition: authinfo.h:49
QMap::iterator end()
void opened()
open succeeds
Definition: slavebase.cpp:508
void setErrorString(const QString &str)
virtual void del(const QUrl &url, bool isfile)
Delete a file or directory.
Definition: slavebase.cpp:945
QString i18n(const char *text, const TYPE &arg...)
QMap::iterator find(const Key &key)
virtual void setHost(const QString &host, quint16 port, const QString &user, const QString &pass)
Set the host.
Definition: slavebase.cpp:832
virtual void setModificationTime(const QUrl &url, const QDateTime &mtime)
Sets the modification time for url.
Definition: slavebase.cpp:961
void redirection(const QUrl &_url)
Call this to signal a redirection.
Definition: slavebase.cpp:688
QMap::const_iterator constEnd() const const
int waitForHostInfo(QHostInfo &info)
Internally used.
Definition: slavebase.cpp:1517
void setError(QHostInfo::HostInfoError error)
virtual void copy(const QUrl &src, const QUrl &dest, int permissions, JobFlags flags)
Copy src into dest.
Definition: slavebase.cpp:941
virtual void openConnection()
Opens the connection (forced).
Definition: slavebase.cpp:882
void addTemporaryAuthorization(const QString &action)
Adds action to the list of PolicyKit actions which the slave is authorized to perform.
Definition: slavebase.cpp:1572
void addAuthInfo(const KIO::AuthInfo &info, qlonglong windowId)
Manually add authentication information to kpasswdserver's cache.
bool configValue(const QString &key, bool defaultValue) const
Returns a bool from the config/meta-data information.
Definition: slavebase.cpp:437
virtual void listDir(const QUrl &url)
Lists the contents of url.
Definition: slavebase.cpp:901
@ UDS_SIZE
Size of the file.
Definition: udsentry.h:203
void reserve(int size)
Calling this function before inserting items into an empty UDSEntry may save time and memory.
Definition: udsentry.cpp:385
QThread * currentThread()
int toInt(bool *ok, int base) const const
void warning(const QString &msg)
Call to signal a warning, to be displayed in a dialog box.
Definition: slavebase.cpp:765
virtual void put(const QUrl &url, int permissions, JobFlags flags)
put, i.e. write data into a file.
Definition: slavebase.cpp:893
void errorPage()
Tell that we will only get an error page here.
Definition: slavebase.cpp:694
void finished()
Call to signal successful completion of any command besides openConnection and closeConnection.
Definition: slavebase.cpp:559
QByteArray mProtocol
Name of the protocol supported by this slave.
Definition: slavebase.h:937
QSet::iterator begin()
void dispatchLoop()
Definition: slavebase.cpp:320
PrivilegeOperationStatus requestPrivilegeOperation(const QString &operationDetails)
Checks with job if privilege operation is allowed.
Definition: slavebase.cpp:1544
void setKillFlag()
Internally used.
Definition: slavebase.cpp:1465
virtual void seek(KIO::filesize_t offset)
seek.
Definition: slavebase.cpp:921
QString metaData(const QString &key) const
Queries for config/meta-data send by the application to the slave.
Definition: slavebase.cpp:407
virtual void dispatch(int command, const QByteArray &data)
Definition: slavebase.cpp:1118
bool checkCachedAuthentication(AuthInfo &info)
Checks for cached authentication based on parameters given by info.
Definition: slavebase.cpp:1357
void setExtraField(const QString &fieldName, const QVariant &value)
Set Extra Field Value.
Definition: authinfo.cpp:154
void dataReq()
Asks for data from the job.
Definition: slavebase.cpp:499
virtual void mkdir(const QUrl &url, int permissions)
Create a directory.
Definition: slavebase.cpp:953
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
virtual void get(const QUrl &url)
get, aka read.
Definition: slavebase.cpp:905
void totalSize(KIO::filesize_t _bytes)
Call this in get and copy, to give the total size of the file.
Definition: slavebase.cpp:627
bool isEmpty() const const
PrivilegeOperationStatus
Specifies privilege file operation status.
Definition: global.h:235
const char * constData() const const
bool hasMetaData(const QString &key) const
Queries for the existence of a certain config/meta-data entry send by the application to the slave.
Definition: slavebase.cpp:421
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...
Definition: slavebase.cpp:841
KConfigGroup * config()
Returns a configuration object to query config/meta-data information from.
Definition: slavebase.cpp:452
void setMetaData(const QString &key, const QString &value)
Sets meta-data to be send to the application before the first data() or finished() signal.
Definition: slavebase.cpp:402
virtual void dispatchOpenCommand(int command, const QByteArray &data)
Definition: slavebase.cpp:1367
virtual void reparseConfiguration()
Called by the scheduler to tell the slave that the configuration changed (i.e. proxy settings).
Definition: slavebase.cpp:975
A namespace for KIO globals.
QSet::iterator end()
int openPasswordDialogV2(KIO::AuthInfo &info, const QString &errorMsg=QString())
Prompt the user for Authorization info (login & password).
Definition: slavebase.cpp:981
virtual void open(const QUrl &url, QIODevice::OpenMode mode)
open.
Definition: slavebase.cpp:909
void setModified(bool flag)
Use this method to indicate that this object has been modified.
Definition: authinfo.cpp:147
void mimeType(const QString &_type)
Call this in mimetype() and in get(), when you know the MIME type.
Definition: slavebase.cpp:709
virtual void chown(const QUrl &url, const QString &owner, const QString &group)
Change ownership of url.
Definition: slavebase.cpp:965
virtual void special(const QByteArray &data)
Used for any command that is specific to this slave (protocol).
Definition: slavebase.cpp:897
void processedPercent(float percent)
Only use this if you can't know in advance the size of the copied data.
Definition: slavebase.cpp:677
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...
Definition: slavebase.cpp:1103
@ Resume
When set, automatically append to the destination file if it exists already.
Definition: job_base.h:260
void setHostName(const QString &hostName)
virtual void write(const QByteArray &data)
write.
Definition: slavebase.cpp:917
void statEntry(const UDSEntry &_entry)
Call this from stat() to express details about an object, the UDSEntry customarily contains the atoms...
Definition: slavebase.cpp:777
@ UDS_ACCESS
Access permissions (part of the mode returned by stat)
Definition: udsentry.h:232
void connectSlave(const QString &path)
internal function to connect a slave to/ disconnect from either the slave pool or the application
Definition: slavebase.cpp:384
bool cacheAuthentication(const AuthInfo &info)
Caches info in a persistent storage like KWallet.
Definition: slavebase.cpp:1407
void sendPostedEvents(QObject *receiver, int event_type)
int responseTimeout()
Definition: slavebase.cpp:1438
void setTestModeEnabled(bool testMode)
virtual void setLinkDest(const QUrl &url, const QString &target)
Change the destination of a symlink.
Definition: slavebase.cpp:949
virtual void close()
close.
Definition: slavebase.cpp:925
virtual void rename(const QUrl &src, const QUrl &dest, JobFlags flags)
Rename oldname into newname.
Definition: slavebase.cpp:933
bool checkAuthInfo(KIO::AuthInfo *info, qlonglong windowId, qlonglong usertime)
Check if kpasswdserver has cached authentication information regarding an AuthInfo object.
void processedSize(KIO::filesize_t _bytes)
Call this during get and copy, once in a while, to give some info about the current state.
Definition: slavebase.cpp:636
void infoMessage(const QString &msg)
Call to signal a message, to be displayed if the application wants to, for instance in a status bar.
Definition: slavebase.cpp:771
const QList< QKeySequence > & end()
bool isEmpty() const const
void canResume()
Call this at the beginning of get(), if the "range-start" metadata was set and returning byte ranges ...
Definition: slavebase.cpp:622
virtual void mimetype(const QUrl &url)
Finds MIME type for one file or directory.
Definition: slavebase.cpp:929
KRemoteEncoding * remoteEncoding()
Returns an object that can translate remote filenames into proper Unicode forms.
Definition: slavebase.cpp:483
MessageBoxType
Type of message box.
Definition: slavebase.h:257
QMap< QString, QVariant > mapConfig() const
Returns a map to query config/meta-data information from.
Definition: slavebase.cpp:432
QString decodeName(const QByteArray &localFileName)
long toLong(bool *ok, int base) const const
bool isEmpty() const const
void error(int _errid, const QString &_text)
Call to signal an error.
Definition: slavebase.cpp:515
virtual void closeConnection()
Closes the connection (forced).
Definition: slavebase.cpp:886
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Thu Feb 15 2024 03:51:27 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.