1 | /* |
2 | This file is part of the KDE libraries |
3 | SPDX-FileCopyrightText: 2000 Yves Arrouye <yves@realnames.com> |
4 | SPDX-FileCopyrightText: 2000, 2010 Dawit Alemayehu <adawit at kde.org> |
5 | |
6 | SPDX-License-Identifier: LGPL-2.0-or-later |
7 | */ |
8 | |
9 | #include "kurifilter.h" |
10 | #include "kurifilterdata_p.h" |
11 | |
12 | #include <KService> |
13 | #include <kio/global.h> |
14 | |
15 | #include <KPluginFactory> |
16 | #include <KPluginMetaData> |
17 | |
18 | #include <QHashIterator> |
19 | #include <QHostAddress> |
20 | #include <QHostInfo> |
21 | #include <QIcon> |
22 | |
23 | #include "kurifilterplugin_p.h" |
24 | |
25 | QString KUriFilterDataPrivate::lookupIconNameFor(const QUrl &url, KUriFilterData::UriTypes type) |
26 | { |
27 | QString iconName; |
28 | |
29 | switch (type) { |
30 | case KUriFilterData::NetProtocol: |
31 | iconName = KIO::iconNameForUrl(url); |
32 | break; |
33 | case KUriFilterData::Executable: { |
34 | QString exeName = url.path(); |
35 | exeName.remove(i: 0, len: exeName.lastIndexOf(c: QLatin1Char('/')) + 1); // strip path if given |
36 | KService::Ptr service = KService::serviceByDesktopName(name: exeName); |
37 | if (service && service->icon() != QLatin1String("unknown" )) { |
38 | iconName = service->icon(); |
39 | } |
40 | // Try to find an icon with the same name as the binary (useful for non-kde apps) |
41 | else if (!QIcon::fromTheme(name: exeName).isNull()) { |
42 | iconName = exeName; |
43 | } else { |
44 | // not found, use default |
45 | iconName = QStringLiteral("system-run" ); |
46 | } |
47 | break; |
48 | } |
49 | case KUriFilterData::Help: { |
50 | iconName = QStringLiteral("khelpcenter" ); |
51 | break; |
52 | } |
53 | case KUriFilterData::Shell: { |
54 | iconName = QStringLiteral("konsole" ); |
55 | break; |
56 | } |
57 | case KUriFilterData::Error: |
58 | case KUriFilterData::Blocked: { |
59 | iconName = QStringLiteral("error" ); |
60 | break; |
61 | } |
62 | default: |
63 | break; |
64 | } |
65 | |
66 | return iconName; |
67 | } |
68 | |
69 | class Q_DECL_HIDDEN KUriFilterSearchProvider::KUriFilterSearchProviderPrivate |
70 | { |
71 | public: |
72 | KUriFilterSearchProviderPrivate() |
73 | { |
74 | } |
75 | KUriFilterSearchProviderPrivate(const KUriFilterSearchProviderPrivate &other) |
76 | : desktopEntryName(other.desktopEntryName) |
77 | , iconName(other.iconName) |
78 | , name(other.name) |
79 | , keys(other.keys) |
80 | { |
81 | } |
82 | |
83 | QString desktopEntryName; |
84 | QString iconName; |
85 | QString name; |
86 | QStringList keys; |
87 | }; |
88 | |
89 | KUriFilterSearchProvider::KUriFilterSearchProvider() |
90 | : d(new KUriFilterSearchProvider::KUriFilterSearchProviderPrivate) |
91 | { |
92 | } |
93 | |
94 | KUriFilterSearchProvider::KUriFilterSearchProvider(const KUriFilterSearchProvider &other) |
95 | : d(new KUriFilterSearchProvider::KUriFilterSearchProviderPrivate(*(other.d))) |
96 | { |
97 | } |
98 | |
99 | KUriFilterSearchProvider::~KUriFilterSearchProvider() = default; |
100 | |
101 | QString KUriFilterSearchProvider::desktopEntryName() const |
102 | { |
103 | return d->desktopEntryName; |
104 | } |
105 | |
106 | QString KUriFilterSearchProvider::iconName() const |
107 | { |
108 | return d->iconName; |
109 | } |
110 | |
111 | QString KUriFilterSearchProvider::name() const |
112 | { |
113 | return d->name; |
114 | } |
115 | |
116 | QStringList KUriFilterSearchProvider::keys() const |
117 | { |
118 | return d->keys; |
119 | } |
120 | |
121 | QString KUriFilterSearchProvider::defaultKey() const |
122 | { |
123 | if (d->keys.isEmpty()) { |
124 | return QString(); |
125 | } |
126 | |
127 | return d->keys.first(); |
128 | } |
129 | |
130 | KUriFilterSearchProvider &KUriFilterSearchProvider::operator=(const KUriFilterSearchProvider &other) |
131 | { |
132 | d->desktopEntryName = other.d->desktopEntryName; |
133 | d->iconName = other.d->iconName; |
134 | d->keys = other.d->keys; |
135 | d->name = other.d->name; |
136 | return *this; |
137 | } |
138 | |
139 | void KUriFilterSearchProvider::setDesktopEntryName(const QString &desktopEntryName) |
140 | { |
141 | d->desktopEntryName = desktopEntryName; |
142 | } |
143 | |
144 | void KUriFilterSearchProvider::setIconName(const QString &iconName) |
145 | { |
146 | d->iconName = iconName; |
147 | } |
148 | |
149 | void KUriFilterSearchProvider::setName(const QString &name) |
150 | { |
151 | d->name = name; |
152 | } |
153 | |
154 | void KUriFilterSearchProvider::setKeys(const QStringList &keys) |
155 | { |
156 | d->keys = keys; |
157 | } |
158 | |
159 | KUriFilterData::KUriFilterData() |
160 | : d(new KUriFilterDataPrivate(QUrl(), QString())) |
161 | { |
162 | } |
163 | |
164 | KUriFilterData::KUriFilterData(const QUrl &url) |
165 | : d(new KUriFilterDataPrivate(url, url.toString())) |
166 | { |
167 | } |
168 | |
169 | KUriFilterData::KUriFilterData(const QString &url) |
170 | : d(new KUriFilterDataPrivate(QUrl::fromUserInput(userInput: url), url)) |
171 | { |
172 | } |
173 | |
174 | KUriFilterData::KUriFilterData(const KUriFilterData &other) |
175 | : d(new KUriFilterDataPrivate(*other.d)) |
176 | { |
177 | } |
178 | |
179 | KUriFilterData::~KUriFilterData() = default; |
180 | |
181 | QUrl KUriFilterData::uri() const |
182 | { |
183 | return d->url; |
184 | } |
185 | |
186 | QString KUriFilterData::errorMsg() const |
187 | { |
188 | return d->errMsg; |
189 | } |
190 | |
191 | KUriFilterData::UriTypes KUriFilterData::uriType() const |
192 | { |
193 | return d->uriType; |
194 | } |
195 | |
196 | QString KUriFilterData::absolutePath() const |
197 | { |
198 | return d->absPath; |
199 | } |
200 | |
201 | bool KUriFilterData::hasAbsolutePath() const |
202 | { |
203 | return !d->absPath.isEmpty(); |
204 | } |
205 | |
206 | QString KUriFilterData::argsAndOptions() const |
207 | { |
208 | return d->args; |
209 | } |
210 | |
211 | bool KUriFilterData::hasArgsAndOptions() const |
212 | { |
213 | return !d->args.isEmpty(); |
214 | } |
215 | |
216 | bool KUriFilterData::checkForExecutables() const |
217 | { |
218 | return d->checkForExecs; |
219 | } |
220 | |
221 | QString KUriFilterData::typedString() const |
222 | { |
223 | return d->typedString; |
224 | } |
225 | |
226 | QString KUriFilterData::searchTerm() const |
227 | { |
228 | return d->searchTerm; |
229 | } |
230 | |
231 | QChar KUriFilterData::searchTermSeparator() const |
232 | { |
233 | return d->searchTermSeparator; |
234 | } |
235 | |
236 | QString KUriFilterData::searchProvider() const |
237 | { |
238 | return d->searchProvider; |
239 | } |
240 | |
241 | QStringList KUriFilterData::preferredSearchProviders() const |
242 | { |
243 | return d->searchProviderList; |
244 | } |
245 | |
246 | KUriFilterSearchProvider KUriFilterData::queryForSearchProvider(const QString &provider) const |
247 | { |
248 | const KUriFilterSearchProvider *searchProvider = d->searchProviderMap.value(key: provider); |
249 | |
250 | if (searchProvider) { |
251 | return *(searchProvider); |
252 | } |
253 | |
254 | return KUriFilterSearchProvider(); |
255 | } |
256 | |
257 | QString KUriFilterData::queryForPreferredSearchProvider(const QString &provider) const |
258 | { |
259 | const KUriFilterSearchProvider *searchProvider = d->searchProviderMap.value(key: provider); |
260 | if (searchProvider) { |
261 | return (searchProvider->defaultKey() % searchTermSeparator() % searchTerm()); |
262 | } |
263 | return QString(); |
264 | } |
265 | |
266 | QStringList KUriFilterData::allQueriesForSearchProvider(const QString &provider) const |
267 | { |
268 | const KUriFilterSearchProvider *searchProvider = d->searchProviderMap.value(key: provider); |
269 | if (searchProvider) { |
270 | return searchProvider->keys(); |
271 | } |
272 | return QStringList(); |
273 | } |
274 | |
275 | QString KUriFilterData::iconNameForPreferredSearchProvider(const QString &provider) const |
276 | { |
277 | const KUriFilterSearchProvider *searchProvider = d->searchProviderMap.value(key: provider); |
278 | if (searchProvider) { |
279 | return searchProvider->iconName(); |
280 | } |
281 | return QString(); |
282 | } |
283 | |
284 | QStringList KUriFilterData::alternateSearchProviders() const |
285 | { |
286 | return d->alternateSearchProviders; |
287 | } |
288 | |
289 | QString KUriFilterData::alternateDefaultSearchProvider() const |
290 | { |
291 | return d->alternateDefaultSearchProvider; |
292 | } |
293 | |
294 | QString KUriFilterData::defaultUrlScheme() const |
295 | { |
296 | return d->defaultUrlScheme; |
297 | } |
298 | |
299 | KUriFilterData::SearchFilterOptions KUriFilterData::searchFilteringOptions() const |
300 | { |
301 | return d->searchFilterOptions; |
302 | } |
303 | |
304 | QString KUriFilterData::iconName() |
305 | { |
306 | auto foundProvider = d->searchProviderMap.constFind(key: searchProvider()); |
307 | if (foundProvider != d->searchProviderMap.cend() && !foundProvider.value()->iconName().isEmpty()) { |
308 | return foundProvider.value()->iconName(); |
309 | } |
310 | |
311 | if (d->wasModified) { |
312 | d->iconName = KUriFilterDataPrivate::lookupIconNameFor(url: d->url, type: d->uriType); |
313 | d->wasModified = false; |
314 | } |
315 | |
316 | return d->iconName; |
317 | } |
318 | |
319 | void KUriFilterData::setData(const QUrl &url) |
320 | { |
321 | d->setData(u: url, typedUrl: url.toString()); |
322 | } |
323 | |
324 | void KUriFilterData::setData(const QString &url) |
325 | { |
326 | d->setData(u: QUrl(url), typedUrl: url); |
327 | } |
328 | |
329 | bool KUriFilterData::setAbsolutePath(const QString &absPath) |
330 | { |
331 | // Since a malformed URL could possibly be a relative |
332 | // URL we tag it as a possible local resource... |
333 | if ((d->url.scheme().isEmpty() || d->url.isLocalFile())) { |
334 | d->absPath = absPath; |
335 | return true; |
336 | } |
337 | return false; |
338 | } |
339 | |
340 | void KUriFilterData::setCheckForExecutables(bool check) |
341 | { |
342 | d->checkForExecs = check; |
343 | } |
344 | |
345 | void KUriFilterData::setAlternateSearchProviders(const QStringList &providers) |
346 | { |
347 | d->alternateSearchProviders = providers; |
348 | } |
349 | |
350 | void KUriFilterData::setAlternateDefaultSearchProvider(const QString &provider) |
351 | { |
352 | d->alternateDefaultSearchProvider = provider; |
353 | } |
354 | |
355 | void KUriFilterData::setDefaultUrlScheme(const QString &scheme) |
356 | { |
357 | d->defaultUrlScheme = scheme; |
358 | } |
359 | |
360 | void KUriFilterData::setSearchFilteringOptions(SearchFilterOptions options) |
361 | { |
362 | d->searchFilterOptions = options; |
363 | } |
364 | |
365 | KUriFilterData &KUriFilterData::operator=(const QUrl &url) |
366 | { |
367 | d->setData(u: url, typedUrl: url.toString()); |
368 | return *this; |
369 | } |
370 | |
371 | KUriFilterData &KUriFilterData::operator=(const QString &url) |
372 | { |
373 | d->setData(u: QUrl(url), typedUrl: url); |
374 | return *this; |
375 | } |
376 | |
377 | /******************************* KUriFilter ******************************/ |
378 | |
379 | class KUriFilterPrivate |
380 | { |
381 | public: |
382 | KUriFilterPrivate() |
383 | { |
384 | } |
385 | ~KUriFilterPrivate() |
386 | { |
387 | qDeleteAll(c: pluginList); |
388 | pluginList.clear(); |
389 | } |
390 | QList<KUriFilterPlugin *> pluginList; |
391 | }; |
392 | |
393 | class KUriFilterSingleton |
394 | { |
395 | public: |
396 | KUriFilter instance; |
397 | }; |
398 | |
399 | Q_GLOBAL_STATIC(KUriFilterSingleton, m_self) |
400 | |
401 | KUriFilter *KUriFilter::self() |
402 | { |
403 | return &m_self()->instance; |
404 | } |
405 | |
406 | KUriFilter::KUriFilter() |
407 | : d(new KUriFilterPrivate()) |
408 | { |
409 | QList<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("kf6/urifilters" )); |
410 | const QString prefKey = QStringLiteral("X-KDE-InitialPreference" ); |
411 | // Sort the plugins by order of priority |
412 | std::sort(first: plugins.begin(), last: plugins.end(), comp: [prefKey](const KPluginMetaData &a, const KPluginMetaData &b) { |
413 | return a.value(key: prefKey, defaultValue: 0) > b.value(key: prefKey, defaultValue: 0); |
414 | }); |
415 | |
416 | for (const KPluginMetaData &pluginMetaData : std::as_const(t&: plugins)) { |
417 | if (auto plugin = KPluginFactory::instantiatePlugin<KUriFilterPlugin>(data: pluginMetaData).plugin) { |
418 | d->pluginList << plugin; |
419 | } |
420 | } |
421 | } |
422 | |
423 | KUriFilter::~KUriFilter() = default; |
424 | |
425 | bool KUriFilter::filterUri(KUriFilterData &data, const QStringList &filters) |
426 | { |
427 | bool filtered = false; |
428 | |
429 | for (KUriFilterPlugin *plugin : std::as_const(t&: d->pluginList)) { |
430 | // If no specific filters were requested, iterate through all the plugins. |
431 | // Otherwise, only use available filters. |
432 | if (filters.isEmpty() || filters.contains(str: plugin->objectName())) { |
433 | if (plugin->filterUri(data)) { |
434 | filtered = true; |
435 | } |
436 | } |
437 | } |
438 | |
439 | return filtered; |
440 | } |
441 | |
442 | bool KUriFilter::filterUri(QUrl &uri, const QStringList &filters) |
443 | { |
444 | KUriFilterData data(uri); |
445 | bool filtered = filterUri(data, filters); |
446 | if (filtered) { |
447 | uri = data.uri(); |
448 | } |
449 | return filtered; |
450 | } |
451 | |
452 | bool KUriFilter::filterUri(QString &uri, const QStringList &filters) |
453 | { |
454 | KUriFilterData data(uri); |
455 | bool filtered = filterUri(data, filters); |
456 | if (filtered) { |
457 | uri = data.uri().toString(); |
458 | } |
459 | return filtered; |
460 | } |
461 | |
462 | QUrl KUriFilter::filteredUri(const QUrl &uri, const QStringList &filters) |
463 | { |
464 | KUriFilterData data(uri); |
465 | filterUri(data, filters); |
466 | return data.uri(); |
467 | } |
468 | |
469 | QString KUriFilter::filteredUri(const QString &uri, const QStringList &filters) |
470 | { |
471 | KUriFilterData data(uri); |
472 | filterUri(data, filters); |
473 | return data.uri().toString(); |
474 | } |
475 | |
476 | bool KUriFilter::filterSearchUri(KUriFilterData &data, SearchFilterTypes types) |
477 | { |
478 | QStringList filters; |
479 | |
480 | if (types & WebShortcutFilter) { |
481 | filters << QStringLiteral("kurisearchfilter" ); |
482 | } |
483 | |
484 | if (types & NormalTextFilter) { |
485 | filters << QStringLiteral("kuriikwsfilter" ); |
486 | } |
487 | |
488 | return filterUri(data, filters); |
489 | } |
490 | |
491 | QStringList KUriFilter::pluginNames() const |
492 | { |
493 | QStringList res; |
494 | res.reserve(asize: d->pluginList.size()); |
495 | std::transform(first: d->pluginList.constBegin(), last: d->pluginList.constEnd(), result: std::back_inserter(x&: res), unary_op: [](const KUriFilterPlugin *plugin) { |
496 | return plugin->objectName(); |
497 | }); |
498 | return res; |
499 | } |
500 | |