File indexing completed on 2024-04-28 05:27:05

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