File indexing completed on 2024-04-28 16:44:28

0001 /* This file is part of the KDE project
0002    SPDX-FileCopyrightText: 1999-2006 David Faure <faure@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-only
0005 */
0006 
0007 #include "kioclient.h"
0008 #include "kio_version.h"
0009 #include "urlinfo.h"
0010 
0011 #include <KIO/CopyJob>
0012 #include <KIO/DeleteJob>
0013 #include <kio/listjob.h>
0014 #include <kio/transferjob.h>
0015 #ifndef KIOCORE_ONLY
0016 #include <KIO/ApplicationLauncherJob>
0017 #include <kio_version.h>
0018 #if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0)
0019 #include <KIO/JobUiDelegateFactory>
0020 #else
0021 #include <KIO/JobUiDelegate>
0022 #endif
0023 #include <KIO/OpenUrlJob>
0024 #include <KIO/StatJob>
0025 #include <KIO/UDSEntry>
0026 #include <KPropertiesDialog>
0027 #include <KService>
0028 #endif
0029 #include <KAboutData>
0030 #include <KLocalizedString>
0031 
0032 #include <QCommandLineParser>
0033 #include <QDBusConnection>
0034 #include <QDebug>
0035 #include <QFileDialog>
0036 #include <QUrlQuery>
0037 #include <iostream>
0038 
0039 bool ClientApp::m_ok = true;
0040 static bool s_interactive = false;
0041 static KIO::JobFlags s_jobFlags = KIO::DefaultFlags;
0042 
0043 static QUrl makeURL(const QString &urlArg)
0044 {
0045     return QUrl::fromUserInput(urlArg, QDir::currentPath());
0046 }
0047 
0048 static QList<QUrl> makeUrls(const QStringList &urlArgs)
0049 {
0050     QList<QUrl> ret;
0051     for (const QString &url : urlArgs) {
0052         ret += makeURL(url);
0053     }
0054     return ret;
0055 }
0056 
0057 #ifdef KIOCLIENT_AS_KIOCLIENT
0058 static void usage()
0059 {
0060     puts(i18n("\nSyntax:\n").toLocal8Bit().constData());
0061     puts(i18nc("The argument is the command \"kioclient openProperties\"",
0062                "  %1 'url'\n"
0063                "            # Opens a properties dialog of 'url'\n\n",
0064                "kioclient openProperties")
0065              .toLocal8Bit()
0066              .constData());
0067 
0068     puts(i18nc("The argument is the command \"kioclient exec\"",
0069                "  %1 'url' ['mimetype']\n"
0070                "            # Tries to open the document pointed to by 'url', in the application\n"
0071                "            # associated with it in KDE. You may omit 'mimetype'.\n"
0072                "            # In that case the mimetype is determined automatically.\n"
0073                "            # 'url' can be the URL of a document, a *.desktop file,\n"
0074                "            # or an executable.\n",
0075                "kioclient exec")
0076              .toLocal8Bit()
0077              .constData());
0078 
0079     puts(i18nc("The argument is the command \"kioclient move\"",
0080                "  %1 'src' 'dest'\n"
0081                "            # Moves the URL 'src' to 'dest'.\n"
0082                "            #   'src' may be a list of URLs.\n"
0083                "            #   'dest' may be \"trash:/\" to move the files to the trash.\n"
0084                "            #   The short version 'kioclient mv' is also available.\n\n",
0085                "kioclient move")
0086              .toLocal8Bit()
0087              .constData());
0088 
0089     puts(i18nc("The argument is the command \"kioclient download\"",
0090                "  %1 ['src']\n"
0091                "            # Copies the URL 'src' to a user-specified location.\n"
0092                "            #   'src' may be a list of URLs, if not present then\n"
0093                "            #   a URL will be requested.\n\n",
0094                "kioclient download")
0095              .toLocal8Bit()
0096              .constData());
0097 
0098     puts(i18nc("The argument is the command \"kioclient copy\"",
0099                "  %1 'src' 'dest'\n"
0100                "            # Copies the URL 'src' to 'dest'.\n"
0101                "            #   'src' may be a list of URLs.\n"
0102                "            #   The short version 'kioclient cp' is also available.\n\n",
0103                "kioclient copy")
0104              .toLocal8Bit()
0105              .constData());
0106 
0107     puts(i18nc("The argument is the command \"kioclient cat\"",
0108                "  %1 'url'\n"
0109                "            # Prints the contents of the file 'url' to the standard output\n\n",
0110                "kioclient cat")
0111              .toLocal8Bit()
0112              .constData());
0113 
0114     puts(i18nc("The argument is the command \"kioclient ls\"",
0115                "  %1 'url'\n"
0116                "            # Lists the contents of the directory 'url' to stdout\n\n",
0117                "kioclient ls")
0118              .toLocal8Bit()
0119              .constData());
0120 
0121     puts(i18nc("The argument is the command \"kioclient remove\"",
0122                "  %1 'url'\n"
0123                "            # Removes the URL\n"
0124                "            #   'url' may be a list of URLs.\n"
0125                "            #   The short version 'kioclient rm' is also available.\n\n",
0126                "kioclient remove")
0127              .toLocal8Bit()
0128              .constData());
0129 
0130     puts(i18nc("The argument is the command \"kioclient stat\"",
0131                "  %1 'url'\n"
0132                "            # Shows all of the available information for 'url'\n\n",
0133                "kioclient stat")
0134              .toLocal8Bit()
0135              .constData());
0136 
0137     puts(i18nc("The argument is the command \"kioclient appmenu\"",
0138                "  %1\n"
0139                "            # Opens a basic application launcher\n\n",
0140                "kioclient appmenu")
0141              .toLocal8Bit()
0142              .constData());
0143 
0144     puts(i18n("*** Examples:\n").toLocal8Bit().constData());
0145     puts(i18n("  kioclient exec file:/home/weis/data/test.html\n"
0146               "             // Opens the file with the default application associated\n"
0147               "             // with this MimeType\n\n")
0148              .toLocal8Bit()
0149              .constData());
0150     puts(i18n("  kioclient exec ftp://localhost/\n"
0151               "             // Opens URL with the default handler for ftp:// scheme\n\n")
0152              .toLocal8Bit()
0153              .constData());
0154     puts(i18n("  kioclient exec file:/root/Desktop/emacs.desktop\n"
0155               "             // Starts emacs\n\n")
0156              .toLocal8Bit()
0157              .constData());
0158     puts(i18n("  kioclient exec .\n"
0159               "             // Opens the current directory in the default\n"
0160               "             // file manager. Very convenient.\n\n")
0161              .toLocal8Bit()
0162              .constData());
0163 }
0164 #endif
0165 
0166 int main(int argc, char **argv)
0167 {
0168 #ifdef KIOCORE_ONLY
0169     QCoreApplication app(argc, argv);
0170 #else
0171     QApplication app(argc, argv);
0172 #endif
0173 
0174     KLocalizedString::setApplicationDomain("kioclient");
0175 
0176     QString appName = QStringLiteral("kioclient");
0177     QString programName = i18n("KIO Client");
0178     QString description = i18n("Command-line tool for network-transparent operations");
0179     QString version = QLatin1String(PROJECT_VERSION);
0180     KAboutData data(appName, programName, version, description, KAboutLicense::LGPL_V2);
0181     KAboutData::setApplicationData(data);
0182 
0183     QCommandLineParser parser;
0184     data.setupCommandLine(&parser);
0185     parser.addOption(QCommandLineOption(QStringLiteral("interactive"), i18n("Use message boxes and other native notifications")));
0186 
0187     parser.addOption(QCommandLineOption(QStringLiteral("noninteractive"),
0188                                         i18n("Non-interactive use: no message boxes. If you don't want a "
0189                                              "graphical connection, use --platform offscreen")));
0190 
0191 #if !defined(KIOCLIENT_AS_KDEOPEN)
0192     parser.addOption(QCommandLineOption(QStringLiteral("overwrite"), i18n("Overwrite destination if it exists (for copy and move)")));
0193 #endif
0194 
0195 #if defined(KIOCLIENT_AS_KDEOPEN)
0196     parser.addPositionalArgument(QStringLiteral("url"), i18n("file or URL"), i18n("urls..."));
0197 #elif defined(KIOCLIENT_AS_KDECP)
0198     parser.addPositionalArgument(QStringLiteral("src"), i18n("Source URL or URLs"), i18n("urls..."));
0199     parser.addPositionalArgument(QStringLiteral("dest"), i18n("Destination URL"), i18n("url"));
0200 #elif defined(KIOCLIENT_AS_KDEMV)
0201     parser.addPositionalArgument(QStringLiteral("src"), i18n("Source URL or URLs"), i18n("urls..."));
0202     parser.addPositionalArgument(QStringLiteral("dest"), i18n("Destination URL"), i18n("url"));
0203 #elif defined(KIOCLIENT_AS_KIOCLIENT)
0204     parser.addOption(QCommandLineOption(QStringLiteral("commands"), i18n("Show available commands")));
0205     parser.addPositionalArgument(QStringLiteral("command"), i18n("Command (see --commands)"), i18n("command"));
0206     parser.addPositionalArgument(QStringLiteral("URLs"), i18n("Arguments for command"), i18n("urls..."));
0207 #endif
0208 
0209     //   KCmdLineArgs::addTempFileOption();
0210 
0211     parser.process(app);
0212     data.processCommandLine(&parser);
0213 
0214 #ifdef KIOCLIENT_AS_KIOCLIENT
0215     if (argc == 1 || parser.isSet(QStringLiteral("commands"))) {
0216         puts(parser.helpText().toLocal8Bit().constData());
0217         puts("\n\n");
0218         usage();
0219         return 0;
0220     }
0221 #endif
0222 
0223     ClientApp client;
0224     return client.doIt(parser) ? 0 /*no error*/ : 1 /*error*/;
0225 }
0226 
0227 static void checkArgumentCount(int count, int min, int max)
0228 {
0229     if (count < min) {
0230         fputs(i18nc("@info:shell", "%1: Syntax error, not enough arguments\n", qAppName()).toLocal8Bit().constData(), stderr);
0231         ::exit(1);
0232     }
0233     if (max && (count > max)) {
0234         fputs(i18nc("@info:shell", "%1: Syntax error, too many arguments\n", qAppName()).toLocal8Bit().constData(), stderr);
0235         ::exit(1);
0236     }
0237 }
0238 
0239 #ifndef KIOCORE_ONLY
0240 bool ClientApp::kde_open(const QString &url, const QString &mimeType, bool allowExec)
0241 {
0242     UrlInfo info(url);
0243 
0244     if (!info.atStart()) {
0245         QUrlQuery q;
0246         q.addQueryItem(QStringLiteral("line"), QString::number(info.line));
0247         q.addQueryItem(QStringLiteral("column"), QString::number(info.column));
0248         info.url.setQuery(q);
0249     }
0250 
0251     auto *job = new KIO::OpenUrlJob(info.url, mimeType);
0252 #if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0)
0253     job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, nullptr));
0254 #else
0255     job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, nullptr));
0256 #endif
0257     job->setRunExecutables(allowExec);
0258     job->setFollowRedirections(false);
0259     bool job_had_error = false;
0260     QObject::connect(job, &KJob::result, this, [&](KJob *job) {
0261         if (job->error()) {
0262             job_had_error = true;
0263         }
0264     });
0265     job->start();
0266     qApp->exec();
0267     return !job_had_error;
0268 }
0269 #endif
0270 
0271 bool ClientApp::doCopy(const QStringList &urls)
0272 {
0273     QList<QUrl> srcLst(makeUrls(urls));
0274     QUrl dest = srcLst.takeLast();
0275     KIO::Job *job = KIO::copy(srcLst, dest, s_jobFlags);
0276     if (!s_interactive) {
0277         job->setUiDelegate(nullptr);
0278         job->setUiDelegateExtension(nullptr);
0279     }
0280     connect(job, &KJob::result, this, &ClientApp::slotResult);
0281     qApp->exec();
0282     return m_ok;
0283 }
0284 
0285 void ClientApp::slotEntries(KIO::Job *, const KIO::UDSEntryList &list)
0286 {
0287     for (const auto &entry : list) {
0288         // For each file...
0289         std::cout << qPrintable(entry.stringValue(KIO::UDSEntry::UDS_NAME)) << '\n';
0290     }
0291 
0292     std::cout << std::endl;
0293 }
0294 
0295 bool ClientApp::doList(const QStringList &urls)
0296 {
0297     const QUrl dir = makeURL(urls.at(0));
0298 
0299     KIO::ListJob *job = KIO::listDir(dir, KIO::HideProgressInfo);
0300     if (!s_interactive) {
0301         job->setUiDelegate(nullptr);
0302         job->setUiDelegateExtension(nullptr);
0303     }
0304 
0305     connect(job, &KIO::ListJob::entries, this, &ClientApp::slotEntries);
0306     connect(job, &KJob::result, this, &ClientApp::slotResult);
0307 
0308     qApp->exec();
0309     return m_ok;
0310 }
0311 
0312 bool ClientApp::doMove(const QStringList &urls)
0313 {
0314     QList<QUrl> srcLst(makeUrls(urls));
0315     const QUrl dest = srcLst.takeLast();
0316 
0317     KIO::Job *job = KIO::move(srcLst, dest, s_jobFlags);
0318     if (!s_interactive) {
0319         job->setUiDelegate(nullptr);
0320         job->setUiDelegateExtension(nullptr);
0321     }
0322 
0323     connect(job, &KJob::result, this, &ClientApp::slotResult);
0324 
0325     qApp->exec();
0326     return m_ok;
0327 }
0328 
0329 bool ClientApp::doRemove(const QStringList &urls)
0330 {
0331     KIO::Job *job = KIO::del(makeUrls(urls), s_jobFlags);
0332     if (!s_interactive) {
0333         job->setUiDelegate(nullptr);
0334         job->setUiDelegateExtension(nullptr);
0335     }
0336 
0337     connect(job, &KJob::result, this, &ClientApp::slotResult);
0338 
0339     qApp->exec();
0340     return m_ok;
0341 }
0342 
0343 bool ClientApp::doStat(const QStringList &urls)
0344 {
0345     KIO::Job *job = KIO::statDetails(makeURL(urls.first()),
0346                                      KIO::StatJob::SourceSide,
0347                                      (KIO::StatBasic | KIO::StatUser | KIO::StatTime | KIO::StatInode | KIO::StatMimeType | KIO::StatAcl),
0348                                      s_jobFlags);
0349     if (!s_interactive) {
0350         job->setUiDelegate(nullptr);
0351         job->setUiDelegateExtension(nullptr);
0352     }
0353 
0354     connect(job, &KJob::result, this, &ClientApp::slotStatResult);
0355 
0356     qApp->exec();
0357     return m_ok;
0358 }
0359 
0360 bool ClientApp::doIt(const QCommandLineParser &parser)
0361 {
0362     const int argc = parser.positionalArguments().count();
0363     checkArgumentCount(argc, 1, 0);
0364 
0365     if (parser.isSet(QStringLiteral("interactive"))) {
0366         s_interactive = true;
0367     } else {
0368         // "noninteractive" is currently the default mode, so we don't check.
0369         // The argument still needs to exist for compatibility
0370         s_interactive = false;
0371         s_jobFlags = KIO::HideProgressInfo;
0372     }
0373 #if !defined(KIOCLIENT_AS_KDEOPEN)
0374     if (parser.isSet(QStringLiteral("overwrite"))) {
0375         s_jobFlags |= KIO::Overwrite;
0376     }
0377 #endif
0378 
0379 #ifdef KIOCLIENT_AS_KDEOPEN
0380     return kde_open(parser.positionalArguments().at(0), QString(), false);
0381 #elif defined(KIOCLIENT_AS_KDECP)
0382     checkArgumentCount(argc, 2, 0);
0383     return doCopy(parser.positionalArguments());
0384 #elif defined(KIOCLIENT_AS_KDEMV)
0385     checkArgumentCount(argc, 2, 0);
0386     return doMove(parser.positionalArguments());
0387 #else
0388     // Normal kioclient mode
0389     const QString command = parser.positionalArguments().at(0);
0390 #ifndef KIOCORE_ONLY
0391     if (command == QLatin1String("openProperties")) {
0392         checkArgumentCount(argc, 2, 2); // openProperties <url>
0393         const QUrl url = makeURL(parser.positionalArguments().constLast());
0394 
0395         KPropertiesDialog *dlg = new KPropertiesDialog(url, nullptr /*no parent*/);
0396         QObject::connect(dlg, &QObject::destroyed, qApp, &QCoreApplication::quit);
0397         QObject::connect(dlg, &KPropertiesDialog::canceled, this, &ClientApp::slotDialogCanceled);
0398         dlg->show();
0399 
0400         qApp->exec();
0401         return m_ok;
0402     } else
0403 #endif
0404         if (command == QLatin1String("cat")) {
0405         checkArgumentCount(argc, 2, 2); // cat <url>
0406         const QUrl url = makeURL(parser.positionalArguments().constLast());
0407 
0408         KIO::TransferJob *job = KIO::get(url, KIO::NoReload, s_jobFlags);
0409         if (!s_interactive) {
0410             job->setUiDelegate(nullptr);
0411             job->setUiDelegateExtension(nullptr);
0412         }
0413         connect(job, &KIO::TransferJob::data, this, &ClientApp::slotPrintData);
0414         connect(job, &KJob::result, this, &ClientApp::slotResult);
0415 
0416         qApp->exec();
0417         return m_ok;
0418     }
0419 #ifndef KIOCORE_ONLY
0420     else if (command == QLatin1String("exec")) {
0421         checkArgumentCount(argc, 2, 3);
0422         return kde_open(parser.positionalArguments().at(1), argc == 3 ? parser.positionalArguments().constLast() : QString(), true);
0423     } else if (command == QLatin1String("appmenu")) {
0424         auto *job = new KIO::ApplicationLauncherJob();
0425 #if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0)
0426         job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, nullptr));
0427 #else
0428         job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, nullptr));
0429 #endif
0430         connect(job, &KJob::result, this, &ClientApp::slotResult);
0431         job->start();
0432 
0433         qApp->exec();
0434         return m_ok;
0435     }
0436 #endif
0437     else if (command == QLatin1String("download")) {
0438         checkArgumentCount(argc, 0, 0);
0439         QStringList args = parser.positionalArguments();
0440         args.removeFirst();
0441         const QList<QUrl> srcLst = makeUrls(args);
0442 
0443         if (srcLst.isEmpty()) {
0444             return m_ok;
0445         }
0446 
0447         const QUrl dsturl = QFileDialog::getSaveFileUrl(nullptr, i18n("Destination where to download the files"), srcLst.at(0));
0448 
0449         if (dsturl.isEmpty()) { // canceled
0450             return m_ok; // AK - really okay?
0451         }
0452 
0453         KIO::Job *job = KIO::copy(srcLst, dsturl, s_jobFlags);
0454         if (!s_interactive) {
0455             job->setUiDelegate(nullptr);
0456             job->setUiDelegateExtension(nullptr);
0457         }
0458 
0459         connect(job, &KJob::result, this, &ClientApp::slotResult);
0460 
0461         qApp->exec();
0462         return m_ok;
0463     } else if (command == QLatin1String("copy") || command == QLatin1String("cp")) {
0464         checkArgumentCount(argc, 3, 0); // cp <src> <dest>
0465         QStringList args = parser.positionalArguments();
0466         args.removeFirst();
0467         return doCopy(args);
0468     } else if (command == QLatin1String("move") || command == QLatin1String("mv")) {
0469         checkArgumentCount(argc, 3, 0); // mv <src> <dest>
0470         QStringList args = parser.positionalArguments();
0471         args.removeFirst();
0472         return doMove(args);
0473     } else if (command == QLatin1String("list") || command == QLatin1String("ls")) {
0474         checkArgumentCount(argc, 2, 2); // ls <url>
0475         QStringList args = parser.positionalArguments();
0476         args.removeFirst();
0477         return doList(args);
0478     } else if (command == QLatin1String("remove") || command == QLatin1String("rm")) {
0479         checkArgumentCount(argc, 2, 0); // rm <url>
0480         QStringList args = parser.positionalArguments();
0481         args.removeFirst();
0482         return doRemove(args);
0483     } else if (command == QLatin1String("stat")) {
0484         checkArgumentCount(argc, 2, 2); // stat <url>
0485         QStringList args = parser.positionalArguments();
0486         args.removeFirst();
0487         return doStat(args);
0488     } else {
0489         fputs(i18nc("@info:shell", "%1: Syntax error, unknown command '%2'\n", qAppName(), command).toLocal8Bit().data(), stderr);
0490         return false;
0491     }
0492     Q_UNREACHABLE();
0493 #endif
0494 }
0495 
0496 void ClientApp::slotResult(KJob *job)
0497 {
0498     if (job->error()) {
0499 #ifndef KIOCORE_ONLY
0500         if (s_interactive) {
0501             static_cast<KIO::Job *>(job)->uiDelegate()->showErrorMessage();
0502         } else
0503 #endif
0504         {
0505             fputs(qPrintable(i18nc("@info:shell", "%1: %2\n", qAppName(), job->errorString())), stderr);
0506         }
0507     }
0508     m_ok = !job->error();
0509     if (qApp->topLevelWindows().isEmpty()) {
0510         qApp->quit();
0511     } else {
0512         qApp->setQuitOnLastWindowClosed(true);
0513     }
0514 }
0515 
0516 void ClientApp::slotDialogCanceled()
0517 {
0518     m_ok = false;
0519     qApp->quit();
0520 }
0521 
0522 void ClientApp::slotPrintData(KIO::Job *, const QByteArray &data)
0523 {
0524     if (!data.isEmpty()) {
0525         std::cout.write(data.constData(), data.size());
0526     }
0527 }
0528 
0529 static void showStatField(const KIO::UDSEntry &entry, uint field, const char *name)
0530 {
0531     if (!entry.contains(field))
0532         return;
0533     std::cout << qPrintable(QString::fromLocal8Bit(name).leftJustified(20, ' ')) << "  ";
0534 
0535     if (field == KIO::UDSEntry::UDS_ACCESS) {
0536         std::cout << qPrintable(QString("0%1").arg(entry.numberValue(field), 3, 8, QLatin1Char('0')));
0537     } else if (field == KIO::UDSEntry::UDS_FILE_TYPE) {
0538         std::cout << qPrintable(QString("0%1").arg((entry.numberValue(field) & S_IFMT), 6, 8, QLatin1Char('0')));
0539     } else if (field & KIO::UDSEntry::UDS_STRING) {
0540         std::cout << qPrintable(entry.stringValue(field));
0541     } else if ((field & KIO::UDSEntry::UDS_TIME) == KIO::UDSEntry::UDS_TIME) {
0542         // The previous comparison is necessary because the value
0543         // of UDS_TIME is 0x04000000|UDS_NUMBER which is 0x06000000.
0544         // So simply testing with (field & KIO::UDSEntry::UDS_TIME)
0545         // would be true for both UDS_TIME and UDS_NUMBER fields.
0546         // The same would happen if UDS_NUMBER were tested first.
0547         const QDateTime dt = QDateTime::fromSecsSinceEpoch(entry.numberValue(field));
0548         if (dt.isValid())
0549             std::cout << qPrintable(dt.toString(Qt::TextDate));
0550     } else if (field & KIO::UDSEntry::UDS_NUMBER) {
0551         std::cout << entry.numberValue(field);
0552     }
0553     std::cout << std::endl;
0554 }
0555 
0556 void ClientApp::slotStatResult(KJob *job)
0557 {
0558     if (!job->error()) {
0559         KIO::StatJob *statJob = qobject_cast<KIO::StatJob *>(job);
0560         Q_ASSERT(statJob != nullptr);
0561         const KIO::UDSEntry &result = statJob->statResult();
0562 
0563         showStatField(result, KIO::UDSEntry::UDS_NAME, "NAME");
0564         showStatField(result, KIO::UDSEntry::UDS_DISPLAY_NAME, "DISPLAY_NAME");
0565         showStatField(result, KIO::UDSEntry::UDS_COMMENT, "COMMENT");
0566         showStatField(result, KIO::UDSEntry::UDS_SIZE, "SIZE");
0567         // This is not requested for the StatJob, so should never be seen
0568         showStatField(result, KIO::UDSEntry::UDS_RECURSIVE_SIZE, "RECURSIVE_SIZE");
0569 
0570         showStatField(result, KIO::UDSEntry::UDS_FILE_TYPE, "FILE_TYPE");
0571         showStatField(result, KIO::UDSEntry::UDS_USER, "USER");
0572         showStatField(result, KIO::UDSEntry::UDS_GROUP, "GROUP");
0573         showStatField(result, KIO::UDSEntry::UDS_HIDDEN, "HIDDEN");
0574         showStatField(result, KIO::UDSEntry::UDS_DEVICE_ID, "DEVICE_ID");
0575         showStatField(result, KIO::UDSEntry::UDS_INODE, "INODE");
0576 
0577         showStatField(result, KIO::UDSEntry::UDS_LINK_DEST, "LINK_DEST");
0578         showStatField(result, KIO::UDSEntry::UDS_URL, "URL");
0579         showStatField(result, KIO::UDSEntry::UDS_LOCAL_PATH, "LOCAL_PATH");
0580         showStatField(result, KIO::UDSEntry::UDS_TARGET_URL, "TARGET_URL");
0581 
0582         showStatField(result, KIO::UDSEntry::UDS_MIME_TYPE, "MIME_TYPE");
0583         showStatField(result, KIO::UDSEntry::UDS_GUESSED_MIME_TYPE, "GUESSED_MIME_TYPE");
0584 
0585         showStatField(result, KIO::UDSEntry::UDS_ICON_NAME, "ICON_NAME");
0586         showStatField(result, KIO::UDSEntry::UDS_ICON_OVERLAY_NAMES, "ICON_OVERLAY_NAMES");
0587 
0588         showStatField(result, KIO::UDSEntry::UDS_ACCESS, "ACCESS");
0589         showStatField(result, KIO::UDSEntry::UDS_EXTENDED_ACL, "EXTENDED_ACL");
0590         showStatField(result, KIO::UDSEntry::UDS_ACL_STRING, "ACL_STRING");
0591         showStatField(result, KIO::UDSEntry::UDS_DEFAULT_ACL_STRING, "DEFAULT_ACL_STRING");
0592 
0593         showStatField(result, KIO::UDSEntry::UDS_MODIFICATION_TIME, "MODIFICATION_TIME");
0594         showStatField(result, KIO::UDSEntry::UDS_ACCESS_TIME, "ACCESS_TIME");
0595         showStatField(result, KIO::UDSEntry::UDS_CREATION_TIME, "CREATION_TIME");
0596 
0597         showStatField(result, KIO::UDSEntry::UDS_XML_PROPERTIES, "XML_PROPERTIES");
0598         showStatField(result, KIO::UDSEntry::UDS_DISPLAY_TYPE, "DISPLAY_TYPE");
0599     }
0600 
0601     slotResult(job);
0602 }
0603 
0604 ClientApp::ClientApp()
0605     : QObject()
0606 {
0607 }