KIO

listjob.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 2000 Stephan Kulow <[email protected]>
3  2000-2009 David Faure <[email protected]>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 
21 #include "listjob.h"
22 #include "job_p.h"
23 #include "scheduler.h"
24 #include <kurlauthorized.h>
25 #include "slave.h"
26 #include "../pathhelpers_p.h"
27 #include <QTimer>
28 
29 #include <QDebug>
30 
31 using namespace KIO;
32 
33 class KIO::ListJobPrivate: public KIO::SimpleJobPrivate
34 {
35 public:
36  ListJobPrivate(const QUrl &url, bool _recursive,
37  const QString &prefix, const QString &displayPrefix,
38  bool _includeHidden)
39  : SimpleJobPrivate(url, CMD_LISTDIR, QByteArray()),
40  recursive(_recursive), includeHidden(_includeHidden),
41  m_prefix(prefix), m_displayPrefix(displayPrefix), m_processedEntries(0)
42  {}
43  bool recursive;
44  bool includeHidden;
45  QString m_prefix;
46  QString m_displayPrefix;
47  unsigned long m_processedEntries;
48  QUrl m_redirectionURL;
49 
56  void start(Slave *slave) override;
57 
58  void slotListEntries(const KIO::UDSEntryList &list);
59  void slotRedirection(const QUrl &url);
60  void gotEntries(KIO::Job *subjob, const KIO::UDSEntryList &list);
61  void slotSubError(ListJob* job, ListJob* subJob);
62 
63  Q_DECLARE_PUBLIC(ListJob)
64 
65  static inline ListJob *newJob(const QUrl &u, bool _recursive,
66  const QString &prefix, const QString &displayPrefix,
67  bool _includeHidden, JobFlags flags = HideProgressInfo)
68  {
69  ListJob *job = new ListJob(*new ListJobPrivate(u, _recursive, prefix, displayPrefix, _includeHidden));
71  if (!(flags & HideProgressInfo)) {
73  }
74  return job;
75  }
76  static inline ListJob *newJobNoUi(const QUrl &u, bool _recursive,
77  const QString &prefix, const QString &displayPrefix,
78  bool _includeHidden)
79  {
80  return new ListJob(*new ListJobPrivate(u, _recursive, prefix, displayPrefix, _includeHidden));
81  }
82 };
83 
84 ListJob::ListJob(ListJobPrivate &dd)
85  : SimpleJob(dd)
86 {
87  Q_D(ListJob);
88  // We couldn't set the args when calling the parent constructor,
89  // so do it now.
90  QDataStream stream(&d->m_packedArgs, QIODevice::WriteOnly);
91  stream << d->m_url;
92 }
93 
94 ListJob::~ListJob()
95 {
96 }
97 
98 void ListJobPrivate::slotListEntries(const KIO::UDSEntryList &list)
99 {
100  Q_Q(ListJob);
101  // Emit progress info (takes care of emit processedSize and percent)
102  m_processedEntries += list.count();
103  slotProcessedSize(m_processedEntries);
104 
105  if (recursive) {
106  UDSEntryList::ConstIterator it = list.begin();
107  const UDSEntryList::ConstIterator end = list.end();
108 
109  for (; it != end; ++it) {
110 
111  const UDSEntry &entry = *it;
112 
113  QUrl itemURL;
114  const QString udsUrl = entry.stringValue(KIO::UDSEntry::UDS_URL);
115  QString filename;
116  if (!udsUrl.isEmpty()) {
117  itemURL = QUrl(udsUrl);
118  filename = itemURL.fileName();
119  } else { // no URL, use the name
120  itemURL = q->url();
121  filename = entry.stringValue(KIO::UDSEntry::UDS_NAME);
122  Q_ASSERT(!filename.isEmpty()); // we'll recurse forever otherwise :)
123  itemURL.setPath(concatPaths(itemURL.path(), filename));
124  }
125 
126  if (entry.isDir() && !entry.isLink()) {
127  Q_ASSERT(!filename.isEmpty());
129  if (displayName.isEmpty()) {
130  displayName = filename;
131  }
132  // skip hidden dirs when listing if requested
133  if (filename != QLatin1String("..") && filename != QLatin1String(".") && (includeHidden || filename[0] != QLatin1Char('.'))) {
134  ListJob *job = ListJobPrivate::newJobNoUi(itemURL,
135  true /*recursive*/,
136  m_prefix + filename + QLatin1Char('/'),
137  m_displayPrefix + displayName + QLatin1Char('/'),
138  includeHidden);
139  Scheduler::setJobPriority(job, 1);
140  QObject::connect(job, &ListJob::entries, q,
141  [this](KIO::Job *job, const KIO::UDSEntryList &list) {gotEntries(job, list);} );
142  QObject::connect(job, &ListJob::subError, q,
143  [this](KIO::ListJob *job, KIO::ListJob *ljob) {slotSubError(job, ljob);} );
144 
145  q->addSubjob(job);
146  }
147  }
148  }
149  }
150 
151  // Not recursive, or top-level of recursive listing : return now (send . and .. as well)
152  // exclusion of hidden files also requires the full sweep, but the case for full-listing
153  // a single dir is probably common enough to justify the shortcut
154  if (m_prefix.isNull() && includeHidden) {
155  emit q->entries(q, list);
156  } else {
157  // cull the unwanted hidden dirs and/or parent dir references from the listing, then emit that
158  UDSEntryList newlist;
159 
160  UDSEntryList::const_iterator it = list.begin();
161  const UDSEntryList::const_iterator end = list.end();
162  for (; it != end; ++it) {
163 
164  // Modify the name in the UDSEntry
165  UDSEntry newone = *it;
166  const QString filename = newone.stringValue(KIO::UDSEntry::UDS_NAME);
168  if (displayName.isEmpty()) {
169  displayName = filename;
170  }
171  // Avoid returning entries like subdir/. and subdir/.., but include . and .. for
172  // the toplevel dir, and skip hidden files/dirs if that was requested
173  if ((m_prefix.isNull() || (filename != QLatin1String("..") && filename != QLatin1String(".")))
174  && (includeHidden || (filename[0] != QLatin1Char('.')))) {
175  // ## Didn't find a way to use the iterator instead of re-doing a key lookup
176  newone.replace(KIO::UDSEntry::UDS_NAME, m_prefix + filename);
177  newone.replace(KIO::UDSEntry::UDS_DISPLAY_NAME, m_displayPrefix + displayName);
178  newlist.append(newone);
179  }
180  }
181 
182  emit q->entries(q, newlist);
183  }
184 }
185 
186 void ListJobPrivate::gotEntries(KIO::Job *, const KIO::UDSEntryList &list)
187 {
188  // Forward entries received by subjob - faking we received them ourselves
189  Q_Q(ListJob);
190  emit q->entries(q, list);
191 }
192 
193 void ListJobPrivate::slotSubError(KIO::ListJob* /*job*/, KIO::ListJob* subJob)
194 {
195  Q_Q(ListJob);
196  emit q->subError(q, subJob); // Let the signal of subError go up
197 }
198 
199 void ListJob::slotResult(KJob *job)
200 {
201  Q_D(ListJob);
202  if (job->error()) {
203  // If we can't list a subdir, the result is still ok
204  // This is why we override KCompositeJob::slotResult - to not set
205  // an error on parent job.
206  // Let's emit a signal about this though
207  emit subError(this, static_cast<KIO::ListJob *>(job));
208  }
209  removeSubjob(job);
210  if (!hasSubjobs() && !d->m_slave) { // if the main directory listing is still running, it will emit result in SimpleJob::slotFinished()
211  emitResult();
212  }
213 }
214 
215 void ListJobPrivate::slotRedirection(const QUrl &url)
216 {
217  Q_Q(ListJob);
218  if (!KUrlAuthorized::authorizeUrlAction(QStringLiteral("redirect"), m_url, url)) {
219  qCWarning(KIO_CORE) << "Redirection from" << m_url << "to" << url << "REJECTED!";
220  return;
221  }
222  m_redirectionURL = url; // We'll remember that when the job finishes
223  emit q->redirection(q, m_redirectionURL);
224 }
225 
226 void ListJob::slotFinished()
227 {
228  Q_D(ListJob);
229 
230  if (!d->m_redirectionURL.isEmpty() && d->m_redirectionURL.isValid() && !error()) {
231 
232  //qDebug() << "Redirection to " << d->m_redirectionURL;
233  if (queryMetaData(QStringLiteral("permanent-redirect")) == QLatin1String("true")) {
234  emit permanentRedirection(this, d->m_url, d->m_redirectionURL);
235  }
236 
237  if (d->m_redirectionHandlingEnabled) {
238  d->m_packedArgs.truncate(0);
239  QDataStream stream(&d->m_packedArgs, QIODevice::WriteOnly);
240  stream << d->m_redirectionURL;
241 
242  d->restartAfterRedirection(&d->m_redirectionURL);
243  return;
244  }
245  }
246 
247  // Return slave to the scheduler
248  SimpleJob::slotFinished();
249 }
250 
251 void ListJob::slotMetaData(const KIO::MetaData &_metaData)
252 {
253  Q_D(ListJob);
254  SimpleJob::slotMetaData(_metaData);
255  storeSSLSessionFromJob(d->m_redirectionURL);
256 }
257 
258 ListJob *KIO::listDir(const QUrl &url, JobFlags flags, bool includeHidden)
259 {
260  return ListJobPrivate::newJob(url, false, QString(), QString(), includeHidden, flags);
261 }
262 
263 ListJob *KIO::listRecursive(const QUrl &url, JobFlags flags, bool includeHidden)
264 {
265  return ListJobPrivate::newJob(url, true, QString(), QString(), includeHidden, flags);
266 }
267 
268 void ListJob::setUnrestricted(bool unrestricted)
269 {
270  Q_D(ListJob);
271  if (unrestricted) {
272  d->m_extraFlags |= JobPrivate::EF_ListJobUnrestricted;
273  } else {
274  d->m_extraFlags &= ~JobPrivate::EF_ListJobUnrestricted;
275  }
276 }
277 
278 void ListJobPrivate::start(Slave *slave)
279 {
280  Q_Q(ListJob);
281  if (!KUrlAuthorized::authorizeUrlAction(QStringLiteral("list"), m_url, m_url) &&
282  !(m_extraFlags & EF_ListJobUnrestricted)) {
283  q->setError(ERR_ACCESS_DENIED);
284  q->setErrorText(m_url.toDisplayString());
285  QTimer::singleShot(0, q, &ListJob::slotFinished);
286  return;
287  }
288  QObject::connect(slave, &Slave::listEntries, q,
289  [this](const KIO::UDSEntryList &list){ slotListEntries(list);} );
290 
291  QObject::connect(slave, &Slave::totalSize, q,
292  [this](KIO::filesize_t size){ slotTotalSize(size);} );
293 
294  QObject::connect(slave, &Slave::redirection, q,
295  [this](const QUrl &url){ slotRedirection(url);} );
296 
297  SimpleJobPrivate::start(slave);
298 }
299 
300 const QUrl &ListJob::redirectionUrl() const
301 {
302  return d_func()->m_redirectionURL;
303 }
304 
305 #include "moc_listjob.cpp"
An alternative URL (If different from the caption).
Definition: udsentry.h:288
QString url(QUrl::FormattingOptions options) const const
qulonglong filesize_t
64-bit file size
Definition: global.h:51
KIOCORE_EXPORT ListJob * listDir(const QUrl &url, JobFlags flags=DefaultFlags, bool includeHidden=true)
List the contents of url, which is assumed to be a directory.
Definition: listjob.cpp:258
bool isLink() const
Definition: udsentry.cpp:380
void setUiDelegate(KJobUiDelegate *delegate)
Universal Directory Service.
Definition: udsentry.h:88
A namespace for KIO globals.
Definition: authinfo.h:34
A ListJob is allows you to get the get the content of a directory.
Definition: listjob.h:40
Hide progress information dialog, i.e.
Definition: job_base.h:287
bool isDir() const
Definition: udsentry.cpp:375
MetaData is a simple map of key/value strings.
Definition: metadata.h:34
bool isNull() const const
void setPath(const QString &path, QUrl::ParsingMode mode)
QSize size() const const
KIOCORE_EXPORT ListJob * listRecursive(const QUrl &url, JobFlags flags=DefaultFlags, bool includeHidden=true)
The same as the previous method, but recurses subdirectories.
Definition: listjob.cpp:263
int count(const T &value) const const
void append(const T &value)
bool isEmpty() const const
KIOCORE_EXPORT KJobUiDelegate * createDefaultJobUiDelegate()
Convenience method: use default factory, if there&#39;s one, to create a delegate and return it...
void error(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Notify)
QString stringValue(uint field) const
Definition: udsentry.cpp:365
QString path(QUrl::ComponentFormattingOptions options) const const
void replace(uint field, const QString &value)
Replace or insert field with string value.
Definition: udsentry.cpp:414
KIOCORE_EXPORT KJobTrackerInterface * getJobTracker()
Returns the job tracker to be used by all KIO jobs (in which HideProgressInfo is not set) ...
Definition: jobtracker.cpp:25
QList::iterator end()
const QList< QKeySequence > & end()
Filename - as displayed in directory listings etc.
Definition: udsentry.h:261
The base class for all jobs.
Definition: job_base.h:57
If set, contains the label to display instead of the &#39;real name&#39; in UDS_NAME.
Definition: udsentry.h:309
virtual void registerJob(KJob *job)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QList::iterator begin()
QString fileName(QUrl::ComponentFormattingOptions options) const const
bool authorizeUrlAction(const QString &action, const QUrl &baseURL, const QUrl &destURL)
Returns whether a certain URL related action is authorized.
int error() const
A simple job (one url and one command).
Definition: simplejob.h:39
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat Jul 11 2020 23:00:27 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.