1 /*
2     SPDX-FileCopyrightText: %{CURRENT_YEAR} %{AUTHOR} <%{EMAIL}>
3 
4     SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6 
7 #include "%{APPNAMELC}.h"
8 
9 #include "%{APPNAMELC}_log.h"
10 #include "mydatasystem.h"
11 // KF
12 #include <KIO/UDSEntry>
13 #include <KLocalizedString>
14 // Qt
15 #include <QCoreApplication>
16 
17 // Pseudo plugin class to embed meta data
18 class KIOPluginForMetaData : public QObject
19 {
20     Q_OBJECT
21     Q_PLUGIN_METADATA(IID "org.kde.kio.slave.myproto" FILE "myproto.json")
22 };
23 
24 extern "C" {
25 int Q_DECL_EXPORT kdemain(int argc, char **argv);
26 }
27 
kdemain(int argc,char ** argv)28 int kdemain(int argc, char **argv)
29 {
30     QCoreApplication app(argc, argv);
31     app.setApplicationName(QStringLiteral("%{APPNAME}"));
32 
33     %{APPNAME} slave(argv[2], argv[3]);
34     slave.dispatchLoop();
35 
36     return 0;
37 }
38 
39 // utils methods to map our data into KIO data
40 namespace
41 {
42 
groupPath(const QUrl & url)43 QStringList groupPath(const QUrl &url)
44 {
45     QString path = url.adjusted(QUrl::StripTrailingSlash).path();
46     if (path.startsWith(QLatin1Char('/'))) {
47         path.remove(0, 1);
48     }
49     return path.isEmpty() ? QStringList() : path.split(QLatin1Char('/'));
50 }
51 
fileEntry(const DataItem & item)52 KIO::UDSEntry fileEntry(const DataItem &item)
53 {
54     KIO::UDSEntry entry;
55     entry.reserve(5);
56     entry.fastInsert(KIO::UDSEntry::UDS_NAME, item.name);
57     entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("text/plain"));
58     entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
59     entry.fastInsert(KIO::UDSEntry::UDS_SIZE, item.data().size());
60     entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH);
61     return entry;
62 }
63 
dirEntry(const QString & name)64 KIO::UDSEntry dirEntry(const QString &name)
65 {
66     KIO::UDSEntry entry;
67 
68     entry.reserve(4);
69     entry.fastInsert(KIO::UDSEntry::UDS_NAME, name);
70     entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("inode/directory"));
71     entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
72     entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH);
73 
74     return entry;
75 }
76 
77 }
78 
79 %{APPNAME}::%{APPNAME}(const QByteArray &pool_socket, const QByteArray &app_socket)
80     : KIO::SlaveBase("myproto", pool_socket, app_socket)
81     , m_dataSystem(new MyDataSystem)
82 {
83     qCDebug(%{APPNAMEUC}_LOG) << "%{APPNAME} starting up";
84 }
85 
86 %{APPNAME}::~%{APPNAME}()
87 {
88     qCDebug(%{APPNAMEUC}_LOG) << "%{APPNAME} shutting down";
89 }
90 
91 
get(const QUrl & url)92 void %{APPNAME}::get(const QUrl &url)
93 {
94     qCDebug(%{APPNAMEUC}_LOG) << "%{APPNAME} starting get" << url;
95 
96     QStringList groupPath = ::groupPath(url);
97     const QString itemName = groupPath.takeLast();
98     const DataItem item = m_dataSystem->item(groupPath, itemName);
99     if (!item.isValid()) {
100         groupPath.append(itemName);
101         if (m_dataSystem->hasGroup(groupPath)) {
102             error(KIO::ERR_IS_DIRECTORY, itemName);
103         } else {
104         }
105             error(KIO::ERR_DOES_NOT_EXIST, itemName);
106         return;
107     }
108 
109     // as first notify about the MIME type, so the handler can be selected
110     mimeType("text/plain");
111 
112     // now emit the data...
113     data(item.data());
114 
115     // and we are done
116     finished();
117 }
118 
stat(const QUrl & url)119 void %{APPNAME}::stat(const QUrl &url)
120 {
121     qCDebug(%{APPNAMEUC}_LOG) << "%{APPNAME} starting stat" << url;
122 
123     QStringList groupPath = ::groupPath(url);
124 
125     // is root directory?
126     if (groupPath.isEmpty()) {
127         statEntry(dirEntry(QStringLiteral(".")));
128         finished();
129         return;
130     }
131     // test subgroup
132     if (m_dataSystem->hasGroup(groupPath)) {
133         statEntry(dirEntry(groupPath.last()));
134         finished();
135         return;
136     }
137 
138     // test item
139     const QString itemName = groupPath.takeLast();
140     const DataItem item = m_dataSystem->item(groupPath, itemName);
141     if (item.isValid()) {
142         statEntry(fileEntry(item));
143         finished();
144         return;
145     }
146 
147     error(KIO::ERR_DOES_NOT_EXIST, i18n("No such path."));
148 }
149 
listDir(const QUrl & url)150 void %{APPNAME}::listDir(const QUrl &url)
151 {
152     const QStringList groupPath = ::groupPath(url);
153     qCDebug(%{APPNAMEUC}_LOG) << "%{APPNAME} starting listDir" << url << groupPath;
154 
155     if (!m_dataSystem->hasGroup(groupPath)) {
156         error(KIO::ERR_DOES_NOT_EXIST, i18n("No such directory."));
157         return;
158     }
159 
160     const QStringList subGroupNames = m_dataSystem->subGroupNames(groupPath);
161     const QList<DataItem> items = m_dataSystem->items(groupPath);
162 
163     // report number of expected entries
164     totalSize(1 + subGroupNames.size() + items.size());
165     // own dir
166     listEntry(dirEntry(QStringLiteral(".")));
167     // subdirs
168     for (const QString &subGroupName : subGroupNames) {
169         listEntry(dirEntry(subGroupName));
170     }
171     // files
172     for (const auto &item : items) {
173         listEntry(fileEntry(item));
174     }
175     finished();
176 }
177